From 2bcc3b48c8ddf2d83cf00a00c0d021970c271fff Mon Sep 17 00:00:00 2001 From: Jason Wang Date: Sat, 16 Jul 2022 20:25:43 +0800 Subject: media: imx-jpeg: Remove unnecessary memset() after dma_alloc_coherent() The `dma_alloc_coherent()' already zeroes out memory for us, so we don't need the redundant memset(). Signed-off-by: Jason Wang Signed-off-by: Hans Verkuil --- drivers/media/platform/nxp/imx-jpeg/mxc-jpeg.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/media/platform/nxp/imx-jpeg/mxc-jpeg.c b/drivers/media/platform/nxp/imx-jpeg/mxc-jpeg.c index 32fd04a3d8bb..482177ee01b6 100644 --- a/drivers/media/platform/nxp/imx-jpeg/mxc-jpeg.c +++ b/drivers/media/platform/nxp/imx-jpeg/mxc-jpeg.c @@ -519,7 +519,6 @@ static bool mxc_jpeg_alloc_slot_data(struct mxc_jpeg_dev *jpeg, GFP_ATOMIC); if (!cfg_stm) goto err; - memset(cfg_stm, 0, MXC_JPEG_MAX_CFG_STREAM); jpeg->slot_data[slot].cfg_stream_vaddr = cfg_stm; skip_alloc: -- cgit v1.2.3 From cfed9632ca8e8bdf0128745ae2400b72c4292886 Mon Sep 17 00:00:00 2001 From: Ming Qian Date: Mon, 18 Jul 2022 10:37:37 +0800 Subject: media: imx-jpeg: Add a timeout mechanism for each frame Add a timeout mechanism for each frame. If the frame can't be decoded or encoded, driver can cancel it to avoid hang. Fixes: 2db16c6ed72ce ("media: imx-jpeg: Add V4L2 driver for i.MX8 JPEG Encoder/Decoder") Signed-off-by: Ming Qian Reviewed-by: Mirela Rabulea Signed-off-by: Hans Verkuil --- drivers/media/platform/nxp/imx-jpeg/mxc-jpeg.c | 55 ++++++++++++++++++++++---- drivers/media/platform/nxp/imx-jpeg/mxc-jpeg.h | 1 + 2 files changed, 49 insertions(+), 7 deletions(-) diff --git a/drivers/media/platform/nxp/imx-jpeg/mxc-jpeg.c b/drivers/media/platform/nxp/imx-jpeg/mxc-jpeg.c index 482177ee01b6..16af887a6e3c 100644 --- a/drivers/media/platform/nxp/imx-jpeg/mxc-jpeg.c +++ b/drivers/media/platform/nxp/imx-jpeg/mxc-jpeg.c @@ -330,6 +330,10 @@ static unsigned int debug; module_param(debug, int, 0644); MODULE_PARM_DESC(debug, "Debug level (0-3)"); +static unsigned int hw_timeout = 2000; +module_param(hw_timeout, int, 0644); +MODULE_PARM_DESC(hw_timeout, "MXC JPEG hw timeout, the number of milliseconds"); + static void mxc_jpeg_bytesperline(struct mxc_jpeg_q_data *q, u32 precision); static void mxc_jpeg_sizeimage(struct mxc_jpeg_q_data *q); @@ -569,6 +573,26 @@ static void mxc_jpeg_check_and_set_last_buffer(struct mxc_jpeg_ctx *ctx, } } +static void mxc_jpeg_job_finish(struct mxc_jpeg_ctx *ctx, enum vb2_buffer_state state, bool reset) +{ + struct mxc_jpeg_dev *jpeg = ctx->mxc_jpeg; + void __iomem *reg = jpeg->base_reg; + struct vb2_v4l2_buffer *src_buf, *dst_buf; + + dst_buf = v4l2_m2m_next_dst_buf(ctx->fh.m2m_ctx); + src_buf = v4l2_m2m_next_src_buf(ctx->fh.m2m_ctx); + mxc_jpeg_check_and_set_last_buffer(ctx, src_buf, dst_buf); + v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx); + v4l2_m2m_dst_buf_remove(ctx->fh.m2m_ctx); + v4l2_m2m_buf_done(src_buf, state); + v4l2_m2m_buf_done(dst_buf, state); + + mxc_jpeg_disable_irq(reg, ctx->slot); + ctx->mxc_jpeg->slot_data[ctx->slot].used = false; + if (reset) + mxc_jpeg_sw_reset(reg); +} + static irqreturn_t mxc_jpeg_dec_irq(int irq, void *priv) { struct mxc_jpeg_dev *jpeg = priv; @@ -601,6 +625,9 @@ static irqreturn_t mxc_jpeg_dec_irq(int irq, void *priv) goto job_unlock; } + if (!jpeg->slot_data[slot].used) + goto job_unlock; + dec_ret = readl(reg + MXC_SLOT_OFFSET(slot, SLOT_STATUS)); writel(dec_ret, reg + MXC_SLOT_OFFSET(slot, SLOT_STATUS)); /* w1c */ @@ -665,14 +692,9 @@ static irqreturn_t mxc_jpeg_dec_irq(int irq, void *priv) buf_state = VB2_BUF_STATE_DONE; buffers_done: - mxc_jpeg_disable_irq(reg, ctx->slot); - jpeg->slot_data[slot].used = false; /* unused, but don't free */ - mxc_jpeg_check_and_set_last_buffer(ctx, src_buf, dst_buf); - v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx); - v4l2_m2m_dst_buf_remove(ctx->fh.m2m_ctx); - v4l2_m2m_buf_done(src_buf, buf_state); - v4l2_m2m_buf_done(dst_buf, buf_state); + mxc_jpeg_job_finish(ctx, buf_state, false); spin_unlock(&jpeg->hw_lock); + cancel_delayed_work(&ctx->task_timer); v4l2_m2m_job_finish(jpeg->m2m_dev, ctx->fh.m2m_ctx); return IRQ_HANDLED; job_unlock: @@ -1003,6 +1025,23 @@ static int mxc_jpeg_job_ready(void *priv) return ctx->source_change ? 0 : 1; } +static void mxc_jpeg_device_run_timeout(struct work_struct *work) +{ + struct delayed_work *dwork = to_delayed_work(work); + struct mxc_jpeg_ctx *ctx = container_of(dwork, struct mxc_jpeg_ctx, task_timer); + struct mxc_jpeg_dev *jpeg = ctx->mxc_jpeg; + unsigned long flags; + + spin_lock_irqsave(&ctx->mxc_jpeg->hw_lock, flags); + if (ctx->slot < MXC_MAX_SLOTS && ctx->mxc_jpeg->slot_data[ctx->slot].used) { + dev_warn(jpeg->dev, "%s timeout, cancel it\n", + ctx->mxc_jpeg->mode == MXC_JPEG_DECODE ? "decode" : "encode"); + mxc_jpeg_job_finish(ctx, VB2_BUF_STATE_ERROR, true); + v4l2_m2m_job_finish(ctx->mxc_jpeg->m2m_dev, ctx->fh.m2m_ctx); + } + spin_unlock_irqrestore(&ctx->mxc_jpeg->hw_lock, flags); +} + static void mxc_jpeg_device_run(void *priv) { struct mxc_jpeg_ctx *ctx = priv; @@ -1088,6 +1127,7 @@ static void mxc_jpeg_device_run(void *priv) &src_buf->vb2_buf, &dst_buf->vb2_buf); mxc_jpeg_dec_mode_go(dev, reg); } + schedule_delayed_work(&ctx->task_timer, msecs_to_jiffies(hw_timeout)); end: spin_unlock_irqrestore(&ctx->mxc_jpeg->hw_lock, flags); } @@ -1671,6 +1711,7 @@ static int mxc_jpeg_open(struct file *file) ctx->fh.ctrl_handler = &ctx->ctrl_handler; mxc_jpeg_set_default_params(ctx); ctx->slot = MXC_MAX_SLOTS; /* slot not allocated yet */ + INIT_DELAYED_WORK(&ctx->task_timer, mxc_jpeg_device_run_timeout); if (mxc_jpeg->mode == MXC_JPEG_DECODE) dev_dbg(dev, "Opened JPEG decoder instance %p\n", ctx); diff --git a/drivers/media/platform/nxp/imx-jpeg/mxc-jpeg.h b/drivers/media/platform/nxp/imx-jpeg/mxc-jpeg.h index c508d41a906f..8104ee4a3b7a 100644 --- a/drivers/media/platform/nxp/imx-jpeg/mxc-jpeg.h +++ b/drivers/media/platform/nxp/imx-jpeg/mxc-jpeg.h @@ -97,6 +97,7 @@ struct mxc_jpeg_ctx { bool header_parsed; struct v4l2_ctrl_handler ctrl_handler; u8 jpeg_quality; + struct delayed_work task_timer; }; struct mxc_jpeg_slot_data { -- cgit v1.2.3 From 11edcbb23eb8af93e4f4f3bf28b1f0dc422f0308 Mon Sep 17 00:00:00 2001 From: Jianhua Lin Date: Tue, 19 Jul 2022 18:02:13 +0800 Subject: dt-bindings: media: mediatek-jpeg-decoder: Add MT8188 compatible string Add compatible for MT8188 jpeg decoder. Signed-off-by: Jianhua Lin Acked-by: Krzysztof Kozlowski Signed-off-by: Hans Verkuil --- Documentation/devicetree/bindings/media/mediatek-jpeg-decoder.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/Documentation/devicetree/bindings/media/mediatek-jpeg-decoder.yaml b/Documentation/devicetree/bindings/media/mediatek-jpeg-decoder.yaml index 052e752157b4..3c77adfa320c 100644 --- a/Documentation/devicetree/bindings/media/mediatek-jpeg-decoder.yaml +++ b/Documentation/devicetree/bindings/media/mediatek-jpeg-decoder.yaml @@ -22,6 +22,7 @@ properties: - items: - enum: - mediatek,mt7623-jpgdec + - mediatek,mt8188-jpgdec - const: mediatek,mt2701-jpgdec reg: -- cgit v1.2.3 From 2c0a1dea8d936d3de0dc8a7674fd8a0014faa126 Mon Sep 17 00:00:00 2001 From: Jianhua Lin Date: Tue, 19 Jul 2022 18:02:14 +0800 Subject: dt-bindings: media: mediatek-jpeg-encoder: Add MT8188 compatible string Add compatible for MT8188 jpeg encoder. Signed-off-by: Jianhua Lin Acked-by: Krzysztof Kozlowski Signed-off-by: Hans Verkuil --- Documentation/devicetree/bindings/media/mediatek-jpeg-encoder.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/Documentation/devicetree/bindings/media/mediatek-jpeg-encoder.yaml b/Documentation/devicetree/bindings/media/mediatek-jpeg-encoder.yaml index 4fd390c042a9..20134b0fc273 100644 --- a/Documentation/devicetree/bindings/media/mediatek-jpeg-encoder.yaml +++ b/Documentation/devicetree/bindings/media/mediatek-jpeg-encoder.yaml @@ -19,6 +19,7 @@ properties: - mediatek,mt2701-jpgenc - mediatek,mt8183-jpgenc - mediatek,mt8186-jpgenc + - mediatek,mt8188-jpgenc - const: mediatek,mtk-jpgenc reg: maxItems: 1 -- cgit v1.2.3 From c76c2e92bcffef66a096de81e086d1acdc5ee944 Mon Sep 17 00:00:00 2001 From: Ming Qian Date: Tue, 26 Jul 2022 17:04:27 +0800 Subject: media: imx-jpeg: Don't clear stop state in handling dynamic resolution change In dynamic resolution change, streamoff and streamon on the capture queue may be called, the V4L2_DEC_CMD_STOP cmd may be called before driver parsed the jpeg header. don't clear the stop state in streamoff of handling the dynamic resolution change, otherwise the drain may not complete. Fixes: 4911c5acf9351 ("media: imx-jpeg: Implement drain using v4l2-mem2mem helpers") Signed-off-by: Ming Qian Signed-off-by: Hans Verkuil --- drivers/media/platform/nxp/imx-jpeg/mxc-jpeg.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/media/platform/nxp/imx-jpeg/mxc-jpeg.c b/drivers/media/platform/nxp/imx-jpeg/mxc-jpeg.c index 16af887a6e3c..ce8a305e49fd 100644 --- a/drivers/media/platform/nxp/imx-jpeg/mxc-jpeg.c +++ b/drivers/media/platform/nxp/imx-jpeg/mxc-jpeg.c @@ -1277,7 +1277,8 @@ static void mxc_jpeg_stop_streaming(struct vb2_queue *q) v4l2_m2m_buf_done(vbuf, VB2_BUF_STATE_ERROR); } - v4l2_m2m_update_stop_streaming_state(ctx->fh.m2m_ctx, q); + if (V4L2_TYPE_IS_OUTPUT(q->type) || !ctx->source_change) + v4l2_m2m_update_stop_streaming_state(ctx->fh.m2m_ctx, q); if (V4L2_TYPE_IS_OUTPUT(q->type) && v4l2_m2m_has_stopped(ctx->fh.m2m_ctx)) { notify_eos(ctx); -- cgit v1.2.3 From c3720e65c9013a7b2a5dbb63e6bf6d74a35dd894 Mon Sep 17 00:00:00 2001 From: Ming Qian Date: Thu, 4 Aug 2022 17:38:41 +0800 Subject: media: imx-jpeg: Disable useless interrupt to avoid kernel panic There is a hardware bug that the interrupt STMBUF_HALF may be triggered after or when disable interrupt. It may led to unexpected kernel panic. And interrupt STMBUF_HALF and STMBUF_RTND have no other effect. So disable them and the unused interrupts. meanwhile clear the interrupt status when disable interrupt. Signed-off-by: Ming Qian Reviewed-by: Mirela Rabulea Signed-off-by: Hans Verkuil --- drivers/media/platform/nxp/imx-jpeg/mxc-jpeg-hw.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/media/platform/nxp/imx-jpeg/mxc-jpeg-hw.c b/drivers/media/platform/nxp/imx-jpeg/mxc-jpeg-hw.c index 9418fcf740a8..ef28122a5ed4 100644 --- a/drivers/media/platform/nxp/imx-jpeg/mxc-jpeg-hw.c +++ b/drivers/media/platform/nxp/imx-jpeg/mxc-jpeg-hw.c @@ -76,12 +76,14 @@ void print_wrapper_info(struct device *dev, void __iomem *reg) void mxc_jpeg_enable_irq(void __iomem *reg, int slot) { - writel(0xFFFFFFFF, reg + MXC_SLOT_OFFSET(slot, SLOT_IRQ_EN)); + writel(0xFFFFFFFF, reg + MXC_SLOT_OFFSET(slot, SLOT_STATUS)); + writel(0xF0C, reg + MXC_SLOT_OFFSET(slot, SLOT_IRQ_EN)); } void mxc_jpeg_disable_irq(void __iomem *reg, int slot) { writel(0x0, reg + MXC_SLOT_OFFSET(slot, SLOT_IRQ_EN)); + writel(0xFFFFFFFF, reg + MXC_SLOT_OFFSET(slot, SLOT_STATUS)); } void mxc_jpeg_sw_reset(void __iomem *reg) -- cgit v1.2.3 From 6611830fa3969a76d5acf1bb385f804504d34a74 Mon Sep 17 00:00:00 2001 From: kyrie wu Date: Thu, 29 Sep 2022 17:08:03 +0800 Subject: dt-bindings: mediatek: Add mediatek, mt8195-jpgenc compatible Add mediatek,mt8195-jpgenc compatible to binding document. Signed-off-by: kyrie wu Signed-off-by: irui wang Reviewed-by: Rob Herring Acked-by: Krzysztof Kozlowski Signed-off-by: Hans Verkuil --- .../bindings/media/mediatek,mt8195-jpegenc.yaml | 147 +++++++++++++++++++++ 1 file changed, 147 insertions(+) create mode 100644 Documentation/devicetree/bindings/media/mediatek,mt8195-jpegenc.yaml diff --git a/Documentation/devicetree/bindings/media/mediatek,mt8195-jpegenc.yaml b/Documentation/devicetree/bindings/media/mediatek,mt8195-jpegenc.yaml new file mode 100644 index 000000000000..95990539f7c0 --- /dev/null +++ b/Documentation/devicetree/bindings/media/mediatek,mt8195-jpegenc.yaml @@ -0,0 +1,147 @@ +# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/media/mediatek,mt8195-jpegenc.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: MediaTek JPEG Encoder + +maintainers: + - kyrie wu + +description: + MediaTek JPEG Encoder is the JPEG encode hardware present in MediaTek SoCs + +properties: + compatible: + const: mediatek,mt8195-jpgenc + + power-domains: + maxItems: 1 + + iommus: + maxItems: 4 + description: + Points to the respective IOMMU block with master port as argument, see + Documentation/devicetree/bindings/iommu/mediatek,iommu.yaml for details. + Ports are according to the HW. + + dma-ranges: + maxItems: 1 + description: | + Describes the physical address space of IOMMU maps to memory. + + "#address-cells": + const: 2 + + "#size-cells": + const: 2 + + ranges: true + +# Required child node: +patternProperties: + "^jpgenc@[0-9a-f]+$": + type: object + description: + The jpeg encoder hardware device node which should be added as subnodes to + the main jpeg node. + + properties: + compatible: + const: mediatek,mt8195-jpgenc-hw + + reg: + maxItems: 1 + + iommus: + minItems: 1 + maxItems: 32 + description: + List of the hardware port in respective IOMMU block for current Socs. + Refer to bindings/iommu/mediatek,iommu.yaml. + + interrupts: + maxItems: 1 + + clocks: + maxItems: 1 + + clock-names: + items: + - const: jpgenc + + power-domains: + maxItems: 1 + + required: + - compatible + - reg + - iommus + - interrupts + - clocks + - clock-names + - power-domains + + additionalProperties: false + +required: + - compatible + - power-domains + - iommus + - dma-ranges + - ranges + +additionalProperties: false + +examples: + - | + #include + #include + #include + #include + #include + + soc { + #address-cells = <2>; + #size-cells = <2>; + + jpgenc-master { + compatible = "mediatek,mt8195-jpgenc"; + power-domains = <&spm MT8195_POWER_DOMAIN_VENC_CORE1>; + iommus = <&iommu_vpp M4U_PORT_L20_JPGENC_Y_RDMA>, + <&iommu_vpp M4U_PORT_L20_JPGENC_C_RDMA>, + <&iommu_vpp M4U_PORT_L20_JPGENC_Q_TABLE>, + <&iommu_vpp M4U_PORT_L20_JPGENC_BSDMA>; + dma-ranges = <0x1 0x0 0x0 0x40000000 0x0 0xfff00000>; + #address-cells = <2>; + #size-cells = <2>; + ranges; + + jpgenc@1a030000 { + compatible = "mediatek,mt8195-jpgenc-hw"; + reg = <0 0x1a030000 0 0x10000>; + iommus = <&iommu_vdo M4U_PORT_L19_JPGENC_Y_RDMA>, + <&iommu_vdo M4U_PORT_L19_JPGENC_C_RDMA>, + <&iommu_vdo M4U_PORT_L19_JPGENC_Q_TABLE>, + <&iommu_vdo M4U_PORT_L19_JPGENC_BSDMA>; + interrupts = ; + clocks = <&vencsys CLK_VENC_JPGENC>; + clock-names = "jpgenc"; + power-domains = <&spm MT8195_POWER_DOMAIN_VENC>; + }; + + jpgenc@1b030000 { + compatible = "mediatek,mt8195-jpgenc-hw"; + reg = <0 0x1b030000 0 0x10000>; + iommus = <&iommu_vpp M4U_PORT_L20_JPGENC_Y_RDMA>, + <&iommu_vpp M4U_PORT_L20_JPGENC_C_RDMA>, + <&iommu_vpp M4U_PORT_L20_JPGENC_Q_TABLE>, + <&iommu_vpp M4U_PORT_L20_JPGENC_BSDMA>; + interrupts = ; + clocks = <&vencsys_core1 CLK_VENC_CORE1_JPGENC>; + clock-names = "jpgenc"; + power-domains = <&spm MT8195_POWER_DOMAIN_VENC_CORE1>; + }; + }; + }; -- cgit v1.2.3 From 8eecf7b3bfb906c1610ee3bbebb9ca4b3755ef9f Mon Sep 17 00:00:00 2001 From: kyrie wu Date: Thu, 29 Sep 2022 17:08:04 +0800 Subject: mtk-jpegenc: export jpeg encoder functions mtk jpeg encoder is built as a module, export some functions to make them visible by other modules. Signed-off-by: kyrie wu Signed-off-by: irui wang Signed-off-by: Hans Verkuil --- drivers/media/platform/mediatek/jpeg/mtk_jpeg_enc_hw.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/drivers/media/platform/mediatek/jpeg/mtk_jpeg_enc_hw.c b/drivers/media/platform/mediatek/jpeg/mtk_jpeg_enc_hw.c index 1cf037bf72dd..368f512ea86e 100644 --- a/drivers/media/platform/mediatek/jpeg/mtk_jpeg_enc_hw.c +++ b/drivers/media/platform/mediatek/jpeg/mtk_jpeg_enc_hw.c @@ -36,12 +36,14 @@ void mtk_jpeg_enc_reset(void __iomem *base) writel(JPEG_ENC_RESET_BIT, base + JPEG_ENC_RSTB); writel(0, base + JPEG_ENC_CODEC_SEL); } +EXPORT_SYMBOL_GPL(mtk_jpeg_enc_reset); u32 mtk_jpeg_enc_get_file_size(void __iomem *base) { return readl(base + JPEG_ENC_DMA_ADDR0) - readl(base + JPEG_ENC_DST_ADDR0); } +EXPORT_SYMBOL_GPL(mtk_jpeg_enc_get_file_size); void mtk_jpeg_enc_start(void __iomem *base) { @@ -51,6 +53,7 @@ void mtk_jpeg_enc_start(void __iomem *base) value |= JPEG_ENC_CTRL_INT_EN_BIT | JPEG_ENC_CTRL_ENABLE_BIT; writel(value, base + JPEG_ENC_CTRL); } +EXPORT_SYMBOL_GPL(mtk_jpeg_enc_start); void mtk_jpeg_set_enc_src(struct mtk_jpeg_ctx *ctx, void __iomem *base, struct vb2_buffer *src_buf) @@ -67,6 +70,7 @@ void mtk_jpeg_set_enc_src(struct mtk_jpeg_ctx *ctx, void __iomem *base, writel(dma_addr, base + JPEG_ENC_SRC_CHROMA_ADDR); } } +EXPORT_SYMBOL_GPL(mtk_jpeg_set_enc_src); void mtk_jpeg_set_enc_dst(struct mtk_jpeg_ctx *ctx, void __iomem *base, struct vb2_buffer *dst_buf) @@ -86,6 +90,7 @@ void mtk_jpeg_set_enc_dst(struct mtk_jpeg_ctx *ctx, void __iomem *base, writel(dma_addr & ~0xf, base + JPEG_ENC_DST_ADDR0); writel((dma_addr + size) & ~0xf, base + JPEG_ENC_STALL_ADDR0); } +EXPORT_SYMBOL_GPL(mtk_jpeg_set_enc_dst); void mtk_jpeg_set_enc_params(struct mtk_jpeg_ctx *ctx, void __iomem *base) { @@ -152,3 +157,4 @@ void mtk_jpeg_set_enc_params(struct mtk_jpeg_ctx *ctx, void __iomem *base) writel(ctx->restart_interval, base + JPEG_ENC_RST_MCU_NUM); } +EXPORT_SYMBOL_GPL(mtk_jpeg_set_enc_params); -- cgit v1.2.3 From 934e8bccac9542540493a4e5257d6b0db4162478 Mon Sep 17 00:00:00 2001 From: kyrie wu Date: Thu, 29 Sep 2022 17:08:05 +0800 Subject: mtk-jpegenc: support jpegenc multi-hardware support jpeg encode multi-hardware includes HW0 and HW1. Signed-off-by: kyrie wu Signed-off-by: irui wang Reported-by: kernel test robot Signed-off-by: Hans Verkuil --- drivers/media/platform/mediatek/jpeg/Makefile | 11 +- .../media/platform/mediatek/jpeg/mtk_jpeg_core.c | 69 +++++---- .../media/platform/mediatek/jpeg/mtk_jpeg_core.h | 42 ++++++ .../media/platform/mediatek/jpeg/mtk_jpeg_enc_hw.c | 161 +++++++++++++++++++++ 4 files changed, 249 insertions(+), 34 deletions(-) diff --git a/drivers/media/platform/mediatek/jpeg/Makefile b/drivers/media/platform/mediatek/jpeg/Makefile index 76c33aad0f3f..69703db4b0a5 100644 --- a/drivers/media/platform/mediatek/jpeg/Makefile +++ b/drivers/media/platform/mediatek/jpeg/Makefile @@ -1,6 +1,9 @@ # SPDX-License-Identifier: GPL-2.0-only -mtk_jpeg-objs := mtk_jpeg_core.o \ +obj-$(CONFIG_VIDEO_MEDIATEK_JPEG) += mtk_jpeg.o \ + mtk-jpeg-enc-hw.o + +mtk_jpeg-y := mtk_jpeg_core.o \ mtk_jpeg_dec_hw.o \ - mtk_jpeg_dec_parse.o \ - mtk_jpeg_enc_hw.o -obj-$(CONFIG_VIDEO_MEDIATEK_JPEG) += mtk_jpeg.o + mtk_jpeg_dec_parse.o + +mtk-jpeg-enc-hw-y := mtk_jpeg_enc_hw.o diff --git a/drivers/media/platform/mediatek/jpeg/mtk_jpeg_core.c b/drivers/media/platform/mediatek/jpeg/mtk_jpeg_core.c index 3071b61946c3..8a82e02a117c 100644 --- a/drivers/media/platform/mediatek/jpeg/mtk_jpeg_core.c +++ b/drivers/media/platform/mediatek/jpeg/mtk_jpeg_core.c @@ -678,7 +678,7 @@ static int mtk_jpeg_buf_prepare(struct vb2_buffer *vb) { struct mtk_jpeg_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue); struct mtk_jpeg_q_data *q_data = NULL; - struct v4l2_plane_pix_format plane_fmt; + struct v4l2_plane_pix_format plane_fmt = {}; int i; q_data = mtk_jpeg_get_q_data(ctx, vb->vb2_queue->type); @@ -1310,38 +1310,51 @@ static int mtk_jpeg_probe(struct platform_device *pdev) spin_lock_init(&jpeg->hw_lock); jpeg->dev = &pdev->dev; jpeg->variant = of_device_get_match_data(jpeg->dev); - INIT_DELAYED_WORK(&jpeg->job_timeout_work, mtk_jpeg_job_timeout_work); - jpeg->reg_base = devm_platform_ioremap_resource(pdev, 0); - if (IS_ERR(jpeg->reg_base)) { - ret = PTR_ERR(jpeg->reg_base); - return ret; + ret = devm_of_platform_populate(&pdev->dev); + if (ret) { + v4l2_err(&jpeg->v4l2_dev, "Master of platform populate failed."); + return -EINVAL; } - jpeg_irq = platform_get_irq(pdev, 0); - if (jpeg_irq < 0) - return jpeg_irq; + if (list_empty(&pdev->dev.devres_head)) { + INIT_DELAYED_WORK(&jpeg->job_timeout_work, + mtk_jpeg_job_timeout_work); - ret = devm_request_irq(&pdev->dev, jpeg_irq, - jpeg->variant->irq_handler, 0, pdev->name, jpeg); - if (ret) { - dev_err(&pdev->dev, "Failed to request jpeg_irq %d (%d)\n", - jpeg_irq, ret); - goto err_req_irq; - } + jpeg->reg_base = devm_platform_ioremap_resource(pdev, 0); + if (IS_ERR(jpeg->reg_base)) { + ret = PTR_ERR(jpeg->reg_base); + return ret; + } - ret = devm_clk_bulk_get(jpeg->dev, jpeg->variant->num_clks, - jpeg->variant->clks); - if (ret) { - dev_err(&pdev->dev, "Failed to init clk, err %d\n", ret); - goto err_clk_init; + jpeg_irq = platform_get_irq(pdev, 0); + if (jpeg_irq < 0) + return jpeg_irq; + + ret = devm_request_irq(&pdev->dev, + jpeg_irq, + jpeg->variant->irq_handler, + 0, + pdev->name, jpeg); + if (ret) { + dev_err(&pdev->dev, "Failed to request jpeg_irq %d (%d)\n", + jpeg_irq, ret); + return ret; + } + + ret = devm_clk_bulk_get(jpeg->dev, + jpeg->variant->num_clks, + jpeg->variant->clks); + if (ret) { + dev_err(&pdev->dev, "Failed to init clk\n"); + return ret; + } } ret = v4l2_device_register(&pdev->dev, &jpeg->v4l2_dev); if (ret) { dev_err(&pdev->dev, "Failed to register v4l2 device\n"); - ret = -EINVAL; - goto err_dev_register; + return -EINVAL; } jpeg->m2m_dev = v4l2_m2m_init(jpeg->variant->m2m_ops); @@ -1399,12 +1412,6 @@ err_vfd_jpeg_alloc: err_m2m_init: v4l2_device_unregister(&jpeg->v4l2_dev); -err_dev_register: - -err_clk_init: - -err_req_irq: - return ret; } @@ -1494,6 +1501,7 @@ static const struct mtk_jpeg_variant mtk_jpeg_drvdata = { .cap_q_default_fourcc = V4L2_PIX_FMT_JPEG, }; +#if defined(CONFIG_OF) static const struct of_device_id mtk_jpeg_match[] = { { .compatible = "mediatek,mt8173-jpgdec", @@ -1511,13 +1519,14 @@ static const struct of_device_id mtk_jpeg_match[] = { }; MODULE_DEVICE_TABLE(of, mtk_jpeg_match); +#endif static struct platform_driver mtk_jpeg_driver = { .probe = mtk_jpeg_probe, .remove = mtk_jpeg_remove, .driver = { .name = MTK_JPEG_NAME, - .of_match_table = mtk_jpeg_match, + .of_match_table = of_match_ptr(mtk_jpeg_match), .pm = &mtk_jpeg_pm_ops, }, }; diff --git a/drivers/media/platform/mediatek/jpeg/mtk_jpeg_core.h b/drivers/media/platform/mediatek/jpeg/mtk_jpeg_core.h index 3e4811a41ba2..1e0ba466303b 100644 --- a/drivers/media/platform/mediatek/jpeg/mtk_jpeg_core.h +++ b/drivers/media/platform/mediatek/jpeg/mtk_jpeg_core.h @@ -9,6 +9,7 @@ #ifndef _MTK_JPEG_CORE_H #define _MTK_JPEG_CORE_H +#include #include #include #include @@ -74,6 +75,40 @@ struct mtk_jpeg_variant { u32 cap_q_default_fourcc; }; +enum mtk_jpegenc_hw_id { + MTK_JPEGENC_HW0, + MTK_JPEGENC_HW1, + MTK_JPEGENC_HW_MAX, +}; + +/** + * struct mtk_jpegenc_clk - Structure used to store vcodec clock information + * @clks: JPEG encode clock + * @clk_num: JPEG encode clock numbers + */ +struct mtk_jpegenc_clk { + struct clk_bulk_data *clks; + int clk_num; +}; + +/** + * struct mtk_jpegenc_comp_dev - JPEG COREX abstraction + * @dev: JPEG device + * @plat_dev: platform device data + * @reg_base: JPEG registers mapping + * @master_dev: mtk_jpeg_dev device + * @venc_clk: jpeg encode clock + * @jpegenc_irq: jpeg encode irq num + */ +struct mtk_jpegenc_comp_dev { + struct device *dev; + struct platform_device *plat_dev; + void __iomem *reg_base; + struct mtk_jpeg_dev *master_dev; + struct mtk_jpegenc_clk venc_clk; + int jpegenc_irq; +}; + /** * struct mtk_jpeg_dev - JPEG IP abstraction * @lock: the mutex protecting this structure @@ -87,6 +122,9 @@ struct mtk_jpeg_variant { * @reg_base: JPEG registers mapping * @job_timeout_work: IRQ timeout structure * @variant: driver variant to be used + * @reg_encbase: jpg encode register base addr + * @enc_hw_dev: jpg encode hardware device + * @is_jpgenc_multihw: the flag of multi-hw core */ struct mtk_jpeg_dev { struct mutex lock; @@ -100,6 +138,10 @@ struct mtk_jpeg_dev { void __iomem *reg_base; struct delayed_work job_timeout_work; const struct mtk_jpeg_variant *variant; + + void __iomem *reg_encbase[MTK_JPEGENC_HW_MAX]; + struct mtk_jpegenc_comp_dev *enc_hw_dev[MTK_JPEGENC_HW_MAX]; + bool is_jpgenc_multihw; }; /** diff --git a/drivers/media/platform/mediatek/jpeg/mtk_jpeg_enc_hw.c b/drivers/media/platform/mediatek/jpeg/mtk_jpeg_enc_hw.c index 368f512ea86e..3dcf83d6d95e 100644 --- a/drivers/media/platform/mediatek/jpeg/mtk_jpeg_enc_hw.c +++ b/drivers/media/platform/mediatek/jpeg/mtk_jpeg_enc_hw.c @@ -5,11 +5,27 @@ * */ +#include +#include +#include #include #include +#include +#include +#include +#include +#include +#include #include #include +#include +#include +#include +#include +#include +#include +#include "mtk_jpeg_core.h" #include "mtk_jpeg_enc_hw.h" static const struct mtk_jpeg_enc_qlt mtk_jpeg_enc_quality[] = { @@ -30,6 +46,16 @@ static const struct mtk_jpeg_enc_qlt mtk_jpeg_enc_quality[] = { {.quality_param = 97, .hardware_value = JPEG_ENC_QUALITY_Q97}, }; +#if defined(CONFIG_OF) +static const struct of_device_id mtk_jpegenc_drv_ids[] = { + { + .compatible = "mediatek,mt8195-jpgenc-hw", + }, + {}, +}; +MODULE_DEVICE_TABLE(of, mtk_jpegenc_drv_ids); +#endif + void mtk_jpeg_enc_reset(void __iomem *base) { writel(0, base + JPEG_ENC_RSTB); @@ -158,3 +184,138 @@ void mtk_jpeg_set_enc_params(struct mtk_jpeg_ctx *ctx, void __iomem *base) writel(ctx->restart_interval, base + JPEG_ENC_RST_MCU_NUM); } EXPORT_SYMBOL_GPL(mtk_jpeg_set_enc_params); + +static irqreturn_t mtk_jpegenc_hw_irq_handler(int irq, void *priv) +{ + struct vb2_v4l2_buffer *src_buf, *dst_buf; + enum vb2_buffer_state buf_state; + struct mtk_jpeg_ctx *ctx; + u32 result_size; + u32 irq_status; + + struct mtk_jpegenc_comp_dev *jpeg = priv; + struct mtk_jpeg_dev *master_jpeg = jpeg->master_dev; + + irq_status = readl(jpeg->reg_base + JPEG_ENC_INT_STS) & + JPEG_ENC_INT_STATUS_MASK_ALLIRQ; + if (irq_status) + writel(0, jpeg->reg_base + JPEG_ENC_INT_STS); + if (!(irq_status & JPEG_ENC_INT_STATUS_DONE)) + return IRQ_NONE; + + ctx = v4l2_m2m_get_curr_priv(master_jpeg->m2m_dev); + if (!ctx) { + v4l2_err(&master_jpeg->v4l2_dev, "Context is NULL\n"); + return IRQ_HANDLED; + } + + src_buf = v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx); + dst_buf = v4l2_m2m_dst_buf_remove(ctx->fh.m2m_ctx); + v4l2_m2m_buf_copy_metadata(src_buf, dst_buf, true); + + result_size = mtk_jpeg_enc_get_file_size(jpeg->reg_base); + vb2_set_plane_payload(&dst_buf->vb2_buf, 0, result_size); + buf_state = VB2_BUF_STATE_DONE; + v4l2_m2m_buf_done(src_buf, buf_state); + v4l2_m2m_buf_done(dst_buf, buf_state); + v4l2_m2m_job_finish(master_jpeg->m2m_dev, ctx->fh.m2m_ctx); + pm_runtime_put(ctx->jpeg->dev); + + return IRQ_HANDLED; +} + +static int mtk_jpegenc_hw_init_irq(struct mtk_jpegenc_comp_dev *dev) +{ + struct platform_device *pdev = dev->plat_dev; + int ret; + + dev->jpegenc_irq = platform_get_irq(pdev, 0); + if (dev->jpegenc_irq < 0) + return dev->jpegenc_irq; + + ret = devm_request_irq(&pdev->dev, + dev->jpegenc_irq, + mtk_jpegenc_hw_irq_handler, + 0, + pdev->name, dev); + if (ret) { + dev_err(&pdev->dev, "Failed to devm_request_irq %d (%d)", + dev->jpegenc_irq, ret); + return ret; + } + + return 0; +} + +static int mtk_jpegenc_hw_probe(struct platform_device *pdev) +{ + struct mtk_jpegenc_clk *jpegenc_clk; + struct mtk_jpeg_dev *master_dev; + struct mtk_jpegenc_comp_dev *dev; + int ret, i; + + struct device *decs = &pdev->dev; + + if (!decs->parent) + return -EPROBE_DEFER; + + master_dev = dev_get_drvdata(decs->parent); + if (!master_dev) + return -EPROBE_DEFER; + + dev = devm_kzalloc(&pdev->dev, sizeof(*dev), GFP_KERNEL); + if (!dev) + return -ENOMEM; + + dev->plat_dev = pdev; + dev->dev = &pdev->dev; + + if (!master_dev->is_jpgenc_multihw) { + master_dev->is_jpgenc_multihw = true; + for (i = 0; i < MTK_JPEGENC_HW_MAX; i++) + master_dev->enc_hw_dev[i] = NULL; + } + + jpegenc_clk = &dev->venc_clk; + + jpegenc_clk->clk_num = devm_clk_bulk_get_all(&pdev->dev, + &jpegenc_clk->clks); + if (jpegenc_clk->clk_num < 0) + return dev_err_probe(&pdev->dev, jpegenc_clk->clk_num, + "Failed to get jpegenc clock count\n"); + + dev->reg_base = devm_platform_ioremap_resource(pdev, 0); + if (IS_ERR(dev->reg_base)) + return PTR_ERR(dev->reg_base); + + ret = mtk_jpegenc_hw_init_irq(dev); + if (ret) + return ret; + + for (i = 0; i < MTK_JPEGENC_HW_MAX; i++) { + if (master_dev->enc_hw_dev[i]) + continue; + + master_dev->enc_hw_dev[i] = dev; + master_dev->reg_encbase[i] = dev->reg_base; + dev->master_dev = master_dev; + } + + platform_set_drvdata(pdev, dev); + pm_runtime_enable(&pdev->dev); + + return 0; +} + +static struct platform_driver mtk_jpegenc_hw_driver = { + .probe = mtk_jpegenc_hw_probe, + .driver = { + .name = "mtk-jpegenc-hw", + .of_match_table = of_match_ptr(mtk_jpegenc_drv_ids), + }, +}; + +module_platform_driver(mtk_jpegenc_hw_driver); + +MODULE_DESCRIPTION("MediaTek JPEG encode HW driver"); +MODULE_LICENSE("GPL"); -- cgit v1.2.3 From faa7a062ab0440831946c5cf89780f4d0574df9c Mon Sep 17 00:00:00 2001 From: kyrie wu Date: Thu, 29 Sep 2022 17:08:06 +0800 Subject: mtk-jpegenc: add jpegenc timeout func interface Generalizes jpegenc timeout func interfaces to handle HW timeout. Signed-off-by: kyrie wu Signed-off-by: irui wang Signed-off-by: Hans Verkuil --- .../media/platform/mediatek/jpeg/mtk_jpeg_core.h | 10 +++++++++ .../media/platform/mediatek/jpeg/mtk_jpeg_enc_hw.c | 25 ++++++++++++++++++++++ 2 files changed, 35 insertions(+) diff --git a/drivers/media/platform/mediatek/jpeg/mtk_jpeg_core.h b/drivers/media/platform/mediatek/jpeg/mtk_jpeg_core.h index 1e0ba466303b..98de83c9ea4c 100644 --- a/drivers/media/platform/mediatek/jpeg/mtk_jpeg_core.h +++ b/drivers/media/platform/mediatek/jpeg/mtk_jpeg_core.h @@ -75,6 +75,12 @@ struct mtk_jpeg_variant { u32 cap_q_default_fourcc; }; +struct mtk_jpeg_hw_param { + struct vb2_v4l2_buffer *src_buffer; + struct vb2_v4l2_buffer *dst_buffer; + struct mtk_jpeg_ctx *curr_ctx; +}; + enum mtk_jpegenc_hw_id { MTK_JPEGENC_HW0, MTK_JPEGENC_HW1, @@ -99,6 +105,8 @@ struct mtk_jpegenc_clk { * @master_dev: mtk_jpeg_dev device * @venc_clk: jpeg encode clock * @jpegenc_irq: jpeg encode irq num + * @job_timeout_work: encode timeout workqueue + * @hw_param: jpeg encode hw parameters */ struct mtk_jpegenc_comp_dev { struct device *dev; @@ -107,6 +115,8 @@ struct mtk_jpegenc_comp_dev { struct mtk_jpeg_dev *master_dev; struct mtk_jpegenc_clk venc_clk; int jpegenc_irq; + struct delayed_work job_timeout_work; + struct mtk_jpeg_hw_param hw_param; }; /** diff --git a/drivers/media/platform/mediatek/jpeg/mtk_jpeg_enc_hw.c b/drivers/media/platform/mediatek/jpeg/mtk_jpeg_enc_hw.c index 3dcf83d6d95e..95812f60ab9f 100644 --- a/drivers/media/platform/mediatek/jpeg/mtk_jpeg_enc_hw.c +++ b/drivers/media/platform/mediatek/jpeg/mtk_jpeg_enc_hw.c @@ -185,6 +185,26 @@ void mtk_jpeg_set_enc_params(struct mtk_jpeg_ctx *ctx, void __iomem *base) } EXPORT_SYMBOL_GPL(mtk_jpeg_set_enc_params); +static void mtk_jpegenc_timeout_work(struct work_struct *work) +{ + struct delayed_work *dly_work = to_delayed_work(work); + struct mtk_jpegenc_comp_dev *cjpeg = + container_of(dly_work, + struct mtk_jpegenc_comp_dev, + job_timeout_work); + enum vb2_buffer_state buf_state = VB2_BUF_STATE_ERROR; + struct vb2_v4l2_buffer *src_buf, *dst_buf; + + src_buf = cjpeg->hw_param.src_buffer; + dst_buf = cjpeg->hw_param.dst_buffer; + v4l2_m2m_buf_copy_metadata(src_buf, dst_buf, true); + + mtk_jpeg_enc_reset(cjpeg->reg_base); + clk_disable_unprepare(cjpeg->venc_clk.clks->clk); + pm_runtime_put(cjpeg->dev); + v4l2_m2m_buf_done(src_buf, buf_state); +} + static irqreturn_t mtk_jpegenc_hw_irq_handler(int irq, void *priv) { struct vb2_v4l2_buffer *src_buf, *dst_buf; @@ -196,6 +216,8 @@ static irqreturn_t mtk_jpegenc_hw_irq_handler(int irq, void *priv) struct mtk_jpegenc_comp_dev *jpeg = priv; struct mtk_jpeg_dev *master_jpeg = jpeg->master_dev; + cancel_delayed_work(&jpeg->job_timeout_work); + irq_status = readl(jpeg->reg_base + JPEG_ENC_INT_STS) & JPEG_ENC_INT_STATUS_MASK_ALLIRQ; if (irq_status) @@ -276,6 +298,9 @@ static int mtk_jpegenc_hw_probe(struct platform_device *pdev) master_dev->enc_hw_dev[i] = NULL; } + INIT_DELAYED_WORK(&dev->job_timeout_work, + mtk_jpegenc_timeout_work); + jpegenc_clk = &dev->venc_clk; jpegenc_clk->clk_num = devm_clk_bulk_get_all(&pdev->dev, -- cgit v1.2.3 From 5fb1c2361e5630491d2a2f9359654eb022601bc0 Mon Sep 17 00:00:00 2001 From: kyrie wu Date: Thu, 29 Sep 2022 17:08:07 +0800 Subject: mtk-jpegenc: add jpeg encode worker interface Add jpeg encoding worker to ensure that two HWs run in parallel in MT8195. Signed-off-by: kyrie wu Signed-off-by: irui wang Signed-off-by: Hans Verkuil --- .../media/platform/mediatek/jpeg/mtk_jpeg_core.c | 183 ++++++++++++++++++++- .../media/platform/mediatek/jpeg/mtk_jpeg_core.h | 20 +++ .../media/platform/mediatek/jpeg/mtk_jpeg_enc_hw.c | 42 +++-- 3 files changed, 232 insertions(+), 13 deletions(-) diff --git a/drivers/media/platform/mediatek/jpeg/mtk_jpeg_core.c b/drivers/media/platform/mediatek/jpeg/mtk_jpeg_core.c index 8a82e02a117c..930384531259 100644 --- a/drivers/media/platform/mediatek/jpeg/mtk_jpeg_core.c +++ b/drivers/media/platform/mediatek/jpeg/mtk_jpeg_core.c @@ -104,11 +104,20 @@ static struct mtk_jpeg_fmt mtk_jpeg_dec_formats[] = { #define MTK_JPEG_ENC_NUM_FORMATS ARRAY_SIZE(mtk_jpeg_enc_formats) #define MTK_JPEG_DEC_NUM_FORMATS ARRAY_SIZE(mtk_jpeg_dec_formats) +#define MTK_JPEG_MAX_RETRY_TIME 5000 + +enum { + MTK_JPEG_BUF_FLAGS_INIT = 0, + MTK_JPEG_BUF_FLAGS_LAST_FRAME = 1, +}; struct mtk_jpeg_src_buf { + u32 frame_num; struct vb2_v4l2_buffer b; struct list_head list; struct mtk_jpeg_dec_param dec_param; + + struct mtk_jpeg_ctx *curr_ctx; }; static int debug; @@ -905,6 +914,148 @@ static int mtk_jpeg_set_dec_dst(struct mtk_jpeg_ctx *ctx, return 0; } +static int mtk_jpegenc_get_hw(struct mtk_jpeg_ctx *ctx) +{ + struct mtk_jpegenc_comp_dev *comp_jpeg; + struct mtk_jpeg_dev *jpeg = ctx->jpeg; + unsigned long flags; + int hw_id = -1; + int i; + + spin_lock_irqsave(&jpeg->hw_lock, flags); + for (i = 0; i < MTK_JPEGENC_HW_MAX; i++) { + comp_jpeg = jpeg->enc_hw_dev[i]; + if (comp_jpeg->hw_state == MTK_JPEG_HW_IDLE) { + hw_id = i; + comp_jpeg->hw_state = MTK_JPEG_HW_BUSY; + break; + } + } + spin_unlock_irqrestore(&jpeg->hw_lock, flags); + + return hw_id; +} + +static int mtk_jpegenc_set_hw_param(struct mtk_jpeg_ctx *ctx, + int hw_id, + struct vb2_v4l2_buffer *src_buf, + struct vb2_v4l2_buffer *dst_buf) +{ + struct mtk_jpegenc_comp_dev *jpeg = ctx->jpeg->enc_hw_dev[hw_id]; + + jpeg->hw_param.curr_ctx = ctx; + jpeg->hw_param.src_buffer = src_buf; + jpeg->hw_param.dst_buffer = dst_buf; + + return 0; +} + +static int mtk_jpegenc_put_hw(struct mtk_jpeg_dev *jpeg, int hw_id) +{ + unsigned long flags; + + spin_lock_irqsave(&jpeg->hw_lock, flags); + jpeg->enc_hw_dev[hw_id]->hw_state = MTK_JPEG_HW_IDLE; + spin_unlock_irqrestore(&jpeg->hw_lock, flags); + + return 0; +} + +static void mtk_jpegenc_worker(struct work_struct *work) +{ + struct mtk_jpegenc_comp_dev *comp_jpeg[MTK_JPEGENC_HW_MAX]; + enum vb2_buffer_state buf_state = VB2_BUF_STATE_ERROR; + struct mtk_jpeg_src_buf *jpeg_dst_buf; + struct vb2_v4l2_buffer *src_buf, *dst_buf; + int ret, i, hw_id = 0; + unsigned long flags; + + struct mtk_jpeg_ctx *ctx = container_of(work, + struct mtk_jpeg_ctx, + jpeg_work); + struct mtk_jpeg_dev *jpeg = ctx->jpeg; + + for (i = 0; i < MTK_JPEGENC_HW_MAX; i++) + comp_jpeg[i] = jpeg->enc_hw_dev[i]; + i = 0; + +retry_select: + hw_id = mtk_jpegenc_get_hw(ctx); + if (hw_id < 0) { + ret = wait_event_interruptible(jpeg->enc_hw_wq, + atomic_read(&jpeg->enchw_rdy) > 0); + if (ret != 0 || (i++ > MTK_JPEG_MAX_RETRY_TIME)) { + dev_err(jpeg->dev, "%s : %d, all HW are busy\n", + __func__, __LINE__); + v4l2_m2m_job_finish(jpeg->m2m_dev, ctx->fh.m2m_ctx); + return; + } + + goto retry_select; + } + + atomic_dec(&jpeg->enchw_rdy); + src_buf = v4l2_m2m_next_src_buf(ctx->fh.m2m_ctx); + if (!src_buf) + goto getbuf_fail; + + dst_buf = v4l2_m2m_next_dst_buf(ctx->fh.m2m_ctx); + if (!dst_buf) + goto getbuf_fail; + + v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx); + v4l2_m2m_dst_buf_remove(ctx->fh.m2m_ctx); + + v4l2_m2m_buf_copy_metadata(src_buf, dst_buf, true); + + mtk_jpegenc_set_hw_param(ctx, hw_id, src_buf, dst_buf); + ret = pm_runtime_get_sync(comp_jpeg[hw_id]->dev); + if (ret < 0) { + dev_err(jpeg->dev, "%s : %d, pm_runtime_get_sync fail !!!\n", + __func__, __LINE__); + goto enc_end; + } + + ret = clk_prepare_enable(comp_jpeg[hw_id]->venc_clk.clks->clk); + if (ret) { + dev_err(jpeg->dev, "%s : %d, jpegenc clk_prepare_enable fail\n", + __func__, __LINE__); + goto enc_end; + } + + schedule_delayed_work(&comp_jpeg[hw_id]->job_timeout_work, + msecs_to_jiffies(MTK_JPEG_HW_TIMEOUT_MSEC)); + + spin_lock_irqsave(&comp_jpeg[hw_id]->hw_lock, flags); + jpeg_dst_buf = mtk_jpeg_vb2_to_srcbuf(&dst_buf->vb2_buf); + jpeg_dst_buf->curr_ctx = ctx; + jpeg_dst_buf->frame_num = ctx->total_frame_num; + ctx->total_frame_num++; + mtk_jpeg_enc_reset(comp_jpeg[hw_id]->reg_base); + mtk_jpeg_set_enc_dst(ctx, + comp_jpeg[hw_id]->reg_base, + &dst_buf->vb2_buf); + mtk_jpeg_set_enc_src(ctx, + comp_jpeg[hw_id]->reg_base, + &src_buf->vb2_buf); + mtk_jpeg_set_enc_params(ctx, comp_jpeg[hw_id]->reg_base); + mtk_jpeg_enc_start(comp_jpeg[hw_id]->reg_base); + v4l2_m2m_job_finish(jpeg->m2m_dev, ctx->fh.m2m_ctx); + spin_unlock_irqrestore(&comp_jpeg[hw_id]->hw_lock, flags); + + return; + +enc_end: + v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx); + v4l2_m2m_dst_buf_remove(ctx->fh.m2m_ctx); + v4l2_m2m_buf_done(src_buf, buf_state); + v4l2_m2m_buf_done(dst_buf, buf_state); +getbuf_fail: + atomic_inc(&jpeg->enchw_rdy); + mtk_jpegenc_put_hw(jpeg, hw_id); + v4l2_m2m_job_finish(jpeg->m2m_dev, ctx->fh.m2m_ctx); +} + static void mtk_jpeg_enc_device_run(void *priv) { struct mtk_jpeg_ctx *ctx = priv; @@ -922,7 +1073,7 @@ static void mtk_jpeg_enc_device_run(void *priv) goto enc_end; schedule_delayed_work(&jpeg->job_timeout_work, - msecs_to_jiffies(MTK_JPEG_HW_TIMEOUT_MSEC)); + msecs_to_jiffies(MTK_JPEG_HW_TIMEOUT_MSEC)); spin_lock_irqsave(&jpeg->hw_lock, flags); @@ -947,6 +1098,14 @@ enc_end: v4l2_m2m_job_finish(jpeg->m2m_dev, ctx->fh.m2m_ctx); } +static void mtk_jpeg_multicore_enc_device_run(void *priv) +{ + struct mtk_jpeg_ctx *ctx = priv; + struct mtk_jpeg_dev *jpeg = ctx->jpeg; + + queue_work(jpeg->workqueue, &ctx->jpeg_work); +} + static void mtk_jpeg_dec_device_run(void *priv) { struct mtk_jpeg_ctx *ctx = priv; @@ -1009,6 +1168,10 @@ static const struct v4l2_m2m_ops mtk_jpeg_enc_m2m_ops = { .device_run = mtk_jpeg_enc_device_run, }; +static const struct v4l2_m2m_ops mtk_jpeg_multicore_enc_m2m_ops = { + .device_run = mtk_jpeg_multicore_enc_device_run, +}; + static const struct v4l2_m2m_ops mtk_jpeg_dec_m2m_ops = { .device_run = mtk_jpeg_dec_device_run, .job_ready = mtk_jpeg_dec_job_ready, @@ -1209,6 +1372,9 @@ static int mtk_jpeg_open(struct file *file) goto free; } + if (jpeg->is_jpgenc_multihw) + INIT_WORK(&ctx->jpeg_work, mtk_jpegenc_worker); + v4l2_fh_init(&ctx->fh, vfd); file->private_data = &ctx->fh; v4l2_fh_add(&ctx->fh); @@ -1501,6 +1667,17 @@ static const struct mtk_jpeg_variant mtk_jpeg_drvdata = { .cap_q_default_fourcc = V4L2_PIX_FMT_JPEG, }; +static struct mtk_jpeg_variant mtk8195_jpegenc_drvdata = { + .formats = mtk_jpeg_enc_formats, + .num_formats = MTK_JPEG_ENC_NUM_FORMATS, + .qops = &mtk_jpeg_enc_qops, + .m2m_ops = &mtk_jpeg_multicore_enc_m2m_ops, + .dev_name = "mtk-jpeg-enc", + .ioctl_ops = &mtk_jpeg_enc_ioctl_ops, + .out_q_default_fourcc = V4L2_PIX_FMT_YUYV, + .cap_q_default_fourcc = V4L2_PIX_FMT_JPEG, +}; + #if defined(CONFIG_OF) static const struct of_device_id mtk_jpeg_match[] = { { @@ -1515,6 +1692,10 @@ static const struct of_device_id mtk_jpeg_match[] = { .compatible = "mediatek,mtk-jpgenc", .data = &mtk_jpeg_drvdata, }, + { + .compatible = "mediatek,mt8195-jpgenc", + .data = &mtk8195_jpegenc_drvdata, + }, {}, }; diff --git a/drivers/media/platform/mediatek/jpeg/mtk_jpeg_core.h b/drivers/media/platform/mediatek/jpeg/mtk_jpeg_core.h index 98de83c9ea4c..cbc6fbc21681 100644 --- a/drivers/media/platform/mediatek/jpeg/mtk_jpeg_core.h +++ b/drivers/media/platform/mediatek/jpeg/mtk_jpeg_core.h @@ -75,6 +75,11 @@ struct mtk_jpeg_variant { u32 cap_q_default_fourcc; }; +enum mtk_jpeg_hw_state { + MTK_JPEG_HW_IDLE = 0, + MTK_JPEG_HW_BUSY = 1, +}; + struct mtk_jpeg_hw_param { struct vb2_v4l2_buffer *src_buffer; struct vb2_v4l2_buffer *dst_buffer; @@ -107,6 +112,9 @@ struct mtk_jpegenc_clk { * @jpegenc_irq: jpeg encode irq num * @job_timeout_work: encode timeout workqueue * @hw_param: jpeg encode hw parameters + * @hw_rdy: record hw ready + * @hw_state: record hw state + * @hw_lock: spinlock protecting the hw device resource */ struct mtk_jpegenc_comp_dev { struct device *dev; @@ -117,6 +125,9 @@ struct mtk_jpegenc_comp_dev { int jpegenc_irq; struct delayed_work job_timeout_work; struct mtk_jpeg_hw_param hw_param; + enum mtk_jpeg_hw_state hw_state; + /* spinlock protecting the hw device resource */ + spinlock_t hw_lock; }; /** @@ -135,6 +146,8 @@ struct mtk_jpegenc_comp_dev { * @reg_encbase: jpg encode register base addr * @enc_hw_dev: jpg encode hardware device * @is_jpgenc_multihw: the flag of multi-hw core + * @enc_hw_wq: jpg encode wait queue + * @enchw_rdy: jpg encode hw ready flag */ struct mtk_jpeg_dev { struct mutex lock; @@ -152,6 +165,8 @@ struct mtk_jpeg_dev { void __iomem *reg_encbase[MTK_JPEGENC_HW_MAX]; struct mtk_jpegenc_comp_dev *enc_hw_dev[MTK_JPEGENC_HW_MAX]; bool is_jpgenc_multihw; + wait_queue_head_t enc_hw_wq; + atomic_t enchw_rdy; }; /** @@ -199,6 +214,8 @@ struct mtk_jpeg_q_data { * @enc_quality: jpeg encoder quality * @restart_interval: jpeg encoder restart interval * @ctrl_hdl: controls handler + * @jpeg_work: jpeg encoder workqueue + * @total_frame_num: encoded frame number */ struct mtk_jpeg_ctx { struct mtk_jpeg_dev *jpeg; @@ -210,6 +227,9 @@ struct mtk_jpeg_ctx { u8 enc_quality; u8 restart_interval; struct v4l2_ctrl_handler ctrl_hdl; + + struct work_struct jpeg_work; + u32 total_frame_num; }; #endif /* _MTK_JPEG_CORE_H */ diff --git a/drivers/media/platform/mediatek/jpeg/mtk_jpeg_enc_hw.c b/drivers/media/platform/mediatek/jpeg/mtk_jpeg_enc_hw.c index 95812f60ab9f..02d6c4993653 100644 --- a/drivers/media/platform/mediatek/jpeg/mtk_jpeg_enc_hw.c +++ b/drivers/media/platform/mediatek/jpeg/mtk_jpeg_enc_hw.c @@ -192,6 +192,7 @@ static void mtk_jpegenc_timeout_work(struct work_struct *work) container_of(dly_work, struct mtk_jpegenc_comp_dev, job_timeout_work); + struct mtk_jpeg_dev *master_jpeg = cjpeg->master_dev; enum vb2_buffer_state buf_state = VB2_BUF_STATE_ERROR; struct vb2_v4l2_buffer *src_buf, *dst_buf; @@ -202,6 +203,9 @@ static void mtk_jpegenc_timeout_work(struct work_struct *work) mtk_jpeg_enc_reset(cjpeg->reg_base); clk_disable_unprepare(cjpeg->venc_clk.clks->clk); pm_runtime_put(cjpeg->dev); + cjpeg->hw_state = MTK_JPEG_HW_IDLE; + atomic_inc(&master_jpeg->enchw_rdy); + wake_up(&master_jpeg->enc_hw_wq); v4l2_m2m_buf_done(src_buf, buf_state); } @@ -218,30 +222,33 @@ static irqreturn_t mtk_jpegenc_hw_irq_handler(int irq, void *priv) cancel_delayed_work(&jpeg->job_timeout_work); + ctx = jpeg->hw_param.curr_ctx; + src_buf = jpeg->hw_param.src_buffer; + dst_buf = jpeg->hw_param.dst_buffer; + v4l2_m2m_buf_copy_metadata(src_buf, dst_buf, true); + irq_status = readl(jpeg->reg_base + JPEG_ENC_INT_STS) & JPEG_ENC_INT_STATUS_MASK_ALLIRQ; if (irq_status) writel(0, jpeg->reg_base + JPEG_ENC_INT_STS); if (!(irq_status & JPEG_ENC_INT_STATUS_DONE)) - return IRQ_NONE; - - ctx = v4l2_m2m_get_curr_priv(master_jpeg->m2m_dev); - if (!ctx) { - v4l2_err(&master_jpeg->v4l2_dev, "Context is NULL\n"); - return IRQ_HANDLED; - } - - src_buf = v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx); - dst_buf = v4l2_m2m_dst_buf_remove(ctx->fh.m2m_ctx); - v4l2_m2m_buf_copy_metadata(src_buf, dst_buf, true); + dev_warn(jpeg->dev, "Jpg Enc occurs unknown Err."); result_size = mtk_jpeg_enc_get_file_size(jpeg->reg_base); vb2_set_plane_payload(&dst_buf->vb2_buf, 0, result_size); buf_state = VB2_BUF_STATE_DONE; v4l2_m2m_buf_done(src_buf, buf_state); v4l2_m2m_buf_done(dst_buf, buf_state); - v4l2_m2m_job_finish(master_jpeg->m2m_dev, ctx->fh.m2m_ctx); pm_runtime_put(ctx->jpeg->dev); + clk_disable_unprepare(jpeg->venc_clk.clks->clk); + if (!list_empty(&ctx->fh.m2m_ctx->out_q_ctx.rdy_queue) || + !list_empty(&ctx->fh.m2m_ctx->cap_q_ctx.rdy_queue)) { + queue_work(master_jpeg->workqueue, &ctx->jpeg_work); + } + + jpeg->hw_state = MTK_JPEG_HW_IDLE; + wake_up(&master_jpeg->enc_hw_wq); + atomic_inc(&master_jpeg->enchw_rdy); return IRQ_HANDLED; } @@ -296,8 +303,19 @@ static int mtk_jpegenc_hw_probe(struct platform_device *pdev) master_dev->is_jpgenc_multihw = true; for (i = 0; i < MTK_JPEGENC_HW_MAX; i++) master_dev->enc_hw_dev[i] = NULL; + + init_waitqueue_head(&master_dev->enc_hw_wq); + master_dev->workqueue = alloc_ordered_workqueue(MTK_JPEG_NAME, + WQ_MEM_RECLAIM + | WQ_FREEZABLE); + if (!master_dev->workqueue) + return -EINVAL; } + atomic_set(&master_dev->enchw_rdy, MTK_JPEGENC_HW_MAX); + spin_lock_init(&dev->hw_lock); + dev->hw_state = MTK_JPEG_HW_IDLE; + INIT_DELAYED_WORK(&dev->job_timeout_work, mtk_jpegenc_timeout_work); -- cgit v1.2.3 From 841a58decd87616c6b10431742133366781a08b5 Mon Sep 17 00:00:00 2001 From: kyrie wu Date: Thu, 29 Sep 2022 17:08:08 +0800 Subject: mtk-jpegenc: add output pic reorder interface There are two HWs in mt8195. Since the two HWs run in parallel, it is necessary to reorder the output images to ensure that the order is consistent with the input images. Signed-off-by: kyrie wu Signed-off-by: irui wang Signed-off-by: Hans Verkuil --- .../media/platform/mediatek/jpeg/mtk_jpeg_core.c | 11 +---- .../media/platform/mediatek/jpeg/mtk_jpeg_core.h | 43 ++++++++++++++------ .../media/platform/mediatek/jpeg/mtk_jpeg_dec_hw.c | 1 + .../media/platform/mediatek/jpeg/mtk_jpeg_dec_hw.h | 3 +- .../media/platform/mediatek/jpeg/mtk_jpeg_enc_hw.c | 47 +++++++++++++++++++++- 5 files changed, 81 insertions(+), 24 deletions(-) diff --git a/drivers/media/platform/mediatek/jpeg/mtk_jpeg_core.c b/drivers/media/platform/mediatek/jpeg/mtk_jpeg_core.c index 930384531259..9a99460ec1e2 100644 --- a/drivers/media/platform/mediatek/jpeg/mtk_jpeg_core.c +++ b/drivers/media/platform/mediatek/jpeg/mtk_jpeg_core.c @@ -111,15 +111,6 @@ enum { MTK_JPEG_BUF_FLAGS_LAST_FRAME = 1, }; -struct mtk_jpeg_src_buf { - u32 frame_num; - struct vb2_v4l2_buffer b; - struct list_head list; - struct mtk_jpeg_dec_param dec_param; - - struct mtk_jpeg_ctx *curr_ctx; -}; - static int debug; module_param(debug, int, 0644); @@ -1375,6 +1366,8 @@ static int mtk_jpeg_open(struct file *file) if (jpeg->is_jpgenc_multihw) INIT_WORK(&ctx->jpeg_work, mtk_jpegenc_worker); + INIT_LIST_HEAD(&ctx->dst_done_queue); + spin_lock_init(&ctx->done_queue_lock); v4l2_fh_init(&ctx->fh, vfd); file->private_data = &ctx->fh; v4l2_fh_add(&ctx->fh); diff --git a/drivers/media/platform/mediatek/jpeg/mtk_jpeg_core.h b/drivers/media/platform/mediatek/jpeg/mtk_jpeg_core.h index cbc6fbc21681..0f69402ffce6 100644 --- a/drivers/media/platform/mediatek/jpeg/mtk_jpeg_core.h +++ b/drivers/media/platform/mediatek/jpeg/mtk_jpeg_core.h @@ -14,10 +14,11 @@ #include #include #include +#include -#define MTK_JPEG_NAME "mtk-jpeg" +#include "mtk_jpeg_dec_hw.h" -#define MTK_JPEG_COMP_MAX 3 +#define MTK_JPEG_NAME "mtk-jpeg" #define MTK_JPEG_FMT_FLAG_OUTPUT BIT(0) #define MTK_JPEG_FMT_FLAG_CAPTURE BIT(1) @@ -75,6 +76,15 @@ struct mtk_jpeg_variant { u32 cap_q_default_fourcc; }; +struct mtk_jpeg_src_buf { + u32 frame_num; + struct vb2_v4l2_buffer b; + struct list_head list; + struct mtk_jpeg_dec_param dec_param; + + struct mtk_jpeg_ctx *curr_ctx; +}; + enum mtk_jpeg_hw_state { MTK_JPEG_HW_IDLE = 0, MTK_JPEG_HW_BUSY = 1, @@ -205,17 +215,20 @@ struct mtk_jpeg_q_data { /** * struct mtk_jpeg_ctx - the device context data - * @jpeg: JPEG IP device for this context - * @out_q: source (output) queue information - * @cap_q: destination (capture) queue queue information - * @fh: V4L2 file handle - * @state: state of the context - * @enable_exif: enable exif mode of jpeg encoder - * @enc_quality: jpeg encoder quality - * @restart_interval: jpeg encoder restart interval - * @ctrl_hdl: controls handler - * @jpeg_work: jpeg encoder workqueue - * @total_frame_num: encoded frame number + * @jpeg: JPEG IP device for this context + * @out_q: source (output) queue information + * @cap_q: destination queue information + * @fh: V4L2 file handle + * @state: state of the context + * @enable_exif: enable exif mode of jpeg encoder + * @enc_quality: jpeg encoder quality + * @restart_interval: jpeg encoder restart interval + * @ctrl_hdl: controls handler + * @jpeg_work: jpeg encoder workqueue + * @total_frame_num: encoded frame number + * @dst_done_queue: encoded frame buffer queue + * @done_queue_lock: encoded frame operation spinlock + * @last_done_frame_num: the last encoded frame number */ struct mtk_jpeg_ctx { struct mtk_jpeg_dev *jpeg; @@ -230,6 +243,10 @@ struct mtk_jpeg_ctx { struct work_struct jpeg_work; u32 total_frame_num; + struct list_head dst_done_queue; + /* spinlock protecting the encode done buffer */ + spinlock_t done_queue_lock; + u32 last_done_frame_num; }; #endif /* _MTK_JPEG_CORE_H */ diff --git a/drivers/media/platform/mediatek/jpeg/mtk_jpeg_dec_hw.c b/drivers/media/platform/mediatek/jpeg/mtk_jpeg_dec_hw.c index afbbfd5d02bc..1e3852295f2f 100644 --- a/drivers/media/platform/mediatek/jpeg/mtk_jpeg_dec_hw.c +++ b/drivers/media/platform/mediatek/jpeg/mtk_jpeg_dec_hw.c @@ -9,6 +9,7 @@ #include #include +#include "mtk_jpeg_core.h" #include "mtk_jpeg_dec_hw.h" #define MTK_JPEG_DUNUM_MASK(val) (((val) - 1) & 0x3) diff --git a/drivers/media/platform/mediatek/jpeg/mtk_jpeg_dec_hw.h b/drivers/media/platform/mediatek/jpeg/mtk_jpeg_dec_hw.h index fa0d45fd7c34..87aaa5c9082b 100644 --- a/drivers/media/platform/mediatek/jpeg/mtk_jpeg_dec_hw.h +++ b/drivers/media/platform/mediatek/jpeg/mtk_jpeg_dec_hw.h @@ -11,9 +11,10 @@ #include -#include "mtk_jpeg_core.h" #include "mtk_jpeg_dec_reg.h" +#define MTK_JPEG_COMP_MAX 3 + enum { MTK_JPEG_DEC_RESULT_EOF_DONE = 0, MTK_JPEG_DEC_RESULT_PAUSE = 1, diff --git a/drivers/media/platform/mediatek/jpeg/mtk_jpeg_enc_hw.c b/drivers/media/platform/mediatek/jpeg/mtk_jpeg_enc_hw.c index 02d6c4993653..1bbb712d78d0 100644 --- a/drivers/media/platform/mediatek/jpeg/mtk_jpeg_enc_hw.c +++ b/drivers/media/platform/mediatek/jpeg/mtk_jpeg_enc_hw.c @@ -185,6 +185,50 @@ void mtk_jpeg_set_enc_params(struct mtk_jpeg_ctx *ctx, void __iomem *base) } EXPORT_SYMBOL_GPL(mtk_jpeg_set_enc_params); +static void mtk_jpegenc_put_buf(struct mtk_jpegenc_comp_dev *jpeg) +{ + struct mtk_jpeg_ctx *ctx; + struct vb2_v4l2_buffer *dst_buffer; + struct list_head *temp_entry; + struct list_head *pos = NULL; + struct mtk_jpeg_src_buf *dst_done_buf, *tmp_dst_done_buf; + unsigned long flags; + + ctx = jpeg->hw_param.curr_ctx; + if (!ctx) { + dev_err(jpeg->dev, "comp_jpeg ctx fail !!!\n"); + return; + } + + dst_buffer = jpeg->hw_param.dst_buffer; + if (!dst_buffer) { + dev_err(jpeg->dev, "comp_jpeg dst_buffer fail !!!\n"); + return; + } + + dst_done_buf = container_of(dst_buffer, + struct mtk_jpeg_src_buf, b); + + spin_lock_irqsave(&ctx->done_queue_lock, flags); + list_add_tail(&dst_done_buf->list, &ctx->dst_done_queue); + while (!list_empty(&ctx->dst_done_queue) && + (pos != &ctx->dst_done_queue)) { + list_for_each_prev_safe(pos, temp_entry, &ctx->dst_done_queue) { + tmp_dst_done_buf = list_entry(pos, + struct mtk_jpeg_src_buf, + list); + if (tmp_dst_done_buf->frame_num == + ctx->last_done_frame_num) { + list_del(&tmp_dst_done_buf->list); + v4l2_m2m_buf_done(&tmp_dst_done_buf->b, + VB2_BUF_STATE_DONE); + ctx->last_done_frame_num++; + } + } + } + spin_unlock_irqrestore(&ctx->done_queue_lock, flags); +} + static void mtk_jpegenc_timeout_work(struct work_struct *work) { struct delayed_work *dly_work = to_delayed_work(work); @@ -207,6 +251,7 @@ static void mtk_jpegenc_timeout_work(struct work_struct *work) atomic_inc(&master_jpeg->enchw_rdy); wake_up(&master_jpeg->enc_hw_wq); v4l2_m2m_buf_done(src_buf, buf_state); + mtk_jpegenc_put_buf(cjpeg); } static irqreturn_t mtk_jpegenc_hw_irq_handler(int irq, void *priv) @@ -238,7 +283,7 @@ static irqreturn_t mtk_jpegenc_hw_irq_handler(int irq, void *priv) vb2_set_plane_payload(&dst_buf->vb2_buf, 0, result_size); buf_state = VB2_BUF_STATE_DONE; v4l2_m2m_buf_done(src_buf, buf_state); - v4l2_m2m_buf_done(dst_buf, buf_state); + mtk_jpegenc_put_buf(jpeg); pm_runtime_put(ctx->jpeg->dev); clk_disable_unprepare(jpeg->venc_clk.clks->clk); if (!list_empty(&ctx->fh.m2m_ctx->out_q_ctx.rdy_queue) || -- cgit v1.2.3 From 8f1f08a6337efe26553ba905fa42d1c68e3bb39b Mon Sep 17 00:00:00 2001 From: kyrie wu Date: Thu, 29 Sep 2022 17:08:09 +0800 Subject: mtk-jpegenc: add stop cmd interface for jpgenc Add stop cmd interface for jpgenc to stop stream Signed-off-by: kyrie wu Signed-off-by: irui wang Signed-off-by: Hans Verkuil --- drivers/media/platform/mediatek/jpeg/mtk_jpeg_core.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/media/platform/mediatek/jpeg/mtk_jpeg_core.c b/drivers/media/platform/mediatek/jpeg/mtk_jpeg_core.c index 9a99460ec1e2..debee9b82158 100644 --- a/drivers/media/platform/mediatek/jpeg/mtk_jpeg_core.c +++ b/drivers/media/platform/mediatek/jpeg/mtk_jpeg_core.c @@ -611,6 +611,9 @@ static const struct v4l2_ioctl_ops mtk_jpeg_enc_ioctl_ops = { .vidioc_streamoff = v4l2_m2m_ioctl_streamoff, .vidioc_unsubscribe_event = v4l2_event_unsubscribe, + + .vidioc_encoder_cmd = v4l2_m2m_ioctl_encoder_cmd, + .vidioc_try_encoder_cmd = v4l2_m2m_ioctl_try_encoder_cmd, }; static const struct v4l2_ioctl_ops mtk_jpeg_dec_ioctl_ops = { @@ -1389,6 +1392,7 @@ static int mtk_jpeg_open(struct file *file) } else { v4l2_ctrl_handler_init(&ctx->ctrl_hdl, 0); } + mtk_jpeg_set_default_params(ctx); mutex_unlock(&jpeg->lock); return 0; -- cgit v1.2.3 From 4c83f6f0b1400d0daa5df01ba0e7e64441e1c350 Mon Sep 17 00:00:00 2001 From: kyrie wu Date: Thu, 29 Sep 2022 17:08:10 +0800 Subject: dt-bindings: mediatek: Add mediatek,mt8195-jpgdec compatible Add mediatek,mt8195-jpgdec compatible to binding document. Signed-off-by: kyrie wu Signed-off-by: irui wang Reviewed-by: Rob Herring Acked-by: Krzysztof Kozlowski Signed-off-by: Hans Verkuil --- .../bindings/media/mediatek,mt8195-jpegdec.yaml | 168 +++++++++++++++++++++ 1 file changed, 168 insertions(+) create mode 100644 Documentation/devicetree/bindings/media/mediatek,mt8195-jpegdec.yaml diff --git a/Documentation/devicetree/bindings/media/mediatek,mt8195-jpegdec.yaml b/Documentation/devicetree/bindings/media/mediatek,mt8195-jpegdec.yaml new file mode 100644 index 000000000000..71595c013dbb --- /dev/null +++ b/Documentation/devicetree/bindings/media/mediatek,mt8195-jpegdec.yaml @@ -0,0 +1,168 @@ +# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/media/mediatek,mt8195-jpegdec.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: MediaTek JPEG Decoder + +maintainers: + - kyrie wu + +description: + MediaTek JPEG Decoder is the JPEG decode hardware present in MediaTek SoCs + +properties: + compatible: + const: mediatek,mt8195-jpgdec + + power-domains: + maxItems: 1 + + iommus: + maxItems: 6 + description: + Points to the respective IOMMU block with master port as argument, see + Documentation/devicetree/bindings/iommu/mediatek,iommu.yaml for details. + Ports are according to the HW. + + dma-ranges: + maxItems: 1 + description: | + Describes the physical address space of IOMMU maps to memory. + + "#address-cells": + const: 2 + + "#size-cells": + const: 2 + + ranges: true + +# Required child node: +patternProperties: + "^jpgdec@[0-9a-f]+$": + type: object + description: + The jpeg decoder hardware device node which should be added as subnodes to + the main jpeg node. + + properties: + compatible: + const: mediatek,mt8195-jpgdec-hw + + reg: + maxItems: 1 + + iommus: + minItems: 1 + maxItems: 32 + description: + List of the hardware port in respective IOMMU block for current Socs. + Refer to bindings/iommu/mediatek,iommu.yaml. + + interrupts: + maxItems: 1 + + clocks: + maxItems: 1 + + clock-names: + items: + - const: jpgdec + + power-domains: + maxItems: 1 + + required: + - compatible + - reg + - iommus + - interrupts + - clocks + - clock-names + - power-domains + + additionalProperties: false + +required: + - compatible + - power-domains + - iommus + - dma-ranges + - ranges + +additionalProperties: false + +examples: + - | + #include + #include + #include + #include + #include + + soc { + #address-cells = <2>; + #size-cells = <2>; + + jpgdec-master { + compatible = "mediatek,mt8195-jpgdec"; + power-domains = <&spm MT8195_POWER_DOMAIN_VDEC1>; + iommus = <&iommu_vpp M4U_PORT_L19_JPGDEC_WDMA0>, + <&iommu_vpp M4U_PORT_L19_JPGDEC_BSDMA0>, + <&iommu_vpp M4U_PORT_L19_JPGDEC_WDMA1>, + <&iommu_vpp M4U_PORT_L19_JPGDEC_BSDMA1>, + <&iommu_vpp M4U_PORT_L19_JPGDEC_BUFF_OFFSET1>, + <&iommu_vpp M4U_PORT_L19_JPGDEC_BUFF_OFFSET0>; + dma-ranges = <0x1 0x0 0x0 0x40000000 0x0 0xfff00000>; + #address-cells = <2>; + #size-cells = <2>; + ranges; + + jpgdec@1a040000 { + compatible = "mediatek,mt8195-jpgdec-hw"; + reg = <0 0x1a040000 0 0x10000>;/* JPGDEC_C0 */ + iommus = <&iommu_vdo M4U_PORT_L19_JPGDEC_WDMA0>, + <&iommu_vdo M4U_PORT_L19_JPGDEC_BSDMA0>, + <&iommu_vdo M4U_PORT_L19_JPGDEC_WDMA1>, + <&iommu_vdo M4U_PORT_L19_JPGDEC_BSDMA1>, + <&iommu_vdo M4U_PORT_L19_JPGDEC_BUFF_OFFSET1>, + <&iommu_vdo M4U_PORT_L19_JPGDEC_BUFF_OFFSET0>; + interrupts = ; + clocks = <&vencsys CLK_VENC_JPGDEC>; + clock-names = "jpgdec"; + power-domains = <&spm MT8195_POWER_DOMAIN_VDEC0>; + }; + + jpgdec@1a050000 { + compatible = "mediatek,mt8195-jpgdec-hw"; + reg = <0 0x1a050000 0 0x10000>;/* JPGDEC_C1 */ + iommus = <&iommu_vdo M4U_PORT_L19_JPGDEC_WDMA0>, + <&iommu_vdo M4U_PORT_L19_JPGDEC_BSDMA0>, + <&iommu_vdo M4U_PORT_L19_JPGDEC_WDMA1>, + <&iommu_vdo M4U_PORT_L19_JPGDEC_BSDMA1>, + <&iommu_vdo M4U_PORT_L19_JPGDEC_BUFF_OFFSET1>, + <&iommu_vdo M4U_PORT_L19_JPGDEC_BUFF_OFFSET0>; + interrupts = ; + clocks = <&vencsys CLK_VENC_JPGDEC_C1>; + clock-names = "jpgdec"; + power-domains = <&spm MT8195_POWER_DOMAIN_VDEC1>; + }; + + jpgdec@1b040000 { + compatible = "mediatek,mt8195-jpgdec-hw"; + reg = <0 0x1b040000 0 0x10000>;/* JPGDEC_C2 */ + iommus = <&iommu_vpp M4U_PORT_L20_JPGDEC_WDMA0>, + <&iommu_vpp M4U_PORT_L20_JPGDEC_BSDMA0>, + <&iommu_vpp M4U_PORT_L20_JPGDEC_WDMA1>, + <&iommu_vpp M4U_PORT_L20_JPGDEC_BSDMA1>, + <&iommu_vpp M4U_PORT_L20_JPGDEC_BUFF_OFFSET1>, + <&iommu_vpp M4U_PORT_L20_JPGDEC_BUFF_OFFSET0>; + interrupts = ; + clocks = <&vencsys_core1 CLK_VENC_CORE1_JPGDEC>; + clock-names = "jpgdec"; + power-domains = <&spm MT8195_POWER_DOMAIN_VDEC2>; + }; + }; + }; -- cgit v1.2.3 From 08d530a8da706f157e9dcb4d9b7b4f0eff908ab9 Mon Sep 17 00:00:00 2001 From: kyrie wu Date: Thu, 29 Sep 2022 17:08:11 +0800 Subject: media: mtk-jpegdec: export jpeg decoder functions mtk jpeg decoder is built as a module, export some functions to make them visible by other modules. Signed-off-by: kyrie wu Signed-off-by: irui wang Signed-off-by: Hans Verkuil --- drivers/media/platform/mediatek/jpeg/mtk_jpeg_dec_hw.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/drivers/media/platform/mediatek/jpeg/mtk_jpeg_dec_hw.c b/drivers/media/platform/mediatek/jpeg/mtk_jpeg_dec_hw.c index 1e3852295f2f..d2f25f43e852 100644 --- a/drivers/media/platform/mediatek/jpeg/mtk_jpeg_dec_hw.c +++ b/drivers/media/platform/mediatek/jpeg/mtk_jpeg_dec_hw.c @@ -189,6 +189,7 @@ int mtk_jpeg_dec_fill_param(struct mtk_jpeg_dec_param *param) return 0; } +EXPORT_SYMBOL_GPL(mtk_jpeg_dec_fill_param); u32 mtk_jpeg_dec_get_int_status(void __iomem *base) { @@ -200,6 +201,7 @@ u32 mtk_jpeg_dec_get_int_status(void __iomem *base) return ret; } +EXPORT_SYMBOL_GPL(mtk_jpeg_dec_get_int_status); u32 mtk_jpeg_dec_enum_result(u32 irq_result) { @@ -216,11 +218,13 @@ u32 mtk_jpeg_dec_enum_result(u32 irq_result) return MTK_JPEG_DEC_RESULT_ERROR_UNKNOWN; } +EXPORT_SYMBOL_GPL(mtk_jpeg_dec_enum_result); void mtk_jpeg_dec_start(void __iomem *base) { writel(0, base + JPGDEC_REG_TRIG); } +EXPORT_SYMBOL_GPL(mtk_jpeg_dec_start); static void mtk_jpeg_dec_soft_reset(void __iomem *base) { @@ -240,6 +244,7 @@ void mtk_jpeg_dec_reset(void __iomem *base) mtk_jpeg_dec_soft_reset(base); mtk_jpeg_dec_hard_reset(base); } +EXPORT_SYMBOL_GPL(mtk_jpeg_dec_reset); static void mtk_jpeg_dec_set_brz_factor(void __iomem *base, u8 yscale_w, u8 yscale_h, u8 uvscale_w, u8 uvscale_h) @@ -408,3 +413,4 @@ void mtk_jpeg_dec_set_config(void __iomem *base, config->dma_last_mcu); mtk_jpeg_dec_set_pause_mcu_idx(base, config->total_mcu); } +EXPORT_SYMBOL_GPL(mtk_jpeg_dec_set_config); -- cgit v1.2.3 From 0fa49df4222f31be08242d41c415215e4ee43b13 Mon Sep 17 00:00:00 2001 From: kyrie wu Date: Thu, 29 Sep 2022 17:08:12 +0800 Subject: media: mtk-jpegdec: support jpegdec multi-hardware support jpegdec multi-hardware includes HW0/HW1/HW2. Signed-off-by: kyrie wu Signed-off-by: irui wang Signed-off-by: Hans Verkuil --- drivers/media/platform/mediatek/jpeg/Makefile | 5 +- .../media/platform/mediatek/jpeg/mtk_jpeg_core.h | 42 +++++ .../media/platform/mediatek/jpeg/mtk_jpeg_dec_hw.c | 169 +++++++++++++++++++++ 3 files changed, 214 insertions(+), 2 deletions(-) diff --git a/drivers/media/platform/mediatek/jpeg/Makefile b/drivers/media/platform/mediatek/jpeg/Makefile index 69703db4b0a5..26e84852523e 100644 --- a/drivers/media/platform/mediatek/jpeg/Makefile +++ b/drivers/media/platform/mediatek/jpeg/Makefile @@ -1,9 +1,10 @@ # SPDX-License-Identifier: GPL-2.0-only obj-$(CONFIG_VIDEO_MEDIATEK_JPEG) += mtk_jpeg.o \ - mtk-jpeg-enc-hw.o + mtk-jpeg-enc-hw.o \ + mtk-jpeg-dec-hw.o mtk_jpeg-y := mtk_jpeg_core.o \ - mtk_jpeg_dec_hw.o \ mtk_jpeg_dec_parse.o mtk-jpeg-enc-hw-y := mtk_jpeg_enc_hw.o +mtk-jpeg-dec-hw-y := mtk_jpeg_dec_hw.o diff --git a/drivers/media/platform/mediatek/jpeg/mtk_jpeg_core.h b/drivers/media/platform/mediatek/jpeg/mtk_jpeg_core.h index 0f69402ffce6..dd974409ae5e 100644 --- a/drivers/media/platform/mediatek/jpeg/mtk_jpeg_core.h +++ b/drivers/media/platform/mediatek/jpeg/mtk_jpeg_core.h @@ -102,6 +102,13 @@ enum mtk_jpegenc_hw_id { MTK_JPEGENC_HW_MAX, }; +enum mtk_jpegdec_hw_id { + MTK_JPEGDEC_HW0, + MTK_JPEGDEC_HW1, + MTK_JPEGDEC_HW2, + MTK_JPEGDEC_HW_MAX, +}; + /** * struct mtk_jpegenc_clk - Structure used to store vcodec clock information * @clks: JPEG encode clock @@ -112,6 +119,16 @@ struct mtk_jpegenc_clk { int clk_num; }; +/** + * struct mtk_jpegdec_clk - Structure used to store vcodec clock information + * @clks: JPEG decode clock + * @clk_num: JPEG decode clock numbers + */ +struct mtk_jpegdec_clk { + struct clk_bulk_data *clks; + int clk_num; +}; + /** * struct mtk_jpegenc_comp_dev - JPEG COREX abstraction * @dev: JPEG device @@ -140,6 +157,24 @@ struct mtk_jpegenc_comp_dev { spinlock_t hw_lock; }; +/** + * struct mtk_jpegdec_comp_dev - JPEG COREX abstraction + * @dev: JPEG device + * @plat_dev: platform device data + * @reg_base: JPEG registers mapping + * @master_dev: mtk_jpeg_dev device + * @jdec_clk: mtk_jpegdec_clk + * @jpegdec_irq: jpeg decode irq num + */ +struct mtk_jpegdec_comp_dev { + struct device *dev; + struct platform_device *plat_dev; + void __iomem *reg_base; + struct mtk_jpeg_dev *master_dev; + struct mtk_jpegdec_clk jdec_clk; + int jpegdec_irq; +}; + /** * struct mtk_jpeg_dev - JPEG IP abstraction * @lock: the mutex protecting this structure @@ -158,6 +193,9 @@ struct mtk_jpegenc_comp_dev { * @is_jpgenc_multihw: the flag of multi-hw core * @enc_hw_wq: jpg encode wait queue * @enchw_rdy: jpg encode hw ready flag + * @reg_decbase: jpg decode register base addr + * @dec_hw_dev: jpg decode hardware device + * @is_jpgdec_multihw: the flag of dec multi-hw core */ struct mtk_jpeg_dev { struct mutex lock; @@ -177,6 +215,10 @@ struct mtk_jpeg_dev { bool is_jpgenc_multihw; wait_queue_head_t enc_hw_wq; atomic_t enchw_rdy; + + void __iomem *reg_decbase[MTK_JPEGDEC_HW_MAX]; + struct mtk_jpegdec_comp_dev *dec_hw_dev[MTK_JPEGDEC_HW_MAX]; + bool is_jpgdec_multihw; }; /** diff --git a/drivers/media/platform/mediatek/jpeg/mtk_jpeg_dec_hw.c b/drivers/media/platform/mediatek/jpeg/mtk_jpeg_dec_hw.c index d2f25f43e852..bab50f750113 100644 --- a/drivers/media/platform/mediatek/jpeg/mtk_jpeg_dec_hw.c +++ b/drivers/media/platform/mediatek/jpeg/mtk_jpeg_dec_hw.c @@ -5,9 +5,24 @@ * Rick Chang */ +#include +#include +#include #include #include +#include +#include +#include +#include +#include +#include #include +#include +#include +#include +#include +#include +#include #include "mtk_jpeg_core.h" #include "mtk_jpeg_dec_hw.h" @@ -24,6 +39,16 @@ enum mtk_jpeg_color { MTK_JPEG_COLOR_400 = 0x00110000 }; +#if defined(CONFIG_OF) +static const struct of_device_id mtk_jpegdec_hw_ids[] = { + { + .compatible = "mediatek,mt8195-jpgdec-hw", + }, + {}, +}; +MODULE_DEVICE_TABLE(of, mtk_jpegdec_hw_ids); +#endif + static inline int mtk_jpeg_verify_align(u32 val, int align, u32 reg) { if (val & (align - 1)) { @@ -414,3 +439,147 @@ void mtk_jpeg_dec_set_config(void __iomem *base, mtk_jpeg_dec_set_pause_mcu_idx(base, config->total_mcu); } EXPORT_SYMBOL_GPL(mtk_jpeg_dec_set_config); + +static irqreturn_t mtk_jpegdec_hw_irq_handler(int irq, void *priv) +{ + struct vb2_v4l2_buffer *src_buf, *dst_buf; + struct mtk_jpeg_src_buf *jpeg_src_buf; + enum vb2_buffer_state buf_state; + struct mtk_jpeg_ctx *ctx; + u32 dec_irq_ret; + u32 irq_status; + int i; + + struct mtk_jpegdec_comp_dev *jpeg = priv; + struct mtk_jpeg_dev *master_jpeg = jpeg->master_dev; + + irq_status = mtk_jpeg_dec_get_int_status(jpeg->reg_base); + dec_irq_ret = mtk_jpeg_dec_enum_result(irq_status); + if (dec_irq_ret >= MTK_JPEG_DEC_RESULT_UNDERFLOW) + mtk_jpeg_dec_reset(jpeg->reg_base); + if (dec_irq_ret != MTK_JPEG_DEC_RESULT_EOF_DONE) + return IRQ_NONE; + + ctx = v4l2_m2m_get_curr_priv(master_jpeg->m2m_dev); + if (!ctx) { + dev_err(jpeg->dev, "Context is NULL\n"); + return IRQ_HANDLED; + } + + src_buf = v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx); + dst_buf = v4l2_m2m_dst_buf_remove(ctx->fh.m2m_ctx); + v4l2_m2m_buf_copy_metadata(src_buf, dst_buf, true); + jpeg_src_buf = + container_of(src_buf, struct mtk_jpeg_src_buf, b); + + for (i = 0; i < dst_buf->vb2_buf.num_planes; i++) + vb2_set_plane_payload(&dst_buf->vb2_buf, i, + jpeg_src_buf->dec_param.comp_size[i]); + + buf_state = VB2_BUF_STATE_DONE; + + v4l2_m2m_buf_done(src_buf, buf_state); + v4l2_m2m_buf_done(dst_buf, buf_state); + v4l2_m2m_job_finish(master_jpeg->m2m_dev, ctx->fh.m2m_ctx); + pm_runtime_put(ctx->jpeg->dev); + + return IRQ_HANDLED; +} + +static int mtk_jpegdec_hw_init_irq(struct mtk_jpegdec_comp_dev *dev) +{ + struct platform_device *pdev = dev->plat_dev; + int ret; + + dev->jpegdec_irq = platform_get_irq(pdev, 0); + if (dev->jpegdec_irq < 0) + return dev->jpegdec_irq; + + ret = devm_request_irq(&pdev->dev, + dev->jpegdec_irq, + mtk_jpegdec_hw_irq_handler, + 0, + pdev->name, dev); + if (ret) { + dev_err(&pdev->dev, "Failed to devm_request_irq %d (%d)", + dev->jpegdec_irq, ret); + return ret; + } + + return 0; +} + +static int mtk_jpegdec_hw_probe(struct platform_device *pdev) +{ + struct mtk_jpegdec_clk *jpegdec_clk; + struct mtk_jpeg_dev *master_dev; + struct mtk_jpegdec_comp_dev *dev; + int ret, i; + + struct device *decs = &pdev->dev; + + if (!decs->parent) + return -EPROBE_DEFER; + + master_dev = dev_get_drvdata(decs->parent); + if (!master_dev) + return -EPROBE_DEFER; + + dev = devm_kzalloc(&pdev->dev, sizeof(*dev), GFP_KERNEL); + if (!dev) + return -ENOMEM; + + dev->plat_dev = pdev; + dev->dev = &pdev->dev; + + if (!master_dev->is_jpgdec_multihw) { + master_dev->is_jpgdec_multihw = true; + for (i = 0; i < MTK_JPEGDEC_HW_MAX; i++) + master_dev->dec_hw_dev[i] = NULL; + } + + jpegdec_clk = &dev->jdec_clk; + + jpegdec_clk->clk_num = devm_clk_bulk_get_all(&pdev->dev, + &jpegdec_clk->clks); + if (jpegdec_clk->clk_num < 0) + return dev_err_probe(&pdev->dev, + jpegdec_clk->clk_num, + "Failed to get jpegdec clock count.\n"); + + dev->reg_base = devm_platform_ioremap_resource(pdev, 0); + if (IS_ERR(dev->reg_base)) + return PTR_ERR(dev->reg_base); + + ret = mtk_jpegdec_hw_init_irq(dev); + if (ret) + return dev_err_probe(&pdev->dev, ret, + "Failed to register JPEGDEC irq handler.\n"); + + for (i = 0; i < MTK_JPEGDEC_HW_MAX; i++) { + if (master_dev->dec_hw_dev[i]) + continue; + + master_dev->dec_hw_dev[i] = dev; + master_dev->reg_decbase[i] = dev->reg_base; + dev->master_dev = master_dev; + } + + platform_set_drvdata(pdev, dev); + pm_runtime_enable(&pdev->dev); + + return 0; +} + +static struct platform_driver mtk_jpegdec_hw_driver = { + .probe = mtk_jpegdec_hw_probe, + .driver = { + .name = "mtk-jpegdec-hw", + .of_match_table = of_match_ptr(mtk_jpegdec_hw_ids), + }, +}; + +module_platform_driver(mtk_jpegdec_hw_driver); + +MODULE_DESCRIPTION("MediaTek JPEG decode HW driver"); +MODULE_LICENSE("GPL"); -- cgit v1.2.3 From e5f969dd937705289b95f91a018ace6a5ab3f5a2 Mon Sep 17 00:00:00 2001 From: kyrie wu Date: Thu, 29 Sep 2022 17:08:13 +0800 Subject: media: mtk-jpegdec: add jpegdec timeout func interface Generalizes jpegdec timeout func interfaces to handle HW timeout. Signed-off-by: kyrie wu Signed-off-by: irui wang Signed-off-by: Hans Verkuil --- .../media/platform/mediatek/jpeg/mtk_jpeg_core.h | 4 ++++ .../media/platform/mediatek/jpeg/mtk_jpeg_dec_hw.c | 24 ++++++++++++++++++++++ 2 files changed, 28 insertions(+) diff --git a/drivers/media/platform/mediatek/jpeg/mtk_jpeg_core.h b/drivers/media/platform/mediatek/jpeg/mtk_jpeg_core.h index dd974409ae5e..391c4ec25b2c 100644 --- a/drivers/media/platform/mediatek/jpeg/mtk_jpeg_core.h +++ b/drivers/media/platform/mediatek/jpeg/mtk_jpeg_core.h @@ -165,6 +165,8 @@ struct mtk_jpegenc_comp_dev { * @master_dev: mtk_jpeg_dev device * @jdec_clk: mtk_jpegdec_clk * @jpegdec_irq: jpeg decode irq num + * @job_timeout_work: decode timeout workqueue + * @hw_param: jpeg decode hw parameters */ struct mtk_jpegdec_comp_dev { struct device *dev; @@ -173,6 +175,8 @@ struct mtk_jpegdec_comp_dev { struct mtk_jpeg_dev *master_dev; struct mtk_jpegdec_clk jdec_clk; int jpegdec_irq; + struct delayed_work job_timeout_work; + struct mtk_jpeg_hw_param hw_param; }; /** diff --git a/drivers/media/platform/mediatek/jpeg/mtk_jpeg_dec_hw.c b/drivers/media/platform/mediatek/jpeg/mtk_jpeg_dec_hw.c index bab50f750113..d65cc0a3b663 100644 --- a/drivers/media/platform/mediatek/jpeg/mtk_jpeg_dec_hw.c +++ b/drivers/media/platform/mediatek/jpeg/mtk_jpeg_dec_hw.c @@ -440,6 +440,25 @@ void mtk_jpeg_dec_set_config(void __iomem *base, } EXPORT_SYMBOL_GPL(mtk_jpeg_dec_set_config); +static void mtk_jpegdec_timeout_work(struct work_struct *work) +{ + enum vb2_buffer_state buf_state = VB2_BUF_STATE_ERROR; + struct mtk_jpegdec_comp_dev *cjpeg = + container_of(work, struct mtk_jpegdec_comp_dev, + job_timeout_work.work); + struct vb2_v4l2_buffer *src_buf, *dst_buf; + + src_buf = cjpeg->hw_param.src_buffer; + dst_buf = cjpeg->hw_param.dst_buffer; + v4l2_m2m_buf_copy_metadata(src_buf, dst_buf, true); + + mtk_jpeg_dec_reset(cjpeg->reg_base); + clk_disable_unprepare(cjpeg->jdec_clk.clks->clk); + pm_runtime_put(cjpeg->dev); + v4l2_m2m_buf_done(src_buf, buf_state); + v4l2_m2m_buf_done(dst_buf, buf_state); +} + static irqreturn_t mtk_jpegdec_hw_irq_handler(int irq, void *priv) { struct vb2_v4l2_buffer *src_buf, *dst_buf; @@ -453,6 +472,8 @@ static irqreturn_t mtk_jpegdec_hw_irq_handler(int irq, void *priv) struct mtk_jpegdec_comp_dev *jpeg = priv; struct mtk_jpeg_dev *master_jpeg = jpeg->master_dev; + cancel_delayed_work(&jpeg->job_timeout_work); + irq_status = mtk_jpeg_dec_get_int_status(jpeg->reg_base); dec_irq_ret = mtk_jpeg_dec_enum_result(irq_status); if (dec_irq_ret >= MTK_JPEG_DEC_RESULT_UNDERFLOW) @@ -538,6 +559,9 @@ static int mtk_jpegdec_hw_probe(struct platform_device *pdev) master_dev->dec_hw_dev[i] = NULL; } + INIT_DELAYED_WORK(&dev->job_timeout_work, + mtk_jpegdec_timeout_work); + jpegdec_clk = &dev->jdec_clk; jpegdec_clk->clk_num = devm_clk_bulk_get_all(&pdev->dev, -- cgit v1.2.3 From dedc21500334b97b80d4ca37ab683cde214fcb03 Mon Sep 17 00:00:00 2001 From: kyrie wu Date: Thu, 29 Sep 2022 17:08:14 +0800 Subject: media: mtk-jpegdec: add jpeg decode worker interface Add jpeg decoding worker to ensure that three HWs run in parallel in MT8195. Signed-off-by: kyrie wu Signed-off-by: irui wang Signed-off-by: Hans Verkuil --- .../media/platform/mediatek/jpeg/mtk_jpeg_core.c | 196 +++++++++++++++++++++ .../media/platform/mediatek/jpeg/mtk_jpeg_core.h | 11 ++ .../media/platform/mediatek/jpeg/mtk_jpeg_dec_hw.c | 39 ++-- 3 files changed, 234 insertions(+), 12 deletions(-) diff --git a/drivers/media/platform/mediatek/jpeg/mtk_jpeg_core.c b/drivers/media/platform/mediatek/jpeg/mtk_jpeg_core.c index debee9b82158..453962e429ae 100644 --- a/drivers/media/platform/mediatek/jpeg/mtk_jpeg_core.c +++ b/drivers/media/platform/mediatek/jpeg/mtk_jpeg_core.c @@ -1100,6 +1100,180 @@ static void mtk_jpeg_multicore_enc_device_run(void *priv) queue_work(jpeg->workqueue, &ctx->jpeg_work); } +static int mtk_jpegdec_get_hw(struct mtk_jpeg_ctx *ctx) +{ + struct mtk_jpegdec_comp_dev *comp_jpeg; + struct mtk_jpeg_dev *jpeg = ctx->jpeg; + unsigned long flags; + int hw_id = -1; + int i; + + spin_lock_irqsave(&jpeg->hw_lock, flags); + for (i = 0; i < MTK_JPEGDEC_HW_MAX; i++) { + comp_jpeg = jpeg->dec_hw_dev[i]; + if (comp_jpeg->hw_state == MTK_JPEG_HW_IDLE) { + hw_id = i; + comp_jpeg->hw_state = MTK_JPEG_HW_BUSY; + break; + } + } + spin_unlock_irqrestore(&jpeg->hw_lock, flags); + + return hw_id; +} + +static int mtk_jpegdec_put_hw(struct mtk_jpeg_dev *jpeg, int hw_id) +{ + unsigned long flags; + + spin_lock_irqsave(&jpeg->hw_lock, flags); + jpeg->dec_hw_dev[hw_id]->hw_state = + MTK_JPEG_HW_IDLE; + spin_unlock_irqrestore(&jpeg->hw_lock, flags); + + return 0; +} + +static int mtk_jpegdec_set_hw_param(struct mtk_jpeg_ctx *ctx, + int hw_id, + struct vb2_v4l2_buffer *src_buf, + struct vb2_v4l2_buffer *dst_buf) +{ + struct mtk_jpegdec_comp_dev *jpeg = + ctx->jpeg->dec_hw_dev[hw_id]; + + jpeg->hw_param.curr_ctx = ctx; + jpeg->hw_param.src_buffer = src_buf; + jpeg->hw_param.dst_buffer = dst_buf; + + return 0; +} + +static void mtk_jpegdec_worker(struct work_struct *work) +{ + struct mtk_jpeg_ctx *ctx = container_of(work, struct mtk_jpeg_ctx, + jpeg_work); + struct mtk_jpegdec_comp_dev *comp_jpeg[MTK_JPEGDEC_HW_MAX]; + enum vb2_buffer_state buf_state = VB2_BUF_STATE_ERROR; + struct mtk_jpeg_src_buf *jpeg_src_buf, *jpeg_dst_buf; + struct vb2_v4l2_buffer *src_buf, *dst_buf; + struct mtk_jpeg_dev *jpeg = ctx->jpeg; + int ret, i, hw_id = 0; + struct mtk_jpeg_bs bs; + struct mtk_jpeg_fb fb; + unsigned long flags; + + for (i = 0; i < MTK_JPEGDEC_HW_MAX; i++) + comp_jpeg[i] = jpeg->dec_hw_dev[i]; + i = 0; + +retry_select: + hw_id = mtk_jpegdec_get_hw(ctx); + if (hw_id < 0) { + ret = wait_event_interruptible_timeout(jpeg->dec_hw_wq, + atomic_read(&jpeg->dechw_rdy) > 0, + MTK_JPEG_HW_TIMEOUT_MSEC); + if (ret != 0 || (i++ > MTK_JPEG_MAX_RETRY_TIME)) { + dev_err(jpeg->dev, "%s : %d, all HW are busy\n", + __func__, __LINE__); + v4l2_m2m_job_finish(jpeg->m2m_dev, ctx->fh.m2m_ctx); + return; + } + + goto retry_select; + } + + atomic_dec(&jpeg->dechw_rdy); + src_buf = v4l2_m2m_next_src_buf(ctx->fh.m2m_ctx); + if (!src_buf) + goto getbuf_fail; + + dst_buf = v4l2_m2m_next_dst_buf(ctx->fh.m2m_ctx); + if (!dst_buf) + goto getbuf_fail; + + v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx); + v4l2_m2m_dst_buf_remove(ctx->fh.m2m_ctx); + + v4l2_m2m_buf_copy_metadata(src_buf, dst_buf, true); + jpeg_src_buf = mtk_jpeg_vb2_to_srcbuf(&src_buf->vb2_buf); + jpeg_dst_buf = mtk_jpeg_vb2_to_srcbuf(&dst_buf->vb2_buf); + + if (mtk_jpeg_check_resolution_change(ctx, + &jpeg_src_buf->dec_param)) { + mtk_jpeg_queue_src_chg_event(ctx); + ctx->state = MTK_JPEG_SOURCE_CHANGE; + goto dec_end; + } + + jpeg_src_buf->curr_ctx = ctx; + jpeg_src_buf->frame_num = ctx->total_frame_num; + jpeg_dst_buf->curr_ctx = ctx; + jpeg_dst_buf->frame_num = ctx->total_frame_num; + ctx->total_frame_num++; + + mtk_jpegdec_set_hw_param(ctx, hw_id, src_buf, dst_buf); + ret = pm_runtime_get_sync(comp_jpeg[hw_id]->dev); + if (ret < 0) { + dev_err(jpeg->dev, "%s : %d, pm_runtime_get_sync fail !!!\n", + __func__, __LINE__); + goto dec_end; + } + + ret = clk_prepare_enable(comp_jpeg[hw_id]->jdec_clk.clks->clk); + if (ret) { + dev_err(jpeg->dev, "%s : %d, jpegdec clk_prepare_enable fail\n", + __func__, __LINE__); + goto clk_end; + } + + schedule_delayed_work(&comp_jpeg[hw_id]->job_timeout_work, + msecs_to_jiffies(MTK_JPEG_HW_TIMEOUT_MSEC)); + + mtk_jpeg_set_dec_src(ctx, &src_buf->vb2_buf, &bs); + if (mtk_jpeg_set_dec_dst(ctx, + &jpeg_src_buf->dec_param, + &dst_buf->vb2_buf, &fb)) { + dev_err(jpeg->dev, "%s : %d, mtk_jpeg_set_dec_dst fail\n", + __func__, __LINE__); + goto setdst_end; + } + + spin_lock_irqsave(&comp_jpeg[hw_id]->hw_lock, flags); + mtk_jpeg_dec_reset(comp_jpeg[hw_id]->reg_base); + mtk_jpeg_dec_set_config(jpeg->reg_base, + &jpeg_src_buf->dec_param, + &bs, + &fb); + mtk_jpeg_dec_start(comp_jpeg[hw_id]->reg_base); + v4l2_m2m_job_finish(jpeg->m2m_dev, ctx->fh.m2m_ctx); + spin_unlock_irqrestore(&comp_jpeg[hw_id]->hw_lock, flags); + + return; + +setdst_end: + clk_disable_unprepare(comp_jpeg[hw_id]->jdec_clk.clks->clk); +clk_end: + pm_runtime_put(comp_jpeg[hw_id]->dev); +dec_end: + v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx); + v4l2_m2m_dst_buf_remove(ctx->fh.m2m_ctx); + v4l2_m2m_buf_done(src_buf, buf_state); + v4l2_m2m_buf_done(dst_buf, buf_state); +getbuf_fail: + atomic_inc(&jpeg->dechw_rdy); + mtk_jpegdec_put_hw(jpeg, hw_id); + v4l2_m2m_job_finish(jpeg->m2m_dev, ctx->fh.m2m_ctx); +} + +static void mtk_jpeg_multicore_dec_device_run(void *priv) +{ + struct mtk_jpeg_ctx *ctx = priv; + struct mtk_jpeg_dev *jpeg = ctx->jpeg; + + queue_work(jpeg->workqueue, &ctx->jpeg_work); +} + static void mtk_jpeg_dec_device_run(void *priv) { struct mtk_jpeg_ctx *ctx = priv; @@ -1166,6 +1340,10 @@ static const struct v4l2_m2m_ops mtk_jpeg_multicore_enc_m2m_ops = { .device_run = mtk_jpeg_multicore_enc_device_run, }; +static const struct v4l2_m2m_ops mtk_jpeg_multicore_dec_m2m_ops = { + .device_run = mtk_jpeg_multicore_dec_device_run, +}; + static const struct v4l2_m2m_ops mtk_jpeg_dec_m2m_ops = { .device_run = mtk_jpeg_dec_device_run, .job_ready = mtk_jpeg_dec_job_ready, @@ -1369,6 +1547,9 @@ static int mtk_jpeg_open(struct file *file) if (jpeg->is_jpgenc_multihw) INIT_WORK(&ctx->jpeg_work, mtk_jpegenc_worker); + if (jpeg->is_jpgdec_multihw) + INIT_WORK(&ctx->jpeg_work, mtk_jpegdec_worker); + INIT_LIST_HEAD(&ctx->dst_done_queue); spin_lock_init(&ctx->done_queue_lock); v4l2_fh_init(&ctx->fh, vfd); @@ -1675,6 +1856,17 @@ static struct mtk_jpeg_variant mtk8195_jpegenc_drvdata = { .cap_q_default_fourcc = V4L2_PIX_FMT_JPEG, }; +static const struct mtk_jpeg_variant mtk8195_jpegdec_drvdata = { + .formats = mtk_jpeg_dec_formats, + .num_formats = MTK_JPEG_DEC_NUM_FORMATS, + .qops = &mtk_jpeg_dec_qops, + .m2m_ops = &mtk_jpeg_multicore_dec_m2m_ops, + .dev_name = "mtk-jpeg-dec", + .ioctl_ops = &mtk_jpeg_dec_ioctl_ops, + .out_q_default_fourcc = V4L2_PIX_FMT_JPEG, + .cap_q_default_fourcc = V4L2_PIX_FMT_YUV420M, +}; + #if defined(CONFIG_OF) static const struct of_device_id mtk_jpeg_match[] = { { @@ -1693,6 +1885,10 @@ static const struct of_device_id mtk_jpeg_match[] = { .compatible = "mediatek,mt8195-jpgenc", .data = &mtk8195_jpegenc_drvdata, }, + { + .compatible = "mediatek,mt8195-jpgdec", + .data = &mtk8195_jpegdec_drvdata, + }, {}, }; diff --git a/drivers/media/platform/mediatek/jpeg/mtk_jpeg_core.h b/drivers/media/platform/mediatek/jpeg/mtk_jpeg_core.h index 391c4ec25b2c..0713b8d14356 100644 --- a/drivers/media/platform/mediatek/jpeg/mtk_jpeg_core.h +++ b/drivers/media/platform/mediatek/jpeg/mtk_jpeg_core.h @@ -167,6 +167,8 @@ struct mtk_jpegenc_comp_dev { * @jpegdec_irq: jpeg decode irq num * @job_timeout_work: decode timeout workqueue * @hw_param: jpeg decode hw parameters + * @hw_state: record hw state + * @hw_lock: spinlock protecting hw */ struct mtk_jpegdec_comp_dev { struct device *dev; @@ -177,6 +179,9 @@ struct mtk_jpegdec_comp_dev { int jpegdec_irq; struct delayed_work job_timeout_work; struct mtk_jpeg_hw_param hw_param; + enum mtk_jpeg_hw_state hw_state; + /* spinlock protecting the hw device resource */ + spinlock_t hw_lock; }; /** @@ -200,6 +205,9 @@ struct mtk_jpegdec_comp_dev { * @reg_decbase: jpg decode register base addr * @dec_hw_dev: jpg decode hardware device * @is_jpgdec_multihw: the flag of dec multi-hw core + * @dec_hw_wq: jpg decode wait queue + * @dec_workqueue: jpg decode work queue + * @dechw_rdy: jpg decode hw ready flag */ struct mtk_jpeg_dev { struct mutex lock; @@ -223,6 +231,9 @@ struct mtk_jpeg_dev { void __iomem *reg_decbase[MTK_JPEGDEC_HW_MAX]; struct mtk_jpegdec_comp_dev *dec_hw_dev[MTK_JPEGDEC_HW_MAX]; bool is_jpgdec_multihw; + wait_queue_head_t dec_hw_wq; + struct workqueue_struct *dec_workqueue; + atomic_t dechw_rdy; }; /** diff --git a/drivers/media/platform/mediatek/jpeg/mtk_jpeg_dec_hw.c b/drivers/media/platform/mediatek/jpeg/mtk_jpeg_dec_hw.c index d65cc0a3b663..f7e3013234d3 100644 --- a/drivers/media/platform/mediatek/jpeg/mtk_jpeg_dec_hw.c +++ b/drivers/media/platform/mediatek/jpeg/mtk_jpeg_dec_hw.c @@ -446,6 +446,7 @@ static void mtk_jpegdec_timeout_work(struct work_struct *work) struct mtk_jpegdec_comp_dev *cjpeg = container_of(work, struct mtk_jpegdec_comp_dev, job_timeout_work.work); + struct mtk_jpeg_dev *master_jpeg = cjpeg->master_dev; struct vb2_v4l2_buffer *src_buf, *dst_buf; src_buf = cjpeg->hw_param.src_buffer; @@ -455,6 +456,9 @@ static void mtk_jpegdec_timeout_work(struct work_struct *work) mtk_jpeg_dec_reset(cjpeg->reg_base); clk_disable_unprepare(cjpeg->jdec_clk.clks->clk); pm_runtime_put(cjpeg->dev); + cjpeg->hw_state = MTK_JPEG_HW_IDLE; + atomic_inc(&master_jpeg->dechw_rdy); + wake_up(&master_jpeg->dec_hw_wq); v4l2_m2m_buf_done(src_buf, buf_state); v4l2_m2m_buf_done(dst_buf, buf_state); } @@ -474,22 +478,19 @@ static irqreturn_t mtk_jpegdec_hw_irq_handler(int irq, void *priv) cancel_delayed_work(&jpeg->job_timeout_work); + ctx = jpeg->hw_param.curr_ctx; + src_buf = jpeg->hw_param.src_buffer; + dst_buf = jpeg->hw_param.dst_buffer; + v4l2_m2m_buf_copy_metadata(src_buf, dst_buf, true); + irq_status = mtk_jpeg_dec_get_int_status(jpeg->reg_base); dec_irq_ret = mtk_jpeg_dec_enum_result(irq_status); if (dec_irq_ret >= MTK_JPEG_DEC_RESULT_UNDERFLOW) mtk_jpeg_dec_reset(jpeg->reg_base); - if (dec_irq_ret != MTK_JPEG_DEC_RESULT_EOF_DONE) - return IRQ_NONE; - ctx = v4l2_m2m_get_curr_priv(master_jpeg->m2m_dev); - if (!ctx) { - dev_err(jpeg->dev, "Context is NULL\n"); - return IRQ_HANDLED; - } + if (dec_irq_ret != MTK_JPEG_DEC_RESULT_EOF_DONE) + dev_warn(jpeg->dev, "Jpg Dec occurs unknown Err."); - src_buf = v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx); - dst_buf = v4l2_m2m_dst_buf_remove(ctx->fh.m2m_ctx); - v4l2_m2m_buf_copy_metadata(src_buf, dst_buf, true); jpeg_src_buf = container_of(src_buf, struct mtk_jpeg_src_buf, b); @@ -498,11 +499,14 @@ static irqreturn_t mtk_jpegdec_hw_irq_handler(int irq, void *priv) jpeg_src_buf->dec_param.comp_size[i]); buf_state = VB2_BUF_STATE_DONE; - v4l2_m2m_buf_done(src_buf, buf_state); v4l2_m2m_buf_done(dst_buf, buf_state); - v4l2_m2m_job_finish(master_jpeg->m2m_dev, ctx->fh.m2m_ctx); pm_runtime_put(ctx->jpeg->dev); + clk_disable_unprepare(jpeg->jdec_clk.clks->clk); + + jpeg->hw_state = MTK_JPEG_HW_IDLE; + wake_up(&master_jpeg->dec_hw_wq); + atomic_inc(&master_jpeg->dechw_rdy); return IRQ_HANDLED; } @@ -557,8 +561,19 @@ static int mtk_jpegdec_hw_probe(struct platform_device *pdev) master_dev->is_jpgdec_multihw = true; for (i = 0; i < MTK_JPEGDEC_HW_MAX; i++) master_dev->dec_hw_dev[i] = NULL; + + init_waitqueue_head(&master_dev->dec_hw_wq); + master_dev->workqueue = alloc_ordered_workqueue(MTK_JPEG_NAME, + WQ_MEM_RECLAIM + | WQ_FREEZABLE); + if (!master_dev->workqueue) + return -EINVAL; } + atomic_set(&master_dev->dechw_rdy, MTK_JPEGDEC_HW_MAX); + spin_lock_init(&dev->hw_lock); + dev->hw_state = MTK_JPEG_HW_IDLE; + INIT_DELAYED_WORK(&dev->job_timeout_work, mtk_jpegdec_timeout_work); -- cgit v1.2.3 From 7915282498e398861a1db7f52ce0252ecc562104 Mon Sep 17 00:00:00 2001 From: kyrie wu Date: Thu, 29 Sep 2022 17:08:15 +0800 Subject: media: mtk-jpegdec: add output pic reorder interface add output reorder func to reorder the output images to ensure the output pic is consistent with the input images. Signed-off-by: kyrie wu Signed-off-by: irui wang Signed-off-by: Hans Verkuil --- .../media/platform/mediatek/jpeg/mtk_jpeg_dec_hw.c | 47 +++++++++++++++++++++- 1 file changed, 45 insertions(+), 2 deletions(-) diff --git a/drivers/media/platform/mediatek/jpeg/mtk_jpeg_dec_hw.c b/drivers/media/platform/mediatek/jpeg/mtk_jpeg_dec_hw.c index f7e3013234d3..95fce3f3c0c6 100644 --- a/drivers/media/platform/mediatek/jpeg/mtk_jpeg_dec_hw.c +++ b/drivers/media/platform/mediatek/jpeg/mtk_jpeg_dec_hw.c @@ -440,6 +440,49 @@ void mtk_jpeg_dec_set_config(void __iomem *base, } EXPORT_SYMBOL_GPL(mtk_jpeg_dec_set_config); +static void mtk_jpegdec_put_buf(struct mtk_jpegdec_comp_dev *jpeg) +{ + struct mtk_jpeg_src_buf *dst_done_buf, *tmp_dst_done_buf; + struct vb2_v4l2_buffer *dst_buffer; + struct list_head *temp_entry; + struct list_head *pos = NULL; + struct mtk_jpeg_ctx *ctx; + unsigned long flags; + + ctx = jpeg->hw_param.curr_ctx; + if (unlikely(!ctx)) { + dev_err(jpeg->dev, "comp_jpeg ctx fail !!!\n"); + return; + } + + dst_buffer = jpeg->hw_param.dst_buffer; + if (!dst_buffer) { + dev_err(jpeg->dev, "comp_jpeg dst_buffer fail !!!\n"); + return; + } + + dst_done_buf = container_of(dst_buffer, struct mtk_jpeg_src_buf, b); + + spin_lock_irqsave(&ctx->done_queue_lock, flags); + list_add_tail(&dst_done_buf->list, &ctx->dst_done_queue); + while (!list_empty(&ctx->dst_done_queue) && + (pos != &ctx->dst_done_queue)) { + list_for_each_prev_safe(pos, temp_entry, &ctx->dst_done_queue) { + tmp_dst_done_buf = list_entry(pos, + struct mtk_jpeg_src_buf, + list); + if (tmp_dst_done_buf->frame_num == + ctx->last_done_frame_num) { + list_del(&tmp_dst_done_buf->list); + v4l2_m2m_buf_done(&tmp_dst_done_buf->b, + VB2_BUF_STATE_DONE); + ctx->last_done_frame_num++; + } + } + } + spin_unlock_irqrestore(&ctx->done_queue_lock, flags); +} + static void mtk_jpegdec_timeout_work(struct work_struct *work) { enum vb2_buffer_state buf_state = VB2_BUF_STATE_ERROR; @@ -460,7 +503,7 @@ static void mtk_jpegdec_timeout_work(struct work_struct *work) atomic_inc(&master_jpeg->dechw_rdy); wake_up(&master_jpeg->dec_hw_wq); v4l2_m2m_buf_done(src_buf, buf_state); - v4l2_m2m_buf_done(dst_buf, buf_state); + mtk_jpegdec_put_buf(cjpeg); } static irqreturn_t mtk_jpegdec_hw_irq_handler(int irq, void *priv) @@ -500,7 +543,7 @@ static irqreturn_t mtk_jpegdec_hw_irq_handler(int irq, void *priv) buf_state = VB2_BUF_STATE_DONE; v4l2_m2m_buf_done(src_buf, buf_state); - v4l2_m2m_buf_done(dst_buf, buf_state); + mtk_jpegdec_put_buf(jpeg); pm_runtime_put(ctx->jpeg->dev); clk_disable_unprepare(jpeg->jdec_clk.clks->clk); -- cgit v1.2.3 From 52f68114857fe55ecb640257e51680e24531466d Mon Sep 17 00:00:00 2001 From: kyrie wu Date: Thu, 29 Sep 2022 17:08:16 +0800 Subject: media: mtk-jpegdec: refactor jpegdec func interface refactor the func interface of mtk_jpeg_dec_set_config for decode Signed-off-by: kyrie wu Signed-off-by: irui wang Signed-off-by: Hans Verkuil --- .../media/platform/mediatek/jpeg/mtk_jpeg_core.c | 38 +++++++++++++-- .../media/platform/mediatek/jpeg/mtk_jpeg_core.h | 1 + .../media/platform/mediatek/jpeg/mtk_jpeg_dec_hw.c | 55 ++++++++++++---------- .../media/platform/mediatek/jpeg/mtk_jpeg_dec_hw.h | 3 +- .../platform/mediatek/jpeg/mtk_jpeg_dec_reg.h | 1 + 5 files changed, 66 insertions(+), 32 deletions(-) diff --git a/drivers/media/platform/mediatek/jpeg/mtk_jpeg_core.c b/drivers/media/platform/mediatek/jpeg/mtk_jpeg_core.c index 453962e429ae..c77496ea4e11 100644 --- a/drivers/media/platform/mediatek/jpeg/mtk_jpeg_core.c +++ b/drivers/media/platform/mediatek/jpeg/mtk_jpeg_core.c @@ -586,6 +586,31 @@ static int mtk_jpeg_enc_s_selection(struct file *file, void *priv, return 0; } +static int mtk_jpeg_qbuf(struct file *file, void *priv, struct v4l2_buffer *buf) +{ + struct v4l2_fh *fh = file->private_data; + struct mtk_jpeg_ctx *ctx = mtk_jpeg_fh_to_ctx(priv); + struct vb2_queue *vq; + struct vb2_buffer *vb; + struct mtk_jpeg_src_buf *jpeg_src_buf; + + if (buf->type != V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) + goto end; + + vq = v4l2_m2m_get_vq(fh->m2m_ctx, buf->type); + if (buf->index >= vq->num_buffers) { + dev_err(ctx->jpeg->dev, "buffer index out of range\n"); + return -EINVAL; + } + + vb = vq->bufs[buf->index]; + jpeg_src_buf = mtk_jpeg_vb2_to_srcbuf(vb); + jpeg_src_buf->bs_size = buf->m.planes[0].bytesused; + +end: + return v4l2_m2m_qbuf(file, fh->m2m_ctx, buf); +} + static const struct v4l2_ioctl_ops mtk_jpeg_enc_ioctl_ops = { .vidioc_querycap = mtk_jpeg_querycap, .vidioc_enum_fmt_vid_cap = mtk_jpeg_enum_fmt_vid_cap, @@ -626,7 +651,7 @@ static const struct v4l2_ioctl_ops mtk_jpeg_dec_ioctl_ops = { .vidioc_g_fmt_vid_out_mplane = mtk_jpeg_g_fmt_vid_mplane, .vidioc_s_fmt_vid_cap_mplane = mtk_jpeg_s_fmt_vid_cap_mplane, .vidioc_s_fmt_vid_out_mplane = mtk_jpeg_s_fmt_vid_out_mplane, - .vidioc_qbuf = v4l2_m2m_ioctl_qbuf, + .vidioc_qbuf = mtk_jpeg_qbuf, .vidioc_subscribe_event = mtk_jpeg_subscribe_event, .vidioc_g_selection = mtk_jpeg_dec_g_selection, @@ -1210,7 +1235,6 @@ retry_select: jpeg_src_buf->frame_num = ctx->total_frame_num; jpeg_dst_buf->curr_ctx = ctx; jpeg_dst_buf->frame_num = ctx->total_frame_num; - ctx->total_frame_num++; mtk_jpegdec_set_hw_param(ctx, hw_id, src_buf, dst_buf); ret = pm_runtime_get_sync(comp_jpeg[hw_id]->dev); @@ -1240,9 +1264,11 @@ retry_select: } spin_lock_irqsave(&comp_jpeg[hw_id]->hw_lock, flags); + ctx->total_frame_num++; mtk_jpeg_dec_reset(comp_jpeg[hw_id]->reg_base); - mtk_jpeg_dec_set_config(jpeg->reg_base, + mtk_jpeg_dec_set_config(comp_jpeg[hw_id]->reg_base, &jpeg_src_buf->dec_param, + jpeg_src_buf->bs_size, &bs, &fb); mtk_jpeg_dec_start(comp_jpeg[hw_id]->reg_base); @@ -1311,8 +1337,10 @@ static void mtk_jpeg_dec_device_run(void *priv) spin_lock_irqsave(&jpeg->hw_lock, flags); mtk_jpeg_dec_reset(jpeg->reg_base); mtk_jpeg_dec_set_config(jpeg->reg_base, - &jpeg_src_buf->dec_param, &bs, &fb); - + &jpeg_src_buf->dec_param, + jpeg_src_buf->bs_size, + &bs, + &fb); mtk_jpeg_dec_start(jpeg->reg_base); spin_unlock_irqrestore(&jpeg->hw_lock, flags); return; diff --git a/drivers/media/platform/mediatek/jpeg/mtk_jpeg_core.h b/drivers/media/platform/mediatek/jpeg/mtk_jpeg_core.h index 0713b8d14356..b9126476be8f 100644 --- a/drivers/media/platform/mediatek/jpeg/mtk_jpeg_core.h +++ b/drivers/media/platform/mediatek/jpeg/mtk_jpeg_core.h @@ -80,6 +80,7 @@ struct mtk_jpeg_src_buf { u32 frame_num; struct vb2_v4l2_buffer b; struct list_head list; + u32 bs_size; struct mtk_jpeg_dec_param dec_param; struct mtk_jpeg_ctx *curr_ctx; diff --git a/drivers/media/platform/mediatek/jpeg/mtk_jpeg_dec_hw.c b/drivers/media/platform/mediatek/jpeg/mtk_jpeg_dec_hw.c index 95fce3f3c0c6..d98f4cdfeea9 100644 --- a/drivers/media/platform/mediatek/jpeg/mtk_jpeg_dec_hw.c +++ b/drivers/media/platform/mediatek/jpeg/mtk_jpeg_dec_hw.c @@ -330,12 +330,14 @@ static void mtk_jpeg_dec_set_bs_write_ptr(void __iomem *base, u32 ptr) writel(ptr, base + JPGDEC_REG_FILE_BRP); } -static void mtk_jpeg_dec_set_bs_info(void __iomem *base, u32 addr, u32 size) +static void mtk_jpeg_dec_set_bs_info(void __iomem *base, u32 addr, u32 size, + u32 bitstream_size) { mtk_jpeg_verify_align(addr, 16, JPGDEC_REG_FILE_ADDR); mtk_jpeg_verify_align(size, 128, JPGDEC_REG_FILE_TOTAL_SIZE); writel(addr, base + JPGDEC_REG_FILE_ADDR); writel(size, base + JPGDEC_REG_FILE_TOTAL_SIZE); + writel(bitstream_size, base + JPGDEC_REG_BIT_STREAM_SIZE); } static void mtk_jpeg_dec_set_comp_id(void __iomem *base, u32 id_y, u32 id_u, @@ -404,39 +406,40 @@ static void mtk_jpeg_dec_set_sampling_factor(void __iomem *base, u32 comp_num, } void mtk_jpeg_dec_set_config(void __iomem *base, - struct mtk_jpeg_dec_param *config, + struct mtk_jpeg_dec_param *cfg, + u32 bitstream_size, struct mtk_jpeg_bs *bs, struct mtk_jpeg_fb *fb) { - mtk_jpeg_dec_set_brz_factor(base, 0, 0, config->uv_brz_w, 0); + mtk_jpeg_dec_set_brz_factor(base, 0, 0, cfg->uv_brz_w, 0); mtk_jpeg_dec_set_dec_mode(base, 0); - mtk_jpeg_dec_set_comp0_du(base, config->unit_num); - mtk_jpeg_dec_set_total_mcu(base, config->total_mcu); - mtk_jpeg_dec_set_bs_info(base, bs->str_addr, bs->size); + mtk_jpeg_dec_set_comp0_du(base, cfg->unit_num); + mtk_jpeg_dec_set_total_mcu(base, cfg->total_mcu); + mtk_jpeg_dec_set_bs_info(base, bs->str_addr, bs->size, bitstream_size); mtk_jpeg_dec_set_bs_write_ptr(base, bs->end_addr); - mtk_jpeg_dec_set_du_membership(base, config->membership, 1, - (config->comp_num == 1) ? 1 : 0); - mtk_jpeg_dec_set_comp_id(base, config->comp_id[0], config->comp_id[1], - config->comp_id[2]); - mtk_jpeg_dec_set_q_table(base, config->qtbl_num[0], - config->qtbl_num[1], config->qtbl_num[2]); - mtk_jpeg_dec_set_sampling_factor(base, config->comp_num, - config->sampling_w[0], - config->sampling_h[0], - config->sampling_w[1], - config->sampling_h[1], - config->sampling_w[2], - config->sampling_h[2]); - mtk_jpeg_dec_set_mem_stride(base, config->mem_stride[0], - config->mem_stride[1]); - mtk_jpeg_dec_set_img_stride(base, config->img_stride[0], - config->img_stride[1]); + mtk_jpeg_dec_set_du_membership(base, cfg->membership, 1, + (cfg->comp_num == 1) ? 1 : 0); + mtk_jpeg_dec_set_comp_id(base, cfg->comp_id[0], cfg->comp_id[1], + cfg->comp_id[2]); + mtk_jpeg_dec_set_q_table(base, cfg->qtbl_num[0], + cfg->qtbl_num[1], cfg->qtbl_num[2]); + mtk_jpeg_dec_set_sampling_factor(base, cfg->comp_num, + cfg->sampling_w[0], + cfg->sampling_h[0], + cfg->sampling_w[1], + cfg->sampling_h[1], + cfg->sampling_w[2], + cfg->sampling_h[2]); + mtk_jpeg_dec_set_mem_stride(base, cfg->mem_stride[0], + cfg->mem_stride[1]); + mtk_jpeg_dec_set_img_stride(base, cfg->img_stride[0], + cfg->img_stride[1]); mtk_jpeg_dec_set_dst_bank0(base, fb->plane_addr[0], fb->plane_addr[1], fb->plane_addr[2]); mtk_jpeg_dec_set_dst_bank1(base, 0, 0, 0); - mtk_jpeg_dec_set_dma_group(base, config->dma_mcu, config->dma_group, - config->dma_last_mcu); - mtk_jpeg_dec_set_pause_mcu_idx(base, config->total_mcu); + mtk_jpeg_dec_set_dma_group(base, cfg->dma_mcu, cfg->dma_group, + cfg->dma_last_mcu); + mtk_jpeg_dec_set_pause_mcu_idx(base, cfg->total_mcu); } EXPORT_SYMBOL_GPL(mtk_jpeg_dec_set_config); diff --git a/drivers/media/platform/mediatek/jpeg/mtk_jpeg_dec_hw.h b/drivers/media/platform/mediatek/jpeg/mtk_jpeg_dec_hw.h index 87aaa5c9082b..8c31c6b12417 100644 --- a/drivers/media/platform/mediatek/jpeg/mtk_jpeg_dec_hw.h +++ b/drivers/media/platform/mediatek/jpeg/mtk_jpeg_dec_hw.h @@ -71,7 +71,8 @@ int mtk_jpeg_dec_fill_param(struct mtk_jpeg_dec_param *param); u32 mtk_jpeg_dec_get_int_status(void __iomem *dec_reg_base); u32 mtk_jpeg_dec_enum_result(u32 irq_result); void mtk_jpeg_dec_set_config(void __iomem *base, - struct mtk_jpeg_dec_param *config, + struct mtk_jpeg_dec_param *cfg, + u32 bitstream_size, struct mtk_jpeg_bs *bs, struct mtk_jpeg_fb *fb); void mtk_jpeg_dec_reset(void __iomem *dec_reg_base); diff --git a/drivers/media/platform/mediatek/jpeg/mtk_jpeg_dec_reg.h b/drivers/media/platform/mediatek/jpeg/mtk_jpeg_dec_reg.h index 21ec8f96797f..27b7711ca341 100644 --- a/drivers/media/platform/mediatek/jpeg/mtk_jpeg_dec_reg.h +++ b/drivers/media/platform/mediatek/jpeg/mtk_jpeg_dec_reg.h @@ -45,5 +45,6 @@ #define JPGDEC_REG_QT_ID 0x0270 #define JPGDEC_REG_INTERRUPT_STATUS 0x0274 #define JPGDEC_REG_STATUS 0x0278 +#define JPGDEC_REG_BIT_STREAM_SIZE 0x0344 #endif /* _MTK_JPEG_REG_H */ -- cgit v1.2.3 From bf8460d2f4e6a135998a8318f870caeed3106641 Mon Sep 17 00:00:00 2001 From: kyrie wu Date: Thu, 29 Sep 2022 17:08:17 +0800 Subject: mtk-jpegdec: add stop cmd interface for jpgdec Add stop cmd interface for jpgdec to stop stream Signed-off-by: kyrie wu Signed-off-by: irui wang Signed-off-by: Hans Verkuil --- drivers/media/platform/mediatek/jpeg/mtk_jpeg_core.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/media/platform/mediatek/jpeg/mtk_jpeg_core.c b/drivers/media/platform/mediatek/jpeg/mtk_jpeg_core.c index c77496ea4e11..969516a940ba 100644 --- a/drivers/media/platform/mediatek/jpeg/mtk_jpeg_core.c +++ b/drivers/media/platform/mediatek/jpeg/mtk_jpeg_core.c @@ -665,6 +665,9 @@ static const struct v4l2_ioctl_ops mtk_jpeg_dec_ioctl_ops = { .vidioc_streamoff = v4l2_m2m_ioctl_streamoff, .vidioc_unsubscribe_event = v4l2_event_unsubscribe, + + .vidioc_decoder_cmd = v4l2_m2m_ioctl_decoder_cmd, + .vidioc_try_decoder_cmd = v4l2_m2m_ioctl_try_decoder_cmd, }; static int mtk_jpeg_queue_setup(struct vb2_queue *q, -- cgit v1.2.3 From 8b450a82a3dc3108b3718b68edf58c60aeed1801 Mon Sep 17 00:00:00 2001 From: Ming Qian Date: Tue, 27 Sep 2022 11:12:16 +0800 Subject: media: imx-jpeg: Implement g_selection and s_selection The codec can support any image size WxH, with arbitrary W (image width) and H (image height) dimensions. But it requires buffer alignment, so driver can report the aligned resolution through the g_fmt, and report the actual resolution through the g_selection. For encoder, it even support to encode a smaller jpeg than the original picture through s_selection api. For the decoder, we do not support cropping a portion smaller than the original picture, due to hardware limitations (wrapper side). Fixes: 9e7aa76cdb02 ("media: imx-jpeg: Align upwards buffer size") Signed-off-by: Ming Qian Signed-off-by: Hans Verkuil --- drivers/media/platform/nxp/imx-jpeg/mxc-jpeg.c | 327 ++++++++++++++++--------- drivers/media/platform/nxp/imx-jpeg/mxc-jpeg.h | 1 + 2 files changed, 208 insertions(+), 120 deletions(-) diff --git a/drivers/media/platform/nxp/imx-jpeg/mxc-jpeg.c b/drivers/media/platform/nxp/imx-jpeg/mxc-jpeg.c index ce8a305e49fd..8db29f763818 100644 --- a/drivers/media/platform/nxp/imx-jpeg/mxc-jpeg.c +++ b/drivers/media/platform/nxp/imx-jpeg/mxc-jpeg.c @@ -923,8 +923,8 @@ static void mxc_jpeg_config_enc_desc(struct vb2_buffer *out_buf, jpeg->slot_data[slot].cfg_stream_size = mxc_jpeg_setup_cfg_stream(cfg_stream_vaddr, q_data->fmt->fourcc, - q_data->w, - q_data->h); + q_data->crop.width, + q_data->crop.height); /* chain the config descriptor with the encoding descriptor */ cfg_desc->next_descpt_ptr = desc_handle | MXC_NXT_DESCPT_EN; @@ -941,11 +941,13 @@ static void mxc_jpeg_config_enc_desc(struct vb2_buffer *out_buf, desc->next_descpt_ptr = 0; /* end of chain */ /* use adjusted resolution for CAST IP job */ - w = q_data->w_adjusted; - h = q_data->h_adjusted; + w = q_data->crop.width; + h = q_data->crop.height; + v4l_bound_align_image(&w, w, MXC_JPEG_MAX_WIDTH, q_data->fmt->h_align, + &h, h, MXC_JPEG_MAX_HEIGHT, q_data->fmt->v_align, 0); mxc_jpeg_set_res(desc, w, h); - mxc_jpeg_set_line_pitch(desc, w * (q_data->fmt->depth / 8)); - mxc_jpeg_set_bufsize(desc, desc->line_pitch * h); + mxc_jpeg_set_line_pitch(desc, q_data->bytesperline[0]); + mxc_jpeg_set_bufsize(desc, ALIGN(vb2_plane_size(dst_buf, 0), 1024)); img_fmt = mxc_jpeg_fourcc_to_imgfmt(q_data->fmt->fourcc); if (img_fmt == MXC_JPEG_INVALID) dev_err(jpeg->dev, "No valid image format detected\n"); @@ -994,6 +996,10 @@ static bool mxc_jpeg_source_change(struct mxc_jpeg_ctx *ctx, q_data_cap->fmt = jpeg_src_buf->fmt; q_data_cap->w_adjusted = q_data_cap->w; q_data_cap->h_adjusted = q_data_cap->h; + q_data_cap->crop.left = 0; + q_data_cap->crop.top = 0; + q_data_cap->crop.width = jpeg_src_buf->w; + q_data_cap->crop.height = jpeg_src_buf->h; /* * align up the resolution for CAST IP, @@ -1006,7 +1012,7 @@ static bool mxc_jpeg_source_change(struct mxc_jpeg_ctx *ctx, &q_data_cap->h_adjusted, q_data_cap->h_adjusted, /* adjust up */ MXC_JPEG_MAX_HEIGHT, - 0, + q_data_cap->fmt->v_align, 0); /* setup bytesperline/sizeimage for capture queue */ @@ -1015,6 +1021,7 @@ static bool mxc_jpeg_source_change(struct mxc_jpeg_ctx *ctx, notify_src_chg(ctx); ctx->source_change = 1; } + return ctx->source_change ? true : false; } @@ -1200,30 +1207,18 @@ static int mxc_jpeg_queue_setup(struct vb2_queue *q, { struct mxc_jpeg_ctx *ctx = vb2_get_drv_priv(q); struct mxc_jpeg_q_data *q_data = NULL; - struct mxc_jpeg_q_data tmp_q; int i; q_data = mxc_jpeg_get_q_data(ctx, q->type); if (!q_data) return -EINVAL; - tmp_q.fmt = q_data->fmt; - tmp_q.w = q_data->w_adjusted; - tmp_q.h = q_data->h_adjusted; - for (i = 0; i < MXC_JPEG_MAX_PLANES; i++) { - tmp_q.bytesperline[i] = q_data->bytesperline[i]; - tmp_q.sizeimage[i] = q_data->sizeimage[i]; - } - mxc_jpeg_sizeimage(&tmp_q); - for (i = 0; i < MXC_JPEG_MAX_PLANES; i++) - tmp_q.sizeimage[i] = max(tmp_q.sizeimage[i], q_data->sizeimage[i]); - /* Handle CREATE_BUFS situation - *nplanes != 0 */ if (*nplanes) { if (*nplanes != q_data->fmt->colplanes) return -EINVAL; for (i = 0; i < *nplanes; i++) { - if (sizes[i] < tmp_q.sizeimage[i]) + if (sizes[i] < q_data->sizeimage[i]) return -EINVAL; } return 0; @@ -1232,7 +1227,7 @@ static int mxc_jpeg_queue_setup(struct vb2_queue *q, /* Handle REQBUFS situation */ *nplanes = q_data->fmt->colplanes; for (i = 0; i < *nplanes; i++) - sizes[i] = tmp_q.sizeimage[i]; + sizes[i] = q_data->sizeimage[i]; return 0; } @@ -1365,17 +1360,17 @@ static void mxc_jpeg_bytesperline(struct mxc_jpeg_q_data *q, u32 precision) * applies to the first plane and is divided by the same factor * as the width field for the other planes */ - q->bytesperline[0] = q->w * DIV_ROUND_UP(precision, 8); + q->bytesperline[0] = q->w_adjusted * DIV_ROUND_UP(precision, 8); q->bytesperline[1] = q->bytesperline[0]; } else if (q->fmt->subsampling == V4L2_JPEG_CHROMA_SUBSAMPLING_422) { - q->bytesperline[0] = q->w * DIV_ROUND_UP(precision, 8) * 2; + q->bytesperline[0] = q->w_adjusted * DIV_ROUND_UP(precision, 8) * 2; q->bytesperline[1] = 0; } else if (q->fmt->subsampling == V4L2_JPEG_CHROMA_SUBSAMPLING_444) { - q->bytesperline[0] = q->w * DIV_ROUND_UP(precision, 8) * q->fmt->nc; + q->bytesperline[0] = q->w_adjusted * DIV_ROUND_UP(precision, 8) * q->fmt->nc; q->bytesperline[1] = 0; } else { /* grayscale */ - q->bytesperline[0] = q->w * DIV_ROUND_UP(precision, 8); + q->bytesperline[0] = q->w_adjusted * DIV_ROUND_UP(precision, 8); q->bytesperline[1] = 0; } } @@ -1394,7 +1389,7 @@ static void mxc_jpeg_sizeimage(struct mxc_jpeg_q_data *q) /* jpeg stream size must be multiple of 1K */ q->sizeimage[0] = ALIGN(q->sizeimage[0], 1024); } else { - q->sizeimage[0] = q->bytesperline[0] * q->h; + q->sizeimage[0] = q->bytesperline[0] * q->h_adjusted; q->sizeimage[1] = 0; if (q->fmt->fourcc == V4L2_PIX_FMT_NV12M) q->sizeimage[1] = q->sizeimage[0] / 2; @@ -1618,6 +1613,10 @@ static void mxc_jpeg_set_default_params(struct mxc_jpeg_ctx *ctx) q[i]->h = MXC_JPEG_DEFAULT_HEIGHT; q[i]->w_adjusted = MXC_JPEG_DEFAULT_WIDTH; q[i]->h_adjusted = MXC_JPEG_DEFAULT_HEIGHT; + q[i]->crop.left = 0; + q[i]->crop.top = 0; + q[i]->crop.width = MXC_JPEG_DEFAULT_WIDTH; + q[i]->crop.height = MXC_JPEG_DEFAULT_HEIGHT; mxc_jpeg_bytesperline(q[i], q[i]->fmt->precision); mxc_jpeg_sizeimage(q[i]); } @@ -1785,55 +1784,84 @@ static int mxc_jpeg_enum_fmt_vid_out(struct file *file, void *priv, return 0; } -static int mxc_jpeg_try_fmt(struct v4l2_format *f, const struct mxc_jpeg_fmt *fmt, - struct mxc_jpeg_ctx *ctx, int q_type) +static u32 mxc_jpeg_get_fmt_type(struct mxc_jpeg_ctx *ctx, u32 type) +{ + if (ctx->mxc_jpeg->mode == MXC_JPEG_DECODE) + return V4L2_TYPE_IS_OUTPUT(type) ? MXC_JPEG_FMT_TYPE_ENC : MXC_JPEG_FMT_TYPE_RAW; + else + return V4L2_TYPE_IS_CAPTURE(type) ? MXC_JPEG_FMT_TYPE_ENC : MXC_JPEG_FMT_TYPE_RAW; +} + +static u32 mxc_jpeg_get_default_fourcc(struct mxc_jpeg_ctx *ctx, u32 type) { + if (ctx->mxc_jpeg->mode == MXC_JPEG_DECODE) + return V4L2_TYPE_IS_OUTPUT(type) ? V4L2_PIX_FMT_JPEG : MXC_JPEG_DEFAULT_PFMT; + else + return V4L2_TYPE_IS_CAPTURE(type) ? V4L2_PIX_FMT_JPEG : MXC_JPEG_DEFAULT_PFMT; +} + +static int mxc_jpeg_try_fmt(struct v4l2_format *f, + struct mxc_jpeg_ctx *ctx, struct mxc_jpeg_q_data *q_data) +{ + const struct mxc_jpeg_fmt *fmt; struct v4l2_pix_format_mplane *pix_mp = &f->fmt.pix_mp; struct v4l2_plane_pix_format *pfmt; + u32 fourcc = f->fmt.pix_mp.pixelformat; u32 w = (pix_mp->width < MXC_JPEG_MAX_WIDTH) ? pix_mp->width : MXC_JPEG_MAX_WIDTH; u32 h = (pix_mp->height < MXC_JPEG_MAX_HEIGHT) ? pix_mp->height : MXC_JPEG_MAX_HEIGHT; int i; - struct mxc_jpeg_q_data tmp_q; + + fmt = mxc_jpeg_find_format(ctx, fourcc); + if (!fmt || fmt->flags != mxc_jpeg_get_fmt_type(ctx, f->type)) { + dev_warn(ctx->mxc_jpeg->dev, "Format not supported: %c%c%c%c, use the default.\n", + (fourcc & 0xff), + (fourcc >> 8) & 0xff, + (fourcc >> 16) & 0xff, + (fourcc >> 24) & 0xff); + fourcc = mxc_jpeg_get_default_fourcc(ctx, f->type); + fmt = mxc_jpeg_find_format(ctx, fourcc); + if (!fmt) + return -EINVAL; + f->fmt.pix_mp.pixelformat = fourcc; + } + q_data->fmt = fmt; memset(pix_mp->reserved, 0, sizeof(pix_mp->reserved)); pix_mp->field = V4L2_FIELD_NONE; pix_mp->num_planes = fmt->colplanes; pix_mp->pixelformat = fmt->fourcc; - pix_mp->width = w; - pix_mp->height = h; - v4l_bound_align_image(&w, + q_data->w = w; + q_data->h = h; + q_data->w_adjusted = w; + q_data->h_adjusted = h; + v4l_bound_align_image(&q_data->w_adjusted, w, /* adjust upwards*/ MXC_JPEG_MAX_WIDTH, fmt->h_align, - &h, + &q_data->h_adjusted, h, /* adjust upwards*/ MXC_JPEG_MAX_HEIGHT, - 0, + fmt->v_align, 0); - - /* get user input into the tmp_q */ - tmp_q.w = w; - tmp_q.h = h; - tmp_q.fmt = fmt; for (i = 0; i < pix_mp->num_planes; i++) { pfmt = &pix_mp->plane_fmt[i]; - tmp_q.bytesperline[i] = pfmt->bytesperline; - tmp_q.sizeimage[i] = pfmt->sizeimage; + q_data->bytesperline[i] = pfmt->bytesperline; + q_data->sizeimage[i] = pfmt->sizeimage; } - /* calculate bytesperline & sizeimage into the tmp_q */ - mxc_jpeg_bytesperline(&tmp_q, fmt->precision); - mxc_jpeg_sizeimage(&tmp_q); + /* calculate bytesperline & sizeimage */ + mxc_jpeg_bytesperline(q_data, fmt->precision); + mxc_jpeg_sizeimage(q_data); /* adjust user format according to our calculations */ for (i = 0; i < pix_mp->num_planes; i++) { pfmt = &pix_mp->plane_fmt[i]; memset(pfmt->reserved, 0, sizeof(pfmt->reserved)); - pfmt->bytesperline = tmp_q.bytesperline[i]; - pfmt->sizeimage = tmp_q.sizeimage[i]; + pfmt->bytesperline = q_data->bytesperline[i]; + pfmt->sizeimage = q_data->sizeimage[i]; } /* fix colorspace information to sRGB for both output & capture */ @@ -1847,6 +1875,16 @@ static int mxc_jpeg_try_fmt(struct v4l2_format *f, const struct mxc_jpeg_fmt *fm */ pix_mp->quantization = V4L2_QUANTIZATION_FULL_RANGE; + if (fmt->flags == MXC_JPEG_FMT_TYPE_RAW) { + q_data->crop.left = 0; + q_data->crop.top = 0; + q_data->crop.width = q_data->w; + q_data->crop.height = q_data->h; + } + + pix_mp->width = q_data->w_adjusted; + pix_mp->height = q_data->h_adjusted; + return 0; } @@ -1856,29 +1894,14 @@ static int mxc_jpeg_try_fmt_vid_cap(struct file *file, void *priv, struct mxc_jpeg_ctx *ctx = mxc_jpeg_fh_to_ctx(priv); struct mxc_jpeg_dev *jpeg = ctx->mxc_jpeg; struct device *dev = jpeg->dev; - const struct mxc_jpeg_fmt *fmt; - u32 fourcc = f->fmt.pix_mp.pixelformat; - - int q_type = (jpeg->mode == MXC_JPEG_DECODE) ? - MXC_JPEG_FMT_TYPE_RAW : MXC_JPEG_FMT_TYPE_ENC; + struct mxc_jpeg_q_data tmp_q; if (!V4L2_TYPE_IS_MULTIPLANAR(f->type)) { dev_err(dev, "TRY_FMT with Invalid type: %d\n", f->type); return -EINVAL; } - fmt = mxc_jpeg_find_format(ctx, fourcc); - if (!fmt || fmt->flags != q_type) { - dev_warn(dev, "Format not supported: %c%c%c%c, use the default.\n", - (fourcc & 0xff), - (fourcc >> 8) & 0xff, - (fourcc >> 16) & 0xff, - (fourcc >> 24) & 0xff); - f->fmt.pix_mp.pixelformat = (jpeg->mode == MXC_JPEG_DECODE) ? - MXC_JPEG_DEFAULT_PFMT : V4L2_PIX_FMT_JPEG; - fmt = mxc_jpeg_find_format(ctx, f->fmt.pix_mp.pixelformat); - } - return mxc_jpeg_try_fmt(f, fmt, ctx, q_type); + return mxc_jpeg_try_fmt(f, ctx, &tmp_q); } static int mxc_jpeg_try_fmt_vid_out(struct file *file, void *priv, @@ -1887,88 +1910,55 @@ static int mxc_jpeg_try_fmt_vid_out(struct file *file, void *priv, struct mxc_jpeg_ctx *ctx = mxc_jpeg_fh_to_ctx(priv); struct mxc_jpeg_dev *jpeg = ctx->mxc_jpeg; struct device *dev = jpeg->dev; - const struct mxc_jpeg_fmt *fmt; - u32 fourcc = f->fmt.pix_mp.pixelformat; - - int q_type = (jpeg->mode == MXC_JPEG_ENCODE) ? - MXC_JPEG_FMT_TYPE_RAW : MXC_JPEG_FMT_TYPE_ENC; + struct mxc_jpeg_q_data tmp_q; if (!V4L2_TYPE_IS_MULTIPLANAR(f->type)) { dev_err(dev, "TRY_FMT with Invalid type: %d\n", f->type); return -EINVAL; } - fmt = mxc_jpeg_find_format(ctx, fourcc); - if (!fmt || fmt->flags != q_type) { - dev_warn(dev, "Format not supported: %c%c%c%c, use the default.\n", - (fourcc & 0xff), - (fourcc >> 8) & 0xff, - (fourcc >> 16) & 0xff, - (fourcc >> 24) & 0xff); - f->fmt.pix_mp.pixelformat = (jpeg->mode == MXC_JPEG_ENCODE) ? - MXC_JPEG_DEFAULT_PFMT : V4L2_PIX_FMT_JPEG; - fmt = mxc_jpeg_find_format(ctx, f->fmt.pix_mp.pixelformat); - } - return mxc_jpeg_try_fmt(f, fmt, ctx, q_type); + return mxc_jpeg_try_fmt(f, ctx, &tmp_q); +} + +static void mxc_jpeg_s_parsed_fmt(struct mxc_jpeg_ctx *ctx, struct v4l2_format *f) +{ + struct v4l2_pix_format_mplane *pix_mp = &f->fmt.pix_mp; + struct mxc_jpeg_q_data *q_data_cap; + + if (ctx->mxc_jpeg->mode != MXC_JPEG_DECODE || !V4L2_TYPE_IS_CAPTURE(f->type)) + return; + if (!ctx->header_parsed) + return; + + q_data_cap = mxc_jpeg_get_q_data(ctx, f->type); + pix_mp->pixelformat = q_data_cap->fmt->fourcc; + pix_mp->width = q_data_cap->w; + pix_mp->height = q_data_cap->h; } static int mxc_jpeg_s_fmt(struct mxc_jpeg_ctx *ctx, struct v4l2_format *f) { struct vb2_queue *vq; - struct mxc_jpeg_q_data *q_data = NULL; - struct v4l2_pix_format_mplane *pix_mp = &f->fmt.pix_mp; struct mxc_jpeg_dev *jpeg = ctx->mxc_jpeg; - int i; vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, f->type); if (!vq) return -EINVAL; - q_data = mxc_jpeg_get_q_data(ctx, f->type); - if (vb2_is_busy(vq)) { v4l2_err(&jpeg->v4l2_dev, "queue busy\n"); return -EBUSY; } - q_data->fmt = mxc_jpeg_find_format(ctx, pix_mp->pixelformat); - q_data->w = pix_mp->width; - q_data->h = pix_mp->height; - - q_data->w_adjusted = q_data->w; - q_data->h_adjusted = q_data->h; - /* - * align up the resolution for CAST IP, - * but leave the buffer resolution unchanged - */ - v4l_bound_align_image(&q_data->w_adjusted, - q_data->w_adjusted, /* adjust upwards */ - MXC_JPEG_MAX_WIDTH, - q_data->fmt->h_align, - &q_data->h_adjusted, - q_data->h_adjusted, /* adjust upwards */ - MXC_JPEG_MAX_HEIGHT, - q_data->fmt->v_align, - 0); - - for (i = 0; i < pix_mp->num_planes; i++) { - q_data->bytesperline[i] = pix_mp->plane_fmt[i].bytesperline; - q_data->sizeimage[i] = pix_mp->plane_fmt[i].sizeimage; - } + mxc_jpeg_s_parsed_fmt(ctx, f); - return 0; + return mxc_jpeg_try_fmt(f, ctx, mxc_jpeg_get_q_data(ctx, f->type)); } static int mxc_jpeg_s_fmt_vid_cap(struct file *file, void *priv, struct v4l2_format *f) { - int ret; - - ret = mxc_jpeg_try_fmt_vid_cap(file, priv, f); - if (ret) - return ret; - return mxc_jpeg_s_fmt(mxc_jpeg_fh_to_ctx(priv), f); } @@ -1982,10 +1972,6 @@ static int mxc_jpeg_s_fmt_vid_out(struct file *file, void *priv, enum v4l2_buf_type cap_type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; struct v4l2_format fc; - ret = mxc_jpeg_try_fmt_vid_out(file, priv, f); - if (ret) - return ret; - ret = mxc_jpeg_s_fmt(mxc_jpeg_fh_to_ctx(priv), f); if (ret) return ret; @@ -2031,6 +2017,10 @@ static int mxc_jpeg_g_fmt_vid(struct file *file, void *priv, pix_mp->width = q_data->w; pix_mp->height = q_data->h; pix_mp->field = V4L2_FIELD_NONE; + if (q_data->fmt->flags == MXC_JPEG_FMT_TYPE_RAW) { + pix_mp->width = q_data->w_adjusted; + pix_mp->height = q_data->h_adjusted; + } /* fix colorspace information to sRGB for both output & capture */ pix_mp->colorspace = V4L2_COLORSPACE_SRGB; @@ -2047,6 +2037,100 @@ static int mxc_jpeg_g_fmt_vid(struct file *file, void *priv, return 0; } +static int mxc_jpeg_dec_g_selection(struct file *file, void *fh, struct v4l2_selection *s) +{ + struct mxc_jpeg_ctx *ctx = mxc_jpeg_fh_to_ctx(fh); + struct mxc_jpeg_q_data *q_data_cap; + + if (s->type != V4L2_BUF_TYPE_VIDEO_CAPTURE && s->type != V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) + return -EINVAL; + + q_data_cap = mxc_jpeg_get_q_data(ctx, s->type); + + switch (s->target) { + case V4L2_SEL_TGT_COMPOSE: + case V4L2_SEL_TGT_COMPOSE_DEFAULT: + s->r = q_data_cap->crop; + break; + case V4L2_SEL_TGT_COMPOSE_PADDED: + case V4L2_SEL_TGT_COMPOSE_BOUNDS: + s->r.left = 0; + s->r.top = 0; + s->r.width = q_data_cap->w_adjusted; + s->r.height = q_data_cap->h_adjusted; + break; + default: + return -EINVAL; + } + + return 0; +} + +static int mxc_jpeg_enc_g_selection(struct file *file, void *fh, struct v4l2_selection *s) +{ + struct mxc_jpeg_ctx *ctx = mxc_jpeg_fh_to_ctx(fh); + struct mxc_jpeg_q_data *q_data_out; + + if (s->type != V4L2_BUF_TYPE_VIDEO_OUTPUT && s->type != V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) + return -EINVAL; + + q_data_out = mxc_jpeg_get_q_data(ctx, s->type); + + switch (s->target) { + case V4L2_SEL_TGT_CROP_DEFAULT: + case V4L2_SEL_TGT_CROP_BOUNDS: + s->r.left = 0; + s->r.top = 0; + s->r.width = q_data_out->w; + s->r.height = q_data_out->h; + break; + case V4L2_SEL_TGT_CROP: + s->r = q_data_out->crop; + break; + default: + return -EINVAL; + } + + return 0; +} + +static int mxc_jpeg_g_selection(struct file *file, void *fh, struct v4l2_selection *s) +{ + struct mxc_jpeg_ctx *ctx = mxc_jpeg_fh_to_ctx(fh); + + if (ctx->mxc_jpeg->mode == MXC_JPEG_DECODE) + return mxc_jpeg_dec_g_selection(file, fh, s); + else + return mxc_jpeg_enc_g_selection(file, fh, s); +} + +static int mxc_jpeg_s_selection(struct file *file, void *fh, struct v4l2_selection *s) +{ + struct mxc_jpeg_ctx *ctx = mxc_jpeg_fh_to_ctx(fh); + struct mxc_jpeg_q_data *q_data_out; + + if (ctx->mxc_jpeg->mode != MXC_JPEG_ENCODE) + return -ENOTTY; + + if (s->type != V4L2_BUF_TYPE_VIDEO_OUTPUT && s->type != V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) + return -EINVAL; + if (s->target != V4L2_SEL_TGT_CROP) + return -EINVAL; + + q_data_out = mxc_jpeg_get_q_data(ctx, s->type); + if (s->r.left || s->r.top) + return -EINVAL; + if (s->r.width > q_data_out->w || s->r.height > q_data_out->h) + return -EINVAL; + + q_data_out->crop.left = 0; + q_data_out->crop.top = 0; + q_data_out->crop.width = s->r.width; + q_data_out->crop.height = s->r.height; + + return 0; +} + static int mxc_jpeg_subscribe_event(struct v4l2_fh *fh, const struct v4l2_event_subscription *sub) { @@ -2076,6 +2160,9 @@ static const struct v4l2_ioctl_ops mxc_jpeg_ioctl_ops = { .vidioc_g_fmt_vid_cap_mplane = mxc_jpeg_g_fmt_vid, .vidioc_g_fmt_vid_out_mplane = mxc_jpeg_g_fmt_vid, + .vidioc_g_selection = mxc_jpeg_g_selection, + .vidioc_s_selection = mxc_jpeg_s_selection, + .vidioc_subscribe_event = mxc_jpeg_subscribe_event, .vidioc_unsubscribe_event = v4l2_event_unsubscribe, diff --git a/drivers/media/platform/nxp/imx-jpeg/mxc-jpeg.h b/drivers/media/platform/nxp/imx-jpeg/mxc-jpeg.h index 8104ee4a3b7a..f75dfc89ff6d 100644 --- a/drivers/media/platform/nxp/imx-jpeg/mxc-jpeg.h +++ b/drivers/media/platform/nxp/imx-jpeg/mxc-jpeg.h @@ -84,6 +84,7 @@ struct mxc_jpeg_q_data { int h; int h_adjusted; unsigned int sequence; + struct v4l2_rect crop; }; struct mxc_jpeg_ctx { -- cgit v1.2.3 From ccc9f1db9c6b06205f35d4dcbd19a9cb16a25d03 Mon Sep 17 00:00:00 2001 From: Ming Qian Date: Tue, 27 Sep 2022 11:12:17 +0800 Subject: media: imx-jpeg: Support contiguous and non contiguous format mxc-jpeg supports non contiguous format nv12m, and in order to compatible with the devices that only support contiguous format nv12, jpeg can support nv12 and nv12m in the same time. Signed-off-by: Ming Qian Signed-off-by: Hans Verkuil [hverkuil: document is_rgb variable] --- drivers/media/platform/nxp/imx-jpeg/mxc-jpeg.c | 226 ++++++++++++++++++++----- drivers/media/platform/nxp/imx-jpeg/mxc-jpeg.h | 8 +- 2 files changed, 186 insertions(+), 48 deletions(-) diff --git a/drivers/media/platform/nxp/imx-jpeg/mxc-jpeg.c b/drivers/media/platform/nxp/imx-jpeg/mxc-jpeg.c index 8db29f763818..d262a563844f 100644 --- a/drivers/media/platform/nxp/imx-jpeg/mxc-jpeg.c +++ b/drivers/media/platform/nxp/imx-jpeg/mxc-jpeg.c @@ -69,7 +69,8 @@ static const struct mxc_jpeg_fmt mxc_formats[] = { .fourcc = V4L2_PIX_FMT_JPEG, .subsampling = -1, .nc = -1, - .colplanes = 1, + .mem_planes = 1, + .comp_planes = 1, .flags = MXC_JPEG_FMT_TYPE_ENC, }, { @@ -78,11 +79,13 @@ static const struct mxc_jpeg_fmt mxc_formats[] = { .subsampling = V4L2_JPEG_CHROMA_SUBSAMPLING_444, .nc = 3, .depth = 24, - .colplanes = 1, + .mem_planes = 1, + .comp_planes = 1, .h_align = 3, .v_align = 3, .flags = MXC_JPEG_FMT_TYPE_RAW, .precision = 8, + .is_rgb = 1, }, { .name = "ABGR", /* ABGR packed format */ @@ -90,11 +93,13 @@ static const struct mxc_jpeg_fmt mxc_formats[] = { .subsampling = V4L2_JPEG_CHROMA_SUBSAMPLING_444, .nc = 4, .depth = 32, - .colplanes = 1, + .mem_planes = 1, + .comp_planes = 1, .h_align = 3, .v_align = 3, .flags = MXC_JPEG_FMT_TYPE_RAW, .precision = 8, + .is_rgb = 1, }, { .name = "YUV420", /* 1st plane = Y, 2nd plane = UV */ @@ -102,7 +107,21 @@ static const struct mxc_jpeg_fmt mxc_formats[] = { .subsampling = V4L2_JPEG_CHROMA_SUBSAMPLING_420, .nc = 3, .depth = 12, /* 6 bytes (4Y + UV) for 4 pixels */ - .colplanes = 2, /* 1 plane Y, 1 plane UV interleaved */ + .mem_planes = 2, + .comp_planes = 2, /* 1 plane Y, 1 plane UV interleaved */ + .h_align = 4, + .v_align = 4, + .flags = MXC_JPEG_FMT_TYPE_RAW, + .precision = 8, + }, + { + .name = "YUV420", /* 1st plane = Y, 2nd plane = UV */ + .fourcc = V4L2_PIX_FMT_NV12, + .subsampling = V4L2_JPEG_CHROMA_SUBSAMPLING_420, + .nc = 3, + .depth = 12, /* 6 bytes (4Y + UV) for 4 pixels */ + .mem_planes = 1, + .comp_planes = 2, /* 1 plane Y, 1 plane UV interleaved */ .h_align = 4, .v_align = 4, .flags = MXC_JPEG_FMT_TYPE_RAW, @@ -114,7 +133,8 @@ static const struct mxc_jpeg_fmt mxc_formats[] = { .subsampling = V4L2_JPEG_CHROMA_SUBSAMPLING_422, .nc = 3, .depth = 16, - .colplanes = 1, + .mem_planes = 1, + .comp_planes = 1, .h_align = 4, .v_align = 3, .flags = MXC_JPEG_FMT_TYPE_RAW, @@ -126,7 +146,8 @@ static const struct mxc_jpeg_fmt mxc_formats[] = { .subsampling = V4L2_JPEG_CHROMA_SUBSAMPLING_444, .nc = 3, .depth = 24, - .colplanes = 1, + .mem_planes = 1, + .comp_planes = 1, .h_align = 3, .v_align = 3, .flags = MXC_JPEG_FMT_TYPE_RAW, @@ -138,7 +159,8 @@ static const struct mxc_jpeg_fmt mxc_formats[] = { .subsampling = V4L2_JPEG_CHROMA_SUBSAMPLING_GRAY, .nc = 1, .depth = 8, - .colplanes = 1, + .mem_planes = 1, + .comp_planes = 1, .h_align = 3, .v_align = 3, .flags = MXC_JPEG_FMT_TYPE_RAW, @@ -419,6 +441,7 @@ static enum mxc_jpeg_image_format mxc_jpeg_fourcc_to_imgfmt(u32 fourcc) return MXC_JPEG_GRAY; case V4L2_PIX_FMT_YUYV: return MXC_JPEG_YUV422; + case V4L2_PIX_FMT_NV12: case V4L2_PIX_FMT_NV12M: return MXC_JPEG_YUV420; case V4L2_PIX_FMT_YUV24: @@ -445,12 +468,17 @@ static void mxc_jpeg_addrs(struct mxc_jpeg_desc *desc, struct vb2_buffer *jpeg_buf, int offset) { int img_fmt = desc->stm_ctrl & STM_CTRL_IMAGE_FORMAT_MASK; + struct mxc_jpeg_ctx *ctx = vb2_get_drv_priv(raw_buf->vb2_queue); + struct mxc_jpeg_q_data *q_data; + q_data = mxc_jpeg_get_q_data(ctx, raw_buf->type); desc->buf_base0 = vb2_dma_contig_plane_dma_addr(raw_buf, 0); desc->buf_base1 = 0; if (img_fmt == STM_CTRL_IMAGE_FORMAT(MXC_JPEG_YUV420)) { - WARN_ON(raw_buf->num_planes < 2); - desc->buf_base1 = vb2_dma_contig_plane_dma_addr(raw_buf, 1); + if (raw_buf->num_planes == 2) + desc->buf_base1 = vb2_dma_contig_plane_dma_addr(raw_buf, 1); + else + desc->buf_base1 = desc->buf_base0 + q_data->sizeimage[0]; } desc->stm_bufbase = vb2_dma_contig_plane_dma_addr(jpeg_buf, 0) + offset; @@ -593,6 +621,28 @@ static void mxc_jpeg_job_finish(struct mxc_jpeg_ctx *ctx, enum vb2_buffer_state mxc_jpeg_sw_reset(reg); } +static u32 mxc_jpeg_get_plane_size(struct mxc_jpeg_q_data *q_data, u32 plane_no) +{ + const struct mxc_jpeg_fmt *fmt = q_data->fmt; + u32 size; + int i; + + if (plane_no >= fmt->mem_planes) + return 0; + + if (fmt->mem_planes == fmt->comp_planes) + return q_data->sizeimage[plane_no]; + + if (plane_no < fmt->mem_planes - 1) + return q_data->sizeimage[plane_no]; + + size = q_data->sizeimage[fmt->mem_planes - 1]; + for (i = fmt->mem_planes; i < fmt->comp_planes; i++) + size += q_data->sizeimage[i]; + + return size; +} + static irqreturn_t mxc_jpeg_dec_irq(int irq, void *priv) { struct mxc_jpeg_dev *jpeg = priv; @@ -672,11 +722,11 @@ static irqreturn_t mxc_jpeg_dec_irq(int irq, void *priv) payload); } else { q_data = mxc_jpeg_get_q_data(ctx, cap_type); - payload = q_data->sizeimage[0]; + payload = mxc_jpeg_get_plane_size(q_data, 0); vb2_set_plane_payload(&dst_buf->vb2_buf, 0, payload); vb2_set_plane_payload(&dst_buf->vb2_buf, 1, 0); - if (q_data->fmt->colplanes == 2) { - payload = q_data->sizeimage[1]; + if (q_data->fmt->mem_planes == 2) { + payload = mxc_jpeg_get_plane_size(q_data, 1); vb2_set_plane_payload(&dst_buf->vb2_buf, 1, payload); } dev_dbg(dev, "Decoding finished, payload size: %ld + %ld\n", @@ -715,6 +765,7 @@ static int mxc_jpeg_fixup_sof(struct mxc_jpeg_sof *sof, _bswap16(&sof->width); switch (fourcc) { + case V4L2_PIX_FMT_NV12: case V4L2_PIX_FMT_NV12M: sof->components_no = 3; sof->comp[0].v = 0x2; @@ -751,6 +802,7 @@ static int mxc_jpeg_fixup_sos(struct mxc_jpeg_sos *sos, u8 *sof_u8 = (u8 *)sos; switch (fourcc) { + case V4L2_PIX_FMT_NV12: case V4L2_PIX_FMT_NV12M: sos->components_no = 3; break; @@ -966,6 +1018,32 @@ static void mxc_jpeg_config_enc_desc(struct vb2_buffer *out_buf, mxc_jpeg_set_desc(cfg_desc_handle, reg, slot); } +static const struct mxc_jpeg_fmt *mxc_jpeg_get_sibling_format(const struct mxc_jpeg_fmt *fmt) +{ + int i; + + for (i = 0; i < MXC_JPEG_NUM_FORMATS; i++) { + if (mxc_formats[i].subsampling == fmt->subsampling && + mxc_formats[i].nc == fmt->nc && + mxc_formats[i].precision == fmt->precision && + mxc_formats[i].is_rgb == fmt->is_rgb && + mxc_formats[i].fourcc != fmt->fourcc) + return &mxc_formats[i]; + } + + return NULL; +} + +static bool mxc_jpeg_compare_format(const struct mxc_jpeg_fmt *fmt1, + const struct mxc_jpeg_fmt *fmt2) +{ + if (fmt1 == fmt2) + return true; + if (mxc_jpeg_get_sibling_format(fmt1) == fmt2) + return true; + return false; +} + static bool mxc_jpeg_source_change(struct mxc_jpeg_ctx *ctx, struct mxc_jpeg_src_buf *jpeg_src_buf) { @@ -976,6 +1054,8 @@ static bool mxc_jpeg_source_change(struct mxc_jpeg_ctx *ctx, return false; q_data_cap = mxc_jpeg_get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE); + if (mxc_jpeg_compare_format(q_data_cap->fmt, jpeg_src_buf->fmt)) + jpeg_src_buf->fmt = q_data_cap->fmt; if (q_data_cap->fmt != jpeg_src_buf->fmt || q_data_cap->w != jpeg_src_buf->w || q_data_cap->h != jpeg_src_buf->h) { @@ -1080,9 +1160,9 @@ static void mxc_jpeg_device_run(void *priv) v4l2_m2m_buf_copy_metadata(src_buf, dst_buf, true); jpeg_src_buf = vb2_to_mxc_buf(&src_buf->vb2_buf); - if (q_data_cap->fmt->colplanes != dst_buf->vb2_buf.num_planes) { + if (q_data_cap->fmt->mem_planes != dst_buf->vb2_buf.num_planes) { dev_err(dev, "Capture format %s has %d planes, but capture buffer has %d planes\n", - q_data_cap->fmt->name, q_data_cap->fmt->colplanes, + q_data_cap->fmt->name, q_data_cap->fmt->mem_planes, dst_buf->vb2_buf.num_planes); jpeg_src_buf->jpeg_parse_error = true; } @@ -1215,19 +1295,19 @@ static int mxc_jpeg_queue_setup(struct vb2_queue *q, /* Handle CREATE_BUFS situation - *nplanes != 0 */ if (*nplanes) { - if (*nplanes != q_data->fmt->colplanes) + if (*nplanes != q_data->fmt->mem_planes) return -EINVAL; for (i = 0; i < *nplanes; i++) { - if (sizes[i] < q_data->sizeimage[i]) + if (sizes[i] < mxc_jpeg_get_plane_size(q_data, i)) return -EINVAL; } return 0; } /* Handle REQBUFS situation */ - *nplanes = q_data->fmt->colplanes; + *nplanes = q_data->fmt->mem_planes; for (i = 0; i < *nplanes; i++) - sizes[i] = q_data->sizeimage[i]; + sizes[i] = mxc_jpeg_get_plane_size(q_data, i); return 0; } @@ -1312,19 +1392,40 @@ static int mxc_jpeg_valid_comp_id(struct device *dev, return valid; } +static bool mxc_jpeg_match_image_format(const struct mxc_jpeg_fmt *fmt, + const struct v4l2_jpeg_header *header) +{ + if (fmt->subsampling != header->frame.subsampling || + fmt->nc != header->frame.num_components || + fmt->precision != header->frame.precision) + return false; + + /* + * If the transform flag from APP14 marker is 0, images that are + * encoded with 3 components have RGB colorspace, see Recommendation + * ITU-T T.872 chapter 6.5.3 APP14 marker segment for colour encoding + */ + if (header->frame.subsampling == V4L2_JPEG_CHROMA_SUBSAMPLING_444) { + u8 is_rgb = header->app14_tf == V4L2_JPEG_APP14_TF_CMYK_RGB ? 1 : 0; + + if (is_rgb != fmt->is_rgb) + return false; + } + return true; +} + static u32 mxc_jpeg_get_image_format(struct device *dev, const struct v4l2_jpeg_header *header) { int i; u32 fourcc = 0; - for (i = 0; i < MXC_JPEG_NUM_FORMATS; i++) - if (mxc_formats[i].subsampling == header->frame.subsampling && - mxc_formats[i].nc == header->frame.num_components && - mxc_formats[i].precision == header->frame.precision) { + for (i = 0; i < MXC_JPEG_NUM_FORMATS; i++) { + if (mxc_jpeg_match_image_format(&mxc_formats[i], header)) { fourcc = mxc_formats[i].fourcc; break; } + } if (fourcc == 0) { dev_err(dev, "Could not identify image format nc=%d, subsampling=%d, precision=%d\n", @@ -1333,17 +1434,6 @@ static u32 mxc_jpeg_get_image_format(struct device *dev, header->frame.precision); return fourcc; } - /* - * If the transform flag from APP14 marker is 0, images that are - * encoded with 3 components have RGB colorspace, see Recommendation - * ITU-T T.872 chapter 6.5.3 APP14 marker segment for colour encoding - */ - if (fourcc == V4L2_PIX_FMT_YUV24 || fourcc == V4L2_PIX_FMT_BGR24) { - if (header->app14_tf == V4L2_JPEG_APP14_TF_CMYK_RGB) - fourcc = V4L2_PIX_FMT_BGR24; - else - fourcc = V4L2_PIX_FMT_YUV24; - } return fourcc; } @@ -1391,7 +1481,7 @@ static void mxc_jpeg_sizeimage(struct mxc_jpeg_q_data *q) } else { q->sizeimage[0] = q->bytesperline[0] * q->h_adjusted; q->sizeimage[1] = 0; - if (q->fmt->fourcc == V4L2_PIX_FMT_NV12M) + if (q->fmt->subsampling == V4L2_JPEG_CHROMA_SUBSAMPLING_420) q->sizeimage[1] = q->sizeimage[0] / 2; } } @@ -1400,6 +1490,7 @@ static int mxc_jpeg_parse(struct mxc_jpeg_ctx *ctx, struct vb2_buffer *vb) { struct device *dev = ctx->mxc_jpeg->dev; struct mxc_jpeg_q_data *q_data_out; + struct mxc_jpeg_q_data *q_data_cap; u32 fourcc; struct v4l2_jpeg_header header; struct mxc_jpeg_sof *psof = NULL; @@ -1457,7 +1548,11 @@ static int mxc_jpeg_parse(struct mxc_jpeg_ctx *ctx, struct vb2_buffer *vb) if (!mxc_jpeg_valid_comp_id(dev, psof, psos)) dev_warn(dev, "JPEG component ids should be 0-3 or 1-4"); - fourcc = mxc_jpeg_get_image_format(dev, &header); + q_data_cap = mxc_jpeg_get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE); + if (q_data_cap->fmt && mxc_jpeg_match_image_format(q_data_cap->fmt, &header)) + fourcc = q_data_cap->fmt->fourcc; + else + fourcc = mxc_jpeg_get_image_format(dev, &header); if (fourcc == 0) return -EINVAL; @@ -1533,8 +1628,8 @@ static int mxc_jpeg_buf_prepare(struct vb2_buffer *vb) q_data = mxc_jpeg_get_q_data(ctx, vb->vb2_queue->type); if (!q_data) return -EINVAL; - for (i = 0; i < q_data->fmt->colplanes; i++) { - sizeimage = q_data->sizeimage[i]; + for (i = 0; i < q_data->fmt->mem_planes; i++) { + sizeimage = mxc_jpeg_get_plane_size(q_data, i); if (vb2_plane_size(vb, i) < sizeimage) { dev_err(dev, "plane %d too small (%lu < %lu)", i, vb2_plane_size(vb, i), sizeimage); @@ -1761,10 +1856,25 @@ static int mxc_jpeg_enum_fmt_vid_cap(struct file *file, void *priv, * (more precisely what was propagated on capture queue * after jpeg parse on the output buffer) */ - if (f->index) - return -EINVAL; - f->pixelformat = q_data->fmt->fourcc; - return 0; + int ret = -EINVAL; + const struct mxc_jpeg_fmt *sibling; + + switch (f->index) { + case 0: + f->pixelformat = q_data->fmt->fourcc; + ret = 0; + break; + case 1: + sibling = mxc_jpeg_get_sibling_format(q_data->fmt); + if (sibling) { + f->pixelformat = sibling->fourcc; + ret = 0; + } + break; + default: + break; + } + return ret; } } @@ -1800,6 +1910,27 @@ static u32 mxc_jpeg_get_default_fourcc(struct mxc_jpeg_ctx *ctx, u32 type) return V4L2_TYPE_IS_CAPTURE(type) ? V4L2_PIX_FMT_JPEG : MXC_JPEG_DEFAULT_PFMT; } +static u32 mxc_jpeg_try_fourcc(struct mxc_jpeg_ctx *ctx, u32 fourcc) +{ + const struct mxc_jpeg_fmt *sibling; + struct mxc_jpeg_q_data *q_data_cap; + + if (ctx->mxc_jpeg->mode != MXC_JPEG_DECODE) + return fourcc; + if (!ctx->header_parsed) + return fourcc; + + q_data_cap = &ctx->cap_q; + if (q_data_cap->fmt->fourcc == fourcc) + return fourcc; + + sibling = mxc_jpeg_get_sibling_format(q_data_cap->fmt); + if (sibling && sibling->fourcc == fourcc) + return sibling->fourcc; + + return q_data_cap->fmt->fourcc; +} + static int mxc_jpeg_try_fmt(struct v4l2_format *f, struct mxc_jpeg_ctx *ctx, struct mxc_jpeg_q_data *q_data) { @@ -1830,7 +1961,7 @@ static int mxc_jpeg_try_fmt(struct v4l2_format *f, memset(pix_mp->reserved, 0, sizeof(pix_mp->reserved)); pix_mp->field = V4L2_FIELD_NONE; - pix_mp->num_planes = fmt->colplanes; + pix_mp->num_planes = fmt->mem_planes; pix_mp->pixelformat = fmt->fourcc; q_data->w = w; @@ -1861,7 +1992,7 @@ static int mxc_jpeg_try_fmt(struct v4l2_format *f, pfmt = &pix_mp->plane_fmt[i]; memset(pfmt->reserved, 0, sizeof(pfmt->reserved)); pfmt->bytesperline = q_data->bytesperline[i]; - pfmt->sizeimage = q_data->sizeimage[i]; + pfmt->sizeimage = mxc_jpeg_get_plane_size(q_data, i); } /* fix colorspace information to sRGB for both output & capture */ @@ -1901,6 +2032,9 @@ static int mxc_jpeg_try_fmt_vid_cap(struct file *file, void *priv, return -EINVAL; } + if (ctx->mxc_jpeg->mode != MXC_JPEG_DECODE && V4L2_TYPE_IS_CAPTURE(f->type)) + f->fmt.pix_mp.pixelformat = mxc_jpeg_try_fourcc(ctx, f->fmt.pix_mp.pixelformat); + return mxc_jpeg_try_fmt(f, ctx, &tmp_q); } @@ -1931,7 +2065,7 @@ static void mxc_jpeg_s_parsed_fmt(struct mxc_jpeg_ctx *ctx, struct v4l2_format * return; q_data_cap = mxc_jpeg_get_q_data(ctx, f->type); - pix_mp->pixelformat = q_data_cap->fmt->fourcc; + pix_mp->pixelformat = mxc_jpeg_try_fourcc(ctx, pix_mp->pixelformat); pix_mp->width = q_data_cap->w; pix_mp->height = q_data_cap->h; } @@ -2028,10 +2162,10 @@ static int mxc_jpeg_g_fmt_vid(struct file *file, void *priv, pix_mp->xfer_func = V4L2_XFER_FUNC_SRGB; pix_mp->quantization = V4L2_QUANTIZATION_FULL_RANGE; - pix_mp->num_planes = q_data->fmt->colplanes; + pix_mp->num_planes = q_data->fmt->mem_planes; for (i = 0; i < pix_mp->num_planes; i++) { pix_mp->plane_fmt[i].bytesperline = q_data->bytesperline[i]; - pix_mp->plane_fmt[i].sizeimage = q_data->sizeimage[i]; + pix_mp->plane_fmt[i].sizeimage = mxc_jpeg_get_plane_size(q_data, i); } return 0; diff --git a/drivers/media/platform/nxp/imx-jpeg/mxc-jpeg.h b/drivers/media/platform/nxp/imx-jpeg/mxc-jpeg.h index f75dfc89ff6d..8fa8c0aec5a2 100644 --- a/drivers/media/platform/nxp/imx-jpeg/mxc-jpeg.h +++ b/drivers/media/platform/nxp/imx-jpeg/mxc-jpeg.h @@ -45,11 +45,13 @@ enum mxc_jpeg_mode { * @subsampling: subsampling of jpeg components * @nc: number of color components * @depth: number of bits per pixel - * @colplanes: number of color planes (1 for packed formats) + * @mem_planes: number of memory planes (1 for packed formats) + * @comp_planes:number of component planes, which includes the alpha plane (1 to 4). * @h_align: horizontal alignment order (align to 2^h_align) * @v_align: vertical alignment order (align to 2^v_align) * @flags: flags describing format applicability * @precision: jpeg sample precision + * @is_rgb: is an RGB pixel format */ struct mxc_jpeg_fmt { const char *name; @@ -57,11 +59,13 @@ struct mxc_jpeg_fmt { enum v4l2_jpeg_chroma_subsampling subsampling; int nc; int depth; - int colplanes; + int mem_planes; + int comp_planes; int h_align; int v_align; u32 flags; u8 precision; + u8 is_rgb; }; struct mxc_jpeg_desc { -- cgit v1.2.3 From df71c6e4d5e54a79a772c3f8a3676ab6bf169c46 Mon Sep 17 00:00:00 2001 From: Ming Qian Date: Fri, 12 Aug 2022 15:22:09 +0800 Subject: media: imx-jpeg: Lock on ioctl encoder/decoder stop cmd the ioctl encoder/decoder cmd is under queue lock, and buf_done is in the irq, it can't be locked with the mutex, they are not synchronized. when v4l2_update_last_buf_state is called to handle the encoder/decoder stop cmd, the last src buffer may be done at the same time. so it's possible that last_src_buf is set, but the output rdy_queue is empty, then driver won't mark it stopped, as v4l2_m2m_is_last_draining_src_buf() will always return false and v4l2_m2m_dst_buf_is_last() return false too. In this case, the drain will be blocked. add the hw lock around the ioctl encoder/decoder cmd, to synchronize with the buf_done. Fixes: 4911c5acf935 ("media: imx-jpeg: Implement drain using v4l2-mem2mem helpers") Signed-off-by: Ming Qian Signed-off-by: Hans Verkuil --- drivers/media/platform/nxp/imx-jpeg/mxc-jpeg.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/drivers/media/platform/nxp/imx-jpeg/mxc-jpeg.c b/drivers/media/platform/nxp/imx-jpeg/mxc-jpeg.c index d262a563844f..bb2bc28b55ed 100644 --- a/drivers/media/platform/nxp/imx-jpeg/mxc-jpeg.c +++ b/drivers/media/platform/nxp/imx-jpeg/mxc-jpeg.c @@ -1224,6 +1224,7 @@ static int mxc_jpeg_decoder_cmd(struct file *file, void *priv, { struct v4l2_fh *fh = file->private_data; struct mxc_jpeg_ctx *ctx = mxc_jpeg_fh_to_ctx(fh); + unsigned long flags; int ret; ret = v4l2_m2m_ioctl_try_decoder_cmd(file, fh, cmd); @@ -1233,7 +1234,9 @@ static int mxc_jpeg_decoder_cmd(struct file *file, void *priv, if (!vb2_is_streaming(v4l2_m2m_get_src_vq(fh->m2m_ctx))) return 0; + spin_lock_irqsave(&ctx->mxc_jpeg->hw_lock, flags); ret = v4l2_m2m_ioctl_decoder_cmd(file, priv, cmd); + spin_unlock_irqrestore(&ctx->mxc_jpeg->hw_lock, flags); if (ret < 0) return ret; @@ -1254,6 +1257,7 @@ static int mxc_jpeg_encoder_cmd(struct file *file, void *priv, { struct v4l2_fh *fh = file->private_data; struct mxc_jpeg_ctx *ctx = mxc_jpeg_fh_to_ctx(fh); + unsigned long flags; int ret; ret = v4l2_m2m_ioctl_try_encoder_cmd(file, fh, cmd); @@ -1264,7 +1268,9 @@ static int mxc_jpeg_encoder_cmd(struct file *file, void *priv, !vb2_is_streaming(v4l2_m2m_get_dst_vq(fh->m2m_ctx))) return 0; + spin_lock_irqsave(&ctx->mxc_jpeg->hw_lock, flags); ret = v4l2_m2m_ioctl_encoder_cmd(file, fh, cmd); + spin_unlock_irqrestore(&ctx->mxc_jpeg->hw_lock, flags); if (ret < 0) return 0; -- cgit v1.2.3