* [PATCH 0/3] Subject: [PATCH 0/3] media: qcom: Add Qualcomm JPEG encoder driver
@ 2026-05-15 11:46 Atanas Filipov
2026-05-15 11:46 ` [PATCH 1/3] media: dt-bindings: qcom: add JPEG encoder binding Atanas Filipov
` (2 more replies)
0 siblings, 3 replies; 15+ messages in thread
From: Atanas Filipov @ 2026-05-15 11:46 UTC (permalink / raw)
To: Bryan O'Donoghue, Mauro Carvalho Chehab, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Kapatrala Syed,
Hariram Purushothaman, Bjorn Andersson, Konrad Dybcio,
Gjorgji Rosikopulos, afilipov
Cc: linux-media, linux-arm-msm, devicetree, linux-kernel,
Atanas Filipov
Add a new Qualcomm JPEG V4L2 mem2mem encoder driver for Qualcomm SoCs.
The driver provides hardware-accelerated JPEG encoding through the V4L2
mem2mem framework.
Currently supported platforms are:
- sc7180
- sm8250
- sm7325
- sc7280
- qcm6490
- sm8550
The driver has been functionally verified only on qcm6490 hardware at
this time. Support for the remaining platforms is based on matching
hardware compatibility and available platform integration data.
Main features:
- V4L2 mem2mem encoder interface
- Hardware JPEG encoding
- DMA-based buffer handling
- Device-tree based platform integration
- Runtime PM support
Testing performed on qcm6490:
- JPEG encoding
- Multiple image resolutions
- Repeated streaming start/stop
- Long-running encode stability tests
- GStreamer pipeline validation
Known limitations:
- Image scaling is currently not supported
- Image width and height must be aligned to 16 pixels
- Other listed platforms are compile-tested only
This series includes:
- DT bindings for Qualcomm JPEG encoder hardware
- core JPEG encoder driver implementation
- V4L2 mem2mem integration
- platform support for supported Qualcomm SoCs
- runtime PM integration
To: Gjorgji Rosikopulos <grosikop@quicinc.com>
To: Kapatrala Syed <akapatra@quicinc.com>
To: Hariram Purushothaman <hariramp@quicinc.com>
Signed-off-by: Atanas Filipov <atanas.filipov@oss.qualcomm.com>
---
Atanas Filipov (3):
media: dt-bindings: qcom: add JPEG encoder binding
qcom: media: jpeg: Add Qualcomm JPEG V4L2 encoder
arm64: qcom: dts: qcm6490: Add JPEG encoder DT properties
.../bindings/media/qcom,jpeg-encoder.yaml | 122 ++
arch/arm64/boot/dts/qcom/kodiak.dtsi | 52 +
drivers/media/platform/qcom/Kconfig | 1 +
drivers/media/platform/qcom/Makefile | 1 +
drivers/media/platform/qcom/jpeg/Kconfig | 17 +
drivers/media/platform/qcom/jpeg/Makefile | 9 +
drivers/media/platform/qcom/jpeg/qcom_jenc_defs.h | 253 ++++
drivers/media/platform/qcom/jpeg/qcom_jenc_dev.c | 370 +++++
drivers/media/platform/qcom/jpeg/qcom_jenc_dev.h | 111 ++
drivers/media/platform/qcom/jpeg/qcom_jenc_hdr.c | 388 +++++
drivers/media/platform/qcom/jpeg/qcom_jenc_hdr.h | 130 ++
drivers/media/platform/qcom/jpeg/qcom_jenc_ops.c | 1522 ++++++++++++++++++++
drivers/media/platform/qcom/jpeg/qcom_jenc_ops.h | 49 +
drivers/media/platform/qcom/jpeg/qcom_jenc_res.c | 268 ++++
drivers/media/platform/qcom/jpeg/qcom_jenc_res.h | 70 +
drivers/media/platform/qcom/jpeg/qcom_jenc_v4l2.c | 1082 ++++++++++++++
drivers/media/platform/qcom/jpeg/qcom_jenc_v4l2.h | 27 +
.../platform/qcom/jpeg/qcom_v165_jenc_hw_info.h | 509 +++++++
.../platform/qcom/jpeg/qcom_v580_jenc_hw_info.h | 509 +++++++
.../platform/qcom/jpeg/qcom_v680_jenc_hw_info.h | 509 +++++++
.../platform/qcom/jpeg/qcom_v780_jenc_hw_info.h | 509 +++++++
21 files changed, 6508 insertions(+)
---
base-commit: 804a18eddd6d57bd554e0716034c764f48659b0a
change-id: 20260515-qcom-jpeg-v4l2-5014defb5bcf
Best regards,
--
Atanas Filipov <atanas.filipov@oss.qualcomm.com>
^ permalink raw reply [flat|nested] 15+ messages in thread
* [PATCH 1/3] media: dt-bindings: qcom: add JPEG encoder binding
2026-05-15 11:46 [PATCH 0/3] Subject: [PATCH 0/3] media: qcom: Add Qualcomm JPEG encoder driver Atanas Filipov
@ 2026-05-15 11:46 ` Atanas Filipov
2026-05-15 11:57 ` sashiko-bot
` (2 more replies)
2026-05-15 11:47 ` [PATCH 2/3] qcom: media: jpeg: Add Qualcomm JPEG V4L2 encoder Atanas Filipov
2026-05-15 11:47 ` [PATCH 3/3] arm64: qcom: dts: qcm6490: Add JPEG encoder DT properties Atanas Filipov
2 siblings, 3 replies; 15+ messages in thread
From: Atanas Filipov @ 2026-05-15 11:46 UTC (permalink / raw)
To: Bryan O'Donoghue, Mauro Carvalho Chehab, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Kapatrala Syed,
Hariram Purushothaman, Bjorn Andersson, Konrad Dybcio,
Gjorgji Rosikopulos, afilipov
Cc: linux-media, linux-arm-msm, devicetree, linux-kernel,
Atanas Filipov
Add YAML device tree binding for the Qualcomm JPEG encoder
hardware. This binding is used by the newly added driver and
describes all required resources, including clocks, power domains,
IOMMU mappings and interconnect paths.
Signed-off-by: Atanas Filipov <atanas.filipov@oss.qualcomm.com>
---
.../bindings/media/qcom,jpeg-encoder.yaml | 122 +++++++++++++++++++++
1 file changed, 122 insertions(+)
diff --git a/Documentation/devicetree/bindings/media/qcom,jpeg-encoder.yaml b/Documentation/devicetree/bindings/media/qcom,jpeg-encoder.yaml
new file mode 100644
index 000000000000..fac3e654458d
--- /dev/null
+++ b/Documentation/devicetree/bindings/media/qcom,jpeg-encoder.yaml
@@ -0,0 +1,122 @@
+# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/media/qcom,jpeg-encoder.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Qualcomm JPEG Encoder
+
+maintainers:
+ - Azam Sadiq Pasha Kapatrala Syed <akapatra@quicinc.com>
+ - Hariram Purushothaman <hariramp@quicinc.com>
+
+description: |
+ Qualcomm JPEG Encoder is the JPEG encode hardware present in Qualcomm SoCs
+
+properties:
+ compatible:
+ items:
+ - enum:
+ - qcom,sc7180-jenc
+ - qcom,sm8250-jenc
+ - qcom,sm7325-jenc
+ - qcom,sc7280-jenc
+ - qcom,qcm6490-jenc
+ - qcom,sm8550-jenc
+
+ reg:
+ maxItems: 2
+
+ reg-names:
+ items:
+ - const: jpeg-regs
+ - const: cpas-regs
+
+ interrupts:
+ maxItems: 1
+
+ clocks:
+ minItems: 6
+ maxItems: 6
+
+ clock-names:
+ items:
+ - const: gcc_hf_axi_clk
+ - const: gcc_sf_axi_clk
+ - const: core_ahb_clk
+ - const: cpas_ahb_clk
+ - const: camnoc_axi_clk
+ - const: jpeg_clk
+
+ power-domains:
+ maxItems: 1
+
+ iommus:
+ maxItems: 2
+
+ interconnects:
+ maxItems: 4
+
+ interconnect-names:
+ items:
+ - const: cam_ahb
+ - const: cam_hf_0_mnoc
+ - const: cam_sf_0_mnoc
+ - const: cam_sf_icp_mnoc
+
+required:
+ - compatible
+ - reg
+ - clocks
+ - interrupts
+ - power-domains
+ - iommus
+ - interconnects
+ - interconnect-names
+
+additionalProperties: false
+
+examples:
+ - |
+ qcom_jpeg_enc: qcom,jpegenc@ac4e000 {
+ cell-index = <0>;
+ compatible = "qcom,qcm6490-jenc";
+ reg =
+ <0 0xac4e000 0 0x4000>,
+ <0 0xac40000 0 0x1000>;
+
+ interrupts = <GIC_SPI 474 IRQ_TYPE_EDGE_RISING>;
+ power-domains = <&camcc CAM_CC_TITAN_TOP_GDSC>;
+
+ clock-names =
+ "gcc_hf_axi_clk",
+ "gcc_sf_axi_clk",
+ "core_ahb_clk",
+ "cpas_ahb_clk",
+ "camnoc_axi_clk",
+ "jpeg_clk";
+
+ clocks =
+ <&gcc GCC_CAMERA_HF_AXI_CLK>,
+ <&gcc GCC_CAMERA_SF_AXI_CLK>,
+ <&camcc CAM_CC_CORE_AHB_CLK>,
+ <&camcc CAM_CC_CPAS_AHB_CLK>,
+ <&camcc CAM_CC_CAMNOC_AXI_CLK>,
+ <&camcc CAM_CC_JPEG_CLK>;
+
+ iommus =
+ <&apps_smmu 0x20C0 0x20>,
+ <&apps_smmu 0x20E0 0x20>;
+
+ interconnects =
+ <&gem_noc MASTER_APPSS_PROC 0 &cnoc2 SLAVE_CAMERA_CFG 0>,
+ <&mmss_noc MASTER_CAMNOC_HF 0 &mc_virt SLAVE_EBI1 0>,
+ <&mmss_noc MASTER_CAMNOC_SF 0 &mc_virt SLAVE_EBI1 0>,
+ <&mmss_noc MASTER_CAMNOC_ICP 0 &mc_virt SLAVE_EBI1 0>;
+
+ interconnect-names =
+ "cam_ahb",
+ "cam_hf_0_mnoc",
+ "cam_sf_0_mnoc",
+ "cam_sf_icp_mnoc";
+ };
--
2.34.1
^ permalink raw reply related [flat|nested] 15+ messages in thread
* [PATCH 2/3] qcom: media: jpeg: Add Qualcomm JPEG V4L2 encoder
2026-05-15 11:46 [PATCH 0/3] Subject: [PATCH 0/3] media: qcom: Add Qualcomm JPEG encoder driver Atanas Filipov
2026-05-15 11:46 ` [PATCH 1/3] media: dt-bindings: qcom: add JPEG encoder binding Atanas Filipov
@ 2026-05-15 11:47 ` Atanas Filipov
2026-05-15 12:21 ` Krzysztof Kozlowski
` (2 more replies)
2026-05-15 11:47 ` [PATCH 3/3] arm64: qcom: dts: qcm6490: Add JPEG encoder DT properties Atanas Filipov
2 siblings, 3 replies; 15+ messages in thread
From: Atanas Filipov @ 2026-05-15 11:47 UTC (permalink / raw)
To: Bryan O'Donoghue, Mauro Carvalho Chehab, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Kapatrala Syed,
Hariram Purushothaman, Bjorn Andersson, Konrad Dybcio,
Gjorgji Rosikopulos, afilipov
Cc: linux-media, linux-arm-msm, devicetree, linux-kernel,
Atanas Filipov
Implementation of a V4L2 JPEG encoder device driver supporting
Qualcomm SC7180, SM8250, SM7280, and SM8550 chipsets.
Signed-off-by: Atanas Filipov <atanas.filipov@oss.qualcomm.com>
---
drivers/media/platform/qcom/Kconfig | 1 +
drivers/media/platform/qcom/Makefile | 1 +
drivers/media/platform/qcom/jpeg/Kconfig | 17 +
drivers/media/platform/qcom/jpeg/Makefile | 9 +
drivers/media/platform/qcom/jpeg/qcom_jenc_defs.h | 253 ++++
drivers/media/platform/qcom/jpeg/qcom_jenc_dev.c | 370 +++++
drivers/media/platform/qcom/jpeg/qcom_jenc_dev.h | 111 ++
drivers/media/platform/qcom/jpeg/qcom_jenc_hdr.c | 388 +++++
drivers/media/platform/qcom/jpeg/qcom_jenc_hdr.h | 130 ++
drivers/media/platform/qcom/jpeg/qcom_jenc_ops.c | 1522 ++++++++++++++++++++
drivers/media/platform/qcom/jpeg/qcom_jenc_ops.h | 49 +
drivers/media/platform/qcom/jpeg/qcom_jenc_res.c | 268 ++++
drivers/media/platform/qcom/jpeg/qcom_jenc_res.h | 70 +
drivers/media/platform/qcom/jpeg/qcom_jenc_v4l2.c | 1082 ++++++++++++++
drivers/media/platform/qcom/jpeg/qcom_jenc_v4l2.h | 27 +
.../platform/qcom/jpeg/qcom_v165_jenc_hw_info.h | 509 +++++++
.../platform/qcom/jpeg/qcom_v580_jenc_hw_info.h | 509 +++++++
.../platform/qcom/jpeg/qcom_v680_jenc_hw_info.h | 509 +++++++
.../platform/qcom/jpeg/qcom_v780_jenc_hw_info.h | 509 +++++++
19 files changed, 6334 insertions(+)
diff --git a/drivers/media/platform/qcom/Kconfig b/drivers/media/platform/qcom/Kconfig
index 4f4d3a68e6e5..f33d53a754a0 100644
--- a/drivers/media/platform/qcom/Kconfig
+++ b/drivers/media/platform/qcom/Kconfig
@@ -5,3 +5,4 @@ comment "Qualcomm media platform drivers"
source "drivers/media/platform/qcom/camss/Kconfig"
source "drivers/media/platform/qcom/iris/Kconfig"
source "drivers/media/platform/qcom/venus/Kconfig"
+source "drivers/media/platform/qcom/jpeg/Kconfig"
diff --git a/drivers/media/platform/qcom/Makefile b/drivers/media/platform/qcom/Makefile
index ea2221a202c0..30c94949e9de 100644
--- a/drivers/media/platform/qcom/Makefile
+++ b/drivers/media/platform/qcom/Makefile
@@ -2,3 +2,4 @@
obj-y += camss/
obj-y += iris/
obj-y += venus/
+obj-y += jpeg/
diff --git a/drivers/media/platform/qcom/jpeg/Kconfig b/drivers/media/platform/qcom/jpeg/Kconfig
new file mode 100644
index 000000000000..51846aeafaf3
--- /dev/null
+++ b/drivers/media/platform/qcom/jpeg/Kconfig
@@ -0,0 +1,17 @@
+# SPDX-License-Identifier: GPL-2.0-only
+config VIDEO_QCOM_JENC
+ tristate "Qualcomm V4L2 JPEG Encoder driver"
+ depends on V4L_MEM2MEM_DRIVERS
+ depends on (ARCH_QCOM && IOMMU_DMA) || COMPILE_TEST
+ depends on VIDEO_DEV
+ select VIDEO_V4L2_SUBDEV_API
+ select VIDEOBUF2_DMA_SG
+ select V4L2_MEM2MEM_DEV
+ help
+ Qualcomm JPEG memory-to-memory V4L2 encoder driver.
+
+ Provides:
+ - qcom-jenc (encode)
+
+ To compile this driver as a module, choose M here: the
+ module will be called qcom-jenc
diff --git a/drivers/media/platform/qcom/jpeg/Makefile b/drivers/media/platform/qcom/jpeg/Makefile
new file mode 100644
index 000000000000..310f6c3c1f19
--- /dev/null
+++ b/drivers/media/platform/qcom/jpeg/Makefile
@@ -0,0 +1,9 @@
+# SPDX-License-Identifier: GPL-2.0-only
+obj-$(CONFIG_VIDEO_QCOM_JENC) += qcom-jenc.o
+
+qcom-jenc-objs += \
+ qcom_jenc_dev.o \
+ qcom_jenc_v4l2.o \
+ qcom_jenc_ops.o \
+ qcom_jenc_res.o \
+ qcom_jenc_hdr.o
diff --git a/drivers/media/platform/qcom/jpeg/qcom_jenc_defs.h b/drivers/media/platform/qcom/jpeg/qcom_jenc_defs.h
new file mode 100644
index 000000000000..40e46820c546
--- /dev/null
+++ b/drivers/media/platform/qcom/jpeg/qcom_jenc_defs.h
@@ -0,0 +1,253 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
+ */
+
+#ifndef QCOM_JENC_DEFS_H_
+#define QCOM_JENC_DEFS_H_
+
+#include <linux/types.h>
+#include <linux/io.h>
+#include <linux/bitfield.h>
+#include <linux/videodev2.h>
+#include <media/videobuf2-core.h>
+
+/* Offline JPEG encoder constraints */
+#define QCOM_JPEG_HW_MAX_WIDTH 9248
+#define QCOM_JPEG_HW_MAX_HEIGHT 8192
+#define QCOM_JPEG_HW_MIN_WIDTH 128
+#define QCOM_JPEG_HW_MIN_HEIGHT 96
+
+#define QCOM_JPEG_HW_DEF_HSTEP 16
+#define QCOM_JPEG_HW_DEF_VSTEP 16
+
+#define QCOM_JPEG_HW_DEF_WIDTH 1920
+#define QCOM_JPEG_HW_DEF_HEIGHT 1080
+
+#define QCOM_JPEG_MAX_PLANES 3
+
+#define QCOM_JPEG_QUALITY_MIN 1
+#define QCOM_JPEG_QUALITY_DEF 95
+#define QCOM_JPEG_QUALITY_MAX 100
+#define QCOM_JPEG_QUALITY_MID (QCOM_JPEG_QUALITY_MAX / 2)
+#define QCOM_JPEG_QUALITY_UNT 1
+
+enum qcom_jpeg_soc_id {
+ QCOM_V165_SOC_ID = 0,
+ QCOM_V580_SOC_ID,
+ QCOM_V680_SOC_ID,
+ QCOM_V780_SOC_ID,
+ QCOM_UNKNOWN_SOC_ID,
+};
+
+enum qcom_soc_perf_level {
+ QCOM_SOC_PERF_SUSPEND = 0,
+ QCOM_SOC_PERF_LOWSVS,
+ QCOM_SOC_PERF_SVS,
+ QCOM_SOC_PERF_SVS_L1,
+ QCOM_SOC_PERF_NOMINAL,
+ QCOM_SOC_PERF_TURBO,
+ QCOM_SOC_PERF_LEVEL_MAX,
+};
+
+enum qcom_jpeg_mask_id {
+ JMSK_HW_VER_STEP,
+ JMSK_HW_VER_MINOR,
+ JMSK_HW_VER_MAJOR,
+
+ JMSK_HW_CAP_ENCODE,
+ JMSK_HW_CAP_DECODE,
+ JMSK_HW_CAP_UPSCALE,
+ JMSK_HW_CAP_DOWNSCALE,
+
+ JMSK_RST_CMD_COMMON,
+ JMSK_RST_CMD_FE_RESET,
+ JMSK_RST_CMD_WE_RESET,
+ JMSK_RST_CMD_ENCODER_RESET,
+ JMSK_RST_CMD_DECODER_RESET,
+ JMSK_RST_CMD_BLOCK_FORMATTER_RST,
+ JMSK_RST_CMD_SCALE_RESET,
+ JMSK_RST_CMD_REGISTER_RESET,
+ JMSK_RST_CMD_MISR_RESET,
+ JMSK_RST_CMD_CORE_RESET,
+ JMSK_RST_CMD_JMSK_DOMAIN_RESET,
+ JMSK_RST_CMD_RESET_BYPASS,
+
+ JMSK_CMD_HW_START,
+ JMSK_CMD_HW_STOP,
+ JMSK_CMD_CLR_RD_PLNS_QUEUE,
+ JMSK_CMD_CLR_WR_PLNS_QUEUE,
+ JMSK_CMD_APPLY_SWC_RD_PARAMS,
+
+ JMSK_CORE_CFG_FE_ENABLE,
+ JMSK_CORE_CFG_WE_ENABLE,
+ JMSK_CORE_CFG_ENC_ENABLE,
+ JMSK_CORE_CFG_SCALE_ENABLE,
+ JMSK_CORE_CFG_TESTBUS_ENABLE,
+ JMSK_CORE_CFG_MODE,
+ JMSK_CORE_CFG_CGC_DISABLE,
+
+ JMSK_CORE_STATUS_ENCODE_STATE,
+ JMSK_CORE_STATUS_SCALE_STATE,
+ JMSK_CORE_STATUS_RT_STATE,
+ JMSK_CORE_STATUS_BUS_STATE,
+ JMSK_CORE_STATUS_CGC_STATE,
+
+ JMSK_IRQ_ENABLE_ALL,
+ JMSK_IRQ_DISABLE_ALL,
+ JMSK_IRQ_CLEAR_ALL,
+
+ JMSK_IRQ_STATUS_SESSION_DONE,
+ JMSK_IRQ_STATUS_RD_BUF_PLN0_DONE,
+ JMSK_IRQ_STATUS_RD_BUF_PLN1_DONE,
+ JMSK_IRQ_STATUS_RD_BUF_PLN2_DONE,
+ JMSK_IRQ_STATUS_RD_BUF_PLNS_ATTN,
+ JMSK_IRQ_STATUS_WR_BUF_PLN0_DONE,
+ JMSK_IRQ_STATUS_WR_BUF_PLN1_DONE,
+ JMSK_IRQ_STATUS_WR_BUF_PLN2_DONE,
+ JMSK_IRQ_STATUS_WR_BUF_PLNS_ATTN,
+ JMSK_IRQ_STATUS_SESSION_ERROR,
+ JMSK_IRQ_STATUS_STOP_ACK,
+ JMSK_IRQ_STATUS_RESET_ACK,
+
+ JMSK_FE_CFG_BYTE_ORDERING,
+ JMSK_FE_CFG_BURST_LENGTH_MAX,
+ JMSK_FE_CFG_MEMORY_FORMAT,
+ JMSK_FE_CFG_CBCR_ORDER,
+ JMSK_FE_CFG_BOTTOM_VPAD_EN,
+ JMSK_FE_CFG_PLN0_EN,
+ JMSK_FE_CFG_PLN1_EN,
+ JMSK_FE_CFG_PLN2_EN,
+ JMSK_FE_CFG_SIXTEEN_MCU_EN,
+ JMSK_FE_CFG_MCUS_PER_BLOCK,
+ JMSK_FE_CFG_MAL_BOUNDARY,
+ JMSK_FE_CFG_MAL_EN,
+
+ JMSK_FE_VBPAD_CFG_BLOCK_ROW,
+
+ JMSK_PLNS_RD_OFFSET,
+ JMSK_PLNS_RD_BUF_SIZE_WIDTH,
+ JMSK_PLNS_RD_BUF_SIZE_HEIGHT,
+ JMSK_PLNS_RD_STRIDE,
+ JMSK_PLNS_RD_HINIT,
+ JMSK_PLNS_RD_VINIT,
+
+ JMSK_WE_CFG_BYTE_ORDERING,
+ JMSK_WE_CFG_BURST_LENGTH_MAX,
+ JMSK_WE_CFG_MEMORY_FORMAT,
+ JMSK_WE_CFG_CBCR_ORDER,
+ JMSK_WE_CFG_PLN0_EN,
+ JMSK_WE_CFG_PLN1_EN,
+ JMSK_WE_CFG_PLN2_EN,
+ JMSK_WE_CFG_MAL_BOUNDARY,
+ JMSK_WE_CFG_MAL_EN,
+ JMSK_WE_CFG_POP_BUFF_ON_EOS,
+
+ JMSK_PLNS_WR_BUF_SIZE_WIDTH,
+ JMSK_PLNS_WR_BUF_SIZE_HEIGHT,
+
+ JMSK_PLNS_WR_STRIDE,
+ JMSK_PLNS_WR_HINIT,
+ JMSK_PLNS_WR_VINIT,
+ JMSK_PLNS_WR_HSTEP,
+ JMSK_PLNS_WR_VSTEP,
+ JMSK_PLNS_WR_BLOCK_CFG_PER_COL,
+ JMSK_PLNS_WR_BLOCK_CFG_PER_RAW,
+
+ JMSK_ENC_CFG_IMAGE_FORMAT,
+ JMSK_ENC_CFG_APPLY_EOI,
+ JMSK_ENC_CFG_HUFFMAN_SEL,
+ JMSK_ENC_CFG_FSC_ENABLE,
+ JMSK_ENC_CFG_OUTPUT_DISABLE,
+ JMSK_ENC_CFG_RST_MARKER_PERIOD,
+ JMSK_ENC_IMAGE_SIZE_WIDTH,
+ JMSK_ENC_IMAGE_SIZE_HEIGHT,
+
+ JMSK_SCALE_CFG_HSCALE_ENABLE,
+ JMSK_SCALE_CFG_VSCALE_ENABLE,
+ JMSK_SCALE_CFG_UPSAMPLE_EN,
+ JMSK_SCALE_CFG_SUBSAMPLE_EN,
+ JMSK_SCALE_CFG_HSCALE_ALGO,
+ JMSK_SCALE_CFG_VSCALE_ALGO,
+ JMSK_SCALE_CFG_H_SCALE_FIR_ALGO,
+ JMSK_SCALE_CFG_V_SCALE_FIR_ALGO,
+
+ JMSK_SCALE_PLNS_OUT_CFG_BLK_WIDTH,
+ JMSK_SCALE_PLNS_OUT_CFG_BLK_HEIGHT,
+
+ JMSK_SCALE_PLNS_HSTEP_FRACTIONAL,
+ JMSK_SCALE_PLNS_HSTEP_INTEGER,
+ JMSK_SCALE_PLNS_VSTEP_FRACTIONAL,
+ JMSK_SCALE_PLNS_VSTEP_INTEGER,
+
+ JMSK_DMI_CFG,
+ JMSK_DMI_ADDR,
+ JMSK_DMI_DATA,
+
+ JMSK_TESTBUS_CFG,
+ JMSK_FE_VBPAD_CFG,
+
+ JMSK_PLN0_RD_HINIT_INT,
+ JMSK_PLN1_RD_HINIT_INT,
+ JMSK_PLN2_RD_HINIT_INT,
+ JMSK_PLN0_RD_VINIT_INT,
+ JMSK_PLN1_RD_VINIT_INT,
+ JMSK_PLN2_RD_VINIT_INT,
+ JMSK_ID_MAX
+};
+
+struct qcom_jpeg_reg_offs {
+ u32 hw_version;
+ u32 hw_capability;
+ u32 reset_cmd;
+ u32 core_cfg;
+ u32 int_mask;
+ u32 int_clr;
+ u32 int_status;
+ u32 hw_cmd;
+ u32 enc_core_state;
+
+ struct {
+ u32 pntr[QCOM_JPEG_MAX_PLANES];
+ u32 offs[QCOM_JPEG_MAX_PLANES];
+ u32 cnsmd[QCOM_JPEG_MAX_PLANES];
+ u32 bsize[QCOM_JPEG_MAX_PLANES];
+ u32 stride[QCOM_JPEG_MAX_PLANES];
+ u32 hinit[QCOM_JPEG_MAX_PLANES];
+ u32 vinit[QCOM_JPEG_MAX_PLANES];
+ u32 pntr_cnt;
+ u32 vbpad_cfg;
+ } fe;
+ u32 fe_cfg;
+
+ struct {
+ u32 pntr[QCOM_JPEG_MAX_PLANES];
+ u32 cnsmd[QCOM_JPEG_MAX_PLANES];
+ u32 bsize[QCOM_JPEG_MAX_PLANES];
+ u32 stride[QCOM_JPEG_MAX_PLANES];
+ u32 hinit[QCOM_JPEG_MAX_PLANES];
+ u32 hstep[QCOM_JPEG_MAX_PLANES];
+ u32 vinit[QCOM_JPEG_MAX_PLANES];
+ u32 vstep[QCOM_JPEG_MAX_PLANES];
+ u32 blocks[QCOM_JPEG_MAX_PLANES];
+ u32 pntr_cnt;
+ } we;
+ u32 we_cfg;
+
+ struct {
+ u32 hstep[QCOM_JPEG_MAX_PLANES];
+ u32 vstep[QCOM_JPEG_MAX_PLANES];
+ } scale;
+ u32 scale_cfg;
+ u32 scale_out_cfg[QCOM_JPEG_MAX_PLANES];
+
+ u32 enc_cfg;
+ u32 enc_img_size;
+ u32 enc_out_size;
+
+ u32 dmi_cfg;
+ u32 dmi_data;
+ u32 dmi_addr;
+} __packed;
+
+#endif /* QCOM_JENC_DEFS_H_ */
diff --git a/drivers/media/platform/qcom/jpeg/qcom_jenc_dev.c b/drivers/media/platform/qcom/jpeg/qcom_jenc_dev.c
new file mode 100644
index 000000000000..4ef6bf9fd48d
--- /dev/null
+++ b/drivers/media/platform/qcom/jpeg/qcom_jenc_dev.c
@@ -0,0 +1,370 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
+ */
+
+#include <linux/clk.h>
+#include <linux/interrupt.h>
+#include <linux/module.h>
+#include <linux/of_device.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+#include <linux/slab.h>
+
+#include <media/v4l2-mem2mem.h>
+
+#include "qcom_jenc_dev.h"
+
+#include "qcom_jenc_defs.h"
+#include "qcom_jenc_ops.h"
+#include "qcom_jenc_res.h"
+#include "qcom_jenc_v4l2.h"
+
+static int qcom_jpeg_match_data(struct qcom_jenc_dev *jenc)
+{
+ struct device *dev = jenc->dev;
+ const struct qcom_dev_resources *res;
+
+ res = device_get_match_data(dev);
+ if (!res)
+ return dev_err_probe(dev, -ENODEV, "unsupported SoC\n");
+
+ jenc->res = res;
+
+ return 0;
+}
+
+static int qcom_jpeg_clk_init(struct qcom_jenc_dev *jenc)
+{
+ const struct qcom_dev_resources *res = jenc->res;
+ int c_idx;
+
+ jenc->clks = devm_kcalloc(jenc->dev, ARRAY_SIZE(res->clk_names), sizeof(*jenc->clks),
+ GFP_KERNEL);
+ if (!jenc->clks)
+ return -ENOMEM;
+
+ for (c_idx = 0; c_idx < ARRAY_SIZE(res->clk_names); c_idx++) {
+ if (!res->clk_names[c_idx])
+ break;
+
+ jenc->clks[c_idx].clk = devm_clk_get(jenc->dev, res->clk_names[c_idx]);
+ if (IS_ERR(jenc->clks[c_idx].clk)) {
+ return dev_err_probe(jenc->dev, PTR_ERR(jenc->clks[c_idx].clk),
+ "failed to get clock %s\n", res->clk_names[c_idx]);
+ }
+
+ jenc->clks[c_idx].id = res->clk_names[c_idx];
+ jenc->num_clks++;
+ }
+
+ return 0;
+}
+
+static int qcom_jpeg_clk_rate(struct qcom_jenc_dev *jenc, enum qcom_soc_perf_level level)
+{
+ const struct qcom_dev_resources *res = jenc->res;
+ const struct qcom_perf_resource *perf = &res->perf_cfg[level];
+ int c_idx;
+ int rc = 0;
+
+ for (c_idx = 0; c_idx < jenc->num_clks; c_idx++) {
+ /* skip clocks with fixed or default frequency */
+ if (!perf->clk_rate[c_idx])
+ continue;
+
+ /* setup frequency according to performance level */
+ rc = clk_set_rate(jenc->clks[c_idx].clk, perf->clk_rate[c_idx]);
+ if (rc < 0) {
+ dev_err(jenc->dev, "clock set rate failed: %d\n", rc);
+ return rc;
+ }
+
+ dev_dbg(jenc->dev, "clock %s current rate: %ld\n",
+ jenc->clks[c_idx].id, clk_get_rate(jenc->clks[c_idx].clk));
+ }
+
+ return rc;
+}
+
+static int qcom_jpeg_clk_on(struct qcom_jenc_dev *jenc)
+{
+ int rc;
+
+ rc = qcom_jpeg_clk_rate(jenc, jenc->perf);
+ if (rc)
+ return rc;
+
+ rc = clk_bulk_prepare_enable(jenc->num_clks, jenc->clks);
+ if (rc)
+ return rc;
+
+ return 0;
+}
+
+static void qcom_jpeg_clk_off(struct qcom_jenc_dev *jenc)
+{
+ clk_bulk_disable_unprepare(jenc->num_clks, jenc->clks);
+}
+
+static int qcom_jpeg_icc_on(struct qcom_jenc_dev *jenc)
+{
+ const struct qcom_dev_resources *res = jenc->res;
+ int p_idx;
+ int rc;
+
+ for (p_idx = 0; p_idx < res->num_of_icc; p_idx++) {
+ rc = icc_set_bw(jenc->icc_paths[p_idx], res->icc_res[p_idx].pair.aggr,
+ res->icc_res[p_idx].pair.peak);
+ if (rc) {
+ dev_err(jenc->dev, "%s failed for path %s: %d\n", __func__,
+ res->icc_res[p_idx].icc_id, rc);
+ goto err_icc_set_bw;
+ }
+ }
+
+ return 0;
+
+err_icc_set_bw:
+ while (--p_idx >= 0)
+ icc_set_bw(jenc->icc_paths[p_idx], 0, 0);
+
+ return rc;
+}
+
+static void qcom_jpeg_icc_off(struct qcom_jenc_dev *jenc)
+{
+ const struct qcom_dev_resources *res = jenc->res;
+ int p_idx;
+
+ for (p_idx = 0; p_idx < res->num_of_icc; p_idx++)
+ icc_set_bw(jenc->icc_paths[p_idx], 0, 0);
+}
+
+static int qcom_jpeg_icc_init(struct qcom_jenc_dev *jenc)
+{
+ const struct qcom_dev_resources *res = jenc->res;
+ int p_idx;
+
+ jenc->icc_paths = devm_kcalloc(jenc->dev, res->num_of_icc, sizeof(*jenc->icc_paths),
+ GFP_KERNEL);
+ if (!jenc->icc_paths)
+ return -ENOMEM;
+
+ for (p_idx = 0; p_idx < res->num_of_icc; p_idx++) {
+ jenc->icc_paths[p_idx] = devm_of_icc_get(jenc->dev, res->icc_res[p_idx].icc_id);
+ if (IS_ERR(jenc->icc_paths[p_idx])) {
+ return dev_err_probe(jenc->dev, PTR_ERR(jenc->icc_paths[p_idx]),
+ "failed to get ICC path: %ld\n",
+ PTR_ERR(jenc->icc_paths[p_idx]));
+ }
+ }
+
+ return 0;
+}
+
+static __maybe_unused int qcom_jpeg_pm_suspend(struct device *dev)
+{
+ struct qcom_jenc_dev *jenc = dev_get_drvdata(dev);
+
+ qcom_jpeg_clk_off(jenc);
+
+ qcom_jpeg_icc_off(jenc);
+
+ return 0;
+}
+
+static __maybe_unused int qcom_jpeg_pm_resume(struct device *dev)
+{
+ struct qcom_jenc_dev *jenc = dev_get_drvdata(dev);
+ int rc;
+
+ rc = qcom_jpeg_icc_on(jenc);
+ if (rc)
+ return rc;
+
+ return qcom_jpeg_clk_on(jenc);
+}
+
+static __maybe_unused int qcom_jpeg_suspend(struct device *dev)
+{
+ struct qcom_jenc_dev *jenc = dev_get_drvdata(dev);
+
+ v4l2_m2m_suspend(jenc->m2m_dev);
+
+ return pm_runtime_force_suspend(dev);
+}
+
+static __maybe_unused int qcom_jpeg_resume(struct device *dev)
+{
+ struct qcom_jenc_dev *jenc = dev_get_drvdata(dev);
+ int rc;
+
+ rc = pm_runtime_force_resume(dev);
+ if (rc)
+ return rc;
+
+ v4l2_m2m_resume(jenc->m2m_dev);
+
+ return rc;
+}
+
+static const struct dev_pm_ops qcom_jpeg_pm_ops = {
+ SET_SYSTEM_SLEEP_PM_OPS(qcom_jpeg_suspend, qcom_jpeg_resume)
+ SET_RUNTIME_PM_OPS(qcom_jpeg_pm_suspend, qcom_jpeg_pm_resume, NULL)
+};
+
+static int qcom_jpeg_probe(struct platform_device *pdev)
+{
+ struct qcom_jenc_dev *jenc;
+ int rc;
+
+ jenc = devm_kzalloc(&pdev->dev, sizeof(*jenc), GFP_KERNEL);
+ if (!jenc)
+ return -ENOMEM;
+
+ jenc->dev = &pdev->dev;
+ mutex_init(&jenc->dev_mutex);
+ spin_lock_init(&jenc->hw_lock);
+ init_completion(&jenc->reset_complete);
+ init_completion(&jenc->stop_complete);
+
+ rc = qcom_jpeg_match_data(jenc);
+ if (rc)
+ return dev_err_probe(jenc->dev, rc, "failed to attach hardware\n");
+
+ if (!jenc->res->hw_offs || !jenc->res->hw_ops)
+ return dev_err_probe(jenc->dev, -EINVAL, "missing hw resources\n");
+
+ rc = dma_set_mask_and_coherent(jenc->dev, DMA_BIT_MASK(32));
+ if (rc)
+ return dev_err_probe(jenc->dev, rc, "failed to set DMA mask\n");
+
+ platform_set_drvdata(pdev, jenc);
+
+ jenc->jpeg_base = devm_platform_ioremap_resource(pdev, 0);
+ if (IS_ERR(jenc->jpeg_base)) {
+ rc = PTR_ERR(jenc->jpeg_base);
+ return dev_err_probe(jenc->dev, rc, "failed to map JPEG resource\n");
+ }
+
+ jenc->cpas_base = devm_platform_ioremap_resource(pdev, 1);
+ if (IS_ERR(jenc->cpas_base)) {
+ rc = PTR_ERR(jenc->cpas_base);
+ return dev_err_probe(jenc->dev, rc, "failed to map CPAS resource\n");
+ }
+
+ rc = qcom_jpeg_clk_init(jenc);
+ if (rc)
+ return dev_err_probe(jenc->dev, rc, "failed to init bulk clocks\n");
+
+ jenc->irq = platform_get_irq(pdev, 0);
+ if (jenc->irq < 0)
+ return dev_err_probe(jenc->dev, jenc->irq, "failed to get IRQ\n");
+
+ rc = devm_request_threaded_irq(jenc->dev, jenc->irq,
+ jenc->res->hw_ops->hw_irq_top,
+ jenc->res->hw_ops->hw_irq_bot,
+ IRQF_ONESHOT, dev_name(jenc->dev), jenc);
+ if (rc)
+ return dev_err_probe(jenc->dev, rc, "failed to request IRQ\n");
+
+ rc = qcom_jpeg_icc_init(jenc);
+ if (rc)
+ return dev_err_probe(jenc->dev, rc, "failed to get ICC resources\n");
+
+ rc = kfifo_alloc(&jenc->kfifo_inst, sizeof(jenc->enc_status) * VB2_MAX_FRAME, GFP_KERNEL);
+ if (rc) {
+ dev_err(jenc->dev, "failed to allocate kfifo\n");
+ return rc;
+ }
+
+ spin_lock_init(&jenc->kfifo_lock);
+
+ rc = v4l2_device_register(jenc->dev, &jenc->v4l2_dev);
+ if (rc) {
+ dev_err(jenc->dev, "failed to register V4L2 device\n");
+ goto err_kfifo_free;
+ }
+
+ rc = qcom_jpeg_v4l2_register(jenc);
+ if (rc) {
+ dev_err(jenc->dev, "failed to register video device\n");
+ goto err_v4l2_device_unregister;
+ }
+
+ jenc->perf = QCOM_SOC_PERF_NOMINAL;
+
+ pm_runtime_enable(jenc->dev);
+
+ dev_info(jenc->dev, "Qualcomm JPEG encoder registered\n");
+
+ return 0;
+
+err_v4l2_device_unregister:
+ v4l2_device_unregister(&jenc->v4l2_dev);
+err_kfifo_free:
+ kfifo_free(&jenc->kfifo_inst);
+
+ return rc;
+}
+
+static void qcom_jpeg_remove(struct platform_device *pdev)
+{
+ struct qcom_jenc_dev *jenc = platform_get_drvdata(pdev);
+
+ pm_runtime_disable(&pdev->dev);
+
+ qcom_jpeg_v4l2_unregister(jenc);
+
+ v4l2_device_unregister(&jenc->v4l2_dev);
+
+ kfifo_free(&jenc->kfifo_inst);
+
+ dev_info(jenc->dev, "Qualcomm JPEG encoder deregistered\n");
+}
+
+static const struct of_device_id qcom_jpeg_of_match[] = {
+ {
+ .compatible = "qcom,sc7180-jenc",
+ .data = &qcom_jpeg_v165_drvdata
+ },
+ {
+ .compatible = "qcom,sm8250-jenc",
+ .data = &qcom_jpeg_v580_drvdata
+ },
+ {
+ .compatible = "qcom,sm7325-jenc",
+ .data = &qcom_jpeg_v580_drvdata
+ },
+ {
+ .compatible = "qcom,sc7280-jenc",
+ .data = &qcom_jpeg_v680_drvdata
+ },
+ {
+ .compatible = "qcom,qcm6490-jenc",
+ .data = &qcom_jpeg_v680_drvdata
+ },
+ {
+ .compatible = "qcom,sm8550-jenc",
+ .data = &qcom_jpeg_v780_drvdata
+ },
+ { }
+};
+MODULE_DEVICE_TABLE(of, qcom_jpeg_of_match);
+
+static struct platform_driver qcom_jpeg_platform_driver = {
+ .probe = qcom_jpeg_probe,
+ .remove = qcom_jpeg_remove,
+ .driver = {
+ .name = QCOM_JPEG_ENC_NAME,
+ .of_match_table = qcom_jpeg_of_match,
+ .pm = &qcom_jpeg_pm_ops,
+ },
+};
+
+module_platform_driver(qcom_jpeg_platform_driver);
+
+MODULE_DESCRIPTION("QCOM JPEG mem2mem V4L2 encoder");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/platform/qcom/jpeg/qcom_jenc_dev.h b/drivers/media/platform/qcom/jpeg/qcom_jenc_dev.h
new file mode 100644
index 000000000000..cf0c1a933163
--- /dev/null
+++ b/drivers/media/platform/qcom/jpeg/qcom_jenc_dev.h
@@ -0,0 +1,111 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
+ */
+
+#ifndef QCOM_JENC_DEV_H
+#define QCOM_JENC_DEV_H
+
+#include <linux/device.h>
+#include <linux/mutex.h>
+#include <linux/irqreturn.h>
+#include <linux/interconnect.h>
+#include <linux/kfifo.h>
+#include <linux/irq_work.h>
+#include <media/videobuf2-core.h>
+
+#include <media/v4l2-device.h>
+#include <media/videobuf2-v4l2.h>
+#include <media/v4l2-ctrls.h>
+
+#include "qcom_jenc_res.h"
+#include "qcom_jenc_hdr.h"
+#include "qcom_jenc_defs.h"
+
+#define QCOM_JPEG_ENC_NAME "qcom-jpeg-enc"
+
+#define TYPE2QID(t) \
+ (V4L2_TYPE_IS_OUTPUT(t) ? JENC_SRC_QUEUE : JENC_DST_QUEUE)
+
+enum qcom_enc_qid {
+ JENC_SRC_QUEUE = 0,
+ JENC_DST_QUEUE,
+ JENC_QUEUE_MAX
+};
+
+struct jenc_enc_format {
+ u32 type;
+ u32 fourcc;
+};
+
+struct qcom_jpeg_buff {
+ struct {
+ struct sg_table *sgt;
+ dma_addr_t dma;
+ unsigned long size;
+
+ } plns[QCOM_JPEG_MAX_PLANES];
+};
+
+struct qcom_jenc_queue {
+ struct v4l2_pix_format_mplane vf;
+ u32 sequence;
+ struct qcom_jpeg_buff buff[VB2_MAX_FRAME];
+ int buff_id;
+};
+
+struct qcom_jenc_dev {
+ struct device *dev;
+ struct v4l2_device v4l2_dev;
+ struct v4l2_m2m_dev *m2m_dev;
+ struct video_device *vdev;
+ const struct qcom_dev_resources *res;
+ enum qcom_soc_perf_level perf;
+ int irq;
+ void __iomem *jpeg_base;
+ void __iomem *cpas_base;
+ struct clk_bulk_data *clks;
+ int num_clks;
+ /* device mutex lock */
+ struct mutex dev_mutex;
+ atomic_t ref_count;
+ struct completion reset_complete;
+ struct completion stop_complete;
+ /* decoder hardware lock */
+ spinlock_t hw_lock;
+ struct jenc_context *actx;
+ struct icc_path **icc_paths;
+
+ struct kfifo kfifo_inst;
+ /* lock kfifo operations */
+ spinlock_t kfifo_lock;
+ u32 enc_status;
+
+ void (*enc_hw_irq_cb)
+ (void *data, enum vb2_buffer_state ev, size_t out_size);
+};
+
+struct jenc_context {
+ struct device *dev;
+ struct qcom_jenc_dev *jenc;
+ struct v4l2_fh fh;
+
+ /* quality update lock */
+ struct mutex quality_mutex;
+ struct v4l2_ctrl *quality_ctl;
+ u32 quality_requested;
+ u32 quality_programmed;
+ struct v4l2_ctrl_handler ctrl_hdl;
+
+ /* session context lock */
+ struct mutex ctx_lock;
+
+ /* decoder state lock */
+ struct mutex stop_lock;
+ bool is_stopping;
+
+ struct qcom_jenc_queue bufq[JENC_QUEUE_MAX];
+ struct qcom_jenc_header hdr_cache;
+};
+
+#endif
diff --git a/drivers/media/platform/qcom/jpeg/qcom_jenc_hdr.c b/drivers/media/platform/qcom/jpeg/qcom_jenc_hdr.c
new file mode 100644
index 000000000000..5a794882b980
--- /dev/null
+++ b/drivers/media/platform/qcom/jpeg/qcom_jenc_hdr.c
@@ -0,0 +1,388 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
+ */
+
+#include <linux/string.h>
+#include <linux/errno.h>
+
+#include "qcom_jenc_hdr.h"
+#include "qcom_jenc_dev.h"
+
+/*
+ * The elements defined in this header are specified
+ * in the ITU-T T.81 / JPEG specification.
+ *
+ * https://www.w3.org/Graphics/JPEG/itu-t81.pdf
+ */
+
+#define JFIF_HEADER_WIDTH_OFFS 0x07
+#define JFIF_HEADER_HEIGHT_OFFS 0x05
+
+struct jpeg_header_buf {
+ u8 *ptr;
+ u32 size;
+ u32 pos;
+};
+
+static const struct jpeg_soi_app0 soi_app0 = {
+ .soi = { 0xff, 0xd8 },
+ .app0_marker = { 0xff, 0xe0 },
+ .app0_length = { 0x00, 0x10 },
+ .jfif_id = { 'J', 'F', 'I', 'F', 0x00 },
+ .version = { 0x01, 0x01 },
+ .units = 0x00,
+ .density_x = { 0x00, 0x01 },
+ .density_y = { 0x00, 0x01 },
+ .thumb_x = 0x00,
+ .thumb_y = 0x00,
+};
+
+static const struct jpeg_record_hdr dqt_luma_hdr = {
+ .marker = { 0xff, 0xdb },
+ .length = { 0, 0x43 }
+};
+
+/* Luminance quantization table */
+static const struct jpeg_dqt_header dqt_luma_data = {
+ .index = 0x00,
+};
+
+static const struct jpeg_record_hdr dqt_chroma_hdr = {
+ .marker = { 0xff, 0xdb },
+ .length = { 0, 0x84 }
+};
+
+/* Chrominance quantization table */
+static const struct jpeg_dqt_header dqt_chroma_data = {
+ .index = 0x01,
+};
+
+static const struct jpeg_record_hdr sof0_mono_hdr = {
+ .marker = { 0xff, 0xc0 },
+ .length = { 0x00, 0x0b },
+};
+
+static const struct jpeg_sof0_mono sof0_mono_data = {
+ .precision = 0x08,
+ .height = { 0x00, 0x00 },
+ .width = { 0x00, 0x00 },
+ .components = 1,
+ .y_id = 1,
+ .y_sampling = 0x11,
+ .y_qtable = 0,
+};
+
+static const struct jpeg_record_hdr sof0_color_hdr = {
+ .marker = { 0xff, 0xc0 },
+ .length = { 0x00, 0x11 },
+};
+
+static const struct jpeg_sof0_color sof0_color_data = {
+ .precision = 0x08,
+ .height = { 0x00, 0x00 },
+ .width = { 0x00, 0x00 },
+ .components = 3,
+ .y_id = 1,
+ .y_sampling = 0x22,
+ .y_qtable = 0,
+ .cb_id = 2,
+ .cb_sampling = 0x11,
+ .cb_qtable = 1,
+ .cr_id = 3,
+ .cr_sampling = 0x11,
+ .cr_qtable = 1,
+};
+
+static const struct jpeg_record_hdr luma_coeff_hdr = {
+ .marker = { 0xff, 0xc4 },
+ .length = { 0x00, 0xb5 },
+};
+
+/*
+ * DC Luminance
+ *
+ * Typical tables for DC difference coding from CCITT T.81
+ * specification K.3.3.1, page 162.
+ */
+static const struct jpeg_dc_coeff_desc luma_dc_coeff = {
+ .index = 0,
+ .bits = {
+ 0x00, 0x01, 0x05, 0x01, 0x01, 0x01, 0x01, 0x01,
+ 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+ },
+ .values = {
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05,
+ 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b
+ }
+};
+
+/*
+ * AC Luminance
+ *
+ * Typical tables for AC coefficient coding from CCITT T.81
+ * specification K.3.3.2, page 162.
+ */
+static const struct jpeg_ac_coeff_desc luma_ac_coeff = {
+ .index = 0x10,
+ .bits = {
+ 0x00, 0x02, 0x01, 0x03, 0x03, 0x02, 0x04, 0x03,
+ 0x05, 0x05, 0x04, 0x04, 0x00, 0x00, 0x01, 0x7d
+ },
+ .values = {
+ 0x01, 0x02, 0x03, 0x00, 0x04, 0x11, 0x05, 0x12, 0x21,
+ 0x31, 0x41, 0x06, 0x13, 0x51, 0x61, 0x07, 0x22, 0x71,
+ 0x14, 0x32, 0x81, 0x91, 0xa1, 0x08, 0x23, 0x42, 0xb1,
+ 0xc1, 0x15, 0x52, 0xd1, 0xf0, 0x24, 0x33, 0x62, 0x72,
+ 0x82, 0x09, 0x0a, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x25,
+ 0x26, 0x27, 0x28, 0x29, 0x2a, 0x34, 0x35, 0x36, 0x37,
+ 0x38, 0x39, 0x3a, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48,
+ 0x49, 0x4a, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59,
+ 0x5a, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a,
+ 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x83,
+ 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8a, 0x92, 0x93,
+ 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9a, 0xa2, 0xa3,
+ 0xa4, 0xa5, 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xb2, 0xb3,
+ 0xb4, 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba, 0xc2, 0xc3,
+ 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xd2, 0xd3,
+ 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xe1, 0xe2,
+ 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea, 0xf1,
+ 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0xfa
+ }
+};
+
+static const struct jpeg_record_hdr coeff_mono_hdr = {
+ .marker = { 0xff, 0xc4 },
+ .length = { 0x00, 0xd2 },
+};
+
+static const struct jpeg_record_hdr coeff_color_hdr = {
+ .marker = { 0xff, 0xc4 },
+ .length = { 0x01, 0xa2 },
+};
+
+/* DC Chrominance */
+static const struct jpeg_dc_coeff_desc chroma_dc_coeff = {
+ .index = 1,
+ .bits = {
+ 0x00, 0x03, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+ 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00
+ },
+ .values = {
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05,
+ 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b
+ }
+};
+
+/* AC Chrominance */
+static const struct jpeg_ac_coeff_desc chroma_ac_coeff = {
+ .index = 0x11,
+ .bits = {
+ 0x00, 0x02, 0x01, 0x02, 0x04, 0x04, 0x03, 0x04,
+ 0x07, 0x05, 0x04, 0x04, 0x00, 0x01, 0x02, 0x77
+ },
+ .values = {
+ 0x00, 0x01, 0x02, 0x03, 0x11, 0x04, 0x05, 0x21, 0x31,
+ 0x06, 0x12, 0x41, 0x51, 0x07, 0x61, 0x71, 0x13, 0x22,
+ 0x32, 0x81, 0x08, 0x14, 0x42, 0x91, 0xa1, 0xb1, 0xc1,
+ 0x09, 0x23, 0x33, 0x52, 0xf0, 0x15, 0x62, 0x72, 0xd1,
+ 0x0a, 0x16, 0x24, 0x34, 0xe1, 0x25, 0xf1, 0x17, 0x18,
+ 0x19, 0x1a, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x35, 0x36,
+ 0x37, 0x38, 0x39, 0x3a, 0x43, 0x44, 0x45, 0x46, 0x47,
+ 0x48, 0x49, 0x4a, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58,
+ 0x59, 0x5a, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69,
+ 0x6a, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a,
+ 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8a,
+ 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9a,
+ 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, 0xa8, 0xa9, 0xaa,
+ 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba,
+ 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xca,
+ 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda,
+ 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea,
+ 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0xfa
+ }
+};
+
+static const struct jpeg_record_hdr sos_mono_hdr = {
+ .marker = { 0xff, 0xda },
+ .length = { 0x00, 0x08 },
+};
+
+static const struct jpeg_sos_mono sos_mono_data = {
+ .components = 1,
+ .y_id = 1,
+ .y_tables = 0x00,
+ .spectral = { 0x00, 0x3f },
+ .approx = 0x00,
+};
+
+static const struct jpeg_record_hdr sos_color_hdr = {
+ .marker = { 0xff, 0xda },
+ .length = { 0x00, 0x0c },
+};
+
+static const struct jpeg_sos_color sos_color_data = {
+ .components = 3,
+ .y_id = 1,
+ .y_tables = 0x00,
+ .cb_id = 2,
+ .cb_tables = 0x11,
+ .cr_id = 3,
+ .cr_tables = 0x11,
+ .spectral = { 0x00, 0x3f },
+ .approx = 0x00,
+};
+
+static inline int jb_put_mem(struct jpeg_header_buf *b, const void *src, u32 len)
+{
+ if (len > b->size - b->pos)
+ return -ENOSPC;
+
+ memcpy(b->ptr + b->pos, src, len);
+ b->pos += len;
+
+ return 0;
+}
+
+static inline void patch_u16be(u8 *buf, u32 off, u16 v)
+{
+ buf[off] = (v >> 8) & 0xff;
+ buf[off + 1] = v & 0xff;
+}
+
+int qcom_jenc_header_init(struct qcom_jenc_header *c, u32 fourcc)
+{
+ int rc;
+ struct jpeg_header_buf b = {
+ .ptr = c->data,
+ .size = sizeof(c->data),
+ .pos = 0,
+ };
+
+ c->sof_offset = 0;
+ c->dqt_one_offs = 0;
+ c->dqt_two_offs = 0;
+
+ rc = jb_put_mem(&b, &soi_app0, sizeof(soi_app0));
+ if (rc)
+ return rc;
+
+ if (fourcc != V4L2_PIX_FMT_GREY) {
+ rc = jb_put_mem(&b, &dqt_chroma_hdr, sizeof(dqt_chroma_hdr));
+ if (rc)
+ return rc;
+
+ /* Store the offset of the first DQT table for later use. */
+ c->dqt_one_offs = b.pos;
+ rc = jb_put_mem(&b, &dqt_luma_data, sizeof(dqt_luma_data));
+ if (rc)
+ return rc;
+
+ /* Store the offset of the second DQT table for later use. */
+ c->dqt_two_offs = b.pos;
+ rc = jb_put_mem(&b, &dqt_chroma_data, sizeof(dqt_chroma_data));
+ if (rc)
+ return rc;
+ } else {
+ rc = jb_put_mem(&b, &dqt_luma_hdr, sizeof(dqt_luma_hdr));
+ if (rc)
+ return rc;
+
+ /* Store the offset of the first DQT table for later use. */
+ c->dqt_one_offs = b.pos;
+ rc = jb_put_mem(&b, &dqt_luma_data, sizeof(dqt_luma_data));
+ if (rc)
+ return rc;
+ }
+
+ /* Store the offset of the SOF record for later use. */
+ c->sof_offset = b.pos;
+
+ if (fourcc != V4L2_PIX_FMT_GREY) {
+ rc = jb_put_mem(&b, &sof0_color_hdr, sizeof(sof0_color_hdr));
+ if (rc)
+ return rc;
+ rc = jb_put_mem(&b, &sof0_color_data, sizeof(sof0_color_data));
+ if (rc)
+ return rc;
+ rc = jb_put_mem(&b, &coeff_color_hdr, sizeof(coeff_color_hdr));
+ if (rc)
+ return rc;
+ rc = jb_put_mem(&b, &luma_dc_coeff, sizeof(luma_dc_coeff));
+ if (rc)
+ return rc;
+ rc = jb_put_mem(&b, &luma_ac_coeff, sizeof(luma_ac_coeff));
+ if (rc)
+ return rc;
+ rc = jb_put_mem(&b, &chroma_dc_coeff, sizeof(chroma_dc_coeff));
+ if (rc)
+ return rc;
+ rc = jb_put_mem(&b, &chroma_ac_coeff, sizeof(chroma_ac_coeff));
+ if (rc)
+ return rc;
+ rc = jb_put_mem(&b, &sos_color_hdr, sizeof(sos_color_hdr));
+ if (rc)
+ return rc;
+ rc = jb_put_mem(&b, &sos_color_data, sizeof(sos_color_data));
+ if (rc)
+ return rc;
+ } else {
+ rc = jb_put_mem(&b, &sof0_mono_hdr, sizeof(sof0_mono_hdr));
+ if (rc)
+ return rc;
+ rc = jb_put_mem(&b, &sof0_mono_data, sizeof(sof0_mono_data));
+ if (rc)
+ return rc;
+ rc = jb_put_mem(&b, &coeff_mono_hdr, sizeof(coeff_mono_hdr));
+ if (rc)
+ return rc;
+ rc = jb_put_mem(&b, &luma_dc_coeff, sizeof(luma_dc_coeff));
+ if (rc)
+ return rc;
+ rc = jb_put_mem(&b, &luma_ac_coeff, sizeof(luma_ac_coeff));
+ if (rc)
+ return rc;
+ rc = jb_put_mem(&b, &sos_mono_hdr, sizeof(sos_mono_hdr));
+ if (rc)
+ return rc;
+ rc = jb_put_mem(&b, &sos_mono_data, sizeof(sos_mono_data));
+ if (rc)
+ return rc;
+ }
+
+ c->size = b.pos;
+
+ return 0;
+}
+
+void qcom_jenc_dqts_emit(const struct qcom_jenc_header *c, u8 *dst)
+{
+ /* Propagate DQT tables into the JPEG header */
+ if (c->dqt_one_offs) {
+ u32 one_offs = c->dqt_one_offs + sizeof(dqt_luma_data.index);
+
+ memcpy(dst + one_offs, &c->data[one_offs], sizeof(dqt_luma_data.value));
+ }
+
+ if (c->dqt_two_offs) {
+ u32 two_offs = c->dqt_two_offs + sizeof(dqt_chroma_data.index);
+
+ memcpy(dst + two_offs, &c->data[two_offs], sizeof(dqt_chroma_data.value));
+ }
+}
+
+u32 qcom_jenc_header_emit(const struct qcom_jenc_header *c, u8 *dst, u32 dst_size, u16 width,
+ u16 height)
+{
+ /* Copy JFIF into JPEG header and update actual image size */
+ if (dst_size < c->size)
+ return 0;
+
+ memcpy(dst, c->data, c->size);
+
+ /* Update output image size */
+ patch_u16be(dst, c->sof_offset + JFIF_HEADER_WIDTH_OFFS, width);
+ patch_u16be(dst, c->sof_offset + JFIF_HEADER_HEIGHT_OFFS, height);
+
+ return c->size;
+}
diff --git a/drivers/media/platform/qcom/jpeg/qcom_jenc_hdr.h b/drivers/media/platform/qcom/jpeg/qcom_jenc_hdr.h
new file mode 100644
index 000000000000..0c5fcc69e7cd
--- /dev/null
+++ b/drivers/media/platform/qcom/jpeg/qcom_jenc_hdr.h
@@ -0,0 +1,130 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
+ */
+
+#ifndef QCOM_JENC_HDR_H
+#define QCOM_JENC_HDR_H
+
+#include <linux/types.h>
+
+#include "qcom_jenc_defs.h"
+
+#define JPEG_QDT_LENGTH 64
+#define JPEG_HEADER_MAX 1024
+
+struct qcom_jenc_header {
+ u8 data[JPEG_HEADER_MAX];
+ u32 size;
+ u32 sof_offset;
+ u32 dqt_one_offs;
+ u32 dqt_two_offs;
+};
+
+struct jpeg_record_hdr {
+ u8 marker[2];
+ u8 length[2];
+} __packed;
+
+struct jpeg_dqt_header {
+ u8 index;
+ u8 value[JPEG_QDT_LENGTH];
+} __packed;
+
+struct jpeg_soi_app0 {
+ u8 soi[2];
+ u8 app0_marker[2];
+ u8 app0_length[2];
+ u8 jfif_id[5];
+ u8 version[2];
+ u8 units;
+ u8 density_x[2];
+ u8 density_y[2];
+ u8 thumb_x;
+ u8 thumb_y;
+} __packed;
+
+struct jpeg_sof0_mono {
+ u8 precision;
+ u8 height[2];
+ u8 width[2];
+ u8 components;
+
+ u8 y_id;
+ u8 y_sampling;
+ u8 y_qtable;
+} __packed;
+
+struct jpeg_sof0_color {
+ u8 precision;
+ u8 height[2];
+ u8 width[2];
+ u8 components;
+
+ u8 y_id;
+ u8 y_sampling;
+ u8 y_qtable;
+
+ u8 cb_id;
+ u8 cb_sampling;
+ u8 cb_qtable;
+
+ u8 cr_id;
+ u8 cr_sampling;
+ u8 cr_qtable;
+} __packed;
+
+struct jpeg_dc_coeff_desc {
+ u8 index;
+ u8 bits[16];
+ u8 values[12];
+} __packed;
+
+struct jpeg_ac_coeff_desc {
+ u8 index;
+ u8 bits[16];
+ u8 values[162];
+} __packed;
+
+struct jpeg_sos_hdr {
+ u8 sos_marker[2];
+ u8 sos_length[2];
+ u8 components;
+} __packed;
+
+struct jpeg_sos_mono {
+ u8 components;
+
+ u8 y_id;
+ u8 y_tables;
+
+ u8 spectral[2];
+ u8 approx;
+} __packed;
+
+struct jpeg_sos_color {
+ u8 components;
+
+ u8 y_id;
+ u8 y_tables;
+
+ u8 cb_id;
+ u8 cb_tables;
+
+ u8 cr_id;
+ u8 cr_tables;
+
+ u8 spectral[2];
+ u8 approx;
+} __packed;
+
+struct jenc_context;
+
+int qcom_jenc_header_init(struct qcom_jenc_header *c, u32 fourcc);
+
+void qcom_jenc_dqts_emit(const struct qcom_jenc_header *c, u8 *dst);
+
+u32 qcom_jenc_header_emit(const struct qcom_jenc_header *c, u8 *dst, u32 dst_size, u16 width,
+ u16 height);
+
+#endif /* QCOM_JENC_HDR_H */
diff --git a/drivers/media/platform/qcom/jpeg/qcom_jenc_ops.c b/drivers/media/platform/qcom/jpeg/qcom_jenc_ops.c
new file mode 100644
index 000000000000..92e3c09df3d1
--- /dev/null
+++ b/drivers/media/platform/qcom/jpeg/qcom_jenc_ops.c
@@ -0,0 +1,1522 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
+ */
+
+#include <asm/div64.h>
+#include <linux/pm_runtime.h>
+
+#include <media/v4l2-common.h>
+#include <media/v4l2-mem2mem.h>
+#include <media/videobuf2-dma-sg.h>
+#include <media/videobuf2-dma-contig.h>
+
+#include "qcom_jenc_dev.h"
+#include "qcom_jenc_ops.h"
+#include "qcom_jenc_defs.h"
+
+#define JPEG_RESET_TIMEOUT_MS 300
+#define JPEG_STOP_TIMEOUT_MS 200
+
+#define JPEG_DQT_SHIFT 20
+#define JPEG_Q5_21_SHIFT 21
+
+#define JPEG_MCU_BLOCK_8 8
+#define JPEG_MCU_BLOCK_16 16
+#define JPEG_MCU_BLOCK_128 128
+#define JPEG_MCU_BLOCK_256 256
+
+#define JPEG_DEFAULT_SCALE_STEP 0x200000
+
+#define JPEG_U32_CLR (0U)
+#define JPEG_U32_SET (~0U)
+
+/*
+ * JPEG | V4L2
+ * ---- | -------
+ * H1V1 | GREY
+ * H1V2 | YUV422M
+ * H2V1 | NV16M
+ * H2V2 | NV12M
+ */
+enum qcom_jpeg_encode_fmt {
+ JPEG_ENCODE_H1V1 = 0,
+ JPEG_ENCODE_H1V2,
+ JPEG_ENCODE_H2V1,
+ JPEG_ENCODE_H2V2,
+ JPEG_ENCODE_MONO,
+};
+
+enum qcom_jpeg_memory_fmt {
+ JPEG_MEM_FMT_PLANAR = 0x0,
+ JPEG_MEM_FMT_PPLANAR = 0x1,
+ JPEG_MEM_FMT_MONO = 0x2,
+ JPEG_MEM_FMT_COEFFICIENT = 0x3
+};
+
+enum jpeg_mal_bounds {
+ JPEG_CFG_MAL_BOUND_32_BYTES = 0x0,
+ JPEG_CFG_MAL_BOUND_64_BYTES = 0x1,
+ JPEG_CFG_MAL_BOUND_128_BYTES = 0x2,
+ JPEG_CFG_MAL_BOUND_256_BYTES = 0x3,
+ JPEG_CFG_MAL_BOUND_512_BYTES = 0x4,
+ JPEG_CFG_MAL_BOUND_1K_BYTES = 0x5,
+ JPEG_CFG_MAL_BOUND_2K_BYTES = 0x6,
+ JPEG_CFG_MAL_BOUND_4K_BYTES = 0x7
+};
+
+struct qcom_jpeg_scale_blocks {
+ u8 w_block[QCOM_JPEG_MAX_PLANES];
+ u8 h_block[QCOM_JPEG_MAX_PLANES];
+};
+
+struct qcom_jpeg_mal_boundary {
+ u32 bytes;
+ int boundary;
+};
+
+struct qcom_jpeg_formats {
+ u32 fourcc;
+ enum qcom_jpeg_encode_fmt encode;
+ enum qcom_jpeg_memory_fmt memory;
+};
+
+/*
+ * Luminance quantization table defined by CCITT T.81.
+ * See: https://www.w3.org/Graphics/JPEG/itu-t81.pdf
+ */
+static const u8 t81k1_dct_luma_table[JPEG_QDT_LENGTH] = {
+ 16, 11, 10, 16, 24, 40, 51, 61,
+ 12, 12, 14, 19, 26, 58, 60, 55,
+ 14, 13, 16, 24, 40, 57, 69, 56,
+ 14, 17, 22, 29, 51, 87, 80, 62,
+ 18, 22, 37, 56, 68, 109, 103, 77,
+ 24, 35, 55, 64, 81, 104, 113, 92,
+ 49, 64, 78, 87, 103, 121, 120, 101,
+ 72, 92, 95, 98, 112, 100, 103, 99
+};
+
+/*
+ * Chrominance quantization table defined by CCITT T.81.
+ * See: https://www.w3.org/Graphics/JPEG/itu-t81.pdf
+ */
+static const u8 t81k2_dct_chroma_table[JPEG_QDT_LENGTH] = {
+ 17, 18, 24, 47, 99, 99, 99, 99,
+ 18, 21, 26, 66, 99, 99, 99, 99,
+ 24, 26, 56, 99, 99, 99, 99, 99,
+ 47, 66, 99, 99, 99, 99, 99, 99,
+ 99, 99, 99, 99, 99, 99, 99, 99,
+ 99, 99, 99, 99, 99, 99, 99, 99,
+ 99, 99, 99, 99, 99, 99, 99, 99,
+ 99, 99, 99, 99, 99, 99, 99, 99
+};
+
+/*
+ * Zig-zag scan order for quantized DCT coefficients
+ * as defined by CCITT T.81.
+ * See: https://www.w3.org/Graphics/JPEG/itu-t81.pdf
+ */
+static const u8 t81a6_dct_zig_zag_table[] = {
+ 0, 1, 5, 6, 14, 15, 27, 28,
+ 2, 4, 7, 13, 16, 26, 29, 42,
+ 3, 8, 12, 17, 25, 30, 41, 43,
+ 9, 11, 18, 24, 31, 40, 44, 53,
+ 10, 19, 23, 32, 39, 45, 52, 54,
+ 20, 22, 33, 38, 46, 51, 55, 60,
+ 21, 34, 37, 47, 50, 56, 59, 61,
+ 35, 36, 48, 49, 57, 58, 62, 63
+};
+
+static const u8 jpeg_mcu_per_ratio[] = {
+ 0, /* MCU = 1, Ratio < 2x */
+ 3, /* MCU = 0, 2x <= Ratio < 4x */
+ 2, /* MCU = 0, 4x <= Ratio < 8x */
+ 1, /* MCU = 0, 8x <= Ratio < 16x */
+ 0, /* MCU = 0, Ratio > 16x */
+};
+
+static const struct qcom_jpeg_formats jpeg_encode_fmt[] = {
+ {
+ .fourcc = V4L2_PIX_FMT_GREY,
+ .encode = JPEG_ENCODE_MONO,
+ .memory = JPEG_MEM_FMT_MONO
+ },
+ {
+ .fourcc = V4L2_PIX_FMT_JPEG,
+ .encode = JPEG_ENCODE_H1V1,
+ .memory = JPEG_MEM_FMT_PPLANAR
+ },
+ {
+ .fourcc = V4L2_PIX_FMT_YUV422M,
+ .encode = JPEG_ENCODE_H1V2,
+ .memory = JPEG_MEM_FMT_PLANAR
+ },
+ {
+ .fourcc = V4L2_PIX_FMT_YVU422M,
+ .encode = JPEG_ENCODE_H1V2,
+ .memory = JPEG_MEM_FMT_PLANAR
+ },
+ {
+ .fourcc = V4L2_PIX_FMT_NV16M,
+ .encode = JPEG_ENCODE_H2V1,
+ .memory = JPEG_MEM_FMT_PPLANAR
+ },
+ {
+ .fourcc = V4L2_PIX_FMT_NV61M,
+ .encode = JPEG_ENCODE_H2V1,
+ .memory = JPEG_MEM_FMT_PPLANAR
+ },
+ {
+ .fourcc = V4L2_PIX_FMT_NV12M,
+ .encode = JPEG_ENCODE_H2V2,
+ .memory = JPEG_MEM_FMT_PPLANAR
+ },
+ {
+ .fourcc = V4L2_PIX_FMT_NV21M,
+ .encode = JPEG_ENCODE_H2V2,
+ .memory = JPEG_MEM_FMT_PPLANAR
+ }
+};
+
+static const struct qcom_jpeg_mal_boundary jpeg_mal_bounds[] = {
+ { .bytes = 32, .boundary = JPEG_CFG_MAL_BOUND_32_BYTES },
+ { .bytes = 64, .boundary = JPEG_CFG_MAL_BOUND_64_BYTES },
+ { .bytes = 128, .boundary = JPEG_CFG_MAL_BOUND_128_BYTES },
+ { .bytes = 256, .boundary = JPEG_CFG_MAL_BOUND_256_BYTES },
+ { .bytes = 512, .boundary = JPEG_CFG_MAL_BOUND_512_BYTES },
+ { .bytes = 1024, .boundary = JPEG_CFG_MAL_BOUND_1K_BYTES },
+ { .bytes = 4096, .boundary = JPEG_CFG_MAL_BOUND_4K_BYTES }
+};
+
+static const struct qcom_jpeg_scale_blocks jpeg_mcu_blocks[] = {
+ [JPEG_ENCODE_H1V1] = {
+ .w_block = { JPEG_MCU_BLOCK_8, JPEG_MCU_BLOCK_8, JPEG_MCU_BLOCK_8 },
+ .h_block = { JPEG_MCU_BLOCK_8, JPEG_MCU_BLOCK_8, JPEG_MCU_BLOCK_8 },
+ },
+ [JPEG_ENCODE_H1V2] = {
+ .w_block = { JPEG_MCU_BLOCK_8, JPEG_MCU_BLOCK_8, JPEG_MCU_BLOCK_8 },
+ .h_block = { JPEG_MCU_BLOCK_16, JPEG_MCU_BLOCK_8, JPEG_MCU_BLOCK_8 },
+ },
+ [JPEG_ENCODE_H2V1] = {
+ .w_block = { JPEG_MCU_BLOCK_16, JPEG_MCU_BLOCK_8, JPEG_MCU_BLOCK_8 },
+ .h_block = { JPEG_MCU_BLOCK_8, JPEG_MCU_BLOCK_8, JPEG_MCU_BLOCK_8 },
+ },
+ [JPEG_ENCODE_H2V2] = {
+ .w_block = { JPEG_MCU_BLOCK_16, JPEG_MCU_BLOCK_8, JPEG_MCU_BLOCK_8 },
+ .h_block = { JPEG_MCU_BLOCK_16, JPEG_MCU_BLOCK_8, JPEG_MCU_BLOCK_8 },
+ },
+ [JPEG_ENCODE_MONO] = {
+ .w_block = { JPEG_MCU_BLOCK_8 },
+ .h_block = { JPEG_MCU_BLOCK_8 }
+ },
+};
+
+static inline int jpeg_get_memory_fmt(u32 fourcc)
+{
+ u32 fi;
+
+ for (fi = 0; fi < ARRAY_SIZE(jpeg_encode_fmt); fi++) {
+ if (jpeg_encode_fmt[fi].fourcc == fourcc)
+ return jpeg_encode_fmt[fi].memory;
+ }
+
+ return -EINVAL;
+}
+
+static inline int jpeg_get_encode_fmt(u32 fourcc)
+{
+ u32 fi;
+
+ for (fi = 0; fi < ARRAY_SIZE(jpeg_encode_fmt); fi++) {
+ if (jpeg_encode_fmt[fi].fourcc == fourcc)
+ return jpeg_encode_fmt[fi].encode;
+ }
+
+ return -EINVAL;
+}
+
+static inline int jpeg_get_mal_boundary(u32 width, const struct qcom_jpeg_mal_boundary *table,
+ u32 count)
+{
+ u32 bi;
+
+ if (!table || !count)
+ return -EINVAL;
+
+ for (bi = 0; bi < count; bi++) {
+ if (table[bi].bytes > width)
+ break;
+ }
+
+ if (!bi)
+ return table[0].boundary;
+
+ return table[bi - 1].boundary;
+}
+
+static inline u8 jpeg_get_mcu_per_block(u32 src_size, u32 dst_size)
+{
+ u8 h_rto;
+
+ if (!src_size || !dst_size)
+ return 0;
+
+ /* Calculate scale factor */
+ h_rto = max(src_size, dst_size) / min(src_size, dst_size);
+
+ if (h_rto >= 0 && h_rto < 2)
+ return jpeg_mcu_per_ratio[0];
+ else if (h_rto >= 2 && h_rto < 4)
+ return jpeg_mcu_per_ratio[1];
+ else if (h_rto >= 4 && h_rto < 8)
+ return jpeg_mcu_per_ratio[2];
+ else if (h_rto >= 8 && h_rto < 16)
+ return jpeg_mcu_per_ratio[3];
+
+ return jpeg_mcu_per_ratio[4];
+}
+
+static inline int jpeg_get_mcu_geometry(enum qcom_jpeg_encode_fmt fmt, u32 width, u32 height,
+ u32 *blk_w, u32 *blk_h, u32 *mcu_cols, u32 *mcu_rows)
+{
+ const struct qcom_jpeg_scale_blocks *blks;
+ u32 bw = 0, bh = 0;
+ u8 pln;
+
+ if (!width || !height)
+ return -EINVAL;
+
+ blks = &jpeg_mcu_blocks[fmt];
+
+ for (pln = 0; pln < QCOM_JPEG_MAX_PLANES; pln++) {
+ bw = max(bw, blks->w_block[pln]);
+ bh = max(bh, blks->h_block[pln]);
+ }
+
+ if (!bw || !bh)
+ return -EINVAL;
+
+ if (blk_w)
+ *blk_w = bw;
+ if (blk_h)
+ *blk_h = bh;
+
+ if (mcu_cols)
+ *mcu_cols = ALIGN(width, bw) / bw;
+
+ if (mcu_rows)
+ *mcu_rows = ALIGN(height, bh) / bh;
+
+ return 0;
+}
+
+/* Integer part of scale */
+static inline s32 jpeg_calc_scale_int(u32 in_width, u32 out_width)
+{
+ if (!out_width)
+ return 0;
+
+ return (s32)(in_width / out_width);
+}
+
+/* Fractional part od scale */
+static inline u32 jpeg_calc_scale_frac(u32 in_width, u32 out_width)
+{
+ u32 remainder = in_width % out_width;
+
+ if (!out_width)
+ return 0;
+
+ /* 64-bit to avoid overflow during shift */
+ return (u32)(((u64)remainder << JPEG_Q5_21_SHIFT) / out_width);
+}
+
+static inline s32 jpeg_calc_q5_21(s32 int_part, u32 frac_part)
+{
+ return ((s32)((u32)int_part << JPEG_Q5_21_SHIFT)) | (frac_part & ((1u << 21) - 1));
+}
+
+static inline u32 jpeg_io_read(struct qcom_jenc_dev *jenc, u32 offset)
+{
+ u32 data;
+
+ rmb(); /* Preventing concurrency read/write interference */
+ data = readl_relaxed(jenc->jpeg_base + offset);
+
+ return data;
+}
+
+static inline void jpeg_io_write(struct qcom_jenc_dev *jenc, u32 offset, u32 value)
+{
+ wmb(); /* Preventing concurrency read/write interference */
+ writel_relaxed(value, jenc->jpeg_base + offset);
+}
+
+/*
+ * Runtime bitfield helpers (for non-constant masks).
+ *
+ * Requirements:
+ * - mask must be non-zero
+ * - mask must be contiguous (e.g. 0x7u << n)
+ */
+
+static inline u32 jpeg_bits_get(u32 mask, u32 reg)
+{
+ return (reg & mask) >> __builtin_ctz(mask);
+}
+
+static inline u32 jpeg_bits_set(u32 mask, u32 val)
+{
+ return (val << __builtin_ctz(mask)) & mask;
+}
+
+static inline u32 jpeg_rd_bits(struct qcom_jenc_dev *jenc, u32 offs, enum qcom_jpeg_mask_id mid)
+{
+ u32 reg = jpeg_io_read(jenc, offs);
+ u32 mask = jenc->res->hw_mask[mid];
+
+ return jpeg_bits_get(mask, reg);
+}
+
+/*
+ * Read-modify-write (for R/W registers)
+ */
+static inline void jpeg_rw_bits(struct qcom_jenc_dev *jenc, u32 offs, enum qcom_jpeg_mask_id mid,
+ u32 val)
+{
+ u32 reg = jpeg_io_read(jenc, offs);
+ u32 mask = jenc->res->hw_mask[mid];
+
+ reg &= ~mask;
+ reg |= jpeg_bits_set(mask, val);
+
+ jpeg_io_write(jenc, offs, reg);
+}
+
+/*
+ * Write-only variant (for write only registers)
+ */
+static inline void jpeg_wo_bits(struct qcom_jenc_dev *jenc, u32 offs, enum qcom_jpeg_mask_id mid,
+ u32 val)
+{
+ u32 mask = jenc->res->hw_mask[mid];
+
+ jpeg_io_write(jenc, offs, jpeg_bits_set(mask, val));
+}
+
+static u8 jpeg_calculate_dqt(struct jenc_context *ectx, u8 dqt_value)
+{
+ u64 ratio;
+ u8 calc_val;
+
+ ratio = (QCOM_JPEG_QUALITY_MAX - ectx->quality_requested) << JPEG_DQT_SHIFT;
+ ratio = max_t(u64, 1, ratio);
+ do_div(ratio, QCOM_JPEG_QUALITY_MID);
+
+ calc_val = DIV64_U64_ROUND_CLOSEST(ratio * dqt_value, 1LU << JPEG_DQT_SHIFT);
+
+ return max_t(u8, 1, calc_val);
+}
+
+static void jpeg_apply_dmi_table(struct jenc_context *ectx)
+{
+ const struct qcom_jpeg_reg_offs *offs = ectx->jenc->res->hw_offs;
+ u32 pcfg = { 0x00000011 };
+ u32 addr = { 0x00000000 };
+ u8 *base;
+ u8 dqt_val, idx;
+ u32 reg_val;
+ int i;
+
+ /* DMI upload start sequence */
+ jpeg_io_write(ectx->jenc, offs->dmi_addr, addr);
+ jpeg_io_write(ectx->jenc, offs->dmi_cfg, pcfg);
+
+ /* DMI Luma upload */
+ base = &ectx->hdr_cache.data[ectx->hdr_cache.dqt_one_offs + 1];
+ for (i = 0; i < ARRAY_SIZE(t81k1_dct_luma_table); i++) {
+ dqt_val = jpeg_calculate_dqt(ectx, t81k1_dct_luma_table[i]);
+ /*
+ * Store the luma to be propagated to the JPEG header at a later stage.
+ * If offs == 0, no DQT is present in the header and the write
+ * should be skipped.
+ */
+ if (ectx->hdr_cache.dqt_one_offs) {
+ idx = t81a6_dct_zig_zag_table[i];
+ /* Perform reordering to arrange transformed DQT in a zigzag pattern */
+ base[idx] = dqt_val;
+ }
+ /* The calculated DQT value cannot be less than 1 */
+ reg_val = div_u64(U16_MAX + 1U, dqt_val);
+ jpeg_io_write(ectx->jenc, offs->dmi_data, clamp_t(u32, reg_val, 0, U16_MAX));
+ }
+
+ /* DMI Chroma upload */
+ base = &ectx->hdr_cache.data[ectx->hdr_cache.dqt_two_offs + 1];
+ for (i = 0; i < ARRAY_SIZE(t81k2_dct_chroma_table); i++) {
+ dqt_val = jpeg_calculate_dqt(ectx, t81k2_dct_chroma_table[i]);
+ /*
+ * Store the chroma to be propagated to the JPEG header at a later stage.
+ * If offs == 0, no DQT is present in the header and the write
+ * should be skipped.
+ */
+ if (ectx->hdr_cache.dqt_two_offs) {
+ idx = t81a6_dct_zig_zag_table[i];
+ /* Perform reordering to arrange transformed DQT in a zigzag pattern */
+ base[idx] = dqt_val;
+ }
+ /* The calculated DQT value cannot be less than 1 */
+ reg_val = div_u64(U16_MAX + 1U, dqt_val);
+ jpeg_io_write(ectx->jenc, offs->dmi_data, clamp_t(u32, reg_val, 0, U16_MAX));
+ }
+
+ /* DMI upload end sequence */
+ jpeg_io_write(ectx->jenc, offs->dmi_cfg, addr);
+
+ ectx->quality_programmed = ectx->quality_requested;
+
+ dev_dbg(ectx->dev, "%s: ctx=%p quality_programmed=%d\n", __func__, ectx,
+ ectx->quality_programmed);
+}
+
+static void jpeg_cpu_access(struct device *dev, struct qcom_jpeg_buff *frame,
+ enum dma_data_direction direction)
+{
+ u8 pln;
+
+ for (pln = 0; pln < QCOM_JPEG_MAX_PLANES; pln++) {
+ struct sg_table *sgt = frame->plns[pln].sgt;
+
+ if (!frame->plns[pln].dma || !sgt)
+ break;
+
+ dma_sync_sg_for_cpu(dev, sgt->sgl, sgt->orig_nents, direction);
+ }
+}
+
+static void jpeg_dev_access(struct device *dev, struct qcom_jpeg_buff *frame,
+ enum dma_data_direction direction)
+{
+ u8 pln;
+
+ for (pln = 0; pln < QCOM_JPEG_MAX_PLANES; pln++) {
+ struct sg_table *sgt = frame->plns[pln].sgt;
+
+ if (!frame->plns[pln].dma || !sgt)
+ continue;
+
+ dma_sync_sg_for_device(dev, sgt->sgl, sgt->orig_nents, direction);
+ }
+}
+
+static int jpeg_init(struct qcom_jenc_dev *jenc)
+{
+ const struct qcom_jpeg_reg_offs *offs;
+ void __iomem *mem_base;
+ unsigned long rtime;
+ u32 hw_ver;
+
+ if (!jenc || !jenc->dev || !jenc->jpeg_base || !jenc->res->hw_offs) {
+ pr_err("encoder HW init failed\n");
+ return -EINVAL;
+ }
+
+ offs = jenc->res->hw_offs;
+ mem_base = jenc->jpeg_base;
+
+ jpeg_wo_bits(jenc, offs->int_clr, JMSK_IRQ_CLEAR_ALL, JPEG_U32_SET);
+ jpeg_rw_bits(jenc, offs->int_mask, JMSK_IRQ_STATUS_RESET_ACK, JPEG_U32_SET);
+
+ reinit_completion(&jenc->reset_complete);
+
+ jpeg_wo_bits(jenc, offs->reset_cmd, JMSK_RST_CMD_COMMON, JPEG_U32_SET);
+
+ rtime = wait_for_completion_timeout(&jenc->reset_complete,
+ msecs_to_jiffies(JPEG_RESET_TIMEOUT_MS));
+ if (!rtime) {
+ dev_err(jenc->dev, "encoder HW reset timeout\n");
+ disable_irq(jenc->irq);
+ return -ETIME;
+ }
+
+ hw_ver = jpeg_io_read(jenc, offs->hw_version);
+ dev_info(jenc->dev, "JPEG HW encoder version %d.%d.%d\n",
+ jpeg_bits_get(jenc->res->hw_mask[JMSK_HW_VER_MAJOR], hw_ver),
+ jpeg_bits_get(jenc->res->hw_mask[JMSK_HW_VER_MINOR], hw_ver),
+ jpeg_bits_get(jenc->res->hw_mask[JMSK_HW_VER_STEP], hw_ver));
+
+ jpeg_wo_bits(jenc, offs->hw_cmd, JMSK_CMD_CLR_RD_PLNS_QUEUE, JPEG_U32_SET);
+ jpeg_wo_bits(jenc, offs->hw_cmd, JMSK_CMD_CLR_RD_PLNS_QUEUE, JPEG_U32_CLR);
+
+ jpeg_wo_bits(jenc, offs->hw_cmd, JMSK_CMD_CLR_WR_PLNS_QUEUE, JPEG_U32_SET);
+ jpeg_wo_bits(jenc, offs->hw_cmd, JMSK_CMD_CLR_WR_PLNS_QUEUE, JPEG_U32_CLR);
+
+ jpeg_wo_bits(jenc, offs->int_clr, JMSK_IRQ_CLEAR_ALL, JPEG_U32_SET);
+ jpeg_rw_bits(jenc, offs->int_mask, JMSK_IRQ_ENABLE_ALL, JPEG_U32_SET);
+
+ return 0;
+}
+
+static int jpeg_exec(struct qcom_jenc_dev *jenc)
+{
+ const struct qcom_jpeg_reg_offs *offs = jenc->res->hw_offs;
+
+ jpeg_wo_bits(jenc, offs->hw_cmd, JMSK_CMD_HW_START, 1);
+
+ return 0;
+}
+
+static void jpeg_stop(struct qcom_jenc_dev *jenc)
+{
+ const struct qcom_jpeg_reg_offs *offs = jenc->res->hw_offs;
+
+ jpeg_wo_bits(jenc, offs->hw_cmd, JMSK_CMD_HW_START, 0);
+
+ jpeg_wo_bits(jenc, offs->hw_cmd, JMSK_CMD_CLR_RD_PLNS_QUEUE, JPEG_U32_SET);
+ jpeg_wo_bits(jenc, offs->hw_cmd, JMSK_CMD_CLR_RD_PLNS_QUEUE, JPEG_U32_CLR);
+
+ jpeg_wo_bits(jenc, offs->hw_cmd, JMSK_CMD_CLR_WR_PLNS_QUEUE, JPEG_U32_SET);
+ jpeg_wo_bits(jenc, offs->hw_cmd, JMSK_CMD_CLR_WR_PLNS_QUEUE, JPEG_U32_CLR);
+
+ jpeg_wo_bits(jenc, offs->int_clr, JMSK_IRQ_CLEAR_ALL, JPEG_U32_SET);
+ jpeg_rw_bits(jenc, offs->int_mask, JMSK_IRQ_ENABLE_ALL, JPEG_U32_SET);
+}
+
+static int jpeg_deinit(struct qcom_jenc_dev *jenc)
+{
+ const struct qcom_jpeg_reg_offs *offs = jenc->res->hw_offs;
+ unsigned long rtime;
+
+ jpeg_wo_bits(jenc, offs->int_clr, JMSK_IRQ_CLEAR_ALL, JPEG_U32_SET);
+ jpeg_rw_bits(jenc, offs->int_mask, JMSK_IRQ_STATUS_STOP_ACK, JPEG_U32_SET);
+
+ jpeg_wo_bits(jenc, offs->hw_cmd, JMSK_CMD_HW_STOP, 1);
+
+ reinit_completion(&jenc->stop_complete);
+ rtime = wait_for_completion_timeout(&jenc->stop_complete,
+ msecs_to_jiffies(JPEG_STOP_TIMEOUT_MS));
+ if (!rtime) {
+ dev_err(jenc->dev, "encoder HW stop timeout\n");
+ return -ETIME;
+ }
+
+ jpeg_rw_bits(jenc, offs->int_mask, JMSK_IRQ_DISABLE_ALL, JPEG_U32_CLR);
+ jpeg_rw_bits(jenc, offs->int_clr, JMSK_IRQ_CLEAR_ALL, JPEG_U32_SET);
+
+ return 0;
+}
+
+static int jpeg_apply_fe_addr(struct jenc_context *ectx, struct qcom_jenc_queue *q,
+ struct vb2_buffer *vb)
+{
+ struct qcom_jenc_dev *jenc = ectx->jenc;
+ const struct qcom_jpeg_reg_offs *offs = jenc->res->hw_offs;
+ struct qcom_jpeg_buff *frame = &q->buff[vb->index];
+ struct v4l2_pix_format_mplane *fmt = &q->vf;
+ u8 pln = 0;
+
+ if (WARN_ON_ONCE(!frame->plns[pln].dma))
+ return -EPERM;
+
+ for (pln = 0; pln < fmt->num_planes; pln++) {
+ if (!frame->plns[pln].sgt || !frame->plns[pln].sgt->sgl)
+ break;
+
+ jpeg_io_write(jenc, offs->fe.pntr[pln], frame->plns[pln].dma);
+ jpeg_io_write(jenc, offs->fe.offs[pln], 0);
+
+ dev_dbg(jenc->dev, "%s: pln=%d addr=0x%llx idx:%d\n", __func__,
+ pln, frame->plns[pln].dma, vb->index);
+ }
+
+ q->buff_id = vb->index;
+
+ jpeg_dev_access(jenc->dev, frame, DMA_TO_DEVICE);
+
+ return 0;
+}
+
+static int jpeg_store_fe_next(struct jenc_context *ectx, struct vb2_buffer *vb2)
+{
+ struct qcom_jenc_queue *q = &ectx->bufq[TYPE2QID(vb2->type)];
+ struct qcom_jpeg_buff *buff = &q->buff[vb2->index];
+ u8 pln = 0;
+
+ buff->plns[pln].sgt = vb2_dma_sg_plane_desc(vb2, pln);
+ if (WARN_ON_ONCE(!buff->plns[pln].sgt))
+ return -EINVAL;
+
+ if (WARN_ON_ONCE(!buff->plns[pln].sgt->sgl))
+ return -EINVAL;
+
+ buff->plns[pln].dma = sg_dma_address(buff->plns[pln].sgt->sgl);
+ if (WARN_ON_ONCE(!buff->plns[pln].dma))
+ return -EINVAL;
+
+ buff->plns[pln].size = vb2_plane_size(vb2, pln);
+ if (WARN_ON_ONCE(!buff->plns[pln].size))
+ return -EINVAL;
+
+ for (pln = 1; pln < q->vf.num_planes; pln++) {
+ buff->plns[pln].sgt = vb2_dma_sg_plane_desc(vb2, pln);
+ if (WARN_ON_ONCE(!buff->plns[pln].sgt || !buff->plns[pln].sgt->sgl))
+ return -EINVAL;
+
+ buff->plns[pln].dma = sg_dma_address(buff->plns[pln].sgt->sgl);
+ if (WARN_ON_ONCE(!buff->plns[pln].dma))
+ return -EINVAL;
+
+ buff->plns[pln].size = vb2_plane_size(vb2, pln);
+ if (WARN_ON_ONCE(!buff->plns[pln].size))
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int jpeg_setup_fe_size(struct jenc_context *ectx, struct qcom_jenc_queue *q)
+{
+ struct qcom_jenc_dev *jenc = ectx->jenc;
+ struct v4l2_pix_format_mplane *sfmt = &q->vf;
+ const struct qcom_jpeg_reg_offs *offs = jenc->res->hw_offs;
+ u8 pln;
+
+ for (pln = 0; pln < QCOM_JPEG_MAX_PLANES; pln++) {
+ jpeg_rw_bits(jenc, offs->fe.bsize[pln], JMSK_PLNS_RD_BUF_SIZE_WIDTH, 0);
+ jpeg_rw_bits(jenc, offs->fe.bsize[pln], JMSK_PLNS_RD_BUF_SIZE_HEIGHT, 0);
+ jpeg_rw_bits(jenc, offs->fe.bsize[pln], JMSK_PLNS_RD_STRIDE, 0);
+ }
+
+ for (pln = 0; pln < sfmt->num_planes; pln++) {
+ jpeg_rw_bits(jenc, offs->fe.bsize[pln], JMSK_PLNS_RD_BUF_SIZE_WIDTH,
+ sfmt->width - 1);
+ jpeg_rw_bits(jenc, offs->fe.bsize[pln], JMSK_PLNS_RD_BUF_SIZE_HEIGHT,
+ sfmt->height - 1);
+ jpeg_rw_bits(jenc, offs->fe.stride[pln], JMSK_PLNS_RD_STRIDE,
+ sfmt->plane_fmt[pln].bytesperline);
+
+ dev_dbg(ectx->dev, "%s: ctx=%p pln=%d width=%d height=%d stride=%d\n",
+ __func__, ectx, pln,
+ jpeg_rd_bits(jenc, offs->fe.bsize[pln], JMSK_PLNS_RD_BUF_SIZE_WIDTH),
+ jpeg_rd_bits(jenc, offs->fe.bsize[pln], JMSK_PLNS_RD_BUF_SIZE_HEIGHT),
+ jpeg_rd_bits(jenc, offs->fe.stride[pln], JMSK_PLNS_RD_STRIDE));
+ }
+
+ return 0;
+}
+
+static int jpeg_setup_fe_hinit(struct jenc_context *ectx, struct qcom_jenc_queue *q)
+{
+ struct qcom_jenc_dev *jenc = ectx->jenc;
+ struct v4l2_pix_format_mplane *sfmt = &q->vf;
+ const struct qcom_jpeg_reg_offs *offs = jenc->res->hw_offs;
+ u8 pln;
+
+ if (!sfmt->width) {
+ dev_err(ectx->dev, "%s: invalid source width=%d\n", __func__, sfmt->width);
+ return -EINVAL;
+ }
+
+ for (pln = 0; pln < QCOM_JPEG_MAX_PLANES; pln++)
+ jpeg_io_write(jenc, offs->fe.hinit[pln], 0);
+
+ return 0;
+}
+
+static int jpeg_setup_fe_vinit(struct jenc_context *ectx, struct qcom_jenc_queue *q)
+{
+ struct qcom_jenc_dev *jenc = ectx->jenc;
+ struct v4l2_pix_format_mplane *sfmt = &q->vf;
+ const struct qcom_jpeg_reg_offs *offs = jenc->res->hw_offs;
+ u8 pln;
+
+ if (!sfmt->height) {
+ dev_err(ectx->dev, "%s: invalid source height=%d\n", __func__, sfmt->height);
+ return -EINVAL;
+ }
+
+ for (pln = 0; pln < QCOM_JPEG_MAX_PLANES; pln++)
+ jpeg_io_write(jenc, offs->fe.vinit[pln], 0);
+
+ return 0;
+}
+
+static int jpeg_setup_fe_params(struct jenc_context *ectx, struct qcom_jenc_queue *q)
+{
+ struct qcom_jenc_dev *jenc = ectx->jenc;
+ struct v4l2_pix_format_mplane *sfmt = &q->vf;
+ struct v4l2_pix_format_mplane *dfmt = &ectx->bufq[JENC_DST_QUEUE].vf;
+ const struct qcom_jpeg_reg_offs *offs = jenc->res->hw_offs;
+ u8 expected_planes, pln;
+ int rval;
+
+ jpeg_rw_bits(jenc, offs->fe_cfg, JMSK_FE_CFG_MAL_EN, 1);
+ jpeg_rw_bits(jenc, offs->fe_cfg, JMSK_FE_CFG_BOTTOM_VPAD_EN, 1);
+
+ rval = jpeg_get_memory_fmt(sfmt->pixelformat);
+ if (rval < 0) {
+ dev_err(ectx->dev, "%s: invalid memory format for v4l2 format:0x%x\n",
+ __func__, sfmt->pixelformat);
+ return -EINVAL;
+ }
+
+ switch (rval) {
+ case JPEG_MEM_FMT_MONO:
+ expected_planes = 1;
+ break;
+ case JPEG_MEM_FMT_PPLANAR:
+ expected_planes = 2;
+ break;
+ case JPEG_MEM_FMT_PLANAR:
+ expected_planes = 3;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ if (sfmt->num_planes != expected_planes) {
+ dev_err(ectx->dev, "%s: plane mismatch fmt=%u expected=%u got=%u\n",
+ __func__, rval, expected_planes, sfmt->num_planes);
+ return -EINVAL;
+ }
+
+ jpeg_rw_bits(jenc, offs->fe_cfg, JMSK_FE_CFG_MEMORY_FORMAT, rval);
+
+ jpeg_rw_bits(jenc, offs->fe_cfg, JMSK_FE_CFG_PLN0_EN, 0);
+ jpeg_rw_bits(jenc, offs->fe_cfg, JMSK_FE_CFG_PLN1_EN, 0);
+ jpeg_rw_bits(jenc, offs->fe_cfg, JMSK_FE_CFG_PLN2_EN, 0);
+
+ if (sfmt->width == dfmt->width && sfmt->height == dfmt->height) {
+ /* No scaling */
+ jpeg_rw_bits(jenc, offs->fe_cfg, JMSK_FE_CFG_SIXTEEN_MCU_EN, 1);
+ jpeg_rw_bits(jenc, offs->fe_cfg, JMSK_FE_CFG_MCUS_PER_BLOCK, 0);
+ } else {
+ u8 mcu_per_blks;
+
+ /* Scaling */
+ jpeg_rw_bits(jenc, offs->fe_cfg, JMSK_FE_CFG_SIXTEEN_MCU_EN, 0);
+ /* get value according to image width */
+ mcu_per_blks = jpeg_get_mcu_per_block(sfmt->width, dfmt->width);
+ /* get value according to image height assign the bigger */
+ mcu_per_blks = max_t(u8, mcu_per_blks,
+ jpeg_get_mcu_per_block(sfmt->height, dfmt->height));
+
+ jpeg_rw_bits(jenc, offs->fe_cfg, JMSK_FE_CFG_MCUS_PER_BLOCK, mcu_per_blks);
+ }
+
+ dev_dbg(ectx->dev, "%s: sixteen MCU enabled=%d, %d MCU per blocks\n", __func__,
+ jpeg_rd_bits(jenc, offs->fe_cfg, JMSK_FE_CFG_SIXTEEN_MCU_EN),
+ jpeg_rd_bits(jenc, offs->fe_cfg, JMSK_FE_CFG_MCUS_PER_BLOCK));
+
+ rval = jpeg_get_mal_boundary(sfmt->width, jpeg_mal_bounds, ARRAY_SIZE(jpeg_mal_bounds));
+ if (rval < 0) {
+ dev_err(ectx->dev, "%s: failed to get FE mal boundary width=%u\n", __func__,
+ sfmt->width);
+ return -EINVAL;
+ }
+ jpeg_rw_bits(jenc, offs->fe_cfg, JMSK_FE_CFG_MAL_BOUNDARY, rval);
+
+ dev_dbg(ectx->dev, "%s: optimal FE mal boundary=%d\n", __func__,
+ jpeg_rd_bits(jenc, offs->fe_cfg, JMSK_FE_CFG_MAL_BOUNDARY));
+
+ rval = jpeg_get_encode_fmt(sfmt->pixelformat);
+ if (rval < 0) {
+ dev_err(ectx->dev, "%s: unsupported encode format fourcc=0x%x\n",
+ __func__, sfmt->pixelformat);
+ return -EINVAL;
+ }
+
+ switch (rval) {
+ case JPEG_ENCODE_MONO:
+ case JPEG_ENCODE_H1V1:
+ case JPEG_ENCODE_H2V1:
+ jpeg_rw_bits(jenc, offs->fe.vbpad_cfg, JMSK_FE_VBPAD_CFG_BLOCK_ROW,
+ DIV_ROUND_UP(sfmt->height, JPEG_MCU_BLOCK_8));
+ break;
+ case JPEG_ENCODE_H1V2:
+ case JPEG_ENCODE_H2V2:
+ jpeg_rw_bits(jenc, offs->fe.vbpad_cfg, JMSK_FE_VBPAD_CFG_BLOCK_ROW,
+ DIV_ROUND_UP(sfmt->height, JPEG_MCU_BLOCK_16));
+ break;
+ default:
+ dev_err(ectx->dev, "%s: unsupported encode format fourcc=0x%x\n", __func__, rval);
+ return -EINVAL;
+ }
+
+ if (sfmt->pixelformat == V4L2_PIX_FMT_NV21 || sfmt->pixelformat == V4L2_PIX_FMT_NV61)
+ jpeg_rw_bits(jenc, offs->fe_cfg, JMSK_FE_CFG_CBCR_ORDER, 1);
+ else
+ jpeg_rw_bits(jenc, offs->fe_cfg, JMSK_FE_CFG_CBCR_ORDER, 0);
+
+ for (pln = 0; pln < sfmt->num_planes; pln++) {
+ if (sfmt->width && sfmt->height) {
+ switch (pln) {
+ case 0:
+ jpeg_rw_bits(jenc, offs->fe_cfg, JMSK_FE_CFG_PLN0_EN, 1);
+ break;
+ case 1:
+ jpeg_rw_bits(jenc, offs->fe_cfg, JMSK_FE_CFG_PLN1_EN, 1);
+ break;
+ case 2:
+ jpeg_rw_bits(jenc, offs->fe_cfg, JMSK_FE_CFG_PLN2_EN, 1);
+ break;
+ }
+ }
+ }
+
+ jpeg_rw_bits(jenc, offs->core_cfg, JMSK_CORE_CFG_FE_ENABLE, 1);
+
+ return 0;
+}
+
+static int jpeg_setup_fe(struct jenc_context *ectx, struct qcom_jenc_queue *q)
+{
+ int rc;
+
+ rc = jpeg_setup_fe_size(ectx, q);
+ if (rc)
+ return rc;
+
+ rc = jpeg_setup_fe_hinit(ectx, q);
+ if (rc)
+ return rc;
+
+ rc = jpeg_setup_fe_vinit(ectx, q);
+ if (rc)
+ return rc;
+
+ rc = jpeg_setup_fe_params(ectx, q);
+ if (rc)
+ return rc;
+
+ return 0;
+}
+
+static int jpeg_apply_we_addr(struct jenc_context *ectx, struct qcom_jenc_queue *q,
+ struct vb2_buffer *vb)
+{
+ struct qcom_jenc_dev *jenc = ectx->jenc;
+ const struct qcom_jpeg_reg_offs *offs = jenc->res->hw_offs;
+ struct qcom_jpeg_buff *frame = &q->buff[vb->index];
+ u8 pln = 0;
+
+ if (WARN_ON_ONCE(!frame->plns[pln].dma))
+ return -EPERM;
+
+ jpeg_io_write(jenc, offs->we.pntr[pln], frame->plns[pln].dma);
+
+ dev_dbg(jenc->dev, "%s: pln=%d addr=0x%llx idx:%d\n", __func__,
+ pln, frame->plns[pln].dma, vb->index);
+
+ q->buff_id = vb->index;
+
+ return 0;
+}
+
+static int jpeg_store_we_next(struct jenc_context *ectx, struct vb2_buffer *vb2)
+{
+ struct qcom_jenc_dev *jenc = ectx->jenc;
+ struct qcom_jenc_queue *q = &ectx->bufq[TYPE2QID(vb2->type)];
+ struct qcom_jpeg_buff *frame = &q->buff[vb2->index];
+ struct qc_jfif *mptr;
+ struct sg_table *sgt;
+ dma_addr_t dma;
+
+ sgt = vb2_dma_sg_plane_desc(vb2, 0);
+ if (WARN_ON_ONCE(!sgt || !sgt->sgl))
+ return -EINVAL;
+
+ dma = sg_dma_address(sgt->sgl);
+ if (WARN_ON_ONCE(!dma))
+ return -EINVAL;
+
+ mptr = vb2_plane_vaddr(vb2, 0);
+ if (WARN_ON_ONCE(!mptr))
+ return -EINVAL;
+
+ mutex_lock(&ectx->quality_mutex);
+ if (ectx->quality_programmed != ectx->quality_requested)
+ jpeg_apply_dmi_table(ectx);
+ mutex_unlock(&ectx->quality_mutex);
+
+ dma += qcom_jenc_header_emit(&ectx->hdr_cache, (void *)mptr,
+ min_t(size_t, vb2->planes[0].length, ectx->hdr_cache.size),
+ q->vf.width, q->vf.height);
+ qcom_jenc_dqts_emit(&ectx->hdr_cache, (void *)mptr);
+
+ frame->plns[0].sgt = sgt;
+ frame->plns[0].dma = dma;
+ frame->plns[0].size = vb2_plane_size(vb2, 0);
+
+ jpeg_dev_access(jenc->dev, frame, DMA_TO_DEVICE);
+
+ return 0;
+}
+
+static int jpeg_setup_we_size(struct jenc_context *ectx, struct qcom_jenc_queue *q)
+{
+ struct qcom_jenc_dev *jenc = ectx->jenc;
+ const struct qcom_jpeg_reg_offs *offs = jenc->res->hw_offs;
+ struct v4l2_pix_format_mplane *dfmt = &q->vf;
+ u8 pln;
+
+ if (!dfmt->plane_fmt[0].sizeimage) {
+ dev_err(ectx->dev, "%s: invalid destination buffer size=0\n", __func__);
+ return -EINVAL;
+ }
+
+ for (pln = 0; pln < QCOM_JPEG_MAX_PLANES; pln++)
+ jpeg_rw_bits(jenc, offs->we.stride[pln], JMSK_PLNS_WR_STRIDE, 0);
+
+ jpeg_io_write(jenc, offs->we.bsize[0], dfmt->plane_fmt[0].sizeimage);
+
+ dev_dbg(ectx->dev, "%s: ctx=%p size=%u\n", __func__,
+ ectx, dfmt->plane_fmt[0].sizeimage);
+
+ return 0;
+}
+
+static int jpeg_setup_we_hinit(struct jenc_context *ectx, struct qcom_jenc_queue *q)
+{
+ struct qcom_jenc_dev *jenc = ectx->jenc;
+ const struct qcom_jpeg_reg_offs *offs = jenc->res->hw_offs;
+ struct v4l2_pix_format_mplane *dfmt = &q->vf;
+ u8 pln;
+
+ if (!dfmt->width) {
+ dev_err(ectx->dev, "%s: invalid destination width=%d\n", __func__, dfmt->width);
+ return -EINVAL;
+ }
+
+ for (pln = 0; pln < QCOM_JPEG_MAX_PLANES; pln++) {
+ jpeg_rw_bits(jenc, offs->we.hinit[pln], JMSK_PLNS_WR_HINIT, 0);
+ jpeg_rw_bits(jenc, offs->we.hstep[pln], JMSK_PLNS_WR_HSTEP, 0);
+ }
+
+ jpeg_rw_bits(jenc, offs->we.hstep[0], JMSK_PLNS_WR_HSTEP, dfmt->width);
+
+ dev_dbg(ectx->dev, "%s: ctx=%p hstep=%u\n", __func__, ectx,
+ jpeg_rd_bits(jenc, offs->we.hstep[0], JMSK_PLNS_WR_HSTEP));
+
+ return 0;
+}
+
+static int jpeg_setup_we_vinit(struct jenc_context *ectx, struct qcom_jenc_queue *q)
+{
+ struct qcom_jenc_dev *jenc = ectx->jenc;
+ const struct qcom_jpeg_reg_offs *offs = jenc->res->hw_offs;
+ struct v4l2_pix_format_mplane *dfmt = &q->vf;
+ u8 pln;
+
+ if (!dfmt->height) {
+ dev_err(ectx->dev, "%s: invalid destination height=%d\n", __func__, dfmt->height);
+ return -EINVAL;
+ }
+
+ for (pln = 0; pln < QCOM_JPEG_MAX_PLANES; pln++) {
+ jpeg_rw_bits(jenc, offs->we.vinit[pln], JMSK_PLNS_WR_VINIT, 0);
+ jpeg_rw_bits(jenc, offs->we.vstep[pln], JMSK_PLNS_WR_VSTEP, 0);
+ }
+
+ jpeg_rw_bits(jenc, offs->we.vstep[0], JMSK_PLNS_WR_VSTEP, dfmt->height);
+
+ dev_dbg(ectx->dev, "%s: ctx=%p vstep=%u\n", __func__, ectx,
+ jpeg_rd_bits(jenc, offs->we.vstep[0], JMSK_PLNS_WR_VSTEP));
+
+ return 0;
+}
+
+static int jpeg_setup_we_params(struct jenc_context *ectx, struct qcom_jenc_queue *q)
+{
+ struct qcom_jenc_dev *jenc = ectx->jenc;
+ const struct qcom_jpeg_reg_offs *offs = jenc->res->hw_offs;
+ struct v4l2_pix_format_mplane *dfmt = &q->vf;
+ u32 blk_w, blk_h, mcu_cols, mcu_rows;
+ int rval;
+
+ rval = jpeg_get_memory_fmt(dfmt->pixelformat);
+ if (rval < 0) {
+ dev_err(ectx->dev, "%s: invalid memory format for v4l2 format:0x%x\n",
+ __func__, dfmt->pixelformat);
+ return -EINVAL;
+ }
+ jpeg_rw_bits(jenc, offs->we_cfg, JMSK_WE_CFG_MEMORY_FORMAT, rval);
+
+ rval = jpeg_get_mal_boundary(dfmt->width, jpeg_mal_bounds, ARRAY_SIZE(jpeg_mal_bounds));
+ if (rval < 0) {
+ dev_err(ectx->dev, "%s: failed to get WE mal boundary width=%u\n",
+ __func__, dfmt->width);
+ return -EINVAL;
+ }
+ jpeg_rw_bits(jenc, offs->we_cfg, JMSK_WE_CFG_MAL_BOUNDARY, rval);
+
+ dev_dbg(ectx->dev, "%s: optimal WE mal boundary=%d\n", __func__,
+ jpeg_rd_bits(jenc, offs->we_cfg, JMSK_WE_CFG_MAL_BOUNDARY));
+
+ rval = jpeg_get_encode_fmt(dfmt->pixelformat);
+ if (rval < 0) {
+ dev_err(ectx->dev, "%s: unsupported encode format fourcc=0x%x\n",
+ __func__, dfmt->pixelformat);
+ return rval;
+ }
+
+ rval = jpeg_get_mcu_geometry(rval, dfmt->width, dfmt->height, &blk_w, &blk_h,
+ &mcu_cols, &mcu_rows);
+ if (rval < 0) {
+ dev_err(ectx->dev, "%s: invalid MCU geometry mcu_cols=%d mcu_rows=%d\n",
+ __func__, mcu_cols, mcu_rows);
+ return rval;
+ }
+
+ dev_dbg(ectx->dev, "%s blk_w=%u blk_h=%u cols=%u rows=%u\n", __func__,
+ blk_w, blk_h, mcu_cols, mcu_rows);
+
+ jpeg_rw_bits(jenc, offs->we.blocks[0], JMSK_PLNS_WR_BLOCK_CFG_PER_RAW, mcu_rows - 1);
+ jpeg_rw_bits(jenc, offs->we.blocks[0], JMSK_PLNS_WR_BLOCK_CFG_PER_COL, mcu_cols - 1);
+
+ jpeg_rw_bits(jenc, offs->we_cfg, JMSK_WE_CFG_CBCR_ORDER, 1);
+ jpeg_rw_bits(jenc, offs->we_cfg, JMSK_WE_CFG_MAL_EN, 1);
+ jpeg_rw_bits(jenc, offs->we_cfg, JMSK_WE_CFG_POP_BUFF_ON_EOS, 1);
+ jpeg_rw_bits(jenc, offs->we_cfg, JMSK_WE_CFG_PLN0_EN, 1);
+
+ jpeg_rw_bits(jenc, offs->core_cfg, JMSK_CORE_CFG_MODE, 1);
+ jpeg_rw_bits(jenc, offs->core_cfg, JMSK_CORE_CFG_WE_ENABLE, 1);
+
+ return 0;
+}
+
+static int jpeg_setup_we(struct jenc_context *ectx, struct qcom_jenc_queue *q)
+{
+ int rc;
+
+ rc = jpeg_setup_we_size(ectx, q);
+ if (rc)
+ return rc;
+
+ rc = jpeg_setup_we_hinit(ectx, q);
+ if (rc)
+ return rc;
+
+ rc = jpeg_setup_we_vinit(ectx, q);
+ if (rc)
+ return rc;
+
+ return jpeg_setup_we_params(ectx, q);
+}
+
+static int jpeg_setup_scale(struct jenc_context *ectx)
+{
+ struct qcom_jenc_dev *jenc = ectx->jenc;
+ const struct qcom_jpeg_reg_offs *offs = jenc->res->hw_offs;
+ struct qcom_jenc_queue *sq = &ectx->bufq[JENC_SRC_QUEUE];
+ struct qcom_jenc_queue *dq = &ectx->bufq[JENC_DST_QUEUE];
+ struct v4l2_pix_format_mplane *sfmt = &sq->vf;
+ struct v4l2_pix_format_mplane *dfmt = &dq->vf;
+ u32 blk_w, blk_h, mcu_cols, mcu_rows;
+ int rval;
+ u8 pln;
+
+ jpeg_rw_bits(jenc, offs->reset_cmd, JMSK_RST_CMD_SCALE_RESET, 1);
+
+ /* explicit no scaling */
+ jpeg_rw_bits(jenc, offs->scale_cfg, JMSK_SCALE_CFG_HSCALE_ENABLE, 0);
+ jpeg_rw_bits(jenc, offs->scale_cfg, JMSK_SCALE_CFG_VSCALE_ENABLE, 0);
+
+ for (pln = 0; pln < QCOM_JPEG_MAX_PLANES; pln++) {
+ jpeg_io_write(jenc, offs->scale.hstep[pln], JPEG_DEFAULT_SCALE_STEP);
+ jpeg_io_write(jenc, offs->scale.vstep[pln], JPEG_DEFAULT_SCALE_STEP);
+ }
+
+ if (jpeg_rd_bits(jenc, offs->scale_cfg, JMSK_SCALE_CFG_HSCALE_ENABLE)) {
+ for (pln = 0; pln < sq->vf.num_planes; pln++) {
+ jpeg_rw_bits(jenc, offs->scale.hstep[pln],
+ JMSK_SCALE_PLNS_HSTEP_INTEGER,
+ jpeg_calc_scale_int(sfmt->width, dfmt->width));
+ jpeg_rw_bits(jenc, offs->scale.hstep[pln],
+ JMSK_SCALE_PLNS_HSTEP_FRACTIONAL,
+ jpeg_calc_scale_frac(sfmt->width, dfmt->width));
+
+ dev_dbg(ectx->dev, "%s: ctx=%p hint=%d hfrac=%d\n",
+ __func__, ectx,
+ jpeg_rd_bits(jenc, offs->scale.hstep[pln],
+ JMSK_SCALE_PLNS_HSTEP_INTEGER),
+ jpeg_rd_bits(jenc, offs->scale.hstep[pln],
+ JMSK_SCALE_PLNS_HSTEP_FRACTIONAL));
+ }
+ }
+
+ if (jpeg_rd_bits(jenc, offs->scale_cfg, JMSK_SCALE_CFG_VSCALE_ENABLE)) {
+ for (pln = 0; pln < sq->vf.num_planes; pln++) {
+ jpeg_rw_bits(jenc, offs->scale.vstep[pln],
+ JMSK_SCALE_PLNS_VSTEP_INTEGER,
+ jpeg_calc_scale_int(sfmt->height, dfmt->height));
+ jpeg_rw_bits(jenc, offs->scale.vstep[pln],
+ JMSK_SCALE_PLNS_VSTEP_FRACTIONAL,
+ jpeg_calc_scale_frac(sfmt->height, dfmt->height));
+
+ dev_dbg(ectx->dev, "%s: ctx=%p vint=%d vfrac=%d\n",
+ __func__, ectx,
+ jpeg_rd_bits(jenc, offs->scale.vstep[pln],
+ JMSK_SCALE_PLNS_VSTEP_INTEGER),
+ jpeg_rd_bits(jenc, offs->scale.vstep[pln],
+ JMSK_SCALE_PLNS_VSTEP_FRACTIONAL));
+ }
+ }
+
+ rval = jpeg_get_encode_fmt(sfmt->pixelformat);
+ if (rval < 0) {
+ dev_err(ectx->dev, "%s: unsupported encode format fourcc=0x%x\n",
+ __func__, sfmt->pixelformat);
+ return -EINVAL;
+ }
+
+ rval = jpeg_get_mcu_geometry(rval, dfmt->width, dfmt->height, &blk_w, &blk_h,
+ &mcu_cols, &mcu_rows);
+ if (rval < 0) {
+ dev_err(ectx->dev, "%s: invalid MCU geometry blk_w=%d blk_h=%d\n",
+ __func__, blk_w, blk_h);
+ return -EINVAL;
+ }
+
+ dev_dbg(ectx->dev, "%s blk_w=%u blk_h=%u cols=%u rows=%u\n", __func__, blk_w, blk_h,
+ mcu_cols, mcu_rows);
+
+ for (pln = 0; pln < sq->vf.num_planes; pln++) {
+ jpeg_rw_bits(jenc, offs->scale_out_cfg[pln],
+ JMSK_SCALE_PLNS_OUT_CFG_BLK_WIDTH, mcu_cols - 1);
+ jpeg_rw_bits(jenc, offs->scale_out_cfg[pln],
+ JMSK_SCALE_PLNS_OUT_CFG_BLK_HEIGHT, mcu_rows - 1);
+ }
+
+ dev_dbg(ectx->dev, "%s: ctx=%p scale src=%ux%u dst=%ux%u enable=%d/%d\n",
+ __func__, ectx, sfmt->width, sfmt->height, dfmt->width, dfmt->height,
+ jpeg_rd_bits(jenc, offs->scale_cfg, JMSK_SCALE_CFG_HSCALE_ENABLE),
+ jpeg_rd_bits(jenc, offs->scale_cfg, JMSK_SCALE_CFG_VSCALE_ENABLE));
+
+ /* Disabled, but must be configured */
+ jpeg_rw_bits(jenc, offs->core_cfg, JMSK_CORE_CFG_SCALE_ENABLE, 0);
+
+ return 0;
+}
+
+static int jpeg_setup_encode(struct jenc_context *ectx)
+{
+ struct qcom_jenc_dev *jenc = ectx->jenc;
+ struct qcom_jenc_queue *sq = &ectx->bufq[JENC_SRC_QUEUE];
+ struct v4l2_pix_format_mplane *sfmt = &sq->vf;
+ const struct qcom_jpeg_reg_offs *offs = jenc->res->hw_offs;
+ u32 blk_w, blk_h, mcu_cols, mcu_rows;
+ int rval;
+
+ if (!sfmt->width || !sfmt->height)
+ return -EINVAL;
+
+ jpeg_rw_bits(jenc, offs->reset_cmd, JMSK_RST_CMD_ENCODER_RESET, 1);
+
+ rval = jpeg_get_encode_fmt(sfmt->pixelformat);
+ if (rval < 0) {
+ dev_err(ectx->dev, "%s: unsupported encode format fourcc=0x%x\n",
+ __func__, sfmt->pixelformat);
+ return -EINVAL;
+ }
+ jpeg_rw_bits(jenc, offs->enc_cfg, JMSK_ENC_CFG_IMAGE_FORMAT, rval);
+
+ rval = jpeg_get_mcu_geometry(rval, sfmt->width, sfmt->height, &blk_w, &blk_h,
+ &mcu_cols, &mcu_rows);
+ if (rval < 0) {
+ dev_err(ectx->dev, "%s: invalid MCU geometry mcu_cols=%d mcu_rows=%d\n",
+ __func__, mcu_cols, mcu_rows);
+ return -EINVAL;
+ }
+
+ dev_dbg(ectx->dev, "%s blk_w=%u blk_h=%u cols=%u rows=%u\n", __func__,
+ blk_w, blk_h, mcu_cols, mcu_rows);
+
+ jpeg_rw_bits(jenc, offs->enc_img_size, JMSK_ENC_IMAGE_SIZE_WIDTH, mcu_cols - 1);
+ jpeg_rw_bits(jenc, offs->enc_img_size, JMSK_ENC_IMAGE_SIZE_HEIGHT, mcu_rows - 1);
+
+ dev_dbg(ectx->dev, "%s: ctx=%p width=%d height=%d\n", __func__, ectx,
+ jpeg_rd_bits(jenc, offs->enc_img_size, JMSK_ENC_IMAGE_SIZE_WIDTH),
+ jpeg_rd_bits(jenc, offs->enc_img_size, JMSK_ENC_IMAGE_SIZE_HEIGHT));
+
+ jpeg_rw_bits(jenc, offs->enc_cfg, JMSK_ENC_CFG_APPLY_EOI, 1);
+ jpeg_rw_bits(jenc, offs->core_cfg, JMSK_CORE_CFG_ENC_ENABLE, 1);
+
+ return 0;
+}
+
+static irqreturn_t op_jpeg_irq_bot(int irq, void *data)
+{
+ struct qcom_jenc_dev *jenc = data;
+ const struct qcom_jpeg_reg_offs *offs = jenc->res->hw_offs;
+ u32 irq_status;
+ u32 irq_mask;
+ unsigned long flags;
+ int rc;
+
+ rc = kfifo_out_spinlocked(&jenc->kfifo_inst, &irq_status, sizeof(irq_status),
+ &jenc->kfifo_lock);
+ if (rc != sizeof(irq_status)) {
+ dev_err(jenc->dev, "IRQ status: FIFO empty\n");
+ return IRQ_HANDLED;
+ }
+
+ irq_mask = jenc->res->hw_mask[JMSK_IRQ_STATUS_SESSION_DONE];
+ if (jpeg_bits_get(irq_mask, irq_status)) {
+ struct jenc_context *ctx = jenc->actx;
+ struct qcom_jenc_queue *dq = &ctx->bufq[JENC_DST_QUEUE];
+ size_t out_size;
+
+ spin_lock_irqsave(&jenc->hw_lock, flags);
+ jenc->actx = NULL;
+ spin_unlock_irqrestore(&jenc->hw_lock, flags);
+
+ if (ctx && dq->buff_id >= 0) {
+ struct qcom_jpeg_buff *frame;
+ unsigned long flags;
+
+ spin_lock_irqsave(&jenc->hw_lock, flags);
+ frame = &dq->buff[dq->buff_id];
+ out_size = jpeg_io_read(jenc, offs->enc_out_size);
+ spin_unlock_irqrestore(&jenc->hw_lock, flags);
+
+ dev_dbg(jenc->dev, "complete idx:%d addr=0x%llx size=%zu\n",
+ dq->buff_id, frame->plns[0].dma, out_size);
+
+ jpeg_cpu_access(jenc->dev, frame, DMA_FROM_DEVICE);
+ jenc->enc_hw_irq_cb(ctx, VB2_BUF_STATE_DONE,
+ out_size + JPEG_HEADER_MAX);
+ jpeg_stop(jenc);
+ }
+ }
+
+ irq_mask = jenc->res->hw_mask[JMSK_IRQ_STATUS_SESSION_ERROR];
+ if (jpeg_bits_get(irq_mask, irq_status)) {
+ struct jenc_context *ctx = jenc->actx;
+
+ spin_lock_irqsave(&jenc->hw_lock, flags);
+ jenc->actx = NULL;
+ spin_unlock_irqrestore(&jenc->hw_lock, flags);
+
+ dev_err(jenc->dev, "encoder hardware failure=0x%x\n",
+ jpeg_bits_get(JMSK_IRQ_STATUS_SESSION_ERROR, irq_status));
+ if (ctx)
+ jenc->enc_hw_irq_cb(ctx, VB2_BUF_STATE_ERROR, 0);
+
+ jpeg_stop(jenc);
+ }
+
+ return IRQ_HANDLED;
+}
+
+static irqreturn_t op_jpeg_irq_top(int irq, void *data)
+{
+ struct qcom_jenc_dev *jenc = data;
+ const struct qcom_jpeg_reg_offs *offs = jenc->res->hw_offs;
+ u32 irq_status;
+ u32 irq_mask;
+ unsigned long flags;
+ int rc;
+
+ spin_lock_irqsave(&jenc->hw_lock, flags);
+
+ irq_status = jpeg_io_read(jenc, offs->int_status);
+ jpeg_wo_bits(jenc, offs->int_clr, JMSK_IRQ_CLEAR_ALL, irq_status);
+
+ irq_mask = jenc->res->hw_mask[JMSK_IRQ_STATUS_RESET_ACK];
+ if (jpeg_bits_get(irq_mask, irq_status)) {
+ complete(&jenc->reset_complete);
+ spin_unlock_irqrestore(&jenc->hw_lock, flags);
+ return IRQ_HANDLED;
+ }
+
+ irq_mask = jenc->res->hw_mask[JMSK_IRQ_STATUS_STOP_ACK];
+ if (jpeg_bits_get(irq_mask, irq_status)) {
+ complete(&jenc->stop_complete);
+ dev_dbg(jenc->dev, "hardware stop acknowledged\n");
+ spin_unlock_irqrestore(&jenc->hw_lock, flags);
+ return IRQ_HANDLED;
+ }
+
+ rc = kfifo_in(&jenc->kfifo_inst, &irq_status, sizeof(irq_status));
+ if (rc != sizeof(irq_status))
+ dev_err(jenc->dev, "IRQ status: FIFO full\n");
+
+ spin_unlock_irqrestore(&jenc->hw_lock, flags);
+
+ return IRQ_WAKE_THREAD;
+}
+
+static void op_jpeg_get_hw_caps(struct qcom_jenc_dev *jenc, u32 *caps)
+{
+ const struct qcom_jpeg_reg_offs *offs = jenc->res->hw_offs;
+ u32 hw_caps;
+
+ hw_caps = jpeg_io_read(jenc, offs->hw_capability);
+ dev_dbg(jenc->dev, "CAPS: encode=%d decode=%d upscale=%d downscale=%d\n",
+ jpeg_bits_get(jenc->res->hw_mask[JMSK_HW_CAP_ENCODE], hw_caps),
+ jpeg_bits_get(jenc->res->hw_mask[JMSK_HW_CAP_DECODE], hw_caps),
+ jpeg_bits_get(jenc->res->hw_mask[JMSK_HW_CAP_UPSCALE], hw_caps),
+ jpeg_bits_get(jenc->res->hw_mask[JMSK_HW_CAP_DOWNSCALE], hw_caps));
+
+ *caps = hw_caps;
+}
+
+static struct qcom_jenc_queue *op_jpeg_get_buff_queue(struct jenc_context *ectx,
+ enum qcom_enc_qid id)
+{
+ return &ectx->bufq[id];
+}
+
+static int op_jpeg_queue_setup(struct jenc_context *ectx, enum qcom_enc_qid id)
+{
+ int rc;
+
+ if (id == JENC_SRC_QUEUE) {
+ struct qcom_jenc_queue *q = &ectx->bufq[id];
+
+ rc = qcom_jenc_header_init(&ectx->hdr_cache, q->vf.pixelformat);
+ if (rc) {
+ dev_err(ectx->dev, "JFIF header init failed\n");
+ return rc;
+ }
+ }
+
+ return 0;
+}
+
+static int op_jpeg_buffer_prepare(struct jenc_context *ectx, struct vb2_buffer *vb2)
+{
+ int rc;
+
+ if (V4L2_TYPE_IS_OUTPUT(vb2->type)) {
+ rc = jpeg_store_fe_next(ectx, vb2);
+ if (rc)
+ dev_err(ectx->dev, "%s: cannot set up fetch addr\n", __func__);
+ } else {
+ rc = jpeg_store_we_next(ectx, vb2);
+ if (rc)
+ dev_err(ectx->dev, "%s: cannot set up write addr\n", __func__);
+ }
+
+ return rc;
+}
+
+static int op_jpeg_process_exec(struct qcom_jenc_dev *jenc, struct jenc_context *ectx,
+ struct vb2_buffer *vb)
+{
+ struct qcom_jenc_queue *sq = &ectx->bufq[JENC_SRC_QUEUE];
+ struct qcom_jenc_queue *dq = &ectx->bufq[JENC_DST_QUEUE];
+ unsigned long flags;
+ int rc;
+
+ spin_lock_irqsave(&jenc->hw_lock, flags);
+ jenc->actx = ectx;
+ spin_unlock_irqrestore(&jenc->hw_lock, flags);
+
+ if (V4L2_TYPE_IS_OUTPUT(vb->type)) {
+ rc = jpeg_setup_fe(ectx, sq);
+ if (rc)
+ return rc;
+
+ jpeg_apply_fe_addr(ectx, sq, vb);
+
+ } else {
+ rc = jpeg_setup_we(ectx, dq);
+ if (rc)
+ return rc;
+
+ jpeg_apply_we_addr(ectx, dq, vb);
+ }
+
+ if (sq->sequence == dq->sequence) {
+ rc = jpeg_setup_scale(ectx);
+ if (rc)
+ return rc;
+
+ rc = jpeg_setup_encode(ectx);
+ if (rc)
+ return rc;
+
+ jpeg_exec(jenc);
+ }
+
+ return 0;
+}
+
+static int op_jpeg_prepare(struct qcom_jenc_dev *jenc)
+{
+ const struct qcom_jpeg_reg_offs *offs = jenc->res->hw_offs;
+
+ jpeg_rw_bits(jenc, offs->reset_cmd, JMSK_RST_CMD_DECODER_RESET, 1);
+ jpeg_rw_bits(jenc, offs->reset_cmd, JMSK_RST_CMD_BLOCK_FORMATTER_RST, 1);
+ jpeg_rw_bits(jenc, offs->reset_cmd, JMSK_RST_CMD_CORE_RESET, 1);
+
+ return 0;
+}
+
+static int op_jpeg_acquire(struct jenc_context *ectx, struct vb2_queue *q)
+{
+ struct qcom_jenc_dev *jenc = ectx->jenc;
+ struct qcom_jenc_queue *sq, *dq;
+ int rc;
+
+ if (atomic_inc_return(&jenc->ref_count) == 1) {
+ rc = pm_runtime_resume_and_get(jenc->dev);
+ if (rc < 0) {
+ dev_err(jenc->dev, "PM runtime get failed\n");
+ atomic_dec(&jenc->ref_count);
+ return rc;
+ }
+
+ rc = jpeg_init(jenc);
+ if (rc) {
+ dev_err(jenc->dev, "hardware init failed\n");
+ atomic_dec(&jenc->ref_count);
+ pm_runtime_put(jenc->dev);
+ return rc;
+ }
+
+ sq = &ectx->bufq[JENC_SRC_QUEUE];
+ sq->sequence = 0;
+ sq->buff_id = -1;
+ dq = &ectx->bufq[JENC_DST_QUEUE];
+ dq->sequence = 0;
+ dq->buff_id = -1;
+ }
+
+ return 0;
+}
+
+static int op_jpeg_release(struct jenc_context *ectx, struct vb2_queue *q)
+{
+ struct qcom_jenc_dev *jenc = ectx->jenc;
+ int rc;
+
+ if (!atomic_dec_if_positive(&jenc->ref_count)) {
+ rc = jpeg_deinit(jenc);
+ if (rc)
+ dev_err(jenc->dev, "hardware exit failed\n");
+
+ rc = pm_runtime_put_sync(jenc->dev);
+ if (rc < 0)
+ dev_err(jenc->dev, "PM runtime put failed\n");
+
+ dev_dbg(jenc->dev, "JPEG HW encoder released\n");
+ }
+
+ return 0;
+}
+
+const struct qcom_jpeg_hw_ops qcom_jpeg_default_ops = {
+ .hw_get_cap = op_jpeg_get_hw_caps,
+ .hw_acquire = op_jpeg_acquire,
+ .hw_release = op_jpeg_release,
+ .hw_prepare = op_jpeg_prepare,
+ .get_queue = op_jpeg_get_buff_queue,
+ .queue_setup = op_jpeg_queue_setup,
+ .buf_prepare = op_jpeg_buffer_prepare,
+ .process_exec = op_jpeg_process_exec,
+ .hw_irq_top = op_jpeg_irq_top,
+ .hw_irq_bot = op_jpeg_irq_bot
+};
diff --git a/drivers/media/platform/qcom/jpeg/qcom_jenc_ops.h b/drivers/media/platform/qcom/jpeg/qcom_jenc_ops.h
new file mode 100644
index 000000000000..751a045a3486
--- /dev/null
+++ b/drivers/media/platform/qcom/jpeg/qcom_jenc_ops.h
@@ -0,0 +1,49 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
+ */
+
+#ifndef QCOM_JENC_OPS_H
+#define QCOM_JENC_OPS_H
+
+#include <linux/types.h>
+#include <linux/device.h>
+#include <media/videobuf2-core.h>
+
+#include "qcom_jenc_dev.h"
+
+/*
+ * JENC encoder hardware operations.
+ */
+struct qcom_jpeg_hw_ops {
+ void (*hw_get_cap)
+ (struct qcom_jenc_dev *jenc_dev, u32 *hw_caps);
+
+ int (*hw_acquire)
+ (struct jenc_context *ectx, struct vb2_queue *queue);
+
+ int (*hw_release)
+ (struct jenc_context *ectx, struct vb2_queue *queue);
+
+ int (*hw_prepare)
+ (struct qcom_jenc_dev *jenc);
+
+ struct qcom_jenc_queue * (*get_queue)
+ (struct jenc_context *ectx, enum qcom_enc_qid id);
+
+ int (*queue_setup)
+ (struct jenc_context *ectx, enum qcom_enc_qid id);
+
+ int (*buf_prepare)
+ (struct jenc_context *ectx, struct vb2_buffer *vb2);
+
+ int (*process_exec)
+ (struct qcom_jenc_dev *jenc, struct jenc_context *ectx, struct vb2_buffer *vb2);
+
+ irqreturn_t (*hw_irq_top)(int irq_num, void *data);
+ irqreturn_t (*hw_irq_bot)(int irq_num, void *data);
+};
+
+extern const struct qcom_jpeg_hw_ops qcom_jpeg_default_ops;
+
+#endif /* QCOM_JENC_OPS_H */
diff --git a/drivers/media/platform/qcom/jpeg/qcom_jenc_res.c b/drivers/media/platform/qcom/jpeg/qcom_jenc_res.c
new file mode 100644
index 000000000000..c935ea690837
--- /dev/null
+++ b/drivers/media/platform/qcom/jpeg/qcom_jenc_res.c
@@ -0,0 +1,268 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
+ */
+
+#include <linux/clk.h>
+
+#include "qcom_jenc_ops.h"
+#include "qcom_jenc_res.h"
+
+#include "qcom_v165_jenc_hw_info.h"
+#include "qcom_v580_jenc_hw_info.h"
+#include "qcom_v680_jenc_hw_info.h"
+#include "qcom_v780_jenc_hw_info.h"
+
+#define QCOM_PERF_ROW(_axi_rate, _jpeg_rate) \
+{ \
+ .clk_rate = { \
+ [JPEG_CAMNOC_AXI_CLK] = (_axi_rate), \
+ [JPEG_CORE_CLK] = (_jpeg_rate), \
+ }, \
+}
+
+/*
+ * Baseline AXI clock rates shared across v165/v580, reused by later
+ * derivatives where the hardware does not change these domains.
+ */
+static const u64 cnoc_axi_clk_base[] = {
+ [QCOM_SOC_PERF_SUSPEND] = 19200000,
+ [QCOM_SOC_PERF_LOWSVS] = 300000000,
+ [QCOM_SOC_PERF_SVS] = 300000000,
+ [QCOM_SOC_PERF_SVS_L1] = 300000000,
+ [QCOM_SOC_PERF_NOMINAL] = 400000000,
+ [QCOM_SOC_PERF_TURBO] = 400000000,
+};
+
+/*
+ * Derivative with an improved CAMNOC AXI frequency range
+ */
+static const u64 cnoc_axi_clk_v680[] = {
+ [QCOM_SOC_PERF_SUSPEND] = 19200000,
+ [QCOM_SOC_PERF_LOWSVS] = 150000000,
+ [QCOM_SOC_PERF_SVS] = 240000000,
+ [QCOM_SOC_PERF_SVS_L1] = 320000000,
+ [QCOM_SOC_PERF_NOMINAL] = 400000000,
+ [QCOM_SOC_PERF_TURBO] = 480000000,
+};
+
+/*
+ * Baseline JPEG clock rates shared across v165/v680, reused by later
+ * derivatives where the hardware does not change these domains.
+ */
+static const u64 qcom_jpeg_clk_base[] = {
+ [QCOM_SOC_PERF_SUSPEND] = 19200000,
+ [QCOM_SOC_PERF_LOWSVS] = 300000000,
+ [QCOM_SOC_PERF_SVS] = 400000000,
+ [QCOM_SOC_PERF_SVS_L1] = 480000000,
+ [QCOM_SOC_PERF_NOMINAL] = 600000000,
+ [QCOM_SOC_PERF_TURBO] = 600000000,
+};
+
+/*
+ * Derivative with an improved maximum JPEG frequency
+ */
+static const u64 qcom_jpeg_clk_v780[] = {
+ [QCOM_SOC_PERF_SUSPEND] = 19200000,
+ [QCOM_SOC_PERF_LOWSVS] = 200000000,
+ [QCOM_SOC_PERF_SVS] = 200000000,
+ [QCOM_SOC_PERF_SVS_L1] = 400000000,
+ [QCOM_SOC_PERF_NOMINAL] = 480000000,
+ [QCOM_SOC_PERF_TURBO] = 785000000,
+};
+
+static const struct qcom_perf_resource qcom_perf_rates_base[] = {
+ [QCOM_SOC_PERF_SUSPEND] =
+ QCOM_PERF_ROW(cnoc_axi_clk_base[QCOM_SOC_PERF_SUSPEND],
+ qcom_jpeg_clk_base[QCOM_SOC_PERF_SUSPEND]),
+
+ [QCOM_SOC_PERF_LOWSVS] =
+ QCOM_PERF_ROW(cnoc_axi_clk_base[QCOM_SOC_PERF_LOWSVS],
+ qcom_jpeg_clk_base[QCOM_SOC_PERF_LOWSVS]),
+
+ [QCOM_SOC_PERF_SVS] =
+ QCOM_PERF_ROW(cnoc_axi_clk_base[QCOM_SOC_PERF_SVS],
+ qcom_jpeg_clk_base[QCOM_SOC_PERF_SVS]),
+
+ [QCOM_SOC_PERF_SVS_L1] =
+ QCOM_PERF_ROW(cnoc_axi_clk_base[QCOM_SOC_PERF_SVS_L1],
+ qcom_jpeg_clk_base[QCOM_SOC_PERF_SVS_L1]),
+
+ [QCOM_SOC_PERF_NOMINAL] =
+ QCOM_PERF_ROW(cnoc_axi_clk_base[QCOM_SOC_PERF_NOMINAL],
+ qcom_jpeg_clk_base[QCOM_SOC_PERF_NOMINAL]),
+
+ [QCOM_SOC_PERF_TURBO] =
+ QCOM_PERF_ROW(cnoc_axi_clk_base[QCOM_SOC_PERF_TURBO],
+ qcom_jpeg_clk_base[QCOM_SOC_PERF_TURBO]),
+};
+
+static const struct qcom_perf_resource qcom_perf_rates_v680[] = {
+ [QCOM_SOC_PERF_SUSPEND] =
+ QCOM_PERF_ROW(cnoc_axi_clk_v680[QCOM_SOC_PERF_SUSPEND],
+ qcom_jpeg_clk_base[QCOM_SOC_PERF_SUSPEND]),
+
+ [QCOM_SOC_PERF_LOWSVS] =
+ QCOM_PERF_ROW(cnoc_axi_clk_v680[QCOM_SOC_PERF_LOWSVS],
+ qcom_jpeg_clk_base[QCOM_SOC_PERF_LOWSVS]),
+
+ [QCOM_SOC_PERF_SVS] =
+ QCOM_PERF_ROW(cnoc_axi_clk_v680[QCOM_SOC_PERF_SVS],
+ qcom_jpeg_clk_base[QCOM_SOC_PERF_SVS]),
+
+ [QCOM_SOC_PERF_SVS_L1] =
+ QCOM_PERF_ROW(cnoc_axi_clk_v680[QCOM_SOC_PERF_SVS_L1],
+ qcom_jpeg_clk_base[QCOM_SOC_PERF_SVS_L1]),
+
+ [QCOM_SOC_PERF_NOMINAL] =
+ QCOM_PERF_ROW(cnoc_axi_clk_v680[QCOM_SOC_PERF_NOMINAL],
+ qcom_jpeg_clk_base[QCOM_SOC_PERF_NOMINAL]),
+
+ [QCOM_SOC_PERF_TURBO] =
+ QCOM_PERF_ROW(cnoc_axi_clk_v680[QCOM_SOC_PERF_TURBO],
+ qcom_jpeg_clk_base[QCOM_SOC_PERF_TURBO]),
+};
+
+static const struct qcom_perf_resource qcom_perf_rates_v780[] = {
+ [QCOM_SOC_PERF_SUSPEND] =
+ QCOM_PERF_ROW(cnoc_axi_clk_base[QCOM_SOC_PERF_SUSPEND],
+ qcom_jpeg_clk_v780[QCOM_SOC_PERF_SUSPEND]),
+
+ [QCOM_SOC_PERF_LOWSVS] =
+ QCOM_PERF_ROW(cnoc_axi_clk_base[QCOM_SOC_PERF_LOWSVS],
+ qcom_jpeg_clk_v780[QCOM_SOC_PERF_LOWSVS]),
+
+ [QCOM_SOC_PERF_SVS] =
+ QCOM_PERF_ROW(cnoc_axi_clk_base[QCOM_SOC_PERF_SVS],
+ qcom_jpeg_clk_v780[QCOM_SOC_PERF_SVS]),
+
+ [QCOM_SOC_PERF_SVS_L1] =
+ QCOM_PERF_ROW(cnoc_axi_clk_base[QCOM_SOC_PERF_SVS_L1],
+ qcom_jpeg_clk_v780[QCOM_SOC_PERF_SVS_L1]),
+
+ [QCOM_SOC_PERF_NOMINAL] =
+ QCOM_PERF_ROW(cnoc_axi_clk_base[QCOM_SOC_PERF_NOMINAL],
+ qcom_jpeg_clk_v780[QCOM_SOC_PERF_NOMINAL]),
+
+ [QCOM_SOC_PERF_TURBO] =
+ QCOM_PERF_ROW(cnoc_axi_clk_base[QCOM_SOC_PERF_TURBO],
+ qcom_jpeg_clk_v780[QCOM_SOC_PERF_TURBO]),
+};
+
+static const struct qcom_icc_resource qcom_jpeg_default_icc[] = {
+ {
+ .icc_id = "cam_ahb",
+ .pair = { 38400, 76800 }
+ },
+ {
+ .icc_id = "cam_hf_0_mnoc",
+ .pair = { 2097152, 2097152 }
+ },
+ {
+ .icc_id = "cam_sf_0_mnoc",
+ .pair = { 0, 2097152 }
+ },
+ {
+ .icc_id = "cam_sf_icp_mnoc",
+ .pair = { 2097152, 2097152 }
+ },
+};
+
+static const struct qcom_mem_resource qcom_jpeg_default_mem[] = {
+ {
+ .map_id = 0,
+ .res_id = "JPEG"
+ },
+ {
+ .map_id = 1,
+ .res_id = "CPAS"
+ }
+};
+
+/*
+ * Resources for T165, T170 JPEG version and derivatives
+ */
+const struct qcom_dev_resources qcom_jpeg_v165_drvdata = {
+ .hw_ops = &qcom_jpeg_default_ops,
+ .hw_offs = &qcom_v165_jpeg_hw_reg_offs,
+ .hw_mask = &qcom_v165_jpeg_hw_reg_mask[0],
+ .icc_res = qcom_jpeg_default_icc,
+ .num_of_icc = ARRAY_SIZE(qcom_jpeg_default_icc),
+ .mem_res = qcom_jpeg_default_mem,
+ .num_of_mem = ARRAY_SIZE(qcom_jpeg_default_mem),
+ .perf_cfg = qcom_perf_rates_base,
+ .clk_names = {
+ [JPEG_CAMNOC_AXI_CLK] = "camnoc_axi_clk",
+ [JPEG_CORE_CLK] = "jpeg_clk",
+ [JPEG_CORE_AHB_CLK] = "core_ahb_clk",
+ [JPEG_CPAS_AHB_CLK] = "cpas_ahb_clk",
+ [JPEG_GCC_HF_AXI] = "gcc_hf_axi_clk",
+ [JPEG_GCC_SF_AXI] = "gcc_sf_axi_clk",
+ }
+};
+
+/*
+ * Resources for T480, T580 JPEG version and derivatives
+ */
+const struct qcom_dev_resources qcom_jpeg_v580_drvdata = {
+ .hw_ops = &qcom_jpeg_default_ops,
+ .hw_offs = &qcom_v580_jpeg_hw_reg_offs,
+ .hw_mask = &qcom_v580_jpeg_hw_reg_mask[0],
+ .icc_res = qcom_jpeg_default_icc,
+ .num_of_icc = ARRAY_SIZE(qcom_jpeg_default_icc),
+ .mem_res = qcom_jpeg_default_mem,
+ .num_of_mem = ARRAY_SIZE(qcom_jpeg_default_mem),
+ .perf_cfg = qcom_perf_rates_base,
+ .clk_names = {
+ [JPEG_CAMNOC_AXI_CLK] = "camnoc_axi_clk",
+ [JPEG_CORE_CLK] = "jpeg_clk",
+ [JPEG_CORE_AHB_CLK] = "core_ahb_clk",
+ [JPEG_CPAS_AHB_CLK] = "cpas_ahb_clk",
+ [JPEG_GCC_HF_AXI] = "gcc_hf_axi_clk",
+ [JPEG_GCC_SF_AXI] = "gcc_sf_axi_clk",
+ }
+};
+
+/*
+ * Resources for T680 JPEG version and derivatives
+ */
+const struct qcom_dev_resources qcom_jpeg_v680_drvdata = {
+ .hw_ops = &qcom_jpeg_default_ops,
+ .hw_offs = &qcom_v680_jpeg_hw_reg_offs,
+ .hw_mask = &qcom_v680_jpeg_hw_reg_mask[0],
+ .icc_res = qcom_jpeg_default_icc,
+ .num_of_icc = ARRAY_SIZE(qcom_jpeg_default_icc),
+ .mem_res = qcom_jpeg_default_mem,
+ .num_of_mem = ARRAY_SIZE(qcom_jpeg_default_mem),
+ .perf_cfg = qcom_perf_rates_v680,
+ .clk_names = {
+ [JPEG_CAMNOC_AXI_CLK] = "camnoc_axi_clk",
+ [JPEG_CORE_CLK] = "jpeg_clk",
+ [JPEG_CORE_AHB_CLK] = "core_ahb_clk",
+ [JPEG_CPAS_AHB_CLK] = "cpas_ahb_clk",
+ [JPEG_GCC_HF_AXI] = "gcc_hf_axi_clk",
+ [JPEG_GCC_SF_AXI] = "gcc_sf_axi_clk",
+ }
+};
+
+/*
+ * Resources for T780 JPEG version and derivatives
+ */
+const struct qcom_dev_resources qcom_jpeg_v780_drvdata = {
+ .hw_ops = &qcom_jpeg_default_ops,
+ .hw_offs = &qcom_v780_jpeg_hw_reg_offs,
+ .hw_mask = &qcom_v780_jpeg_hw_reg_mask[0],
+ .icc_res = qcom_jpeg_default_icc,
+ .num_of_icc = ARRAY_SIZE(qcom_jpeg_default_icc),
+ .mem_res = qcom_jpeg_default_mem,
+ .num_of_mem = ARRAY_SIZE(qcom_jpeg_default_mem),
+ .perf_cfg = qcom_perf_rates_v780,
+ .clk_names = {
+ [JPEG_CAMNOC_AXI_CLK] = "camnoc_axi_clk",
+ [JPEG_CORE_CLK] = "jpeg_clk",
+ [JPEG_CORE_AHB_CLK] = "core_ahb_clk",
+ [JPEG_CPAS_AHB_CLK] = "cpas_ahb_clk",
+ [JPEG_GCC_HF_AXI] = "gcc_hf_axi_clk",
+ [JPEG_GCC_SF_AXI] = "gcc_sf_axi_clk",
+ }
+};
diff --git a/drivers/media/platform/qcom/jpeg/qcom_jenc_res.h b/drivers/media/platform/qcom/jpeg/qcom_jenc_res.h
new file mode 100644
index 000000000000..5152594b0f47
--- /dev/null
+++ b/drivers/media/platform/qcom/jpeg/qcom_jenc_res.h
@@ -0,0 +1,70 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
+ */
+
+#ifndef QCOM_JENC_RES_H
+#define QCOM_JENC_RES_H
+
+#include "qcom_jenc_defs.h"
+
+/*
+ * clk_rate == 0 means: do not change this clock rate.
+ * Clock is still enabled/disabled normally.
+ */
+enum qcom_jpeg_clock_ids {
+ JPEG_CAMNOC_AXI_CLK,
+ JPEG_CORE_CLK,
+ JPEG_CORE_AHB_CLK,
+ JPEG_CPAS_AHB_CLK,
+ JPEG_GCC_HF_AXI,
+ JPEG_GCC_SF_AXI,
+ JPEG_MAX_CLOCKS
+};
+
+struct qcom_freq_resource {
+ const u64 *freq;
+ u8 num_of_freq;
+};
+
+struct qcom_icc_resource {
+ const char *icc_id;
+ struct {
+ u32 aggr;
+ u32 peak;
+ } pair;
+};
+
+struct qcom_mem_resource {
+ unsigned int map_id;
+ const char *res_id;
+};
+
+struct qcom_perf_resource {
+ u64 clk_rate[JPEG_MAX_CLOCKS];
+};
+
+struct qcom_dev_resources {
+ const struct qcom_jpeg_hw_ops *hw_ops;
+ const struct qcom_jpeg_reg_offs *hw_offs;
+ const u32 *hw_mask;
+
+ const struct qcom_icc_resource *icc_res;
+ unsigned int num_of_icc;
+ const struct qcom_mem_resource *mem_res;
+ unsigned int num_of_mem;
+ const struct qcom_perf_resource *perf_cfg;
+ const char *clk_names[JPEG_MAX_CLOCKS];
+};
+
+int qcom_find_clk_id(const struct qcom_dev_resources *res, const char *clk_name);
+
+extern const struct qcom_dev_resources qcom_jpeg_v165_drvdata;
+
+extern const struct qcom_dev_resources qcom_jpeg_v580_drvdata;
+
+extern const struct qcom_dev_resources qcom_jpeg_v680_drvdata;
+
+extern const struct qcom_dev_resources qcom_jpeg_v780_drvdata;
+
+#endif /* QCOM_JENC_RES_H */
diff --git a/drivers/media/platform/qcom/jpeg/qcom_jenc_v4l2.c b/drivers/media/platform/qcom/jpeg/qcom_jenc_v4l2.c
new file mode 100644
index 000000000000..8f5e4bd8a36e
--- /dev/null
+++ b/drivers/media/platform/qcom/jpeg/qcom_jenc_v4l2.c
@@ -0,0 +1,1082 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
+ */
+
+#include <linux/init.h>
+#include <linux/interconnect.h>
+#include <linux/ioctl.h>
+#include <linux/kernel.h>
+#include <linux/list.h>
+#include <linux/module.h>
+#include <linux/of_platform.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/videodev2.h>
+#include <linux/vmalloc.h>
+#include <linux/pm_runtime.h>
+
+#include <media/v4l2-common.h>
+#include <media/v4l2-ctrls.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-event.h>
+#include <media/v4l2-fh.h>
+#include <media/v4l2-mem2mem.h>
+#include <media/videobuf2-dma-contig.h>
+#include <media/videobuf2-dma-sg.h>
+#include <media/videobuf2-v4l2.h>
+#include <media/videobuf2-vmalloc.h>
+
+#include "qcom_jenc_dev.h"
+#include "qcom_jenc_v4l2.h"
+#include "qcom_jenc_ops.h"
+#include "qcom_jenc_defs.h"
+
+static const struct v4l2_frmsizeenum jpeg_def_frmsize = {
+ .stepwise = {
+ .min_width = QCOM_JPEG_HW_MIN_WIDTH,
+ .max_width = QCOM_JPEG_HW_MAX_WIDTH,
+ .step_width = QCOM_JPEG_HW_DEF_HSTEP,
+ .min_height = QCOM_JPEG_HW_MIN_HEIGHT,
+ .max_height = QCOM_JPEG_HW_MAX_HEIGHT,
+ .step_height = QCOM_JPEG_HW_DEF_VSTEP,
+ },
+ .type = V4L2_FRMSIZE_TYPE_STEPWISE
+};
+
+static const struct jenc_enc_format jpeg_src_formats[] = {
+ {
+ .fourcc = V4L2_PIX_FMT_NV12M,
+ .type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE,
+ },
+ {
+ .fourcc = V4L2_PIX_FMT_NV21M,
+ .type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE,
+ },
+ {
+ .fourcc = V4L2_PIX_FMT_GREY,
+ .type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE,
+ },
+};
+
+#define JPEG_SRC_FMT_COUNT ARRAY_SIZE(jpeg_src_formats)
+
+static const struct jenc_enc_format jpeg_dst_formats[] = {
+ {
+ .fourcc = V4L2_PIX_FMT_JPEG,
+ .type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE,
+ }
+};
+
+#define JPEG_DST_FMT_COUNT ARRAY_SIZE(jpeg_dst_formats)
+
+static inline struct jenc_context *jpeg_file2ctx(struct file *file)
+{
+ struct v4l2_fh *fh = file->private_data;
+
+ if (!fh)
+ return NULL;
+
+ return container_of(fh, struct jenc_context, fh);
+}
+
+static struct qcom_jenc_queue *jpeg_get_bufq(struct jenc_context *ectx, enum qcom_enc_qid id)
+{
+ return &ectx->bufq[id];
+}
+
+static bool jpeg_v4l2_queues_busy(struct jenc_context *ctx)
+{
+ struct vb2_queue *out_q;
+ struct vb2_queue *cap_q;
+
+ out_q = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE);
+
+ cap_q = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE);
+
+ return vb2_is_busy(out_q) || vb2_is_busy(cap_q);
+}
+
+static bool jpeg_is_invalid_src(struct jenc_context *ectx, u32 type)
+{
+ bool is_invalid = (type != V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE);
+
+ if (is_invalid)
+ dev_err(ectx->dev, "invalid src type or format\n");
+
+ return is_invalid;
+}
+
+static bool jpeg_is_invalid_dst(struct jenc_context *ectx, u32 type)
+{
+ bool is_invalid = (type != V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE);
+
+ if (is_invalid)
+ dev_err(ectx->dev, "invalid dst type or format\n");
+
+ return is_invalid;
+}
+
+static const struct jenc_enc_format *jpeg_find_pix_format(enum qcom_enc_qid id, u32 fourcc)
+{
+ const struct jenc_enc_format *efmt;
+ unsigned int i, count;
+
+ if (id == JENC_SRC_QUEUE) {
+ count = JPEG_SRC_FMT_COUNT;
+ efmt = &jpeg_src_formats[0];
+ } else {
+ count = JPEG_DST_FMT_COUNT;
+ efmt = &jpeg_dst_formats[0];
+ }
+
+ for (i = 0; i < count; i++) {
+ if (efmt[i].fourcc == fourcc)
+ return &efmt[i];
+ }
+
+ return NULL;
+}
+
+static const struct jenc_enc_format *jpeg_get_format(struct jenc_context *ectx,
+ enum qcom_enc_qid qid, u32 pixelformat)
+{
+ const struct jenc_enc_format *efmt;
+
+ if (qid == JENC_SRC_QUEUE) {
+ efmt = jpeg_find_pix_format(qid, pixelformat);
+ if (!efmt)
+ efmt = &jpeg_src_formats[0];
+ } else {
+ efmt = jpeg_find_pix_format(qid, pixelformat);
+ if (!efmt)
+ efmt = &jpeg_dst_formats[0];
+ }
+
+ return efmt;
+}
+
+static int jpeg_update_src_planes(const struct jenc_enc_format *ef, struct v4l2_format *v4f)
+{
+ struct v4l2_pix_format_mplane *f = &v4f->fmt.pix_mp;
+ const struct v4l2_format_info *info = v4l2_format_info(ef->fourcc);
+ int rc;
+
+ if (!info)
+ return -EINVAL;
+
+ f->pixelformat = ef->fourcc;
+
+ f->field = V4L2_FIELD_NONE;
+ f->colorspace = V4L2_COLORSPACE_SRGB;
+ f->xfer_func = V4L2_MAP_XFER_FUNC_DEFAULT(f->colorspace);
+ f->ycbcr_enc = V4L2_MAP_YCBCR_ENC_DEFAULT(f->colorspace);
+ f->quantization =
+ V4L2_MAP_QUANTIZATION_DEFAULT(f->ycbcr_enc == V4L2_YCBCR_ENC_601,
+ f->colorspace, f->ycbcr_enc);
+
+ v4l2_apply_frmsize_constraints(&f->width, &f->height, &jpeg_def_frmsize.stepwise);
+
+ rc = v4l2_fill_pixfmt_mp(f, ef->fourcc, f->width, f->height);
+ if (rc)
+ return rc;
+
+ return 0;
+}
+
+static void jpeg_update_dst_plane(const struct jenc_enc_format *ef, struct v4l2_format *v4f)
+{
+ struct v4l2_pix_format_mplane *f = &v4f->fmt.pix_mp;
+ u64 size;
+ u32 nbx, nby;
+
+ f->pixelformat = ef->fourcc;
+ f->field = V4L2_FIELD_NONE;
+ f->colorspace = V4L2_COLORSPACE_SRGB;
+ f->xfer_func = V4L2_MAP_XFER_FUNC_DEFAULT(f->colorspace);
+ f->ycbcr_enc = V4L2_MAP_YCBCR_ENC_DEFAULT(f->colorspace);
+ f->quantization =
+ V4L2_MAP_QUANTIZATION_DEFAULT(f->ycbcr_enc == V4L2_YCBCR_ENC_601,
+ f->colorspace, f->ycbcr_enc);
+
+ v4l2_apply_frmsize_constraints(&f->width, &f->height, &jpeg_def_frmsize.stepwise);
+
+ /*
+ * JPEG is a variable-size format. The output size cannot be derived
+ * from bits per point or line stride.
+ *
+ * Provide a conservative upper bound based on worst-case entropy
+ * coding of 8x8 DCT blocks:
+ *
+ * - Each 8x8 block has 64 coefficients (1 DC + 63 AC).
+ * - In worst-case (high-entropy input, low quantization), all
+ * coefficients may be non-zero.
+ * - Huffman coding then emits (code + magnitude bits) per coefficient,
+ * which can approach ~2 bytes per coefficient in the worst case.
+ *
+ * => Worst-case is 64 coefficients * 2 bytes = 128 bytes per 8x8 block
+ * => approximately 2 bytes per point
+ *
+ * This bound implicitly covers byte stuffing (0xFF escaping) and is
+ * conservative with respect to subsampled formats (e.g. 4:2:0).
+ *
+ * Additional margin is added for headers and alignment.
+ *
+ * Note: This is a conservative upper bound, not an exact size.
+ */
+
+ nbx = DIV_ROUND_UP(f->width, 8);
+ nby = DIV_ROUND_UP(f->height, 8);
+
+ size = nbx * nby * 128;
+ size += SZ_4K; /* header + safety margin */
+
+ f->plane_fmt[0].bytesperline = 0;
+ f->plane_fmt[0].sizeimage = ALIGN(size, SZ_4K);
+}
+
+static int jpeg_enum_fmt_src(struct v4l2_fmtdesc *f)
+{
+ if (f->index >= JPEG_SRC_FMT_COUNT)
+ return -EINVAL;
+
+ f->pixelformat = jpeg_src_formats[f->index].fourcc;
+
+ return 0;
+}
+
+static int jpeg_enum_fmt_dst(struct v4l2_fmtdesc *f)
+{
+ if (f->index >= JPEG_DST_FMT_COUNT)
+ return -EINVAL;
+
+ f->pixelformat = jpeg_dst_formats[f->index].fourcc;
+
+ return 0;
+}
+
+static int jpeg_v4l2_try_format(struct jenc_context *ectx, struct v4l2_format *f)
+{
+ struct v4l2_pix_format_mplane *pm = &f->fmt.pix_mp;
+ const struct jenc_enc_format *ef;
+ int rc;
+
+ /* The function always returns valid driver format */
+ ef = jpeg_get_format(ectx, TYPE2QID(f->type), pm->pixelformat);
+
+ dev_dbg(ectx->dev, "type=%d %c%c%c%c\n",
+ TYPE2QID(f->type),
+ (ef->fourcc >> 0) & 0xff,
+ (ef->fourcc >> 8) & 0xff,
+ (ef->fourcc >> 16) & 0xff,
+ (ef->fourcc >> 24) & 0xff);
+
+ if (V4L2_TYPE_IS_CAPTURE(f->type)) {
+ f->fmt.pix_mp.num_planes = 1;
+
+ jpeg_update_dst_plane(ef, f);
+
+ dev_dbg(ectx->dev, "\tImage: %dx%d Size:%9d\n", f->fmt.pix_mp.width,
+ f->fmt.pix_mp.height, f->fmt.pix_mp.plane_fmt[0].sizeimage);
+ } else {
+ /*
+ * The used format is an internal driver format that must be
+ * present in the V4L2 common formats; therefore, the errors
+ * below should never occur.
+ */
+ const struct v4l2_format_info *info = v4l2_format_info(ef->fourcc);
+ u8 pln = 0;
+
+ if (WARN_ON_ONCE(!info))
+ return -EINVAL;
+
+ f->fmt.pix_mp.num_planes = info->comp_planes;
+
+ rc = jpeg_update_src_planes(ef, f);
+ if (WARN_ON_ONCE(rc))
+ return -EINVAL;
+
+ for (pln = 0; pln < f->fmt.pix_mp.num_planes; pln++)
+ dev_dbg(ectx->dev, "\tImage: %dx%d BPL:%5d Size:%9d\n",
+ pm->width, pm->height, pm->plane_fmt[pln].bytesperline,
+ pm->plane_fmt[pln].sizeimage);
+ }
+
+ return 0;
+}
+
+static int jpeg_v4l2_set_defaults(struct jenc_context *ectx)
+{
+ struct qcom_jenc_queue *sq = jpeg_get_bufq(ectx, JENC_SRC_QUEUE);
+ struct qcom_jenc_queue *dq = jpeg_get_bufq(ectx, JENC_DST_QUEUE);
+ struct v4l2_format f = {0};
+ int rc;
+
+ f.type = jpeg_src_formats->type;
+ f.fmt.pix_mp.pixelformat = jpeg_src_formats->fourcc;
+ f.fmt.pix_mp.width = QCOM_JPEG_HW_DEF_WIDTH;
+ f.fmt.pix_mp.height = QCOM_JPEG_HW_DEF_HEIGHT;
+
+ rc = jpeg_v4l2_try_format(ectx, &f);
+ if (rc)
+ return rc;
+
+ sq->vf = f.fmt.pix_mp;
+
+ f.type = jpeg_dst_formats->type;
+ f.fmt.pix_mp.pixelformat = jpeg_dst_formats->fourcc;
+ f.fmt.pix_mp.width = QCOM_JPEG_HW_DEF_WIDTH;
+ f.fmt.pix_mp.height = QCOM_JPEG_HW_DEF_HEIGHT;
+
+ rc = jpeg_v4l2_try_format(ectx, &f);
+ if (rc)
+ return rc;
+
+ dq->vf = f.fmt.pix_mp;
+
+ return 0;
+}
+
+static int jpeg_v4l2_set_format(struct jenc_context *ectx, struct v4l2_format *f)
+{
+ struct qcom_jenc_queue *q = jpeg_get_bufq(ectx, TYPE2QID(f->type));
+ struct v4l2_pix_format_mplane *pm = &f->fmt.pix_mp;
+ int rc;
+
+ if (jpeg_v4l2_queues_busy(ectx))
+ return -EBUSY;
+
+ if (!v4l2_m2m_get_vq(ectx->fh.m2m_ctx, f->type)) {
+ dev_err(ectx->dev, "cannot get video queue\n");
+ return -EINVAL;
+ }
+
+ rc = jpeg_v4l2_try_format(ectx, f);
+ if (rc)
+ return rc;
+
+ /*
+ * Because scaling is not supported, source and destination image
+ * sizes must be equal.
+ */
+ if (V4L2_TYPE_IS_CAPTURE(f->type)) {
+ struct qcom_jenc_queue *sq = jpeg_get_bufq(ectx, JENC_SRC_QUEUE);
+
+ /* Adjust source size to match capture size */
+ if (pm->width != sq->vf.width || pm->height != sq->vf.height) {
+ struct v4l2_format nf = {0};
+
+ nf.type = jpeg_src_formats->type;
+ nf.fmt.pix_mp.pixelformat = sq->vf.pixelformat;
+ nf.fmt.pix_mp.width = pm->width;
+ nf.fmt.pix_mp.height = pm->height;
+
+ rc = jpeg_v4l2_try_format(ectx, &nf);
+ if (rc)
+ return rc;
+
+ sq->vf = nf.fmt.pix_mp;
+ }
+
+ } else {
+ struct qcom_jenc_queue *dq = jpeg_get_bufq(ectx, JENC_DST_QUEUE);
+ struct v4l2_format nf = {0};
+
+ /* Adjust destination size to match source size */
+ if (pm->width != dq->vf.width || pm->height != dq->vf.height) {
+ nf.type = jpeg_dst_formats->type;
+ nf.fmt.pix_mp.pixelformat = dq->vf.pixelformat;
+ nf.fmt.pix_mp.width = pm->width;
+ nf.fmt.pix_mp.height = pm->height;
+
+ rc = jpeg_v4l2_try_format(ectx, &nf);
+ if (rc)
+ return rc;
+
+ dq->vf = nf.fmt.pix_mp;
+
+ /*
+ * The horizontal alignment of the destination is larger, and the
+ * result after adjustment may still differ. In this case, the
+ * requested image size should also be modified.
+ */
+ if (pm->width != nf.fmt.pix_mp.width ||
+ pm->height != nf.fmt.pix_mp.height) {
+ pm->width = nf.fmt.pix_mp.width;
+ pm->height = nf.fmt.pix_mp.height;
+ }
+ }
+ }
+
+ q->vf = *pm;
+
+ return 0;
+}
+
+static void jpeg_v4l2_get_format(struct jenc_context *ectx, struct v4l2_format *f)
+{
+ struct qcom_jenc_queue *q = jpeg_get_bufq(ectx, TYPE2QID(f->type));
+
+ f->fmt.pix_mp = q->vf;
+}
+
+static void jpeg_v4l2_work_done(struct qcom_jenc_dev *jenc, struct jenc_context *ctx,
+ size_t out_size)
+{
+ struct vb2_v4l2_buffer *vb;
+
+ vb = v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx);
+ if (vb)
+ v4l2_m2m_buf_done(vb, VB2_BUF_STATE_DONE);
+
+ vb = v4l2_m2m_dst_buf_remove(ctx->fh.m2m_ctx);
+ if (vb) {
+ vb2_set_plane_payload(&vb->vb2_buf, 0, out_size);
+ v4l2_m2m_buf_done(vb, VB2_BUF_STATE_DONE);
+ }
+
+ v4l2_m2m_job_finish(jenc->m2m_dev, ctx->fh.m2m_ctx);
+}
+
+static void jpeg_v4l2_work_stop(struct qcom_jenc_dev *jenc, struct jenc_context *ctx,
+ enum vb2_buffer_state buff_state)
+{
+ struct vb2_v4l2_buffer *vb;
+
+ while ((vb = v4l2_m2m_dst_buf_remove(ctx->fh.m2m_ctx))) {
+ if (v4l2_m2m_last_dst_buf(ctx->fh.m2m_ctx)) {
+ mutex_lock(&ctx->stop_lock);
+ if (ctx->is_stopping) {
+ ctx->is_stopping = false;
+ vb2_set_plane_payload(&vb->vb2_buf, 0, 0);
+ }
+ mutex_unlock(&ctx->stop_lock);
+ v4l2_m2m_last_buffer_done(ctx->fh.m2m_ctx, vb);
+ } else {
+ v4l2_m2m_buf_done(vb, buff_state);
+ }
+ }
+
+ while ((vb = v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx)))
+ v4l2_m2m_buf_done(vb, buff_state);
+
+ v4l2_m2m_job_finish(jenc->m2m_dev, ctx->fh.m2m_ctx);
+}
+
+static void jpeg_v4l2_process_cb(void *priv, enum vb2_buffer_state ev, size_t out_size)
+{
+ struct jenc_context *ctx = priv;
+ struct qcom_jenc_dev *jenc = ctx->jenc;
+
+ mutex_lock(&jenc->dev_mutex);
+
+ if (ev == VB2_BUF_STATE_DONE && out_size)
+ jpeg_v4l2_work_done(ctx->jenc, ctx, out_size);
+ else
+ jpeg_v4l2_work_stop(ctx->jenc, ctx, ev);
+
+ mutex_unlock(&jenc->dev_mutex);
+}
+
+static int cop_jpeg_v4l2_set_ctrls(struct v4l2_ctrl *ctrl)
+{
+ struct jenc_context *ectx = container_of(ctrl->handler, struct jenc_context, ctrl_hdl);
+
+ switch (ctrl->id) {
+ case V4L2_CID_JPEG_COMPRESSION_QUALITY:
+ mutex_lock(&ectx->quality_mutex);
+ ectx->quality_requested = ctrl->val;
+ mutex_unlock(&ectx->quality_mutex);
+ break;
+ default:
+ dev_err(ectx->dev, "%s: invalid control=%#x\n", __func__, ctrl->id);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static const struct v4l2_ctrl_ops qcom_jpeg_v4l2_ctrl_ops = {
+ .s_ctrl = cop_jpeg_v4l2_set_ctrls,
+};
+
+static int bop_jpeg_vb2_queue_setup(struct vb2_queue *vq, unsigned int *nbuffers,
+ unsigned int *plns_per_buff, unsigned int sizes[],
+ struct device *alloc_devs[])
+{
+ struct jenc_context *ectx = vb2_get_drv_priv(vq);
+ struct qcom_jenc_dev *jenc = ectx->jenc;
+ const struct qcom_jpeg_hw_ops *hw = jenc->res->hw_ops;
+ struct qcom_jenc_queue *q;
+ int pln;
+
+ q = hw->get_queue(ectx, TYPE2QID(vq->type));
+ if (!q || !q->vf.num_planes)
+ return -EINVAL;
+
+ if (*plns_per_buff) {
+ if (*plns_per_buff != q->vf.num_planes)
+ return -EINVAL;
+
+ for (pln = 0; pln < q->vf.num_planes; ++pln) {
+ if (sizes[pln] < q->vf.plane_fmt[pln].sizeimage)
+ return -EINVAL;
+ }
+
+ return 0;
+ }
+
+ *plns_per_buff = q->vf.num_planes;
+ for (pln = 0; pln < q->vf.num_planes; ++pln) {
+ sizes[pln] = q->vf.plane_fmt[pln].sizeimage;
+ dev_dbg(ectx->dev, "%s: queue=%d size[%d]=%d\n", __func__, TYPE2QID(vq->type),
+ pln, sizes[pln]);
+ }
+
+ if (V4L2_TYPE_IS_CAPTURE(vq->type))
+ sizes[0] += JPEG_HEADER_MAX;
+
+ return hw->queue_setup(ectx, TYPE2QID(vq->type));
+}
+
+static int bop_jpeg_vb2_buf_out_validate(struct vb2_buffer *vb)
+{
+ struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
+
+ if (vbuf->field == V4L2_FIELD_ANY)
+ vbuf->field = V4L2_FIELD_NONE;
+
+ if (vbuf->field != V4L2_FIELD_NONE)
+ return -EINVAL;
+
+ return 0;
+}
+
+static int bop_jpeg_vb2_buf_prepare(struct vb2_buffer *vb)
+{
+ struct jenc_context *ectx = vb2_get_drv_priv(vb->vb2_queue);
+ struct qcom_jenc_dev *jenc = ectx->jenc;
+ const struct qcom_jpeg_hw_ops *hw = jenc->res->hw_ops;
+ struct qcom_jenc_queue *q = &ectx->bufq[TYPE2QID(vb->type)];
+ int pln;
+ int rc;
+
+ if (vb->num_planes != q->vf.num_planes)
+ return -EINVAL;
+
+ for (pln = 0; pln < q->vf.num_planes; pln++) {
+ if (q->vf.plane_fmt[pln].sizeimage == 0)
+ return -EINVAL;
+
+ if (vb2_plane_size(vb, pln) < q->vf.plane_fmt[pln].sizeimage)
+ return -EINVAL;
+ }
+
+ rc = hw->buf_prepare(ectx, vb);
+ if (rc) {
+ dev_err_ratelimited(ectx->dev, "buffer prepare failed\n");
+ jpeg_v4l2_process_cb(ectx, VB2_BUF_STATE_ERROR, 0);
+ return rc;
+ }
+
+ return 0;
+}
+
+static void bop_jpeg_vb2_buf_queue(struct vb2_buffer *vb)
+{
+ struct jenc_context *ectx = vb2_get_drv_priv(vb->vb2_queue);
+ struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
+
+ v4l2_m2m_buf_queue(ectx->fh.m2m_ctx, vbuf);
+}
+
+static int bop_jpeg_vb2_start_streaming(struct vb2_queue *q, unsigned int count)
+{
+ struct jenc_context *ectx = vb2_get_drv_priv(q);
+ struct qcom_jenc_dev *jenc = ectx->jenc;
+ const struct qcom_jpeg_hw_ops *hw = jenc->res->hw_ops;
+ struct qcom_jenc_queue *sq = jpeg_get_bufq(ectx, JENC_SRC_QUEUE);
+ struct qcom_jenc_queue *dq = jpeg_get_bufq(ectx, JENC_DST_QUEUE);
+ u32 hw_caps;
+ u8 pln;
+ int rc;
+
+ if (V4L2_TYPE_IS_OUTPUT(q->type)) {
+ dev_dbg(ectx->dev, "%c%c%c%c %dx%d\n",
+ (sq->vf.pixelformat >> 0) & 0xff,
+ (sq->vf.pixelformat >> 8) & 0xff,
+ (sq->vf.pixelformat >> 16) & 0xff,
+ (sq->vf.pixelformat >> 24) & 0xff,
+ sq->vf.width, sq->vf.height);
+
+ for (pln = 0; pln < sq->vf.num_planes; pln++) {
+ dev_dbg(ectx->dev, "\tpln=%d %dx%d bpl:%d size:%d\n", pln,
+ sq->vf.width, sq->vf.height,
+ sq->vf.plane_fmt[pln].bytesperline,
+ sq->vf.plane_fmt[pln].sizeimage);
+ }
+ } else {
+ dev_dbg(ectx->dev, "%c%c%c%c %dx%d\n",
+ (dq->vf.pixelformat >> 0) & 0xff,
+ (dq->vf.pixelformat >> 8) & 0xff,
+ (dq->vf.pixelformat >> 16) & 0xff,
+ (dq->vf.pixelformat >> 24) & 0xff,
+ dq->vf.width, dq->vf.height);
+ }
+
+ mutex_lock(&jenc->dev_mutex);
+
+ ectx->quality_requested = QCOM_JPEG_QUALITY_MAX;
+
+ rc = hw->hw_acquire(ectx, q);
+
+ hw->hw_get_cap(jenc, &hw_caps);
+ dev_dbg(ectx->dev, "hw_caps=0x%x\n", hw_caps);
+
+ mutex_unlock(&jenc->dev_mutex);
+
+ return rc;
+}
+
+static void bop_jpeg_vb2_stop_streaming(struct vb2_queue *q)
+{
+ struct jenc_context *ectx = vb2_get_drv_priv(q);
+ struct qcom_jenc_dev *jenc = ectx->jenc;
+ const struct qcom_jpeg_hw_ops *hw = jenc->res->hw_ops;
+
+ mutex_lock(&jenc->dev_mutex);
+
+ jpeg_v4l2_work_stop(jenc, ectx, VB2_BUF_STATE_ERROR);
+
+ hw->hw_release(ectx, q);
+
+ mutex_unlock(&jenc->dev_mutex);
+}
+
+static const struct vb2_ops qcom_jpeg_v4l2_vb2_ops = {
+ .queue_setup = bop_jpeg_vb2_queue_setup,
+ .buf_out_validate = bop_jpeg_vb2_buf_out_validate,
+ .buf_prepare = bop_jpeg_vb2_buf_prepare,
+ .buf_queue = bop_jpeg_vb2_buf_queue,
+ .start_streaming = bop_jpeg_vb2_start_streaming,
+ .stop_streaming = bop_jpeg_vb2_stop_streaming,
+ .wait_prepare = vb2_ops_wait_prepare,
+ .wait_finish = vb2_ops_wait_finish,
+};
+
+static void mop_jpeg_m2m_job_abort(void *priv)
+{
+ struct jenc_context *ectx = priv;
+ struct qcom_jenc_dev *jenc = ectx->jenc;
+
+ mutex_lock(&jenc->dev_mutex);
+
+ jpeg_v4l2_work_stop(jenc, ectx, VB2_BUF_STATE_ERROR);
+
+ mutex_unlock(&jenc->dev_mutex);
+}
+
+static void mop_jpeg_m2m_job_run(void *priv)
+{
+ struct jenc_context *ectx = priv;
+ struct qcom_jenc_dev *jenc = ectx->jenc;
+ const struct qcom_jpeg_hw_ops *hw = jenc->res->hw_ops;
+ struct vb2_v4l2_buffer *src_vb, *dst_vb;
+ struct qcom_jenc_queue *sq, *dq;
+
+ mutex_lock(&jenc->dev_mutex);
+
+ src_vb = v4l2_m2m_next_src_buf(ectx->fh.m2m_ctx);
+ dst_vb = v4l2_m2m_next_dst_buf(ectx->fh.m2m_ctx);
+
+ if (!src_vb || !dst_vb) {
+ jpeg_v4l2_work_stop(jenc, ectx, VB2_BUF_STATE_ERROR);
+ mutex_unlock(&jenc->dev_mutex);
+ return;
+ }
+
+ ectx->quality_requested = QCOM_JPEG_QUALITY_MAX;
+
+ hw->hw_prepare(jenc);
+
+ sq = hw->get_queue(ectx, TYPE2QID(src_vb->vb2_buf.type));
+ src_vb->sequence = sq->sequence++;
+ hw->process_exec(jenc, ectx, &src_vb->vb2_buf);
+
+ dq = hw->get_queue(ectx, TYPE2QID(dst_vb->vb2_buf.type));
+ dst_vb->sequence = dq->sequence++;
+ hw->process_exec(jenc, ectx, &dst_vb->vb2_buf);
+
+ v4l2_m2m_buf_copy_metadata(src_vb, dst_vb, false);
+
+ mutex_unlock(&jenc->dev_mutex);
+}
+
+static const struct v4l2_m2m_ops qcom_jpeg_v4l2_m2m_ops = {
+ .device_run = mop_jpeg_m2m_job_run,
+ .job_abort = mop_jpeg_m2m_job_abort,
+};
+
+static int iop_jpeg_querycap(struct file *file, void *priv, struct v4l2_capability *cap)
+{
+ strscpy(cap->driver, QCOM_JPEG_ENC_NAME, sizeof(cap->driver));
+ strscpy(cap->card, QCOM_JPEG_ENC_NAME, sizeof(cap->card));
+ snprintf(cap->bus_info, sizeof(cap->bus_info), "platform:%s", QCOM_JPEG_ENC_NAME);
+
+ return 0;
+}
+
+static int iop_jpeg_enum_fmt_vid_dst(struct file *file, void *priv, struct v4l2_fmtdesc *f)
+{
+ struct jenc_context *ectx = jpeg_file2ctx(file);
+
+ if (jpeg_is_invalid_dst(ectx, f->type))
+ return -EINVAL;
+
+ return jpeg_enum_fmt_dst(f);
+}
+
+static int iop_jpeg_enum_framesizes(struct file *file, void *priv, struct v4l2_frmsizeenum *fsize)
+{
+ const struct jenc_enc_format *efmt;
+
+ if (fsize->index != 0)
+ return -EINVAL;
+
+ efmt = jpeg_find_pix_format(JENC_SRC_QUEUE, fsize->pixel_format);
+ if (efmt) {
+ fsize->type = jpeg_def_frmsize.type;
+ fsize->stepwise = jpeg_def_frmsize.stepwise;
+ return 0;
+ }
+
+ efmt = jpeg_find_pix_format(JENC_DST_QUEUE, fsize->pixel_format);
+ if (efmt) {
+ fsize->type = jpeg_def_frmsize.type;
+ fsize->stepwise = jpeg_def_frmsize.stepwise;
+ return 0;
+ }
+
+ return -EINVAL;
+}
+
+static int iop_jpeg_enum_fmt_vid_src(struct file *file, void *priv, struct v4l2_fmtdesc *f)
+{
+ struct jenc_context *ectx = jpeg_file2ctx(file);
+
+ if (jpeg_is_invalid_src(ectx, f->type))
+ return -EINVAL;
+
+ return jpeg_enum_fmt_src(f);
+}
+
+static int iop_jpeg_get_fmt_vid_dst(struct file *file, void *priv, struct v4l2_format *f)
+{
+ struct jenc_context *ectx = jpeg_file2ctx(file);
+
+ if (jpeg_is_invalid_dst(ectx, f->type))
+ return -EINVAL;
+
+ jpeg_v4l2_get_format(ectx, f);
+
+ return 0;
+}
+
+static int iop_jpeg_try_fmt_vid_dst(struct file *file, void *priv, struct v4l2_format *f)
+{
+ struct jenc_context *ectx = jpeg_file2ctx(file);
+
+ if (jpeg_is_invalid_dst(ectx, f->type))
+ return -EINVAL;
+
+ return jpeg_v4l2_try_format(ectx, f);
+}
+
+static int iop_jpeg_set_fmt_vid_dst(struct file *file, void *priv, struct v4l2_format *f)
+{
+ struct jenc_context *ectx = jpeg_file2ctx(file);
+
+ if (jpeg_is_invalid_dst(ectx, f->type))
+ return -EINVAL;
+
+ return jpeg_v4l2_set_format(ectx, f);
+}
+
+static int iop_jpeg_get_fmt_vid_src(struct file *file, void *priv, struct v4l2_format *f)
+{
+ struct jenc_context *ectx = jpeg_file2ctx(file);
+
+ if (jpeg_is_invalid_src(ectx, f->type))
+ return -EINVAL;
+
+ jpeg_v4l2_get_format(ectx, f);
+
+ return 0;
+}
+
+static int iop_jpeg_try_fmt_vid_src(struct file *file, void *priv, struct v4l2_format *f)
+{
+ struct jenc_context *ectx = jpeg_file2ctx(file);
+
+ if (jpeg_is_invalid_src(ectx, f->type))
+ return -EINVAL;
+
+ return jpeg_v4l2_try_format(ectx, f);
+}
+
+static int iop_jpeg_set_fmt_vid_src(struct file *file, void *priv, struct v4l2_format *f)
+{
+ struct jenc_context *ectx = jpeg_file2ctx(file);
+
+ if (jpeg_is_invalid_src(ectx, f->type))
+ return -EINVAL;
+
+ return jpeg_v4l2_set_format(ectx, f);
+}
+
+static int iop_jpeg_encoder_command(struct file *file, void *priv, struct v4l2_encoder_cmd *ec)
+{
+ struct jenc_context *ectx = jpeg_file2ctx(file);
+ struct vb2_queue *vq;
+
+ if (ec->cmd == V4L2_ENC_CMD_STOP) {
+ vq = v4l2_m2m_get_src_vq(ectx->fh.m2m_ctx);
+ if (!vb2_is_streaming(vq))
+ return 0;
+
+ vq = v4l2_m2m_get_dst_vq(ectx->fh.m2m_ctx);
+ if (!vb2_is_streaming(vq))
+ return 0;
+
+ mutex_lock(&ectx->stop_lock);
+ ectx->is_stopping = true;
+ mutex_unlock(&ectx->stop_lock);
+ jpeg_v4l2_work_stop(ectx->jenc, ectx, VB2_BUF_STATE_ERROR);
+
+ return 0;
+ }
+
+ return v4l2_m2m_ioctl_encoder_cmd(file, priv, ec);
+}
+
+static const struct v4l2_ioctl_ops qcom_jpeg_v4l2_ioctl_ops = {
+ .vidioc_querycap = iop_jpeg_querycap,
+ .vidioc_enum_fmt_vid_cap = iop_jpeg_enum_fmt_vid_dst,
+ .vidioc_enum_fmt_vid_out = iop_jpeg_enum_fmt_vid_src,
+ .vidioc_enum_framesizes = iop_jpeg_enum_framesizes,
+
+ .vidioc_g_fmt_vid_cap_mplane = iop_jpeg_get_fmt_vid_dst,
+ .vidioc_try_fmt_vid_cap_mplane = iop_jpeg_try_fmt_vid_dst,
+ .vidioc_s_fmt_vid_cap_mplane = iop_jpeg_set_fmt_vid_dst,
+ .vidioc_g_fmt_vid_out_mplane = iop_jpeg_get_fmt_vid_src,
+ .vidioc_try_fmt_vid_out_mplane = iop_jpeg_try_fmt_vid_src,
+ .vidioc_s_fmt_vid_out_mplane = iop_jpeg_set_fmt_vid_src,
+
+ .vidioc_reqbufs = v4l2_m2m_ioctl_reqbufs,
+ .vidioc_querybuf = v4l2_m2m_ioctl_querybuf,
+ .vidioc_prepare_buf = v4l2_m2m_ioctl_prepare_buf,
+ .vidioc_create_bufs = v4l2_m2m_ioctl_create_bufs,
+ .vidioc_streamon = v4l2_m2m_ioctl_streamon,
+ .vidioc_streamoff = v4l2_m2m_ioctl_streamoff,
+ .vidioc_qbuf = v4l2_m2m_ioctl_qbuf,
+ .vidioc_dqbuf = v4l2_m2m_ioctl_dqbuf,
+ .vidioc_expbuf = v4l2_m2m_ioctl_expbuf,
+
+ .vidioc_subscribe_event = v4l2_ctrl_subscribe_event,
+ .vidioc_unsubscribe_event = v4l2_event_unsubscribe,
+
+ .vidioc_encoder_cmd = iop_jpeg_encoder_command,
+ .vidioc_try_encoder_cmd = v4l2_m2m_ioctl_try_encoder_cmd,
+};
+
+static int jpeg_v4l2_init_queue(void *priv, struct vb2_queue *sq, struct vb2_queue *dq)
+{
+ struct jenc_context *ectx = priv;
+ int rc;
+
+ sq->drv_priv = ectx;
+ sq->dev = ectx->dev;
+ sq->type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
+ sq->io_modes = VB2_MMAP | VB2_DMABUF | VB2_USERPTR;
+ sq->buf_struct_size = sizeof(struct v4l2_m2m_buffer);
+ sq->ops = &qcom_jpeg_v4l2_vb2_ops;
+ sq->mem_ops = &vb2_dma_sg_memops;
+ sq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY;
+ sq->lock = &ectx->ctx_lock;
+ sq->min_queued_buffers = 1;
+
+ rc = vb2_queue_init(sq);
+ if (rc)
+ return rc;
+
+ dq->drv_priv = ectx;
+ dq->dev = ectx->dev;
+ dq->type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
+ dq->io_modes = VB2_MMAP | VB2_DMABUF | VB2_USERPTR;
+ dq->buf_struct_size = sizeof(struct v4l2_m2m_buffer);
+ dq->ops = &qcom_jpeg_v4l2_vb2_ops;
+ dq->mem_ops = &vb2_dma_sg_memops;
+ dq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY;
+ dq->lock = &ectx->ctx_lock;
+ dq->min_queued_buffers = 1;
+
+ rc = vb2_queue_init(dq);
+ if (rc) {
+ vb2_queue_release(sq);
+ return rc;
+ }
+
+ return 0;
+}
+
+static int fop_jpeg_file_open(struct file *file)
+{
+ struct video_device *vdev = video_devdata(file);
+ struct qcom_jenc_dev *jenc = video_drvdata(file);
+ struct jenc_context *ectx;
+ int rc;
+
+ ectx = kzalloc(sizeof(*ectx), GFP_KERNEL);
+ if (!ectx)
+ return -ENOMEM;
+
+ ectx->dev = jenc->dev;
+ ectx->jenc = jenc;
+
+ mutex_init(&ectx->ctx_lock);
+ mutex_init(&ectx->quality_mutex);
+ mutex_init(&ectx->stop_lock);
+
+ rc = jpeg_v4l2_set_defaults(ectx);
+ if (rc)
+ goto err_unlock_free;
+
+ v4l2_fh_init(&ectx->fh, vdev);
+ v4l2_fh_add(&ectx->fh, file);
+
+ v4l2_ctrl_handler_init(&ectx->ctrl_hdl, 1);
+ ectx->quality_ctl = v4l2_ctrl_new_std(&ectx->ctrl_hdl,
+ &qcom_jpeg_v4l2_ctrl_ops,
+ V4L2_CID_JPEG_COMPRESSION_QUALITY,
+ QCOM_JPEG_QUALITY_MIN,
+ QCOM_JPEG_QUALITY_MAX,
+ QCOM_JPEG_QUALITY_UNT,
+ QCOM_JPEG_QUALITY_DEF);
+ if (ectx->ctrl_hdl.error) {
+ rc = ectx->ctrl_hdl.error;
+ goto err_fh_exit;
+ }
+
+ ectx->fh.ctrl_handler = &ectx->ctrl_hdl;
+
+ rc = v4l2_ctrl_handler_setup(&ectx->ctrl_hdl);
+ if (rc)
+ goto err_ctrl_handler_free;
+
+ ectx->fh.m2m_ctx = v4l2_m2m_ctx_init(jenc->m2m_dev, ectx, &jpeg_v4l2_init_queue);
+ if (IS_ERR(ectx->fh.m2m_ctx)) {
+ rc = PTR_ERR(ectx->fh.m2m_ctx);
+ goto err_ctrl_handler_free;
+ }
+
+ return 0;
+
+err_ctrl_handler_free:
+ v4l2_ctrl_handler_free(&ectx->ctrl_hdl);
+err_fh_exit:
+ v4l2_fh_del(&ectx->fh, file);
+ v4l2_fh_exit(&ectx->fh);
+err_unlock_free:
+
+ kfree(ectx);
+
+ return rc;
+}
+
+static int fop_jpeg_file_release(struct file *file)
+{
+ struct jenc_context *ectx = jpeg_file2ctx(file);
+
+ v4l2_m2m_ctx_release(ectx->fh.m2m_ctx);
+ v4l2_ctrl_handler_free(&ectx->ctrl_hdl);
+ v4l2_fh_del(&ectx->fh, file);
+ v4l2_fh_exit(&ectx->fh);
+ kfree(ectx);
+
+ return 0;
+}
+
+static const struct v4l2_file_operations qcom_jpeg_v4l2_file_ops = {
+ .owner = THIS_MODULE,
+ .open = fop_jpeg_file_open,
+ .release = fop_jpeg_file_release,
+ .poll = v4l2_m2m_fop_poll,
+ .mmap = v4l2_m2m_fop_mmap,
+ .unlocked_ioctl = video_ioctl2,
+};
+
+int qcom_jpeg_v4l2_register(struct qcom_jenc_dev *jenc)
+{
+ int rc;
+
+ mutex_lock(&jenc->dev_mutex);
+
+ jenc->enc_hw_irq_cb = jpeg_v4l2_process_cb;
+
+ jenc->m2m_dev = v4l2_m2m_init(&qcom_jpeg_v4l2_m2m_ops);
+ if (IS_ERR(jenc->m2m_dev)) {
+ dev_err(jenc->dev, "failed to init mem2mem device\n");
+ rc = PTR_ERR(jenc->m2m_dev);
+ goto err_mutex_unlock;
+ }
+
+ jenc->vdev = video_device_alloc();
+ if (!jenc->vdev) {
+ rc = -ENOMEM;
+ goto err_video_device_release;
+ }
+
+ snprintf(jenc->vdev->name, sizeof(jenc->vdev->name), "%s", QCOM_JPEG_ENC_NAME);
+ jenc->vdev->fops = &qcom_jpeg_v4l2_file_ops;
+ jenc->vdev->ioctl_ops = &qcom_jpeg_v4l2_ioctl_ops;
+ jenc->vdev->minor = -1;
+ jenc->vdev->release = video_device_release;
+ jenc->vdev->lock = &jenc->dev_mutex;
+ jenc->vdev->v4l2_dev = &jenc->v4l2_dev;
+ jenc->vdev->vfl_dir = VFL_DIR_M2M;
+ jenc->vdev->device_caps = V4L2_CAP_STREAMING | V4L2_CAP_VIDEO_M2M_MPLANE;
+
+ rc = video_register_device(jenc->vdev, VFL_TYPE_VIDEO, -1);
+ if (rc) {
+ dev_err(jenc->dev, "failed to register video device\n");
+ goto err_video_device_release;
+ }
+
+ video_set_drvdata(jenc->vdev, jenc);
+
+ mutex_unlock(&jenc->dev_mutex);
+
+ dev_info(jenc->dev, "device registered as /dev/video%d\n", jenc->vdev->num);
+
+ return rc;
+
+err_video_device_release:
+ if (jenc->vdev)
+ video_device_release(jenc->vdev);
+ v4l2_m2m_release(jenc->m2m_dev);
+err_mutex_unlock:
+ mutex_unlock(&jenc->dev_mutex);
+
+ return rc;
+}
+
+void qcom_jpeg_v4l2_unregister(struct qcom_jenc_dev *jenc)
+{
+ mutex_lock(&jenc->dev_mutex);
+
+ video_unregister_device(jenc->vdev);
+
+ v4l2_m2m_release(jenc->m2m_dev);
+
+ mutex_unlock(&jenc->dev_mutex);
+}
diff --git a/drivers/media/platform/qcom/jpeg/qcom_jenc_v4l2.h b/drivers/media/platform/qcom/jpeg/qcom_jenc_v4l2.h
new file mode 100644
index 000000000000..0305d2911717
--- /dev/null
+++ b/drivers/media/platform/qcom/jpeg/qcom_jenc_v4l2.h
@@ -0,0 +1,27 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
+ */
+
+#ifndef QCOM_JENC_V4L2_H
+#define QCOM_JENC_V4L2_H
+
+#include <linux/types.h>
+#include <linux/videodev2.h>
+
+#include <media/v4l2-device.h>
+#include <media/videobuf2-v4l2.h>
+#include <media/videobuf2-dma-contig.h>
+#include <media/v4l2-dev.h>
+#include <media/v4l2-ioctl.h>
+#include <media/v4l2-ctrls.h>
+
+struct qcom_jenc_dev;
+
+struct jenc_context;
+
+int qcom_jpeg_v4l2_register(struct qcom_jenc_dev *jenc);
+
+void qcom_jpeg_v4l2_unregister(struct qcom_jenc_dev *jenc);
+
+#endif /* QCOM_JENC_V4L2_H */
diff --git a/drivers/media/platform/qcom/jpeg/qcom_v165_jenc_hw_info.h b/drivers/media/platform/qcom/jpeg/qcom_v165_jenc_hw_info.h
new file mode 100644
index 000000000000..16e4eae04d5f
--- /dev/null
+++ b/drivers/media/platform/qcom/jpeg/qcom_v165_jenc_hw_info.h
@@ -0,0 +1,509 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
+ */
+
+#ifndef QCOM_JENC_HW_INFO_V165_H
+#define QCOM_JENC_HW_INFO_V165_H
+
+#include "qcom_jenc_defs.h"
+
+#define JPEG_V165_HW_VER_STEP_POS 0
+#define JPEG_V165_HW_VER_STEP_MSK \
+ (0xffff << JPEG_V165_HW_VER_STEP_POS)
+
+#define JPEG_V165_HW_VER_MINOR_POS 16
+#define JPEG_V165_HW_VER_MINOR_MSK \
+ (0x0fff << JPEG_V165_HW_VER_MINOR_POS)
+
+#define JPEG_V165_HW_VER_MAJOR_POS 28
+#define JPEG_V165_HW_VER_MAJOR_MSK \
+ (0xf << JPEG_V165_HW_VER_MAJOR_POS)
+
+#define JPEG_V165_HW_CAP_ENCODE_MSK BIT(0)
+#define JPEG_V165_HW_CAP_DECODE_MSK BIT(1)
+
+#define JPEG_V165_HW_CAP_UPSCALE_POS 4
+#define JPEG_V165_HW_CAP_UPSCALE_MSK \
+ (0x7 << JPEG_V165_HW_CAP_UPSCALE_POS)
+
+#define JPEG_V165_HW_CAP_DOWNSCALE_POS 8
+#define JPEG_V165_HW_CAP_DOWNSCALE_MSK \
+ (0x7 << JPEG_V165_HW_CAP_DOWNSCALE_POS)
+
+#define JPEG_V165_RST_CMD_FE_RESET_MSK BIT(0)
+#define JPEG_V165_RST_CMD_WE_RESET_MSK BIT(1)
+#define JPEG_V165_RST_CMD_ENCODER_RESET_MSK BIT(4)
+#define JPEG_V165_RST_CMD_DECODER_RESET_MSK BIT(5)
+#define JPEG_V165_RST_CMD_BLOCK_FORMATTER_RST_MSK BIT(6)
+#define JPEG_V165_RST_CMD_SCALE_RESET_MSK BIT(7)
+#define JPEG_V165_RST_CMD_REGISTER_RESET_MSK BIT(13)
+#define JPEG_V165_RST_CMD_MISR_RESET_MSK BIT(16)
+#define JPEG_V165_RST_CMD_CORE_RESET_MSK BIT(17)
+#define JPEG_V165_RST_CMD_JPEG_V165_DOMAIN_RESET_MSK BIT(29)
+#define JPEG_V165_RST_CMD_RESET_BYPASS_MSK BIT(31)
+
+#define JPEG_V165_CORE_CFG_FE_ENABLE_MSK BIT(0)
+#define JPEG_V165_CORE_CFG_WE_ENABLE_MSK BIT(1)
+#define JPEG_V165_CORE_CFG_ENC_ENABLE_MSK BIT(4)
+#define JPEG_V165_CORE_CFG_SCALE_ENABLE_MSK BIT(7)
+#define JPEG_V165_CORE_CFG_TESTBUS_ENABLE_MSK BIT(19)
+#define JPEG_V165_CORE_CFG_MODE_MSK BIT(24)
+#define JPEG_V165_CORE_CFG_CGC_DISABLE_MSK BIT(31)
+
+#define JPEG_V165_CMD_HW_START_MSK BIT(0)
+#define JPEG_V165_CMD_HW_STOP_MSK BIT(1)
+#define JPEG_V165_CMD_CLR_RD_PLN0_QUEUE_MSK BIT(4)
+#define JPEG_V165_CMD_CLR_RD_PLN1_QUEUE_MSK BIT(5)
+#define JPEG_V165_CMD_CLR_RD_PLN2_QUEUE_MSK BIT(6)
+#define JPEG_V165_CMD_CLR_WR_PLN0_QUEUE_MSK BIT(8)
+#define JPEG_V165_CMD_CLR_WR_PLN1_QUEUE_MSK BIT(9)
+#define JPEG_V165_CMD_CLR_WR_PLN2_QUEUE_MSK BIT(10)
+#define JPEG_V165_CMD_APPLY_SWC_RD_PARAMS_MSK BIT(11)
+
+#define JPEG_V165_CORE_STATE_STATUS_ENCODE_STATE_MSK BIT(0)
+#define JPEG_V165_CORE_STATE_STATUS_SCALE_STATE_MSK BIT(2)
+#define JPEG_V165_CORE_STATE_STATUS_REALTIME_STATE_MSK BIT(4)
+#define JPEG_V165_CORE_STATE_STATUS_BUS_STATE_MSK BIT(8)
+#define JPEG_V165_CORE_STATE_STATUS_CGC_STATE_MSK BIT(9)
+
+#define JPEG_V165_FE_CFG_BYTE_ORDERING_POS 0
+#define JPEG_V165_FE_CFG_BYTE_ORDERING_MSK \
+ (0xf << JPEG_V165_FE_CFG_BYTE_ORDERING_POS)
+
+#define JPEG_V165_FE_CFG_BURST_LENGTH_MAX_POS 4
+#define JPEG_V165_FE_CFG_BURST_LENGTH_MAX_MSK \
+ (0xf << JPEG_V165_WE_CFG_BURST_LENGTH_MAX_POS)
+
+#define JPEG_V165_FE_CFG_MEMORY_FORMAT_POS 8
+#define JPEG_V165_FE_CFG_MEMORY_FORMAT_MSK \
+ (0x3 << JPEG_V165_WE_CFG_MEMORY_FORMAT_POS)
+
+#define JPEG_V165_FE_CFG_CBCR_ORDER_MSK BIT(12)
+#define JPEG_V165_FE_CFG_BOTTOM_VPAD_EN_MSK BIT(13)
+#define JPEG_V165_FE_CFG_PLN0_EN_MSK BIT(16)
+#define JPEG_V165_FE_CFG_PLN1_EN_MSK BIT(17)
+#define JPEG_V165_FE_CFG_PLN2_EN_MSK BIT(18)
+#define JPEG_V165_FE_CFG_SIXTEEN_MCU_EN_MSK BIT(21)
+#define JPEG_V165_FE_CFG_MCUS_PER_BLOCK_MSK BIT(22)
+#define JPEG_V165_FE_CFG_MAL_BOUNDARY_MSK BIT(24)
+#define JPEG_V165_FE_CFG_MAL_EN_MSK BIT(27)
+
+#define JPEG_V165_PLN_RD_OFFS_OFFSET_POS 0
+#define JPEG_V165_PLN_RD_OFFS_OFFSET_MSK \
+ (0x1fffffff << JPEG_V165_PLN_RD_OFFS_OFFSET_POS)
+
+#define JPEG_V165_PLN_RD_BUFF_SIZE_WIDTH_POS 0
+#define JPEG_V165_PLN_RD_BUFF_SIZE_WIDTH_MSK \
+ (0xffff << JPEG_V165_PLN_RD_BUFF_SIZE_WIDTH_POS)
+
+#define JPEG_V165_PLN_RD_BUFF_SIZE_HEIGHT_POS 16
+#define JPEG_V165_PLN_RD_BUFF_SIZE_HEIGHT_MSK \
+ (0xffff << JPEG_V165_PLN_RD_BUFF_SIZE_HEIGHT_POS)
+
+#define JPEG_V165_PLN_RD_STRIDE_STRIDE_POS 0
+#define JPEG_V165_PLN_RD_STRIDE_STRIDE_MSK \
+ (0xffff << JPEG_V165_PLN_RD_STRIDE_STRIDE_POS)
+
+#define JPEG_V165_PLN_RD_HINIT_FRACTIONAL_POS 0
+#define JPEG_V165_PLN_RD_HINIT_FRACTIONAL_MSK \
+ (0x1fffff << JPEG_V165_PLN_RD_HINIT_FRACTIONAL_POS)
+
+#define JPEG_V165_PLN_RD_VINIT_FRACTIONAL_POS 0
+#define JPEG_V165_PLN_RD_VINIT_FRACTIONAL_MSK \
+ (0x1fffff << JPEG_V165_PLN_RD_VINIT_FRACTIONAL_POS)
+
+#define JPEG_V165_WE_CFG_BYTE_ORDERING_POS 0
+#define JPEG_V165_WE_CFG_BYTE_ORDERING_MSK \
+ (0xf << JPEG_V165_WE_CFG_BYTE_ORDERING_POS)
+
+#define JPEG_V165_WE_CFG_BURST_LENGTH_MAX_POS 4
+#define JPEG_V165_WE_CFG_BURST_LENGTH_MAX_MSK \
+ (0xf << JPEG_V165_WE_CFG_BURST_LENGTH_MAX_POS)
+
+#define JPEG_V165_WE_CFG_MEMORY_FORMAT_POS 8
+#define JPEG_V165_WE_CFG_MEMORY_FORMAT_MSK \
+ (0x3 << JPEG_V165_WE_CFG_MEMORY_FORMAT_POS)
+
+#define JPEG_V165_WE_CFG_CBCR_ORDER_MSK BIT(12)
+#define JPEG_V165_WE_CFG_PLN0_EN_MSK BIT(16)
+#define JPEG_V165_WE_CFG_PLN1_EN_MSK BIT(17)
+#define JPEG_V165_WE_CFG_PLN2_EN_MSK BIT(18)
+#define JPEG_V165_WE_CFG_MAL_BOUNDARY_MSK BIT(24)
+#define JPEG_V165_WE_CFG_MAL_EN_MSK BIT(27)
+#define JPEG_V165_WE_CFG_POP_BUFF_ON_EOS_MSK BIT(28)
+
+#define JPEG_V165_PLN_WR_BUFF_SIZE_WIDTH_POS 0
+#define JPEG_V165_PLN_WR_BUFF_SIZE_WIDTH_MSK \
+ (0xffff << JPEG_V165_PLN_WR_BUFF_SIZE_WIDTH_POS)
+
+#define JPEG_V165_PLN_WR_BUFF_SIZE_HEIGHT_POS 16
+#define JPEG_V165_PLN_WR_BUFF_SIZE_HEIGHT_MSK \
+ (0xffff << JPEG_V165_PLN_WR_BUFF_SIZE_HEIGHT_POS)
+
+#define JPEG_V165_PLN_WR_STRIDE_STRIDE_POS 0
+#define JPEG_V165_PLN_WR_STRIDE_STRIDE_MSK \
+ (0xffff << JPEG_V165_PLN_WR_STRIDE_STRIDE_POS)
+
+#define JPEG_V165_PLN_WR_HINIT_INTEGER_POS 0
+#define JPEG_V165_PLN_WR_HINIT_INTEGER_MSK \
+ (0xffff << JPEG_V165_PLN_WR_HINIT_INTEGER_POS)
+
+#define JPEG_V165_PLN_WR_VINIT_INTEGER_POS 0
+#define JPEG_V165_PLN_WR_VINIT_INTEGER_MSK \
+ (0xffff << JPEG_V165_PLN_WR_VINIT_INTEGER_POS)
+
+#define JPEG_V165_PLN_WR_HSTEP_INTEGER_POS 0
+#define JPEG_V165_PLN_WR_HSTEP_INTEGER_MSK \
+ (0x1ffff << JPEG_V165_PLN_WR_HSTEP_INTEGER_POS)
+
+#define JPEG_V165_PLN_WR_VSTEP_INTEGER_POS 0
+#define JPEG_V165_PLN_WR_VSTEP_INTEGER_MSK \
+ (0x1ffff << JPEG_V165_PLN_WR_VSTEP_INTEGER_POS)
+
+#define JPEG_V165_PLN_WR_BLK_CFG_BLOCKS_PER_COL_POS 0
+#define JPEG_V165_PLN_WR_BLK_CFG_BLOCKS_PER_COL_MSK \
+ (0xffff << JPEG_V165_PLN_WR_BLK_CFG_BLOCKS_PER_COL_POS)
+
+#define JPEG_V165_PLN_WR_BLK_CFG_BLOCKS_PER_ROW_POS 16
+#define JPEG_V165_PLN_WR_BLK_CFG_BLOCKS_PER_ROW_MSK \
+ (0xffff << JPEG_V165_PLN_WR_BLK_CFG_BLOCKS_PER_ROW_POS)
+
+#define JPEG_V165_ENC_CFG_IMAGE_FORMAT_POS 0
+#define JPEG_V165_ENC_CFG_IMAGE_FORMAT_MSK \
+ (0x7 << JPEG_V165_ENC_CFG_IMAGE_FORMAT_POS)
+
+#define JPEG_V165_ENC_CFG_APPLY_EOI_MSK BIT(7)
+#define JPEG_V165_ENC_CFG_HUFFMAN_SEL_MSK BIT(8)
+#define JPEG_V165_ENC_CFG_FSC_ENABLE_MSK BIT(11)
+#define JPEG_V165_ENC_CFG_OUTPUT_DISABLE_MSK BIT(15)
+#define JPEG_V165_ENC_CFG_RST_MARKER_PERIOD_MSK BIT(16)
+
+#define JPEG_V165_ENC_IMG_SIZE_ENCODE_WIDTH_POS 0u
+#define JPEG_V165_ENC_IMG_SIZE_ENCODE_WIDTH_MSK \
+ (0x1fffu << JPEG_V165_ENC_IMG_SIZE_ENCODE_WIDTH_POS)
+
+#define JPEG_V165_ENC_IMG_SIZE_ENCODE_HEIGHT_POS 16u
+#define JPEG_V165_ENC_IMG_SIZE_ENCODE_HEIGHT_MSK \
+ (0x1fffu << JPEG_V165_ENC_IMG_SIZE_ENCODE_HEIGHT_POS)
+
+#define JPEG_V165_OUTPUT_SIZE_STATUS_OUT_SIZE_BYTES_POS 0
+#define JPEG_V165_OUTPUT_SIZE_STATUS_OUT_SIZE_BYTES_MSK \
+ (0x1fffffff << JPEG_V165_OUTPUT_SIZE_STATUS_OUT_SIZE_BYTES_POS)
+
+#define JPEG_V165_SCALE_CFG_HSCALE_ENABLE_MSK BIT(4)
+#define JPEG_V165_SCALE_CFG_VSCALE_ENABLE_MSK BIT(5)
+#define JPEG_V165_SCALE_CFG_UPSAMPLE_EN_MSK BIT(6)
+#define JPEG_V165_SCALE_CFG_SUBSAMPLE_EN_MSK BIT(7)
+#define JPEG_V165_SCALE_CFG_HSCALE_ALGO_MSK BIT(8)
+#define JPEG_V165_SCALE_CFG_VSCALE_ALGO_MSK BIT(9)
+
+#define JPEG_V165_SCALE_CFG_H_SCALE_FIR_ALGO_POS 12u
+#define JPEG_V165_SCALE_CFG_H_SCALE_FIR_ALGO_MSK \
+ (0x3u << JPEG_V165_SCALE_CFG_H_SCALE_FIR_ALGO_POS)
+
+#define JPEG_V165_SCALE_CFG_V_SCALE_FIR_ALGO_POS 16u
+#define JPEG_V165_SCALE_CFG_V_SCALE_FIR_ALGO_MSK \
+ (0x3u << JPEG_V165_SCALE_CFG_V_SCALE_FIR_ALGO_POS)
+
+#define JPEG_V165_SCALE_OUT_CFG_BLOCK_WIDTH_POS 0
+#define JPEG_V165_SCALE_OUT_CFG_BLOCK_WIDTH_MSK \
+ (0xff << JPEG_V165_SCALE_OUT_CFG_BLOCK_WIDTH_POS)
+
+#define JPEG_V165_SCALE_OUT_CFG_BLOCK_HEIGHT_POS 16
+#define JPEG_V165_SCALE_OUT_CFG_BLOCK_HEIGHT_MSK \
+ (0xf << JPEG_V165_SCALE_OUT_CFG_BLOCK_HEIGHT_POS)
+
+#define JPEG_V165_SCALE_PLN_HSTEP_FRACTIONAL_POS 0
+#define JPEG_V165_SCALE_PLN_HSTEP_FRACTIONAL_MSK \
+ (0x1fffff << JPEG_V165_SCALE_PLN_HSTEP_FRACTIONAL_POS)
+
+#define JPEG_V165_SCALE_PLN_HSTEP_INTEGER_POS 21
+#define JPEG_V165_SCALE_PLN_HSTEP_INTEGER_MSK \
+ (0x3f << JPEG_V165_SCALE_PLN_HSTEP_INTEGER_POS)
+
+#define JPEG_V165_SCALE_PLN_VSTEP_FRACTIONAL_POS 0
+#define JPEG_V165_SCALE_PLN_VSTEP_FRACTIONAL_MSK \
+ (0x1fffff << JPEG_V165_SCALE_PLN_VSTEP_FRACTIONAL_POS)
+
+#define JPEG_V165_SCALE_PLN_VSTEP_INTEGER_POS 21
+#define JPEG_V165_SCALE_PLN_VSTEP_INTEGER_MSK \
+ (0x3f << JPEG_V165_SCALE_PLN_VSTEP_INTEGER_POS)
+
+#define JPEG_V165_DMI_CFG_MEM_SEL_POS 0
+#define JPEG_V165_DMI_CFG_MEM_SEL_MSK \
+ (0x7 << JPEG_V165_DMI_CFG_MEM_SEL_POS)
+
+#define JPEG_V165_DMI_CFG_AUTO_INC_EN_MSK BIT(4)
+
+#define JPEG_V165_DMI_ADDR_ADDR_POS 0
+#define JPEG_V165_DMI_ADDR_ADDR_MSK \
+ (0x3ff << JPEG_V165_DMI_ADDR_ADDR_POS)
+
+#define JPEG_V165_TESTBUS_CFG_BUS_SEL_POS 0
+#define JPEG_V165_TESTBUS_CFG_BUS_SEL_MSK \
+ (0x3f << JPEG_V165_TESTBUS_CFG_BUS_SEL_POS)
+
+#define JPEG_V165_FE_VBPAD_CFG_BLOCK_ROW_POS 0
+#define JPEG_V165_FE_VBPAD_CFG_BLOCK_ROW_MSK \
+ (0x1fff << JPEG_V165_FE_VBPAD_CFG_BLOCK_ROW_POS)
+
+#define JPEG_V165_PLN_RD_HINIT_INT_INTEGER_POS 0
+#define JPEG_V165_PLN_RD_HINIT_INT_INTEGER_MSK \
+ (0x1ffff << JPEG_V165_PLN_RD_HINIT_INT_INTEGER_POS)
+
+#define JPEG_V165_PLN_RD_VINIT_INT_INTEGER_POS 0
+#define JPEG_V165_PLN_RD_VINIT_INT_INTEGER_MSK \
+ (0x1ffff << JPEG_V165_PLN_RD_VINIT_INT_INTEGER_POS)
+
+#define JPEG_V165_IRQ_STATUS_SESSION_DONE_MSK BIT(0)
+#define JPEG_V165_IRQ_STATUS_RD_BUF_PLN0_DONE_MSK BIT(4)
+#define JPEG_V165_IRQ_STATUS_RD_BUF_PLN1_DONE_MSK BIT(5)
+#define JPEG_V165_IRQ_STATUS_RD_BUF_PLN2_DONE_MSK BIT(6)
+#define JPEG_V165_IRQ_STATUS_RD_BUF_PLN0_REQ_ATTN_MSK BIT(7)
+#define JPEG_V165_IRQ_STATUS_RD_BUF_PLN1_REQ_ATTN_MSK BIT(8)
+#define JPEG_V165_IRQ_STATUS_RD_BUF_PLN2_REQ_ATTN_MSK BIT(9)
+#define JPEG_V165_IRQ_STATUS_WR_BUF_PLN0_DONE_MSK BIT(10)
+#define JPEG_V165_IRQ_STATUS_WR_BUF_PLN1_DONE_MSK BIT(11)
+#define JPEG_V165_IRQ_STATUS_WR_BUF_PLN2_DONE_MSK BIT(12)
+#define JPEG_V165_IRQ_STATUS_WR_BUF_PLN0_REQ_ATTN_MSK BIT(13)
+#define JPEG_V165_IRQ_STATUS_WR_BUF_PLN1_REQ_ATTN_MSK BIT(14)
+#define JPEG_V165_IRQ_STATUS_WR_BUF_PLN2_REQ_ATTN_MSK BIT(15)
+#define JPEG_V165_IRQ_STATUS_DCD_UNESCAPED_FF_MSK BIT(19)
+#define JPEG_V165_IRQ_STATUS_DCD_HUFFMAN_ERROR_MSK BIT(20)
+#define JPEG_V165_IRQ_STATUS_DCD_COEFF_ERROR_MSK BIT(21)
+#define JPEG_V165_IRQ_STATUS_DCD_MISSING_BITSTUFF_MSK BIT(22)
+#define JPEG_V165_IRQ_STATUS_DCD_SCAN_UNDERFLOW_MSK BIT(23)
+#define JPEG_V165_IRQ_STATUS_DCD_INVALID_RSM_MSK BIT(24)
+#define JPEG_V165_IRQ_STATUS_DCD_INVALID_RSM_SEQ_MSK BIT(25)
+#define JPEG_V165_IRQ_STATUS_DCD_MISSING_RSM_MSK BIT(26)
+#define JPEG_V165_IRQ_STATUS_STOP_ACK_MSK BIT(27)
+#define JPEG_V165_IRQ_STATUS_RESET_ACK_MSK BIT(28)
+
+#define JPEG_V165_IRQ_STATUS_ENABLE_ALL_MSK ~0
+#define JPEG_V165_IRQ_STATUS_DISABLE_ALL_MSK 0
+#define JPEG_V165_IRQ_STATUS_CLEAR_ALL_MSK JPEG_V165_IRQ_STATUS_ENABLE_ALL_MSK
+
+const u32 qcom_v165_jpeg_hw_reg_mask[] = {
+ [JMSK_HW_VER_STEP] = JPEG_V165_HW_VER_STEP_MSK,
+ [JMSK_HW_VER_MINOR] = JPEG_V165_HW_VER_MINOR_MSK,
+ [JMSK_HW_VER_MAJOR] = JPEG_V165_HW_VER_MAJOR_MSK,
+
+ [JMSK_HW_CAP_ENCODE] = JPEG_V165_HW_CAP_ENCODE_MSK,
+ [JMSK_HW_CAP_DECODE] = JPEG_V165_HW_CAP_DECODE_MSK,
+ [JMSK_HW_CAP_UPSCALE] = JPEG_V165_HW_CAP_UPSCALE_MSK,
+ [JMSK_HW_CAP_DOWNSCALE] = JPEG_V165_HW_CAP_DOWNSCALE_MSK,
+
+ [JMSK_RST_CMD_COMMON] =
+ (JPEG_V165_RST_CMD_FE_RESET_MSK |
+ JPEG_V165_RST_CMD_WE_RESET_MSK |
+ JPEG_V165_RST_CMD_ENCODER_RESET_MSK |
+ JPEG_V165_RST_CMD_BLOCK_FORMATTER_RST_MSK |
+ JPEG_V165_RST_CMD_SCALE_RESET_MSK |
+ JPEG_V165_RST_CMD_REGISTER_RESET_MSK |
+ JPEG_V165_RST_CMD_MISR_RESET_MSK |
+ JPEG_V165_RST_CMD_CORE_RESET_MSK |
+ JPEG_V165_RST_CMD_JPEG_V165_DOMAIN_RESET_MSK),
+
+ [JMSK_RST_CMD_FE_RESET] = JPEG_V165_RST_CMD_FE_RESET_MSK,
+ [JMSK_RST_CMD_WE_RESET] = JPEG_V165_RST_CMD_WE_RESET_MSK,
+ [JMSK_RST_CMD_ENCODER_RESET] = JPEG_V165_RST_CMD_ENCODER_RESET_MSK,
+ [JMSK_RST_CMD_DECODER_RESET] = JPEG_V165_RST_CMD_DECODER_RESET_MSK,
+ [JMSK_RST_CMD_BLOCK_FORMATTER_RST] = JPEG_V165_RST_CMD_BLOCK_FORMATTER_RST_MSK,
+ [JMSK_RST_CMD_SCALE_RESET] = JPEG_V165_RST_CMD_SCALE_RESET_MSK,
+ [JMSK_RST_CMD_REGISTER_RESET] = JPEG_V165_RST_CMD_REGISTER_RESET_MSK,
+ [JMSK_RST_CMD_MISR_RESET] = JPEG_V165_RST_CMD_MISR_RESET_MSK,
+ [JMSK_RST_CMD_CORE_RESET] = JPEG_V165_RST_CMD_CORE_RESET_MSK,
+ [JMSK_RST_CMD_JMSK_DOMAIN_RESET] = JPEG_V165_RST_CMD_JPEG_V165_DOMAIN_RESET_MSK,
+ [JMSK_RST_CMD_RESET_BYPASS] = JPEG_V165_RST_CMD_RESET_BYPASS_MSK,
+
+ [JMSK_CORE_CFG_FE_ENABLE] = JPEG_V165_CORE_CFG_FE_ENABLE_MSK,
+ [JMSK_CORE_CFG_WE_ENABLE] = JPEG_V165_CORE_CFG_WE_ENABLE_MSK,
+ [JMSK_CORE_CFG_ENC_ENABLE] = JPEG_V165_CORE_CFG_ENC_ENABLE_MSK,
+ [JMSK_CORE_CFG_SCALE_ENABLE] = JPEG_V165_CORE_CFG_SCALE_ENABLE_MSK,
+ [JMSK_CORE_CFG_TESTBUS_ENABLE] = JPEG_V165_CORE_CFG_TESTBUS_ENABLE_MSK,
+ [JMSK_CORE_CFG_MODE] = JPEG_V165_CORE_CFG_ENC_ENABLE_MSK,
+ [JMSK_CORE_CFG_CGC_DISABLE] = JPEG_V165_CORE_CFG_CGC_DISABLE_MSK,
+
+ [JMSK_CMD_HW_START] = JPEG_V165_CMD_HW_START_MSK,
+ [JMSK_CMD_HW_STOP] = JPEG_V165_CMD_HW_STOP_MSK,
+
+ [JMSK_CMD_CLR_RD_PLNS_QUEUE] =
+ (JPEG_V165_CMD_CLR_RD_PLN0_QUEUE_MSK |
+ JPEG_V165_CMD_CLR_RD_PLN1_QUEUE_MSK |
+ JPEG_V165_CMD_CLR_RD_PLN2_QUEUE_MSK),
+ [JMSK_CMD_CLR_WR_PLNS_QUEUE] =
+ (JPEG_V165_CMD_CLR_WR_PLN0_QUEUE_MSK |
+ JPEG_V165_CMD_CLR_WR_PLN1_QUEUE_MSK |
+ JPEG_V165_CMD_CLR_WR_PLN2_QUEUE_MSK),
+
+ [JMSK_CMD_APPLY_SWC_RD_PARAMS] = JPEG_V165_CMD_APPLY_SWC_RD_PARAMS_MSK,
+
+ [JMSK_CORE_STATUS_ENCODE_STATE] = JPEG_V165_CORE_STATE_STATUS_ENCODE_STATE_MSK,
+ [JMSK_CORE_STATUS_SCALE_STATE] = JPEG_V165_CORE_STATE_STATUS_SCALE_STATE_MSK,
+ [JMSK_CORE_STATUS_RT_STATE] = JPEG_V165_CORE_STATE_STATUS_REALTIME_STATE_MSK,
+ [JMSK_CORE_STATUS_BUS_STATE] = JPEG_V165_CORE_STATE_STATUS_BUS_STATE_MSK,
+ [JMSK_CORE_STATUS_CGC_STATE] = JPEG_V165_CORE_STATE_STATUS_CGC_STATE_MSK,
+
+ [JMSK_IRQ_ENABLE_ALL] = JPEG_V165_IRQ_STATUS_ENABLE_ALL_MSK,
+ [JMSK_IRQ_DISABLE_ALL] = JPEG_V165_IRQ_STATUS_DISABLE_ALL_MSK,
+ [JMSK_IRQ_CLEAR_ALL] = JPEG_V165_IRQ_STATUS_CLEAR_ALL_MSK,
+
+ [JMSK_IRQ_STATUS_SESSION_DONE] = JPEG_V165_IRQ_STATUS_SESSION_DONE_MSK,
+
+ [JMSK_IRQ_STATUS_RD_BUF_PLN0_DONE] = JPEG_V165_IRQ_STATUS_RD_BUF_PLN0_DONE_MSK,
+ [JMSK_IRQ_STATUS_RD_BUF_PLN1_DONE] = JPEG_V165_IRQ_STATUS_RD_BUF_PLN1_DONE_MSK,
+ [JMSK_IRQ_STATUS_RD_BUF_PLN2_DONE] = JPEG_V165_IRQ_STATUS_RD_BUF_PLN2_DONE_MSK,
+ [JMSK_IRQ_STATUS_RD_BUF_PLNS_ATTN] =
+ (JPEG_V165_IRQ_STATUS_RD_BUF_PLN0_REQ_ATTN_MSK |
+ JPEG_V165_IRQ_STATUS_RD_BUF_PLN1_REQ_ATTN_MSK |
+ JPEG_V165_IRQ_STATUS_RD_BUF_PLN2_REQ_ATTN_MSK),
+
+ [JMSK_IRQ_STATUS_WR_BUF_PLN0_DONE] = JPEG_V165_IRQ_STATUS_WR_BUF_PLN0_DONE_MSK,
+ [JMSK_IRQ_STATUS_WR_BUF_PLN1_DONE] = JPEG_V165_IRQ_STATUS_WR_BUF_PLN1_DONE_MSK,
+ [JMSK_IRQ_STATUS_WR_BUF_PLN2_DONE] = JPEG_V165_IRQ_STATUS_WR_BUF_PLN2_DONE_MSK,
+ [JMSK_IRQ_STATUS_WR_BUF_PLNS_ATTN] =
+ (JPEG_V165_IRQ_STATUS_WR_BUF_PLN0_REQ_ATTN_MSK |
+ JPEG_V165_IRQ_STATUS_WR_BUF_PLN1_REQ_ATTN_MSK |
+ JPEG_V165_IRQ_STATUS_WR_BUF_PLN2_REQ_ATTN_MSK),
+
+ [JMSK_IRQ_STATUS_SESSION_ERROR] =
+ (JPEG_V165_IRQ_STATUS_DCD_UNESCAPED_FF_MSK |
+ JPEG_V165_IRQ_STATUS_DCD_HUFFMAN_ERROR_MSK |
+ JPEG_V165_IRQ_STATUS_DCD_COEFF_ERROR_MSK |
+ JPEG_V165_IRQ_STATUS_DCD_MISSING_BITSTUFF_MSK |
+ JPEG_V165_IRQ_STATUS_DCD_SCAN_UNDERFLOW_MSK |
+ JPEG_V165_IRQ_STATUS_DCD_INVALID_RSM_MSK |
+ JPEG_V165_IRQ_STATUS_DCD_INVALID_RSM_SEQ_MSK |
+ JPEG_V165_IRQ_STATUS_DCD_MISSING_RSM_MSK),
+
+ [JMSK_IRQ_STATUS_STOP_ACK] = JPEG_V165_IRQ_STATUS_STOP_ACK_MSK,
+ [JMSK_IRQ_STATUS_RESET_ACK] = JPEG_V165_IRQ_STATUS_RESET_ACK_MSK,
+
+ [JMSK_FE_CFG_BYTE_ORDERING] = JPEG_V165_FE_CFG_BYTE_ORDERING_MSK,
+ [JMSK_FE_CFG_BURST_LENGTH_MAX] = JPEG_V165_FE_CFG_BURST_LENGTH_MAX_MSK,
+ [JMSK_FE_CFG_MEMORY_FORMAT] = JPEG_V165_FE_CFG_MEMORY_FORMAT_MSK,
+ [JMSK_FE_CFG_CBCR_ORDER] = JPEG_V165_FE_CFG_CBCR_ORDER_MSK,
+ [JMSK_FE_CFG_BOTTOM_VPAD_EN] = JPEG_V165_FE_CFG_BOTTOM_VPAD_EN_MSK,
+ [JMSK_FE_CFG_PLN0_EN] = JPEG_V165_FE_CFG_PLN0_EN_MSK,
+ [JMSK_FE_CFG_PLN1_EN] = JPEG_V165_FE_CFG_PLN1_EN_MSK,
+ [JMSK_FE_CFG_PLN2_EN] = JPEG_V165_FE_CFG_PLN2_EN_MSK,
+ [JMSK_FE_CFG_SIXTEEN_MCU_EN] = JPEG_V165_FE_CFG_SIXTEEN_MCU_EN_MSK,
+ [JMSK_FE_CFG_MCUS_PER_BLOCK] = JPEG_V165_FE_CFG_MCUS_PER_BLOCK_MSK,
+ [JMSK_FE_CFG_MAL_BOUNDARY] = JPEG_V165_FE_CFG_MAL_BOUNDARY_MSK,
+ [JMSK_FE_CFG_MAL_EN] = JPEG_V165_FE_CFG_MAL_EN_MSK,
+
+ [JMSK_FE_VBPAD_CFG_BLOCK_ROW] = JPEG_V165_FE_VBPAD_CFG_BLOCK_ROW_MSK,
+
+ [JMSK_PLNS_RD_OFFSET] = JPEG_V165_PLN_RD_OFFS_OFFSET_MSK,
+ [JMSK_PLNS_RD_BUF_SIZE_WIDTH] = JPEG_V165_PLN_RD_BUFF_SIZE_WIDTH_MSK,
+ [JMSK_PLNS_RD_BUF_SIZE_HEIGHT] = JPEG_V165_PLN_RD_BUFF_SIZE_HEIGHT_MSK,
+ [JMSK_PLNS_RD_STRIDE] = JPEG_V165_PLN_RD_STRIDE_STRIDE_MSK,
+ [JMSK_PLNS_RD_HINIT] = JPEG_V165_PLN_RD_HINIT_FRACTIONAL_MSK,
+ [JMSK_PLNS_RD_VINIT] = JPEG_V165_PLN_RD_VINIT_FRACTIONAL_MSK,
+
+ [JMSK_WE_CFG_BYTE_ORDERING] = JPEG_V165_WE_CFG_BYTE_ORDERING_MSK,
+ [JMSK_WE_CFG_BURST_LENGTH_MAX] = JPEG_V165_WE_CFG_BURST_LENGTH_MAX_MSK,
+ [JMSK_WE_CFG_MEMORY_FORMAT] = JPEG_V165_WE_CFG_MEMORY_FORMAT_MSK,
+ [JMSK_WE_CFG_CBCR_ORDER] = JPEG_V165_WE_CFG_CBCR_ORDER_MSK,
+ [JMSK_WE_CFG_PLN0_EN] = JPEG_V165_WE_CFG_PLN0_EN_MSK,
+ [JMSK_WE_CFG_PLN1_EN] = JPEG_V165_WE_CFG_PLN1_EN_MSK,
+ [JMSK_WE_CFG_PLN2_EN] = JPEG_V165_WE_CFG_PLN2_EN_MSK,
+ [JMSK_WE_CFG_MAL_BOUNDARY] = JPEG_V165_WE_CFG_MAL_BOUNDARY_MSK,
+ [JMSK_WE_CFG_MAL_EN] = JPEG_V165_WE_CFG_MAL_EN_MSK,
+ [JMSK_WE_CFG_POP_BUFF_ON_EOS] = JPEG_V165_WE_CFG_POP_BUFF_ON_EOS_MSK,
+
+ [JMSK_PLNS_WR_BUF_SIZE_WIDTH] = JPEG_V165_PLN_WR_BUFF_SIZE_WIDTH_MSK,
+ [JMSK_PLNS_WR_BUF_SIZE_HEIGHT] = JPEG_V165_PLN_WR_BUFF_SIZE_HEIGHT_MSK,
+
+ [JMSK_PLNS_WR_STRIDE] = JPEG_V165_PLN_WR_STRIDE_STRIDE_MSK,
+ [JMSK_PLNS_WR_HINIT] = JPEG_V165_PLN_WR_HINIT_INTEGER_MSK,
+ [JMSK_PLNS_WR_VINIT] = JPEG_V165_PLN_WR_VINIT_INTEGER_MSK,
+ [JMSK_PLNS_WR_HSTEP] = JPEG_V165_PLN_WR_HSTEP_INTEGER_MSK,
+ [JMSK_PLNS_WR_VSTEP] = JPEG_V165_PLN_WR_VSTEP_INTEGER_MSK,
+
+ [JMSK_PLNS_WR_BLOCK_CFG_PER_COL] = JPEG_V165_PLN_WR_BLK_CFG_BLOCKS_PER_COL_MSK,
+ [JMSK_PLNS_WR_BLOCK_CFG_PER_RAW] = JPEG_V165_PLN_WR_BLK_CFG_BLOCKS_PER_ROW_MSK,
+
+ [JMSK_SCALE_CFG_HSCALE_ENABLE] = JPEG_V165_SCALE_CFG_HSCALE_ENABLE_MSK,
+ [JMSK_SCALE_CFG_VSCALE_ENABLE] = JPEG_V165_SCALE_CFG_VSCALE_ENABLE_MSK,
+ [JMSK_SCALE_CFG_UPSAMPLE_EN] = JPEG_V165_SCALE_CFG_UPSAMPLE_EN_MSK,
+ [JMSK_SCALE_CFG_SUBSAMPLE_EN] = JPEG_V165_SCALE_CFG_SUBSAMPLE_EN_MSK,
+ [JMSK_SCALE_CFG_HSCALE_ALGO] = JPEG_V165_SCALE_CFG_HSCALE_ALGO_MSK,
+ [JMSK_SCALE_CFG_VSCALE_ALGO] = JPEG_V165_SCALE_CFG_VSCALE_ALGO_MSK,
+ [JMSK_SCALE_CFG_H_SCALE_FIR_ALGO] = JPEG_V165_SCALE_CFG_H_SCALE_FIR_ALGO_MSK,
+ [JMSK_SCALE_CFG_V_SCALE_FIR_ALGO] = JPEG_V165_SCALE_CFG_V_SCALE_FIR_ALGO_MSK,
+
+ [JMSK_SCALE_PLNS_OUT_CFG_BLK_WIDTH] = JPEG_V165_SCALE_OUT_CFG_BLOCK_WIDTH_MSK,
+ [JMSK_SCALE_PLNS_OUT_CFG_BLK_HEIGHT] = JPEG_V165_SCALE_OUT_CFG_BLOCK_HEIGHT_MSK,
+
+ [JMSK_SCALE_PLNS_HSTEP_FRACTIONAL] = JPEG_V165_SCALE_PLN_HSTEP_FRACTIONAL_MSK,
+ [JMSK_SCALE_PLNS_HSTEP_INTEGER] = JPEG_V165_SCALE_PLN_HSTEP_INTEGER_MSK,
+ [JMSK_SCALE_PLNS_VSTEP_FRACTIONAL] = JPEG_V165_SCALE_PLN_VSTEP_FRACTIONAL_MSK,
+ [JMSK_SCALE_PLNS_VSTEP_INTEGER] = JPEG_V165_SCALE_PLN_VSTEP_INTEGER_MSK,
+
+ [JMSK_ENC_CFG_IMAGE_FORMAT] = JPEG_V165_ENC_CFG_IMAGE_FORMAT_MSK,
+ [JMSK_ENC_CFG_APPLY_EOI] = JPEG_V165_ENC_CFG_APPLY_EOI_MSK,
+ [JMSK_ENC_CFG_HUFFMAN_SEL] = JPEG_V165_ENC_CFG_HUFFMAN_SEL_MSK,
+ [JMSK_ENC_CFG_FSC_ENABLE] = JPEG_V165_ENC_CFG_FSC_ENABLE_MSK,
+ [JMSK_ENC_CFG_OUTPUT_DISABLE] = JPEG_V165_ENC_CFG_OUTPUT_DISABLE_MSK,
+ [JMSK_ENC_CFG_RST_MARKER_PERIOD] = JPEG_V165_ENC_CFG_RST_MARKER_PERIOD_MSK,
+ [JMSK_ENC_IMAGE_SIZE_WIDTH] = JPEG_V165_ENC_IMG_SIZE_ENCODE_WIDTH_MSK,
+ [JMSK_ENC_IMAGE_SIZE_HEIGHT] = JPEG_V165_ENC_IMG_SIZE_ENCODE_HEIGHT_MSK,
+};
+
+const struct qcom_jpeg_reg_offs qcom_v165_jpeg_hw_reg_offs = {
+ .hw_version = 0x000,
+ .hw_capability = 0x004,
+ .reset_cmd = 0x008,
+ .core_cfg = 0x00c,
+ .hw_cmd = 0x010,
+ .int_mask = 0x018,
+ .int_clr = 0x01c,
+ .int_status = 0x020,
+ .enc_core_state = 0x014,
+
+ .fe = {
+ .pntr = { 0x038, 0x044, 0x050 },
+ .offs = { 0x03c, 0x048, 0x054 },
+ .cnsmd = { 0x040, 0x04c, 0x058 },
+ .bsize = { 0x060, 0x068, 0x070 },
+ .stride = { 0x064, 0x06c, 0x08c },
+ .hinit = { 0x074, 0x078, 0x07c },
+ .vinit = { 0x080, 0x084, 0x088 },
+ .pntr_cnt = 0x05c,
+ .vbpad_cfg = 0x2e8
+ },
+ .fe_cfg = 0x024,
+
+ .we = {
+ .pntr = { 0x0cc, 0x0d0, 0x0d4 },
+ .cnsmd = { 0x0d8, 0x0dc, 0x0e0 },
+ .bsize = { 0x0e8, 0x0ec, 0x0f0 },
+ .stride = { 0x0f4, 0x0f8, 0x0fc },
+ .hinit = { 0x100, 0x104, 0x108 },
+ .hstep = { 0x118, 0x11c, 0x120 },
+ .vinit = { 0x10c, 0x110, 0x114 },
+ .vstep = { 0x124, 0x128, 0x12c },
+ .blocks = { 0x130, 0x134, 0x138 },
+ .pntr_cnt = 0x0e4
+ },
+ .we_cfg = 0x0c0,
+
+ .scale = {
+ .hstep = { 0x27c, 0x280, 0x284 },
+ .vstep = { 0x28c, 0x290, 0x294 },
+ },
+ .scale_cfg = 0x26c,
+ .scale_out_cfg = { 0x270, 0x274, 0x278 },
+
+ .enc_cfg = 0x13c,
+ .enc_img_size = 0x140,
+ .enc_out_size = 0x180,
+
+ .dmi_cfg = 0x298,
+ .dmi_data = 0x2a0,
+ .dmi_addr = 0x29c,
+};
+
+#endif /* QCOM_JENC_HW_INFO_V165_H */
diff --git a/drivers/media/platform/qcom/jpeg/qcom_v580_jenc_hw_info.h b/drivers/media/platform/qcom/jpeg/qcom_v580_jenc_hw_info.h
new file mode 100644
index 000000000000..2fb779530c6c
--- /dev/null
+++ b/drivers/media/platform/qcom/jpeg/qcom_v580_jenc_hw_info.h
@@ -0,0 +1,509 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
+ */
+
+#ifndef QCOM_JENC_HW_INFO_V580_H
+#define QCOM_JENC_HW_INFO_V580_H
+
+#include "qcom_jenc_defs.h"
+
+#define JPEG_V580_HW_VER_STEP_POS 0
+#define JPEG_V580_HW_VER_STEP_MSK \
+ (0xffff << JPEG_V580_HW_VER_STEP_POS)
+
+#define JPEG_V580_HW_VER_MINOR_POS 16
+#define JPEG_V580_HW_VER_MINOR_MSK \
+ (0x0fff << JPEG_V580_HW_VER_MINOR_POS)
+
+#define JPEG_V580_HW_VER_MAJOR_POS 28
+#define JPEG_V580_HW_VER_MAJOR_MSK \
+ (0xf << JPEG_V580_HW_VER_MAJOR_POS)
+
+#define JPEG_V580_HW_CAP_ENCODE_MSK BIT(0)
+#define JPEG_V580_HW_CAP_DECODE_MSK BIT(1)
+
+#define JPEG_V580_HW_CAP_UPSCALE_POS 4
+#define JPEG_V580_HW_CAP_UPSCALE_MSK \
+ (0x7 << JPEG_V580_HW_CAP_UPSCALE_POS)
+
+#define JPEG_V580_HW_CAP_DOWNSCALE_POS 8
+#define JPEG_V580_HW_CAP_DOWNSCALE_MSK \
+ (0x7 << JPEG_V580_HW_CAP_DOWNSCALE_POS)
+
+#define JPEG_V580_RST_CMD_FE_RESET_MSK BIT(0)
+#define JPEG_V580_RST_CMD_WE_RESET_MSK BIT(1)
+#define JPEG_V580_RST_CMD_ENCODER_RESET_MSK BIT(4)
+#define JPEG_V580_RST_CMD_DECODER_RESET_MSK BIT(5)
+#define JPEG_V580_RST_CMD_BLOCK_FORMATTER_RST_MSK BIT(6)
+#define JPEG_V580_RST_CMD_SCALE_RESET_MSK BIT(7)
+#define JPEG_V580_RST_CMD_REGISTER_RESET_MSK BIT(13)
+#define JPEG_V580_RST_CMD_MISR_RESET_MSK BIT(16)
+#define JPEG_V580_RST_CMD_CORE_RESET_MSK BIT(17)
+#define JPEG_V580_RST_CMD_JPEG_V580_DOMAIN_RESET_MSK BIT(29)
+#define JPEG_V580_RST_CMD_RESET_BYPASS_MSK BIT(31)
+
+#define JPEG_V580_CORE_CFG_FE_ENABLE_MSK BIT(0)
+#define JPEG_V580_CORE_CFG_WE_ENABLE_MSK BIT(1)
+#define JPEG_V580_CORE_CFG_ENC_ENABLE_MSK BIT(4)
+#define JPEG_V580_CORE_CFG_SCALE_ENABLE_MSK BIT(7)
+#define JPEG_V580_CORE_CFG_TESTBUS_ENABLE_MSK BIT(19)
+#define JPEG_V580_CORE_CFG_MODE_MSK BIT(24)
+#define JPEG_V580_CORE_CFG_CGC_DISABLE_MSK BIT(31)
+
+#define JPEG_V580_CMD_HW_START_MSK BIT(0)
+#define JPEG_V580_CMD_HW_STOP_MSK BIT(1)
+#define JPEG_V580_CMD_CLR_RD_PLN0_QUEUE_MSK BIT(4)
+#define JPEG_V580_CMD_CLR_RD_PLN1_QUEUE_MSK BIT(5)
+#define JPEG_V580_CMD_CLR_RD_PLN2_QUEUE_MSK BIT(6)
+#define JPEG_V580_CMD_CLR_WR_PLN0_QUEUE_MSK BIT(8)
+#define JPEG_V580_CMD_CLR_WR_PLN1_QUEUE_MSK BIT(9)
+#define JPEG_V580_CMD_CLR_WR_PLN2_QUEUE_MSK BIT(10)
+#define JPEG_V580_CMD_APPLY_SWC_RD_PARAMS_MSK BIT(11)
+
+#define JPEG_V580_CORE_STATE_STATUS_ENCODE_STATE_MSK BIT(0)
+#define JPEG_V580_CORE_STATE_STATUS_SCALE_STATE_MSK BIT(2)
+#define JPEG_V580_CORE_STATE_STATUS_REALTIME_STATE_MSK BIT(4)
+#define JPEG_V580_CORE_STATE_STATUS_BUS_STATE_MSK BIT(8)
+#define JPEG_V580_CORE_STATE_STATUS_CGC_STATE_MSK BIT(9)
+
+#define JPEG_V580_FE_CFG_BYTE_ORDERING_POS 0
+#define JPEG_V580_FE_CFG_BYTE_ORDERING_MSK \
+ (0xf << JPEG_V580_FE_CFG_BYTE_ORDERING_POS)
+
+#define JPEG_V580_FE_CFG_BURST_LENGTH_MAX_POS 4
+#define JPEG_V580_FE_CFG_BURST_LENGTH_MAX_MSK \
+ (0xf << JPEG_V580_WE_CFG_BURST_LENGTH_MAX_POS)
+
+#define JPEG_V580_FE_CFG_MEMORY_FORMAT_POS 8
+#define JPEG_V580_FE_CFG_MEMORY_FORMAT_MSK \
+ (0x3 << JPEG_V580_WE_CFG_MEMORY_FORMAT_POS)
+
+#define JPEG_V580_FE_CFG_CBCR_ORDER_MSK BIT(12)
+#define JPEG_V580_FE_CFG_BOTTOM_VPAD_EN_MSK BIT(13)
+#define JPEG_V580_FE_CFG_PLN0_EN_MSK BIT(16)
+#define JPEG_V580_FE_CFG_PLN1_EN_MSK BIT(17)
+#define JPEG_V580_FE_CFG_PLN2_EN_MSK BIT(18)
+#define JPEG_V580_FE_CFG_SIXTEEN_MCU_EN_MSK BIT(21)
+#define JPEG_V580_FE_CFG_MCUS_PER_BLOCK_MSK BIT(22)
+#define JPEG_V580_FE_CFG_MAL_BOUNDARY_MSK BIT(24)
+#define JPEG_V580_FE_CFG_MAL_EN_MSK BIT(27)
+
+#define JPEG_V580_PLN_RD_OFFS_OFFSET_POS 0
+#define JPEG_V580_PLN_RD_OFFS_OFFSET_MSK \
+ (0x1fffffff << JPEG_V580_PLN_RD_OFFS_OFFSET_POS)
+
+#define JPEG_V580_PLN_RD_BUFF_SIZE_WIDTH_POS 0
+#define JPEG_V580_PLN_RD_BUFF_SIZE_WIDTH_MSK \
+ (0xffff << JPEG_V580_PLN_RD_BUFF_SIZE_WIDTH_POS)
+
+#define JPEG_V580_PLN_RD_BUFF_SIZE_HEIGHT_POS 16
+#define JPEG_V580_PLN_RD_BUFF_SIZE_HEIGHT_MSK \
+ (0xffff << JPEG_V580_PLN_RD_BUFF_SIZE_HEIGHT_POS)
+
+#define JPEG_V580_PLN_RD_STRIDE_STRIDE_POS 0
+#define JPEG_V580_PLN_RD_STRIDE_STRIDE_MSK \
+ (0xffff << JPEG_V580_PLN_RD_STRIDE_STRIDE_POS)
+
+#define JPEG_V580_PLN_RD_HINIT_FRACTIONAL_POS 0
+#define JPEG_V580_PLN_RD_HINIT_FRACTIONAL_MSK \
+ (0x1fffff << JPEG_V580_PLN_RD_HINIT_FRACTIONAL_POS)
+
+#define JPEG_V580_PLN_RD_VINIT_FRACTIONAL_POS 0
+#define JPEG_V580_PLN_RD_VINIT_FRACTIONAL_MSK \
+ (0x1fffff << JPEG_V580_PLN_RD_VINIT_FRACTIONAL_POS)
+
+#define JPEG_V580_WE_CFG_BYTE_ORDERING_POS 0
+#define JPEG_V580_WE_CFG_BYTE_ORDERING_MSK \
+ (0xf << JPEG_V580_WE_CFG_BYTE_ORDERING_POS)
+
+#define JPEG_V580_WE_CFG_BURST_LENGTH_MAX_POS 4
+#define JPEG_V580_WE_CFG_BURST_LENGTH_MAX_MSK \
+ (0xf << JPEG_V580_WE_CFG_BURST_LENGTH_MAX_POS)
+
+#define JPEG_V580_WE_CFG_MEMORY_FORMAT_POS 8
+#define JPEG_V580_WE_CFG_MEMORY_FORMAT_MSK \
+ (0x3 << JPEG_V580_WE_CFG_MEMORY_FORMAT_POS)
+
+#define JPEG_V580_WE_CFG_CBCR_ORDER_MSK BIT(12)
+#define JPEG_V580_WE_CFG_PLN0_EN_MSK BIT(16)
+#define JPEG_V580_WE_CFG_PLN1_EN_MSK BIT(17)
+#define JPEG_V580_WE_CFG_PLN2_EN_MSK BIT(18)
+#define JPEG_V580_WE_CFG_MAL_BOUNDARY_MSK BIT(24)
+#define JPEG_V580_WE_CFG_MAL_EN_MSK BIT(27)
+#define JPEG_V580_WE_CFG_POP_BUFF_ON_EOS_MSK BIT(28)
+
+#define JPEG_V580_PLN_WR_BUFF_SIZE_WIDTH_POS 0
+#define JPEG_V580_PLN_WR_BUFF_SIZE_WIDTH_MSK \
+ (0xffff << JPEG_V580_PLN_WR_BUFF_SIZE_WIDTH_POS)
+
+#define JPEG_V580_PLN_WR_BUFF_SIZE_HEIGHT_POS 16
+#define JPEG_V580_PLN_WR_BUFF_SIZE_HEIGHT_MSK \
+ (0xffff << JPEG_V580_PLN_WR_BUFF_SIZE_HEIGHT_POS)
+
+#define JPEG_V580_PLN_WR_STRIDE_STRIDE_POS 0
+#define JPEG_V580_PLN_WR_STRIDE_STRIDE_MSK \
+ (0xffff << JPEG_V580_PLN_WR_STRIDE_STRIDE_POS)
+
+#define JPEG_V580_PLN_WR_HINIT_INTEGER_POS 0
+#define JPEG_V580_PLN_WR_HINIT_INTEGER_MSK \
+ (0xffff << JPEG_V580_PLN_WR_HINIT_INTEGER_POS)
+
+#define JPEG_V580_PLN_WR_VINIT_INTEGER_POS 0
+#define JPEG_V580_PLN_WR_VINIT_INTEGER_MSK \
+ (0xffff << JPEG_V580_PLN_WR_VINIT_INTEGER_POS)
+
+#define JPEG_V580_PLN_WR_HSTEP_INTEGER_POS 0
+#define JPEG_V580_PLN_WR_HSTEP_INTEGER_MSK \
+ (0x1ffff << JPEG_V580_PLN_WR_HSTEP_INTEGER_POS)
+
+#define JPEG_V580_PLN_WR_VSTEP_INTEGER_POS 0
+#define JPEG_V580_PLN_WR_VSTEP_INTEGER_MSK \
+ (0x1ffff << JPEG_V580_PLN_WR_VSTEP_INTEGER_POS)
+
+#define JPEG_V580_PLN_WR_BLK_CFG_BLOCKS_PER_COL_POS 0
+#define JPEG_V580_PLN_WR_BLK_CFG_BLOCKS_PER_COL_MSK \
+ (0xffff << JPEG_V580_PLN_WR_BLK_CFG_BLOCKS_PER_COL_POS)
+
+#define JPEG_V580_PLN_WR_BLK_CFG_BLOCKS_PER_ROW_POS 16
+#define JPEG_V580_PLN_WR_BLK_CFG_BLOCKS_PER_ROW_MSK \
+ (0xffff << JPEG_V580_PLN_WR_BLK_CFG_BLOCKS_PER_ROW_POS)
+
+#define JPEG_V580_ENC_CFG_IMAGE_FORMAT_POS 0
+#define JPEG_V580_ENC_CFG_IMAGE_FORMAT_MSK \
+ (0x7 << JPEG_V580_ENC_CFG_IMAGE_FORMAT_POS)
+
+#define JPEG_V580_ENC_CFG_APPLY_EOI_MSK BIT(7)
+#define JPEG_V580_ENC_CFG_HUFFMAN_SEL_MSK BIT(8)
+#define JPEG_V580_ENC_CFG_FSC_ENABLE_MSK BIT(11)
+#define JPEG_V580_ENC_CFG_OUTPUT_DISABLE_MSK BIT(15)
+#define JPEG_V580_ENC_CFG_RST_MARKER_PERIOD_MSK BIT(16)
+
+#define JPEG_V580_ENC_IMG_SIZE_ENCODE_WIDTH_POS 0u
+#define JPEG_V580_ENC_IMG_SIZE_ENCODE_WIDTH_MSK \
+ (0x1fffu << JPEG_V580_ENC_IMG_SIZE_ENCODE_WIDTH_POS)
+
+#define JPEG_V580_ENC_IMG_SIZE_ENCODE_HEIGHT_POS 16u
+#define JPEG_V580_ENC_IMG_SIZE_ENCODE_HEIGHT_MSK \
+ (0x1fffu << JPEG_V580_ENC_IMG_SIZE_ENCODE_HEIGHT_POS)
+
+#define JPEG_V580_OUTPUT_SIZE_STATUS_OUT_SIZE_BYTES_POS 0
+#define JPEG_V580_OUTPUT_SIZE_STATUS_OUT_SIZE_BYTES_MSK \
+ (0x1fffffff << JPEG_V580_OUTPUT_SIZE_STATUS_OUT_SIZE_BYTES_POS)
+
+#define JPEG_V580_SCALE_CFG_HSCALE_ENABLE_MSK BIT(4)
+#define JPEG_V580_SCALE_CFG_VSCALE_ENABLE_MSK BIT(5)
+#define JPEG_V580_SCALE_CFG_UPSAMPLE_EN_MSK BIT(6)
+#define JPEG_V580_SCALE_CFG_SUBSAMPLE_EN_MSK BIT(7)
+#define JPEG_V580_SCALE_CFG_HSCALE_ALGO_MSK BIT(8)
+#define JPEG_V580_SCALE_CFG_VSCALE_ALGO_MSK BIT(9)
+
+#define JPEG_V580_SCALE_CFG_H_SCALE_FIR_ALGO_POS 12u
+#define JPEG_V580_SCALE_CFG_H_SCALE_FIR_ALGO_MSK \
+ (0x3u << JPEG_V580_SCALE_CFG_H_SCALE_FIR_ALGO_POS)
+
+#define JPEG_V580_SCALE_CFG_V_SCALE_FIR_ALGO_POS 16u
+#define JPEG_V580_SCALE_CFG_V_SCALE_FIR_ALGO_MSK \
+ (0x3u << JPEG_V580_SCALE_CFG_V_SCALE_FIR_ALGO_POS)
+
+#define JPEG_V580_SCALE_OUT_CFG_BLOCK_WIDTH_POS 0
+#define JPEG_V580_SCALE_OUT_CFG_BLOCK_WIDTH_MSK \
+ (0xff << JPEG_V580_SCALE_OUT_CFG_BLOCK_WIDTH_POS)
+
+#define JPEG_V580_SCALE_OUT_CFG_BLOCK_HEIGHT_POS 16
+#define JPEG_V580_SCALE_OUT_CFG_BLOCK_HEIGHT_MSK \
+ (0xf << JPEG_V580_SCALE_OUT_CFG_BLOCK_HEIGHT_POS)
+
+#define JPEG_V580_SCALE_PLN_HSTEP_FRACTIONAL_POS 0
+#define JPEG_V580_SCALE_PLN_HSTEP_FRACTIONAL_MSK \
+ (0x1fffff << JPEG_V580_SCALE_PLN_HSTEP_FRACTIONAL_POS)
+
+#define JPEG_V580_SCALE_PLN_HSTEP_INTEGER_POS 21
+#define JPEG_V580_SCALE_PLN_HSTEP_INTEGER_MSK \
+ (0x3f << JPEG_V580_SCALE_PLN_HSTEP_INTEGER_POS)
+
+#define JPEG_V580_SCALE_PLN_VSTEP_FRACTIONAL_POS 0
+#define JPEG_V580_SCALE_PLN_VSTEP_FRACTIONAL_MSK \
+ (0x1fffff << JPEG_V580_SCALE_PLN_VSTEP_FRACTIONAL_POS)
+
+#define JPEG_V580_SCALE_PLN_VSTEP_INTEGER_POS 21
+#define JPEG_V580_SCALE_PLN_VSTEP_INTEGER_MSK \
+ (0x3f << JPEG_V580_SCALE_PLN_VSTEP_INTEGER_POS)
+
+#define JPEG_V580_DMI_CFG_MEM_SEL_POS 0
+#define JPEG_V580_DMI_CFG_MEM_SEL_MSK \
+ (0x7 << JPEG_V580_DMI_CFG_MEM_SEL_POS)
+
+#define JPEG_V580_DMI_CFG_AUTO_INC_EN_MSK BIT(4)
+
+#define JPEG_V580_DMI_ADDR_ADDR_POS 0
+#define JPEG_V580_DMI_ADDR_ADDR_MSK \
+ (0x3ff << JPEG_V580_DMI_ADDR_ADDR_POS)
+
+#define JPEG_V580_TESTBUS_CFG_BUS_SEL_POS 0
+#define JPEG_V580_TESTBUS_CFG_BUS_SEL_MSK \
+ (0x3f << JPEG_V580_TESTBUS_CFG_BUS_SEL_POS)
+
+#define JPEG_V580_FE_VBPAD_CFG_BLOCK_ROW_POS 0
+#define JPEG_V580_FE_VBPAD_CFG_BLOCK_ROW_MSK \
+ (0x1fff << JPEG_V580_FE_VBPAD_CFG_BLOCK_ROW_POS)
+
+#define JPEG_V580_PLN_RD_HINIT_INT_INTEGER_POS 0
+#define JPEG_V580_PLN_RD_HINIT_INT_INTEGER_MSK \
+ (0x1ffff << JPEG_V580_PLN_RD_HINIT_INT_INTEGER_POS)
+
+#define JPEG_V580_PLN_RD_VINIT_INT_INTEGER_POS 0
+#define JPEG_V580_PLN_RD_VINIT_INT_INTEGER_MSK \
+ (0x1ffff << JPEG_V580_PLN_RD_VINIT_INT_INTEGER_POS)
+
+#define JPEG_V580_IRQ_STATUS_SESSION_DONE_MSK BIT(0)
+#define JPEG_V580_IRQ_STATUS_RD_BUF_PLN0_DONE_MSK BIT(4)
+#define JPEG_V580_IRQ_STATUS_RD_BUF_PLN1_DONE_MSK BIT(5)
+#define JPEG_V580_IRQ_STATUS_RD_BUF_PLN2_DONE_MSK BIT(6)
+#define JPEG_V580_IRQ_STATUS_RD_BUF_PLN0_REQ_ATTN_MSK BIT(7)
+#define JPEG_V580_IRQ_STATUS_RD_BUF_PLN1_REQ_ATTN_MSK BIT(8)
+#define JPEG_V580_IRQ_STATUS_RD_BUF_PLN2_REQ_ATTN_MSK BIT(9)
+#define JPEG_V580_IRQ_STATUS_WR_BUF_PLN0_DONE_MSK BIT(10)
+#define JPEG_V580_IRQ_STATUS_WR_BUF_PLN1_DONE_MSK BIT(11)
+#define JPEG_V580_IRQ_STATUS_WR_BUF_PLN2_DONE_MSK BIT(12)
+#define JPEG_V580_IRQ_STATUS_WR_BUF_PLN0_REQ_ATTN_MSK BIT(13)
+#define JPEG_V580_IRQ_STATUS_WR_BUF_PLN1_REQ_ATTN_MSK BIT(14)
+#define JPEG_V580_IRQ_STATUS_WR_BUF_PLN2_REQ_ATTN_MSK BIT(15)
+#define JPEG_V580_IRQ_STATUS_DCD_UNESCAPED_FF_MSK BIT(19)
+#define JPEG_V580_IRQ_STATUS_DCD_HUFFMAN_ERROR_MSK BIT(20)
+#define JPEG_V580_IRQ_STATUS_DCD_COEFF_ERROR_MSK BIT(21)
+#define JPEG_V580_IRQ_STATUS_DCD_MISSING_BITSTUFF_MSK BIT(22)
+#define JPEG_V580_IRQ_STATUS_DCD_SCAN_UNDERFLOW_MSK BIT(23)
+#define JPEG_V580_IRQ_STATUS_DCD_INVALID_RSM_MSK BIT(24)
+#define JPEG_V580_IRQ_STATUS_DCD_INVALID_RSM_SEQ_MSK BIT(25)
+#define JPEG_V580_IRQ_STATUS_DCD_MISSING_RSM_MSK BIT(26)
+#define JPEG_V580_IRQ_STATUS_STOP_ACK_MSK BIT(27)
+#define JPEG_V580_IRQ_STATUS_RESET_ACK_MSK BIT(28)
+
+#define JPEG_V580_IRQ_STATUS_ENABLE_ALL_MSK ~0
+#define JPEG_V580_IRQ_STATUS_DISABLE_ALL_MSK 0
+#define JPEG_V580_IRQ_STATUS_CLEAR_ALL_MSK JPEG_V580_IRQ_STATUS_ENABLE_ALL_MSK
+
+const u32 qcom_v580_jpeg_hw_reg_mask[] = {
+ [JMSK_HW_VER_STEP] = JPEG_V580_HW_VER_STEP_MSK,
+ [JMSK_HW_VER_MINOR] = JPEG_V580_HW_VER_MINOR_MSK,
+ [JMSK_HW_VER_MAJOR] = JPEG_V580_HW_VER_MAJOR_MSK,
+
+ [JMSK_HW_CAP_ENCODE] = JPEG_V580_HW_CAP_ENCODE_MSK,
+ [JMSK_HW_CAP_DECODE] = JPEG_V580_HW_CAP_DECODE_MSK,
+ [JMSK_HW_CAP_UPSCALE] = JPEG_V580_HW_CAP_UPSCALE_MSK,
+ [JMSK_HW_CAP_DOWNSCALE] = JPEG_V580_HW_CAP_DOWNSCALE_MSK,
+
+ [JMSK_RST_CMD_COMMON] =
+ (JPEG_V580_RST_CMD_FE_RESET_MSK |
+ JPEG_V580_RST_CMD_WE_RESET_MSK |
+ JPEG_V580_RST_CMD_ENCODER_RESET_MSK |
+ JPEG_V580_RST_CMD_BLOCK_FORMATTER_RST_MSK |
+ JPEG_V580_RST_CMD_SCALE_RESET_MSK |
+ JPEG_V580_RST_CMD_REGISTER_RESET_MSK |
+ JPEG_V580_RST_CMD_MISR_RESET_MSK |
+ JPEG_V580_RST_CMD_CORE_RESET_MSK |
+ JPEG_V580_RST_CMD_JPEG_V580_DOMAIN_RESET_MSK),
+
+ [JMSK_RST_CMD_FE_RESET] = JPEG_V580_RST_CMD_FE_RESET_MSK,
+ [JMSK_RST_CMD_WE_RESET] = JPEG_V580_RST_CMD_WE_RESET_MSK,
+ [JMSK_RST_CMD_ENCODER_RESET] = JPEG_V580_RST_CMD_ENCODER_RESET_MSK,
+ [JMSK_RST_CMD_DECODER_RESET] = JPEG_V580_RST_CMD_DECODER_RESET_MSK,
+ [JMSK_RST_CMD_BLOCK_FORMATTER_RST] = JPEG_V580_RST_CMD_BLOCK_FORMATTER_RST_MSK,
+ [JMSK_RST_CMD_SCALE_RESET] = JPEG_V580_RST_CMD_SCALE_RESET_MSK,
+ [JMSK_RST_CMD_REGISTER_RESET] = JPEG_V580_RST_CMD_REGISTER_RESET_MSK,
+ [JMSK_RST_CMD_MISR_RESET] = JPEG_V580_RST_CMD_MISR_RESET_MSK,
+ [JMSK_RST_CMD_CORE_RESET] = JPEG_V580_RST_CMD_CORE_RESET_MSK,
+ [JMSK_RST_CMD_JMSK_DOMAIN_RESET] = JPEG_V580_RST_CMD_JPEG_V580_DOMAIN_RESET_MSK,
+ [JMSK_RST_CMD_RESET_BYPASS] = JPEG_V580_RST_CMD_RESET_BYPASS_MSK,
+
+ [JMSK_CORE_CFG_FE_ENABLE] = JPEG_V580_CORE_CFG_FE_ENABLE_MSK,
+ [JMSK_CORE_CFG_WE_ENABLE] = JPEG_V580_CORE_CFG_WE_ENABLE_MSK,
+ [JMSK_CORE_CFG_ENC_ENABLE] = JPEG_V580_CORE_CFG_ENC_ENABLE_MSK,
+ [JMSK_CORE_CFG_SCALE_ENABLE] = JPEG_V580_CORE_CFG_SCALE_ENABLE_MSK,
+ [JMSK_CORE_CFG_TESTBUS_ENABLE] = JPEG_V580_CORE_CFG_TESTBUS_ENABLE_MSK,
+ [JMSK_CORE_CFG_MODE] = JPEG_V580_CORE_CFG_ENC_ENABLE_MSK,
+ [JMSK_CORE_CFG_CGC_DISABLE] = JPEG_V580_CORE_CFG_CGC_DISABLE_MSK,
+
+ [JMSK_CMD_HW_START] = JPEG_V580_CMD_HW_START_MSK,
+ [JMSK_CMD_HW_STOP] = JPEG_V580_CMD_HW_STOP_MSK,
+
+ [JMSK_CMD_CLR_RD_PLNS_QUEUE] =
+ (JPEG_V580_CMD_CLR_RD_PLN0_QUEUE_MSK |
+ JPEG_V580_CMD_CLR_RD_PLN1_QUEUE_MSK |
+ JPEG_V580_CMD_CLR_RD_PLN2_QUEUE_MSK),
+ [JMSK_CMD_CLR_WR_PLNS_QUEUE] =
+ (JPEG_V580_CMD_CLR_WR_PLN0_QUEUE_MSK |
+ JPEG_V580_CMD_CLR_WR_PLN1_QUEUE_MSK |
+ JPEG_V580_CMD_CLR_WR_PLN2_QUEUE_MSK),
+
+ [JMSK_CMD_APPLY_SWC_RD_PARAMS] = JPEG_V580_CMD_APPLY_SWC_RD_PARAMS_MSK,
+
+ [JMSK_CORE_STATUS_ENCODE_STATE] = JPEG_V580_CORE_STATE_STATUS_ENCODE_STATE_MSK,
+ [JMSK_CORE_STATUS_SCALE_STATE] = JPEG_V580_CORE_STATE_STATUS_SCALE_STATE_MSK,
+ [JMSK_CORE_STATUS_RT_STATE] = JPEG_V580_CORE_STATE_STATUS_REALTIME_STATE_MSK,
+ [JMSK_CORE_STATUS_BUS_STATE] = JPEG_V580_CORE_STATE_STATUS_BUS_STATE_MSK,
+ [JMSK_CORE_STATUS_CGC_STATE] = JPEG_V580_CORE_STATE_STATUS_CGC_STATE_MSK,
+
+ [JMSK_IRQ_ENABLE_ALL] = JPEG_V580_IRQ_STATUS_ENABLE_ALL_MSK,
+ [JMSK_IRQ_DISABLE_ALL] = JPEG_V580_IRQ_STATUS_DISABLE_ALL_MSK,
+ [JMSK_IRQ_CLEAR_ALL] = JPEG_V580_IRQ_STATUS_CLEAR_ALL_MSK,
+
+ [JMSK_IRQ_STATUS_SESSION_DONE] = JPEG_V580_IRQ_STATUS_SESSION_DONE_MSK,
+
+ [JMSK_IRQ_STATUS_RD_BUF_PLN0_DONE] = JPEG_V580_IRQ_STATUS_RD_BUF_PLN0_DONE_MSK,
+ [JMSK_IRQ_STATUS_RD_BUF_PLN1_DONE] = JPEG_V580_IRQ_STATUS_RD_BUF_PLN1_DONE_MSK,
+ [JMSK_IRQ_STATUS_RD_BUF_PLN2_DONE] = JPEG_V580_IRQ_STATUS_RD_BUF_PLN2_DONE_MSK,
+ [JMSK_IRQ_STATUS_RD_BUF_PLNS_ATTN] =
+ (JPEG_V580_IRQ_STATUS_RD_BUF_PLN0_REQ_ATTN_MSK |
+ JPEG_V580_IRQ_STATUS_RD_BUF_PLN1_REQ_ATTN_MSK |
+ JPEG_V580_IRQ_STATUS_RD_BUF_PLN2_REQ_ATTN_MSK),
+
+ [JMSK_IRQ_STATUS_WR_BUF_PLN0_DONE] = JPEG_V580_IRQ_STATUS_WR_BUF_PLN0_DONE_MSK,
+ [JMSK_IRQ_STATUS_WR_BUF_PLN1_DONE] = JPEG_V580_IRQ_STATUS_WR_BUF_PLN1_DONE_MSK,
+ [JMSK_IRQ_STATUS_WR_BUF_PLN2_DONE] = JPEG_V580_IRQ_STATUS_WR_BUF_PLN2_DONE_MSK,
+ [JMSK_IRQ_STATUS_WR_BUF_PLNS_ATTN] =
+ (JPEG_V580_IRQ_STATUS_WR_BUF_PLN0_REQ_ATTN_MSK |
+ JPEG_V580_IRQ_STATUS_WR_BUF_PLN1_REQ_ATTN_MSK |
+ JPEG_V580_IRQ_STATUS_WR_BUF_PLN2_REQ_ATTN_MSK),
+
+ [JMSK_IRQ_STATUS_SESSION_ERROR] =
+ (JPEG_V580_IRQ_STATUS_DCD_UNESCAPED_FF_MSK |
+ JPEG_V580_IRQ_STATUS_DCD_HUFFMAN_ERROR_MSK |
+ JPEG_V580_IRQ_STATUS_DCD_COEFF_ERROR_MSK |
+ JPEG_V580_IRQ_STATUS_DCD_MISSING_BITSTUFF_MSK |
+ JPEG_V580_IRQ_STATUS_DCD_SCAN_UNDERFLOW_MSK |
+ JPEG_V580_IRQ_STATUS_DCD_INVALID_RSM_MSK |
+ JPEG_V580_IRQ_STATUS_DCD_INVALID_RSM_SEQ_MSK |
+ JPEG_V580_IRQ_STATUS_DCD_MISSING_RSM_MSK),
+
+ [JMSK_IRQ_STATUS_STOP_ACK] = JPEG_V580_IRQ_STATUS_STOP_ACK_MSK,
+ [JMSK_IRQ_STATUS_RESET_ACK] = JPEG_V580_IRQ_STATUS_RESET_ACK_MSK,
+
+ [JMSK_FE_CFG_BYTE_ORDERING] = JPEG_V580_FE_CFG_BYTE_ORDERING_MSK,
+ [JMSK_FE_CFG_BURST_LENGTH_MAX] = JPEG_V580_FE_CFG_BURST_LENGTH_MAX_MSK,
+ [JMSK_FE_CFG_MEMORY_FORMAT] = JPEG_V580_FE_CFG_MEMORY_FORMAT_MSK,
+ [JMSK_FE_CFG_CBCR_ORDER] = JPEG_V580_FE_CFG_CBCR_ORDER_MSK,
+ [JMSK_FE_CFG_BOTTOM_VPAD_EN] = JPEG_V580_FE_CFG_BOTTOM_VPAD_EN_MSK,
+ [JMSK_FE_CFG_PLN0_EN] = JPEG_V580_FE_CFG_PLN0_EN_MSK,
+ [JMSK_FE_CFG_PLN1_EN] = JPEG_V580_FE_CFG_PLN1_EN_MSK,
+ [JMSK_FE_CFG_PLN2_EN] = JPEG_V580_FE_CFG_PLN2_EN_MSK,
+ [JMSK_FE_CFG_SIXTEEN_MCU_EN] = JPEG_V580_FE_CFG_SIXTEEN_MCU_EN_MSK,
+ [JMSK_FE_CFG_MCUS_PER_BLOCK] = JPEG_V580_FE_CFG_MCUS_PER_BLOCK_MSK,
+ [JMSK_FE_CFG_MAL_BOUNDARY] = JPEG_V580_FE_CFG_MAL_BOUNDARY_MSK,
+ [JMSK_FE_CFG_MAL_EN] = JPEG_V580_FE_CFG_MAL_EN_MSK,
+
+ [JMSK_FE_VBPAD_CFG_BLOCK_ROW] = JPEG_V580_FE_VBPAD_CFG_BLOCK_ROW_MSK,
+
+ [JMSK_PLNS_RD_OFFSET] = JPEG_V580_PLN_RD_OFFS_OFFSET_MSK,
+ [JMSK_PLNS_RD_BUF_SIZE_WIDTH] = JPEG_V580_PLN_RD_BUFF_SIZE_WIDTH_MSK,
+ [JMSK_PLNS_RD_BUF_SIZE_HEIGHT] = JPEG_V580_PLN_RD_BUFF_SIZE_HEIGHT_MSK,
+ [JMSK_PLNS_RD_STRIDE] = JPEG_V580_PLN_RD_STRIDE_STRIDE_MSK,
+ [JMSK_PLNS_RD_HINIT] = JPEG_V580_PLN_RD_HINIT_FRACTIONAL_MSK,
+ [JMSK_PLNS_RD_VINIT] = JPEG_V580_PLN_RD_VINIT_FRACTIONAL_MSK,
+
+ [JMSK_WE_CFG_BYTE_ORDERING] = JPEG_V580_WE_CFG_BYTE_ORDERING_MSK,
+ [JMSK_WE_CFG_BURST_LENGTH_MAX] = JPEG_V580_WE_CFG_BURST_LENGTH_MAX_MSK,
+ [JMSK_WE_CFG_MEMORY_FORMAT] = JPEG_V580_WE_CFG_MEMORY_FORMAT_MSK,
+ [JMSK_WE_CFG_CBCR_ORDER] = JPEG_V580_WE_CFG_CBCR_ORDER_MSK,
+ [JMSK_WE_CFG_PLN0_EN] = JPEG_V580_WE_CFG_PLN0_EN_MSK,
+ [JMSK_WE_CFG_PLN1_EN] = JPEG_V580_WE_CFG_PLN1_EN_MSK,
+ [JMSK_WE_CFG_PLN2_EN] = JPEG_V580_WE_CFG_PLN2_EN_MSK,
+ [JMSK_WE_CFG_MAL_BOUNDARY] = JPEG_V580_WE_CFG_MAL_BOUNDARY_MSK,
+ [JMSK_WE_CFG_MAL_EN] = JPEG_V580_WE_CFG_MAL_EN_MSK,
+ [JMSK_WE_CFG_POP_BUFF_ON_EOS] = JPEG_V580_WE_CFG_POP_BUFF_ON_EOS_MSK,
+
+ [JMSK_PLNS_WR_BUF_SIZE_WIDTH] = JPEG_V580_PLN_WR_BUFF_SIZE_WIDTH_MSK,
+ [JMSK_PLNS_WR_BUF_SIZE_HEIGHT] = JPEG_V580_PLN_WR_BUFF_SIZE_HEIGHT_MSK,
+
+ [JMSK_PLNS_WR_STRIDE] = JPEG_V580_PLN_WR_STRIDE_STRIDE_MSK,
+ [JMSK_PLNS_WR_HINIT] = JPEG_V580_PLN_WR_HINIT_INTEGER_MSK,
+ [JMSK_PLNS_WR_VINIT] = JPEG_V580_PLN_WR_VINIT_INTEGER_MSK,
+ [JMSK_PLNS_WR_HSTEP] = JPEG_V580_PLN_WR_HSTEP_INTEGER_MSK,
+ [JMSK_PLNS_WR_VSTEP] = JPEG_V580_PLN_WR_VSTEP_INTEGER_MSK,
+
+ [JMSK_PLNS_WR_BLOCK_CFG_PER_COL] = JPEG_V580_PLN_WR_BLK_CFG_BLOCKS_PER_COL_MSK,
+ [JMSK_PLNS_WR_BLOCK_CFG_PER_RAW] = JPEG_V580_PLN_WR_BLK_CFG_BLOCKS_PER_ROW_MSK,
+
+ [JMSK_SCALE_CFG_HSCALE_ENABLE] = JPEG_V580_SCALE_CFG_HSCALE_ENABLE_MSK,
+ [JMSK_SCALE_CFG_VSCALE_ENABLE] = JPEG_V580_SCALE_CFG_VSCALE_ENABLE_MSK,
+ [JMSK_SCALE_CFG_UPSAMPLE_EN] = JPEG_V580_SCALE_CFG_UPSAMPLE_EN_MSK,
+ [JMSK_SCALE_CFG_SUBSAMPLE_EN] = JPEG_V580_SCALE_CFG_SUBSAMPLE_EN_MSK,
+ [JMSK_SCALE_CFG_HSCALE_ALGO] = JPEG_V580_SCALE_CFG_HSCALE_ALGO_MSK,
+ [JMSK_SCALE_CFG_VSCALE_ALGO] = JPEG_V580_SCALE_CFG_VSCALE_ALGO_MSK,
+ [JMSK_SCALE_CFG_H_SCALE_FIR_ALGO] = JPEG_V580_SCALE_CFG_H_SCALE_FIR_ALGO_MSK,
+ [JMSK_SCALE_CFG_V_SCALE_FIR_ALGO] = JPEG_V580_SCALE_CFG_V_SCALE_FIR_ALGO_MSK,
+
+ [JMSK_SCALE_PLNS_OUT_CFG_BLK_WIDTH] = JPEG_V580_SCALE_OUT_CFG_BLOCK_WIDTH_MSK,
+ [JMSK_SCALE_PLNS_OUT_CFG_BLK_HEIGHT] = JPEG_V580_SCALE_OUT_CFG_BLOCK_HEIGHT_MSK,
+
+ [JMSK_SCALE_PLNS_HSTEP_FRACTIONAL] = JPEG_V580_SCALE_PLN_HSTEP_FRACTIONAL_MSK,
+ [JMSK_SCALE_PLNS_HSTEP_INTEGER] = JPEG_V580_SCALE_PLN_HSTEP_INTEGER_MSK,
+ [JMSK_SCALE_PLNS_VSTEP_FRACTIONAL] = JPEG_V580_SCALE_PLN_VSTEP_FRACTIONAL_MSK,
+ [JMSK_SCALE_PLNS_VSTEP_INTEGER] = JPEG_V580_SCALE_PLN_VSTEP_INTEGER_MSK,
+
+ [JMSK_ENC_CFG_IMAGE_FORMAT] = JPEG_V580_ENC_CFG_IMAGE_FORMAT_MSK,
+ [JMSK_ENC_CFG_APPLY_EOI] = JPEG_V580_ENC_CFG_APPLY_EOI_MSK,
+ [JMSK_ENC_CFG_HUFFMAN_SEL] = JPEG_V580_ENC_CFG_HUFFMAN_SEL_MSK,
+ [JMSK_ENC_CFG_FSC_ENABLE] = JPEG_V580_ENC_CFG_FSC_ENABLE_MSK,
+ [JMSK_ENC_CFG_OUTPUT_DISABLE] = JPEG_V580_ENC_CFG_OUTPUT_DISABLE_MSK,
+ [JMSK_ENC_CFG_RST_MARKER_PERIOD] = JPEG_V580_ENC_CFG_RST_MARKER_PERIOD_MSK,
+ [JMSK_ENC_IMAGE_SIZE_WIDTH] = JPEG_V580_ENC_IMG_SIZE_ENCODE_WIDTH_MSK,
+ [JMSK_ENC_IMAGE_SIZE_HEIGHT] = JPEG_V580_ENC_IMG_SIZE_ENCODE_HEIGHT_MSK,
+};
+
+const struct qcom_jpeg_reg_offs qcom_v580_jpeg_hw_reg_offs = {
+ .hw_version = 0x000,
+ .hw_capability = 0x004,
+ .reset_cmd = 0x008,
+ .core_cfg = 0x00c,
+ .hw_cmd = 0x010,
+ .int_mask = 0x018,
+ .int_clr = 0x01c,
+ .int_status = 0x020,
+ .enc_core_state = 0x014,
+
+ .fe = {
+ .pntr = { 0x038, 0x044, 0x050 },
+ .offs = { 0x03c, 0x048, 0x054 },
+ .cnsmd = { 0x040, 0x04c, 0x058 },
+ .bsize = { 0x060, 0x068, 0x070 },
+ .stride = { 0x064, 0x06c, 0x08c },
+ .hinit = { 0x074, 0x078, 0x07c },
+ .vinit = { 0x080, 0x084, 0x088 },
+ .pntr_cnt = 0x05c,
+ .vbpad_cfg = 0x2e8
+ },
+ .fe_cfg = 0x024,
+
+ .we = {
+ .pntr = { 0x0cc, 0x0d0, 0x0d4 },
+ .cnsmd = { 0x0d8, 0x0dc, 0x0e0 },
+ .bsize = { 0x0e8, 0x0ec, 0x0f0 },
+ .stride = { 0x0f4, 0x0f8, 0x0fc },
+ .hinit = { 0x100, 0x104, 0x108 },
+ .hstep = { 0x118, 0x11c, 0x120 },
+ .vinit = { 0x10c, 0x110, 0x114 },
+ .vstep = { 0x124, 0x128, 0x12c },
+ .blocks = { 0x130, 0x134, 0x138 },
+ .pntr_cnt = 0x0e4
+ },
+ .we_cfg = 0x0c0,
+
+ .scale = {
+ .hstep = { 0x27c, 0x280, 0x284 },
+ .vstep = { 0x28c, 0x290, 0x294 },
+ },
+ .scale_cfg = 0x26c,
+ .scale_out_cfg = { 0x270, 0x274, 0x278 },
+
+ .enc_cfg = 0x13c,
+ .enc_img_size = 0x140,
+ .enc_out_size = 0x180,
+
+ .dmi_cfg = 0x298,
+ .dmi_data = 0x2a0,
+ .dmi_addr = 0x29c,
+};
+
+#endif /* QCOM_JENC_HW_INFO_V580_H */
diff --git a/drivers/media/platform/qcom/jpeg/qcom_v680_jenc_hw_info.h b/drivers/media/platform/qcom/jpeg/qcom_v680_jenc_hw_info.h
new file mode 100644
index 000000000000..7e02cb587019
--- /dev/null
+++ b/drivers/media/platform/qcom/jpeg/qcom_v680_jenc_hw_info.h
@@ -0,0 +1,509 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
+ */
+
+#ifndef QCOM_JENC_HW_INFO_V680_H
+#define QCOM_JENC_HW_INFO_V680_H
+
+#include "qcom_jenc_defs.h"
+
+#define JPEG_V680_HW_VER_STEP_POS 0
+#define JPEG_V680_HW_VER_STEP_MSK \
+ (0xffff << JPEG_V680_HW_VER_STEP_POS)
+
+#define JPEG_V680_HW_VER_MINOR_POS 16
+#define JPEG_V680_HW_VER_MINOR_MSK \
+ (0x0fff << JPEG_V680_HW_VER_MINOR_POS)
+
+#define JPEG_V680_HW_VER_MAJOR_POS 28
+#define JPEG_V680_HW_VER_MAJOR_MSK \
+ (0xf << JPEG_V680_HW_VER_MAJOR_POS)
+
+#define JPEG_V680_HW_CAP_ENCODE_MSK BIT(0)
+#define JPEG_V680_HW_CAP_DECODE_MSK BIT(1)
+
+#define JPEG_V680_HW_CAP_UPSCALE_POS 4
+#define JPEG_V680_HW_CAP_UPSCALE_MSK \
+ (0x7 << JPEG_V680_HW_CAP_UPSCALE_POS)
+
+#define JPEG_V680_HW_CAP_DOWNSCALE_POS 8
+#define JPEG_V680_HW_CAP_DOWNSCALE_MSK \
+ (0x7 << JPEG_V680_HW_CAP_DOWNSCALE_POS)
+
+#define JPEG_V680_RST_CMD_FE_RESET_MSK BIT(0)
+#define JPEG_V680_RST_CMD_WE_RESET_MSK BIT(1)
+#define JPEG_V680_RST_CMD_ENCODER_RESET_MSK BIT(4)
+#define JPEG_V680_RST_CMD_DECODER_RESET_MSK BIT(5)
+#define JPEG_V680_RST_CMD_BLOCK_FORMATTER_RST_MSK BIT(6)
+#define JPEG_V680_RST_CMD_SCALE_RESET_MSK BIT(7)
+#define JPEG_V680_RST_CMD_REGISTER_RESET_MSK BIT(13)
+#define JPEG_V680_RST_CMD_MISR_RESET_MSK BIT(16)
+#define JPEG_V680_RST_CMD_CORE_RESET_MSK BIT(17)
+#define JPEG_V680_RST_CMD_JPEG_V680_DOMAIN_RESET_MSK BIT(29)
+#define JPEG_V680_RST_CMD_RESET_BYPASS_MSK BIT(31)
+
+#define JPEG_V680_CORE_CFG_FE_ENABLE_MSK BIT(0)
+#define JPEG_V680_CORE_CFG_WE_ENABLE_MSK BIT(1)
+#define JPEG_V680_CORE_CFG_ENC_ENABLE_MSK BIT(4)
+#define JPEG_V680_CORE_CFG_SCALE_ENABLE_MSK BIT(7)
+#define JPEG_V680_CORE_CFG_TESTBUS_ENABLE_MSK BIT(19)
+#define JPEG_V680_CORE_CFG_MODE_MSK BIT(24)
+#define JPEG_V680_CORE_CFG_CGC_DISABLE_MSK BIT(31)
+
+#define JPEG_V680_CMD_HW_START_MSK BIT(0)
+#define JPEG_V680_CMD_HW_STOP_MSK BIT(1)
+#define JPEG_V680_CMD_CLR_RD_PLN0_QUEUE_MSK BIT(4)
+#define JPEG_V680_CMD_CLR_RD_PLN1_QUEUE_MSK BIT(5)
+#define JPEG_V680_CMD_CLR_RD_PLN2_QUEUE_MSK BIT(6)
+#define JPEG_V680_CMD_CLR_WR_PLN0_QUEUE_MSK BIT(8)
+#define JPEG_V680_CMD_CLR_WR_PLN1_QUEUE_MSK BIT(9)
+#define JPEG_V680_CMD_CLR_WR_PLN2_QUEUE_MSK BIT(10)
+#define JPEG_V680_CMD_APPLY_SWC_RD_PARAMS_MSK BIT(11)
+
+#define JPEG_V680_CORE_STATE_STATUS_ENCODE_STATE_MSK BIT(0)
+#define JPEG_V680_CORE_STATE_STATUS_SCALE_STATE_MSK BIT(2)
+#define JPEG_V680_CORE_STATE_STATUS_REALTIME_STATE_MSK BIT(4)
+#define JPEG_V680_CORE_STATE_STATUS_BUS_STATE_MSK BIT(8)
+#define JPEG_V680_CORE_STATE_STATUS_CGC_STATE_MSK BIT(9)
+
+#define JPEG_V680_FE_CFG_BYTE_ORDERING_POS 0
+#define JPEG_V680_FE_CFG_BYTE_ORDERING_MSK \
+ (0xf << JPEG_V680_FE_CFG_BYTE_ORDERING_POS)
+
+#define JPEG_V680_FE_CFG_BURST_LENGTH_MAX_POS 4
+#define JPEG_V680_FE_CFG_BURST_LENGTH_MAX_MSK \
+ (0xf << JPEG_V680_WE_CFG_BURST_LENGTH_MAX_POS)
+
+#define JPEG_V680_FE_CFG_MEMORY_FORMAT_POS 8
+#define JPEG_V680_FE_CFG_MEMORY_FORMAT_MSK \
+ (0x3 << JPEG_V680_WE_CFG_MEMORY_FORMAT_POS)
+
+#define JPEG_V680_FE_CFG_CBCR_ORDER_MSK BIT(12)
+#define JPEG_V680_FE_CFG_BOTTOM_VPAD_EN_MSK BIT(13)
+#define JPEG_V680_FE_CFG_PLN0_EN_MSK BIT(16)
+#define JPEG_V680_FE_CFG_PLN1_EN_MSK BIT(17)
+#define JPEG_V680_FE_CFG_PLN2_EN_MSK BIT(18)
+#define JPEG_V680_FE_CFG_SIXTEEN_MCU_EN_MSK BIT(21)
+#define JPEG_V680_FE_CFG_MCUS_PER_BLOCK_MSK BIT(22)
+#define JPEG_V680_FE_CFG_MAL_BOUNDARY_MSK BIT(24)
+#define JPEG_V680_FE_CFG_MAL_EN_MSK BIT(27)
+
+#define JPEG_V680_PLN_RD_OFFS_OFFSET_POS 0
+#define JPEG_V680_PLN_RD_OFFS_OFFSET_MSK \
+ (0x1fffffff << JPEG_V680_PLN_RD_OFFS_OFFSET_POS)
+
+#define JPEG_V680_PLN_RD_BUFF_SIZE_WIDTH_POS 0
+#define JPEG_V680_PLN_RD_BUFF_SIZE_WIDTH_MSK \
+ (0xffff << JPEG_V680_PLN_RD_BUFF_SIZE_WIDTH_POS)
+
+#define JPEG_V680_PLN_RD_BUFF_SIZE_HEIGHT_POS 16
+#define JPEG_V680_PLN_RD_BUFF_SIZE_HEIGHT_MSK \
+ (0xffff << JPEG_V680_PLN_RD_BUFF_SIZE_HEIGHT_POS)
+
+#define JPEG_V680_PLN_RD_STRIDE_STRIDE_POS 0
+#define JPEG_V680_PLN_RD_STRIDE_STRIDE_MSK \
+ (0xffff << JPEG_V680_PLN_RD_STRIDE_STRIDE_POS)
+
+#define JPEG_V680_PLN_RD_HINIT_FRACTIONAL_POS 0
+#define JPEG_V680_PLN_RD_HINIT_FRACTIONAL_MSK \
+ (0x1fffff << JPEG_V680_PLN_RD_HINIT_FRACTIONAL_POS)
+
+#define JPEG_V680_PLN_RD_VINIT_FRACTIONAL_POS 0
+#define JPEG_V680_PLN_RD_VINIT_FRACTIONAL_MSK \
+ (0x1fffff << JPEG_V680_PLN_RD_VINIT_FRACTIONAL_POS)
+
+#define JPEG_V680_WE_CFG_BYTE_ORDERING_POS 0
+#define JPEG_V680_WE_CFG_BYTE_ORDERING_MSK \
+ (0xf << JPEG_V680_WE_CFG_BYTE_ORDERING_POS)
+
+#define JPEG_V680_WE_CFG_BURST_LENGTH_MAX_POS 4
+#define JPEG_V680_WE_CFG_BURST_LENGTH_MAX_MSK \
+ (0xf << JPEG_V680_WE_CFG_BURST_LENGTH_MAX_POS)
+
+#define JPEG_V680_WE_CFG_MEMORY_FORMAT_POS 8
+#define JPEG_V680_WE_CFG_MEMORY_FORMAT_MSK \
+ (0x3 << JPEG_V680_WE_CFG_MEMORY_FORMAT_POS)
+
+#define JPEG_V680_WE_CFG_CBCR_ORDER_MSK BIT(12)
+#define JPEG_V680_WE_CFG_PLN0_EN_MSK BIT(16)
+#define JPEG_V680_WE_CFG_PLN1_EN_MSK BIT(17)
+#define JPEG_V680_WE_CFG_PLN2_EN_MSK BIT(18)
+#define JPEG_V680_WE_CFG_MAL_BOUNDARY_MSK BIT(24)
+#define JPEG_V680_WE_CFG_MAL_EN_MSK BIT(27)
+#define JPEG_V680_WE_CFG_POP_BUFF_ON_EOS_MSK BIT(28)
+
+#define JPEG_V680_PLN_WR_BUFF_SIZE_WIDTH_POS 0
+#define JPEG_V680_PLN_WR_BUFF_SIZE_WIDTH_MSK \
+ (0xffff << JPEG_V680_PLN_WR_BUFF_SIZE_WIDTH_POS)
+
+#define JPEG_V680_PLN_WR_BUFF_SIZE_HEIGHT_POS 16
+#define JPEG_V680_PLN_WR_BUFF_SIZE_HEIGHT_MSK \
+ (0xffff << JPEG_V680_PLN_WR_BUFF_SIZE_HEIGHT_POS)
+
+#define JPEG_V680_PLN_WR_STRIDE_STRIDE_POS 0
+#define JPEG_V680_PLN_WR_STRIDE_STRIDE_MSK \
+ (0xffff << JPEG_V680_PLN_WR_STRIDE_STRIDE_POS)
+
+#define JPEG_V680_PLN_WR_HINIT_INTEGER_POS 0
+#define JPEG_V680_PLN_WR_HINIT_INTEGER_MSK \
+ (0xffff << JPEG_V680_PLN_WR_HINIT_INTEGER_POS)
+
+#define JPEG_V680_PLN_WR_VINIT_INTEGER_POS 0
+#define JPEG_V680_PLN_WR_VINIT_INTEGER_MSK \
+ (0xffff << JPEG_V680_PLN_WR_VINIT_INTEGER_POS)
+
+#define JPEG_V680_PLN_WR_HSTEP_INTEGER_POS 0
+#define JPEG_V680_PLN_WR_HSTEP_INTEGER_MSK \
+ (0x1ffff << JPEG_V680_PLN_WR_HSTEP_INTEGER_POS)
+
+#define JPEG_V680_PLN_WR_VSTEP_INTEGER_POS 0
+#define JPEG_V680_PLN_WR_VSTEP_INTEGER_MSK \
+ (0x1ffff << JPEG_V680_PLN_WR_VSTEP_INTEGER_POS)
+
+#define JPEG_V680_PLN_WR_BLK_CFG_BLOCKS_PER_COL_POS 0
+#define JPEG_V680_PLN_WR_BLK_CFG_BLOCKS_PER_COL_MSK \
+ (0xffff << JPEG_V680_PLN_WR_BLK_CFG_BLOCKS_PER_COL_POS)
+
+#define JPEG_V680_PLN_WR_BLK_CFG_BLOCKS_PER_ROW_POS 16
+#define JPEG_V680_PLN_WR_BLK_CFG_BLOCKS_PER_ROW_MSK \
+ (0xffff << JPEG_V680_PLN_WR_BLK_CFG_BLOCKS_PER_ROW_POS)
+
+#define JPEG_V680_ENC_CFG_IMAGE_FORMAT_POS 0
+#define JPEG_V680_ENC_CFG_IMAGE_FORMAT_MSK \
+ (0x7 << JPEG_V680_ENC_CFG_IMAGE_FORMAT_POS)
+
+#define JPEG_V680_ENC_CFG_APPLY_EOI_MSK BIT(7)
+#define JPEG_V680_ENC_CFG_HUFFMAN_SEL_MSK BIT(8)
+#define JPEG_V680_ENC_CFG_FSC_ENABLE_MSK BIT(11)
+#define JPEG_V680_ENC_CFG_OUTPUT_DISABLE_MSK BIT(15)
+#define JPEG_V680_ENC_CFG_RST_MARKER_PERIOD_MSK BIT(16)
+
+#define JPEG_V680_ENC_IMG_SIZE_ENCODE_WIDTH_POS 0u
+#define JPEG_V680_ENC_IMG_SIZE_ENCODE_WIDTH_MSK \
+ (0x1fffu << JPEG_V680_ENC_IMG_SIZE_ENCODE_WIDTH_POS)
+
+#define JPEG_V680_ENC_IMG_SIZE_ENCODE_HEIGHT_POS 16u
+#define JPEG_V680_ENC_IMG_SIZE_ENCODE_HEIGHT_MSK \
+ (0x1fffu << JPEG_V680_ENC_IMG_SIZE_ENCODE_HEIGHT_POS)
+
+#define JPEG_V680_OUTPUT_SIZE_STATUS_OUT_SIZE_BYTES_POS 0
+#define JPEG_V680_OUTPUT_SIZE_STATUS_OUT_SIZE_BYTES_MSK \
+ (0x1fffffff << JPEG_V680_OUTPUT_SIZE_STATUS_OUT_SIZE_BYTES_POS)
+
+#define JPEG_V680_SCALE_CFG_HSCALE_ENABLE_MSK BIT(4)
+#define JPEG_V680_SCALE_CFG_VSCALE_ENABLE_MSK BIT(5)
+#define JPEG_V680_SCALE_CFG_UPSAMPLE_EN_MSK BIT(6)
+#define JPEG_V680_SCALE_CFG_SUBSAMPLE_EN_MSK BIT(7)
+#define JPEG_V680_SCALE_CFG_HSCALE_ALGO_MSK BIT(8)
+#define JPEG_V680_SCALE_CFG_VSCALE_ALGO_MSK BIT(9)
+
+#define JPEG_V680_SCALE_CFG_H_SCALE_FIR_ALGO_POS 12u
+#define JPEG_V680_SCALE_CFG_H_SCALE_FIR_ALGO_MSK \
+ (0x3u << JPEG_V680_SCALE_CFG_H_SCALE_FIR_ALGO_POS)
+
+#define JPEG_V680_SCALE_CFG_V_SCALE_FIR_ALGO_POS 16u
+#define JPEG_V680_SCALE_CFG_V_SCALE_FIR_ALGO_MSK \
+ (0x3u << JPEG_V680_SCALE_CFG_V_SCALE_FIR_ALGO_POS)
+
+#define JPEG_V680_SCALE_OUT_CFG_BLOCK_WIDTH_POS 0
+#define JPEG_V680_SCALE_OUT_CFG_BLOCK_WIDTH_MSK \
+ (0xff << JPEG_V680_SCALE_OUT_CFG_BLOCK_WIDTH_POS)
+
+#define JPEG_V680_SCALE_OUT_CFG_BLOCK_HEIGHT_POS 16
+#define JPEG_V680_SCALE_OUT_CFG_BLOCK_HEIGHT_MSK \
+ (0xf << JPEG_V680_SCALE_OUT_CFG_BLOCK_HEIGHT_POS)
+
+#define JPEG_V680_SCALE_PLN_HSTEP_FRACTIONAL_POS 0
+#define JPEG_V680_SCALE_PLN_HSTEP_FRACTIONAL_MSK \
+ (0x1fffff << JPEG_V680_SCALE_PLN_HSTEP_FRACTIONAL_POS)
+
+#define JPEG_V680_SCALE_PLN_HSTEP_INTEGER_POS 21
+#define JPEG_V680_SCALE_PLN_HSTEP_INTEGER_MSK \
+ (0x3f << JPEG_V680_SCALE_PLN_HSTEP_INTEGER_POS)
+
+#define JPEG_V680_SCALE_PLN_VSTEP_FRACTIONAL_POS 0
+#define JPEG_V680_SCALE_PLN_VSTEP_FRACTIONAL_MSK \
+ (0x1fffff << JPEG_V680_SCALE_PLN_VSTEP_FRACTIONAL_POS)
+
+#define JPEG_V680_SCALE_PLN_VSTEP_INTEGER_POS 21
+#define JPEG_V680_SCALE_PLN_VSTEP_INTEGER_MSK \
+ (0x3f << JPEG_V680_SCALE_PLN_VSTEP_INTEGER_POS)
+
+#define JPEG_V680_DMI_CFG_MEM_SEL_POS 0
+#define JPEG_V680_DMI_CFG_MEM_SEL_MSK \
+ (0x7 << JPEG_V680_DMI_CFG_MEM_SEL_POS)
+
+#define JPEG_V680_DMI_CFG_AUTO_INC_EN_MSK BIT(4)
+
+#define JPEG_V680_DMI_ADDR_ADDR_POS 0
+#define JPEG_V680_DMI_ADDR_ADDR_MSK \
+ (0x3ff << JPEG_V680_DMI_ADDR_ADDR_POS)
+
+#define JPEG_V680_TESTBUS_CFG_BUS_SEL_POS 0
+#define JPEG_V680_TESTBUS_CFG_BUS_SEL_MSK \
+ (0x3f << JPEG_V680_TESTBUS_CFG_BUS_SEL_POS)
+
+#define JPEG_V680_FE_VBPAD_CFG_BLOCK_ROW_POS 0
+#define JPEG_V680_FE_VBPAD_CFG_BLOCK_ROW_MSK \
+ (0x1fff << JPEG_V680_FE_VBPAD_CFG_BLOCK_ROW_POS)
+
+#define JPEG_V680_PLN_RD_HINIT_INT_INTEGER_POS 0
+#define JPEG_V680_PLN_RD_HINIT_INT_INTEGER_MSK \
+ (0x1ffff << JPEG_V680_PLN_RD_HINIT_INT_INTEGER_POS)
+
+#define JPEG_V680_PLN_RD_VINIT_INT_INTEGER_POS 0
+#define JPEG_V680_PLN_RD_VINIT_INT_INTEGER_MSK \
+ (0x1ffff << JPEG_V680_PLN_RD_VINIT_INT_INTEGER_POS)
+
+#define JPEG_V680_IRQ_STATUS_SESSION_DONE_MSK BIT(0)
+#define JPEG_V680_IRQ_STATUS_RD_BUF_PLN0_DONE_MSK BIT(4)
+#define JPEG_V680_IRQ_STATUS_RD_BUF_PLN1_DONE_MSK BIT(5)
+#define JPEG_V680_IRQ_STATUS_RD_BUF_PLN2_DONE_MSK BIT(6)
+#define JPEG_V680_IRQ_STATUS_RD_BUF_PLN0_REQ_ATTN_MSK BIT(7)
+#define JPEG_V680_IRQ_STATUS_RD_BUF_PLN1_REQ_ATTN_MSK BIT(8)
+#define JPEG_V680_IRQ_STATUS_RD_BUF_PLN2_REQ_ATTN_MSK BIT(9)
+#define JPEG_V680_IRQ_STATUS_WR_BUF_PLN0_DONE_MSK BIT(10)
+#define JPEG_V680_IRQ_STATUS_WR_BUF_PLN1_DONE_MSK BIT(11)
+#define JPEG_V680_IRQ_STATUS_WR_BUF_PLN2_DONE_MSK BIT(12)
+#define JPEG_V680_IRQ_STATUS_WR_BUF_PLN0_REQ_ATTN_MSK BIT(13)
+#define JPEG_V680_IRQ_STATUS_WR_BUF_PLN1_REQ_ATTN_MSK BIT(14)
+#define JPEG_V680_IRQ_STATUS_WR_BUF_PLN2_REQ_ATTN_MSK BIT(15)
+#define JPEG_V680_IRQ_STATUS_DCD_UNESCAPED_FF_MSK BIT(19)
+#define JPEG_V680_IRQ_STATUS_DCD_HUFFMAN_ERROR_MSK BIT(20)
+#define JPEG_V680_IRQ_STATUS_DCD_COEFF_ERROR_MSK BIT(21)
+#define JPEG_V680_IRQ_STATUS_DCD_MISSING_BITSTUFF_MSK BIT(22)
+#define JPEG_V680_IRQ_STATUS_DCD_SCAN_UNDERFLOW_MSK BIT(23)
+#define JPEG_V680_IRQ_STATUS_DCD_INVALID_RSM_MSK BIT(24)
+#define JPEG_V680_IRQ_STATUS_DCD_INVALID_RSM_SEQ_MSK BIT(25)
+#define JPEG_V680_IRQ_STATUS_DCD_MISSING_RSM_MSK BIT(26)
+#define JPEG_V680_IRQ_STATUS_STOP_ACK_MSK BIT(27)
+#define JPEG_V680_IRQ_STATUS_RESET_ACK_MSK BIT(28)
+
+#define JPEG_V680_IRQ_STATUS_ENABLE_ALL_MSK ~0
+#define JPEG_V680_IRQ_STATUS_DISABLE_ALL_MSK 0
+#define JPEG_V680_IRQ_STATUS_CLEAR_ALL_MSK JPEG_V680_IRQ_STATUS_ENABLE_ALL_MSK
+
+const u32 qcom_v680_jpeg_hw_reg_mask[] = {
+ [JMSK_HW_VER_STEP] = JPEG_V680_HW_VER_STEP_MSK,
+ [JMSK_HW_VER_MINOR] = JPEG_V680_HW_VER_MINOR_MSK,
+ [JMSK_HW_VER_MAJOR] = JPEG_V680_HW_VER_MAJOR_MSK,
+
+ [JMSK_HW_CAP_ENCODE] = JPEG_V680_HW_CAP_ENCODE_MSK,
+ [JMSK_HW_CAP_DECODE] = JPEG_V680_HW_CAP_DECODE_MSK,
+ [JMSK_HW_CAP_UPSCALE] = JPEG_V680_HW_CAP_UPSCALE_MSK,
+ [JMSK_HW_CAP_DOWNSCALE] = JPEG_V680_HW_CAP_DOWNSCALE_MSK,
+
+ [JMSK_RST_CMD_COMMON] =
+ (JPEG_V680_RST_CMD_FE_RESET_MSK |
+ JPEG_V680_RST_CMD_WE_RESET_MSK |
+ JPEG_V680_RST_CMD_ENCODER_RESET_MSK |
+ JPEG_V680_RST_CMD_BLOCK_FORMATTER_RST_MSK |
+ JPEG_V680_RST_CMD_SCALE_RESET_MSK |
+ JPEG_V680_RST_CMD_REGISTER_RESET_MSK |
+ JPEG_V680_RST_CMD_MISR_RESET_MSK |
+ JPEG_V680_RST_CMD_CORE_RESET_MSK |
+ JPEG_V680_RST_CMD_JPEG_V680_DOMAIN_RESET_MSK),
+
+ [JMSK_RST_CMD_FE_RESET] = JPEG_V680_RST_CMD_FE_RESET_MSK,
+ [JMSK_RST_CMD_WE_RESET] = JPEG_V680_RST_CMD_WE_RESET_MSK,
+ [JMSK_RST_CMD_ENCODER_RESET] = JPEG_V680_RST_CMD_ENCODER_RESET_MSK,
+ [JMSK_RST_CMD_DECODER_RESET] = JPEG_V680_RST_CMD_DECODER_RESET_MSK,
+ [JMSK_RST_CMD_BLOCK_FORMATTER_RST] = JPEG_V680_RST_CMD_BLOCK_FORMATTER_RST_MSK,
+ [JMSK_RST_CMD_SCALE_RESET] = JPEG_V680_RST_CMD_SCALE_RESET_MSK,
+ [JMSK_RST_CMD_REGISTER_RESET] = JPEG_V680_RST_CMD_REGISTER_RESET_MSK,
+ [JMSK_RST_CMD_MISR_RESET] = JPEG_V680_RST_CMD_MISR_RESET_MSK,
+ [JMSK_RST_CMD_CORE_RESET] = JPEG_V680_RST_CMD_CORE_RESET_MSK,
+ [JMSK_RST_CMD_JMSK_DOMAIN_RESET] = JPEG_V680_RST_CMD_JPEG_V680_DOMAIN_RESET_MSK,
+ [JMSK_RST_CMD_RESET_BYPASS] = JPEG_V680_RST_CMD_RESET_BYPASS_MSK,
+
+ [JMSK_CORE_CFG_FE_ENABLE] = JPEG_V680_CORE_CFG_FE_ENABLE_MSK,
+ [JMSK_CORE_CFG_WE_ENABLE] = JPEG_V680_CORE_CFG_WE_ENABLE_MSK,
+ [JMSK_CORE_CFG_ENC_ENABLE] = JPEG_V680_CORE_CFG_ENC_ENABLE_MSK,
+ [JMSK_CORE_CFG_SCALE_ENABLE] = JPEG_V680_CORE_CFG_SCALE_ENABLE_MSK,
+ [JMSK_CORE_CFG_TESTBUS_ENABLE] = JPEG_V680_CORE_CFG_TESTBUS_ENABLE_MSK,
+ [JMSK_CORE_CFG_MODE] = JPEG_V680_CORE_CFG_ENC_ENABLE_MSK,
+ [JMSK_CORE_CFG_CGC_DISABLE] = JPEG_V680_CORE_CFG_CGC_DISABLE_MSK,
+
+ [JMSK_CMD_HW_START] = JPEG_V680_CMD_HW_START_MSK,
+ [JMSK_CMD_HW_STOP] = JPEG_V680_CMD_HW_STOP_MSK,
+
+ [JMSK_CMD_CLR_RD_PLNS_QUEUE] =
+ (JPEG_V680_CMD_CLR_RD_PLN0_QUEUE_MSK |
+ JPEG_V680_CMD_CLR_RD_PLN1_QUEUE_MSK |
+ JPEG_V680_CMD_CLR_RD_PLN2_QUEUE_MSK),
+ [JMSK_CMD_CLR_WR_PLNS_QUEUE] =
+ (JPEG_V680_CMD_CLR_WR_PLN0_QUEUE_MSK |
+ JPEG_V680_CMD_CLR_WR_PLN1_QUEUE_MSK |
+ JPEG_V680_CMD_CLR_WR_PLN2_QUEUE_MSK),
+
+ [JMSK_CMD_APPLY_SWC_RD_PARAMS] = JPEG_V680_CMD_APPLY_SWC_RD_PARAMS_MSK,
+
+ [JMSK_CORE_STATUS_ENCODE_STATE] = JPEG_V680_CORE_STATE_STATUS_ENCODE_STATE_MSK,
+ [JMSK_CORE_STATUS_SCALE_STATE] = JPEG_V680_CORE_STATE_STATUS_SCALE_STATE_MSK,
+ [JMSK_CORE_STATUS_RT_STATE] = JPEG_V680_CORE_STATE_STATUS_REALTIME_STATE_MSK,
+ [JMSK_CORE_STATUS_BUS_STATE] = JPEG_V680_CORE_STATE_STATUS_BUS_STATE_MSK,
+ [JMSK_CORE_STATUS_CGC_STATE] = JPEG_V680_CORE_STATE_STATUS_CGC_STATE_MSK,
+
+ [JMSK_IRQ_ENABLE_ALL] = JPEG_V680_IRQ_STATUS_ENABLE_ALL_MSK,
+ [JMSK_IRQ_DISABLE_ALL] = JPEG_V680_IRQ_STATUS_DISABLE_ALL_MSK,
+ [JMSK_IRQ_CLEAR_ALL] = JPEG_V680_IRQ_STATUS_CLEAR_ALL_MSK,
+
+ [JMSK_IRQ_STATUS_SESSION_DONE] = JPEG_V680_IRQ_STATUS_SESSION_DONE_MSK,
+
+ [JMSK_IRQ_STATUS_RD_BUF_PLN0_DONE] = JPEG_V680_IRQ_STATUS_RD_BUF_PLN0_DONE_MSK,
+ [JMSK_IRQ_STATUS_RD_BUF_PLN1_DONE] = JPEG_V680_IRQ_STATUS_RD_BUF_PLN1_DONE_MSK,
+ [JMSK_IRQ_STATUS_RD_BUF_PLN2_DONE] = JPEG_V680_IRQ_STATUS_RD_BUF_PLN2_DONE_MSK,
+ [JMSK_IRQ_STATUS_RD_BUF_PLNS_ATTN] =
+ (JPEG_V680_IRQ_STATUS_RD_BUF_PLN0_REQ_ATTN_MSK |
+ JPEG_V680_IRQ_STATUS_RD_BUF_PLN1_REQ_ATTN_MSK |
+ JPEG_V680_IRQ_STATUS_RD_BUF_PLN2_REQ_ATTN_MSK),
+
+ [JMSK_IRQ_STATUS_WR_BUF_PLN0_DONE] = JPEG_V680_IRQ_STATUS_WR_BUF_PLN0_DONE_MSK,
+ [JMSK_IRQ_STATUS_WR_BUF_PLN1_DONE] = JPEG_V680_IRQ_STATUS_WR_BUF_PLN1_DONE_MSK,
+ [JMSK_IRQ_STATUS_WR_BUF_PLN2_DONE] = JPEG_V680_IRQ_STATUS_WR_BUF_PLN2_DONE_MSK,
+ [JMSK_IRQ_STATUS_WR_BUF_PLNS_ATTN] =
+ (JPEG_V680_IRQ_STATUS_WR_BUF_PLN0_REQ_ATTN_MSK |
+ JPEG_V680_IRQ_STATUS_WR_BUF_PLN1_REQ_ATTN_MSK |
+ JPEG_V680_IRQ_STATUS_WR_BUF_PLN2_REQ_ATTN_MSK),
+
+ [JMSK_IRQ_STATUS_SESSION_ERROR] =
+ (JPEG_V680_IRQ_STATUS_DCD_UNESCAPED_FF_MSK |
+ JPEG_V680_IRQ_STATUS_DCD_HUFFMAN_ERROR_MSK |
+ JPEG_V680_IRQ_STATUS_DCD_COEFF_ERROR_MSK |
+ JPEG_V680_IRQ_STATUS_DCD_MISSING_BITSTUFF_MSK |
+ JPEG_V680_IRQ_STATUS_DCD_SCAN_UNDERFLOW_MSK |
+ JPEG_V680_IRQ_STATUS_DCD_INVALID_RSM_MSK |
+ JPEG_V680_IRQ_STATUS_DCD_INVALID_RSM_SEQ_MSK |
+ JPEG_V680_IRQ_STATUS_DCD_MISSING_RSM_MSK),
+
+ [JMSK_IRQ_STATUS_STOP_ACK] = JPEG_V680_IRQ_STATUS_STOP_ACK_MSK,
+ [JMSK_IRQ_STATUS_RESET_ACK] = JPEG_V680_IRQ_STATUS_RESET_ACK_MSK,
+
+ [JMSK_FE_CFG_BYTE_ORDERING] = JPEG_V680_FE_CFG_BYTE_ORDERING_MSK,
+ [JMSK_FE_CFG_BURST_LENGTH_MAX] = JPEG_V680_FE_CFG_BURST_LENGTH_MAX_MSK,
+ [JMSK_FE_CFG_MEMORY_FORMAT] = JPEG_V680_FE_CFG_MEMORY_FORMAT_MSK,
+ [JMSK_FE_CFG_CBCR_ORDER] = JPEG_V680_FE_CFG_CBCR_ORDER_MSK,
+ [JMSK_FE_CFG_BOTTOM_VPAD_EN] = JPEG_V680_FE_CFG_BOTTOM_VPAD_EN_MSK,
+ [JMSK_FE_CFG_PLN0_EN] = JPEG_V680_FE_CFG_PLN0_EN_MSK,
+ [JMSK_FE_CFG_PLN1_EN] = JPEG_V680_FE_CFG_PLN1_EN_MSK,
+ [JMSK_FE_CFG_PLN2_EN] = JPEG_V680_FE_CFG_PLN2_EN_MSK,
+ [JMSK_FE_CFG_SIXTEEN_MCU_EN] = JPEG_V680_FE_CFG_SIXTEEN_MCU_EN_MSK,
+ [JMSK_FE_CFG_MCUS_PER_BLOCK] = JPEG_V680_FE_CFG_MCUS_PER_BLOCK_MSK,
+ [JMSK_FE_CFG_MAL_BOUNDARY] = JPEG_V680_FE_CFG_MAL_BOUNDARY_MSK,
+ [JMSK_FE_CFG_MAL_EN] = JPEG_V680_FE_CFG_MAL_EN_MSK,
+
+ [JMSK_FE_VBPAD_CFG_BLOCK_ROW] = JPEG_V680_FE_VBPAD_CFG_BLOCK_ROW_MSK,
+
+ [JMSK_PLNS_RD_OFFSET] = JPEG_V680_PLN_RD_OFFS_OFFSET_MSK,
+ [JMSK_PLNS_RD_BUF_SIZE_WIDTH] = JPEG_V680_PLN_RD_BUFF_SIZE_WIDTH_MSK,
+ [JMSK_PLNS_RD_BUF_SIZE_HEIGHT] = JPEG_V680_PLN_RD_BUFF_SIZE_HEIGHT_MSK,
+ [JMSK_PLNS_RD_STRIDE] = JPEG_V680_PLN_RD_STRIDE_STRIDE_MSK,
+ [JMSK_PLNS_RD_HINIT] = JPEG_V680_PLN_RD_HINIT_FRACTIONAL_MSK,
+ [JMSK_PLNS_RD_VINIT] = JPEG_V680_PLN_RD_VINIT_FRACTIONAL_MSK,
+
+ [JMSK_WE_CFG_BYTE_ORDERING] = JPEG_V680_WE_CFG_BYTE_ORDERING_MSK,
+ [JMSK_WE_CFG_BURST_LENGTH_MAX] = JPEG_V680_WE_CFG_BURST_LENGTH_MAX_MSK,
+ [JMSK_WE_CFG_MEMORY_FORMAT] = JPEG_V680_WE_CFG_MEMORY_FORMAT_MSK,
+ [JMSK_WE_CFG_CBCR_ORDER] = JPEG_V680_WE_CFG_CBCR_ORDER_MSK,
+ [JMSK_WE_CFG_PLN0_EN] = JPEG_V680_WE_CFG_PLN0_EN_MSK,
+ [JMSK_WE_CFG_PLN1_EN] = JPEG_V680_WE_CFG_PLN1_EN_MSK,
+ [JMSK_WE_CFG_PLN2_EN] = JPEG_V680_WE_CFG_PLN2_EN_MSK,
+ [JMSK_WE_CFG_MAL_BOUNDARY] = JPEG_V680_WE_CFG_MAL_BOUNDARY_MSK,
+ [JMSK_WE_CFG_MAL_EN] = JPEG_V680_WE_CFG_MAL_EN_MSK,
+ [JMSK_WE_CFG_POP_BUFF_ON_EOS] = JPEG_V680_WE_CFG_POP_BUFF_ON_EOS_MSK,
+
+ [JMSK_PLNS_WR_BUF_SIZE_WIDTH] = JPEG_V680_PLN_WR_BUFF_SIZE_WIDTH_MSK,
+ [JMSK_PLNS_WR_BUF_SIZE_HEIGHT] = JPEG_V680_PLN_WR_BUFF_SIZE_HEIGHT_MSK,
+
+ [JMSK_PLNS_WR_STRIDE] = JPEG_V680_PLN_WR_STRIDE_STRIDE_MSK,
+ [JMSK_PLNS_WR_HINIT] = JPEG_V680_PLN_WR_HINIT_INTEGER_MSK,
+ [JMSK_PLNS_WR_VINIT] = JPEG_V680_PLN_WR_VINIT_INTEGER_MSK,
+ [JMSK_PLNS_WR_HSTEP] = JPEG_V680_PLN_WR_HSTEP_INTEGER_MSK,
+ [JMSK_PLNS_WR_VSTEP] = JPEG_V680_PLN_WR_VSTEP_INTEGER_MSK,
+
+ [JMSK_PLNS_WR_BLOCK_CFG_PER_COL] = JPEG_V680_PLN_WR_BLK_CFG_BLOCKS_PER_COL_MSK,
+ [JMSK_PLNS_WR_BLOCK_CFG_PER_RAW] = JPEG_V680_PLN_WR_BLK_CFG_BLOCKS_PER_ROW_MSK,
+
+ [JMSK_SCALE_CFG_HSCALE_ENABLE] = JPEG_V680_SCALE_CFG_HSCALE_ENABLE_MSK,
+ [JMSK_SCALE_CFG_VSCALE_ENABLE] = JPEG_V680_SCALE_CFG_VSCALE_ENABLE_MSK,
+ [JMSK_SCALE_CFG_UPSAMPLE_EN] = JPEG_V680_SCALE_CFG_UPSAMPLE_EN_MSK,
+ [JMSK_SCALE_CFG_SUBSAMPLE_EN] = JPEG_V680_SCALE_CFG_SUBSAMPLE_EN_MSK,
+ [JMSK_SCALE_CFG_HSCALE_ALGO] = JPEG_V680_SCALE_CFG_HSCALE_ALGO_MSK,
+ [JMSK_SCALE_CFG_VSCALE_ALGO] = JPEG_V680_SCALE_CFG_VSCALE_ALGO_MSK,
+ [JMSK_SCALE_CFG_H_SCALE_FIR_ALGO] = JPEG_V680_SCALE_CFG_H_SCALE_FIR_ALGO_MSK,
+ [JMSK_SCALE_CFG_V_SCALE_FIR_ALGO] = JPEG_V680_SCALE_CFG_V_SCALE_FIR_ALGO_MSK,
+
+ [JMSK_SCALE_PLNS_OUT_CFG_BLK_WIDTH] = JPEG_V680_SCALE_OUT_CFG_BLOCK_WIDTH_MSK,
+ [JMSK_SCALE_PLNS_OUT_CFG_BLK_HEIGHT] = JPEG_V680_SCALE_OUT_CFG_BLOCK_HEIGHT_MSK,
+
+ [JMSK_SCALE_PLNS_HSTEP_FRACTIONAL] = JPEG_V680_SCALE_PLN_HSTEP_FRACTIONAL_MSK,
+ [JMSK_SCALE_PLNS_HSTEP_INTEGER] = JPEG_V680_SCALE_PLN_HSTEP_INTEGER_MSK,
+ [JMSK_SCALE_PLNS_VSTEP_FRACTIONAL] = JPEG_V680_SCALE_PLN_VSTEP_FRACTIONAL_MSK,
+ [JMSK_SCALE_PLNS_VSTEP_INTEGER] = JPEG_V680_SCALE_PLN_VSTEP_INTEGER_MSK,
+
+ [JMSK_ENC_CFG_IMAGE_FORMAT] = JPEG_V680_ENC_CFG_IMAGE_FORMAT_MSK,
+ [JMSK_ENC_CFG_APPLY_EOI] = JPEG_V680_ENC_CFG_APPLY_EOI_MSK,
+ [JMSK_ENC_CFG_HUFFMAN_SEL] = JPEG_V680_ENC_CFG_HUFFMAN_SEL_MSK,
+ [JMSK_ENC_CFG_FSC_ENABLE] = JPEG_V680_ENC_CFG_FSC_ENABLE_MSK,
+ [JMSK_ENC_CFG_OUTPUT_DISABLE] = JPEG_V680_ENC_CFG_OUTPUT_DISABLE_MSK,
+ [JMSK_ENC_CFG_RST_MARKER_PERIOD] = JPEG_V680_ENC_CFG_RST_MARKER_PERIOD_MSK,
+ [JMSK_ENC_IMAGE_SIZE_WIDTH] = JPEG_V680_ENC_IMG_SIZE_ENCODE_WIDTH_MSK,
+ [JMSK_ENC_IMAGE_SIZE_HEIGHT] = JPEG_V680_ENC_IMG_SIZE_ENCODE_HEIGHT_MSK,
+};
+
+const struct qcom_jpeg_reg_offs qcom_v680_jpeg_hw_reg_offs = {
+ .hw_version = 0x000,
+ .hw_capability = 0x004,
+ .reset_cmd = 0x008,
+ .core_cfg = 0x00c,
+ .hw_cmd = 0x010,
+ .int_mask = 0x018,
+ .int_clr = 0x01c,
+ .int_status = 0x020,
+ .enc_core_state = 0x014,
+
+ .fe = {
+ .pntr = { 0x038, 0x044, 0x050 },
+ .offs = { 0x03c, 0x048, 0x054 },
+ .cnsmd = { 0x040, 0x04c, 0x058 },
+ .bsize = { 0x060, 0x068, 0x070 },
+ .stride = { 0x064, 0x06c, 0x08c },
+ .hinit = { 0x074, 0x078, 0x07c },
+ .vinit = { 0x080, 0x084, 0x088 },
+ .pntr_cnt = 0x05c,
+ .vbpad_cfg = 0x2e8
+ },
+ .fe_cfg = 0x024,
+
+ .we = {
+ .pntr = { 0x0cc, 0x0d0, 0x0d4 },
+ .cnsmd = { 0x0d8, 0x0dc, 0x0e0 },
+ .bsize = { 0x0e8, 0x0ec, 0x0f0 },
+ .stride = { 0x0f4, 0x0f8, 0x0fc },
+ .hinit = { 0x100, 0x104, 0x108 },
+ .hstep = { 0x118, 0x11c, 0x120 },
+ .vinit = { 0x10c, 0x110, 0x114 },
+ .vstep = { 0x124, 0x128, 0x12c },
+ .blocks = { 0x130, 0x134, 0x138 },
+ .pntr_cnt = 0x0e4
+ },
+ .we_cfg = 0x0c0,
+
+ .scale = {
+ .hstep = { 0x27c, 0x280, 0x284 },
+ .vstep = { 0x28c, 0x290, 0x294 },
+ },
+ .scale_cfg = 0x26c,
+ .scale_out_cfg = { 0x270, 0x274, 0x278 },
+
+ .enc_cfg = 0x13c,
+ .enc_img_size = 0x140,
+ .enc_out_size = 0x180,
+
+ .dmi_cfg = 0x298,
+ .dmi_data = 0x2a0,
+ .dmi_addr = 0x29c,
+};
+
+#endif /* QCOM_JENC_HW_INFO_V680_H */
diff --git a/drivers/media/platform/qcom/jpeg/qcom_v780_jenc_hw_info.h b/drivers/media/platform/qcom/jpeg/qcom_v780_jenc_hw_info.h
new file mode 100644
index 000000000000..bf9b4f603cd1
--- /dev/null
+++ b/drivers/media/platform/qcom/jpeg/qcom_v780_jenc_hw_info.h
@@ -0,0 +1,509 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
+ */
+
+#ifndef QCOM_JENC_HW_INFO_V780_H
+#define QCOM_JENC_HW_INFO_V780_H
+
+#include "qcom_jenc_defs.h"
+
+#define JPEG_V780_HW_VER_STEP_POS 0
+#define JPEG_V780_HW_VER_STEP_MSK \
+ (0xffff << JPEG_V780_HW_VER_STEP_POS)
+
+#define JPEG_V780_HW_VER_MINOR_POS 16
+#define JPEG_V780_HW_VER_MINOR_MSK \
+ (0x0fff << JPEG_V780_HW_VER_MINOR_POS)
+
+#define JPEG_V780_HW_VER_MAJOR_POS 28
+#define JPEG_V780_HW_VER_MAJOR_MSK \
+ (0xf << JPEG_V780_HW_VER_MAJOR_POS)
+
+#define JPEG_V780_HW_CAP_ENCODE_MSK BIT(0)
+#define JPEG_V780_HW_CAP_DECODE_MSK BIT(1)
+
+#define JPEG_V780_HW_CAP_UPSCALE_POS 4
+#define JPEG_V780_HW_CAP_UPSCALE_MSK \
+ (0x7 << JPEG_V780_HW_CAP_UPSCALE_POS)
+
+#define JPEG_V780_HW_CAP_DOWNSCALE_POS 8
+#define JPEG_V780_HW_CAP_DOWNSCALE_MSK \
+ (0x7 << JPEG_V780_HW_CAP_DOWNSCALE_POS)
+
+#define JPEG_V780_RST_CMD_FE_RESET_MSK BIT(0)
+#define JPEG_V780_RST_CMD_WE_RESET_MSK BIT(1)
+#define JPEG_V780_RST_CMD_ENCODER_RESET_MSK BIT(4)
+#define JPEG_V780_RST_CMD_DECODER_RESET_MSK BIT(5)
+#define JPEG_V780_RST_CMD_BLOCK_FORMATTER_RST_MSK BIT(6)
+#define JPEG_V780_RST_CMD_SCALE_RESET_MSK BIT(7)
+#define JPEG_V780_RST_CMD_REGISTER_RESET_MSK BIT(13)
+#define JPEG_V780_RST_CMD_MISR_RESET_MSK BIT(16)
+#define JPEG_V780_RST_CMD_CORE_RESET_MSK BIT(17)
+#define JPEG_V780_RST_CMD_JPEG_V780_DOMAIN_RESET_MSK BIT(29)
+#define JPEG_V780_RST_CMD_RESET_BYPASS_MSK BIT(31)
+
+#define JPEG_V780_CORE_CFG_FE_ENABLE_MSK BIT(0)
+#define JPEG_V780_CORE_CFG_WE_ENABLE_MSK BIT(1)
+#define JPEG_V780_CORE_CFG_ENC_ENABLE_MSK BIT(4)
+#define JPEG_V780_CORE_CFG_SCALE_ENABLE_MSK BIT(7)
+#define JPEG_V780_CORE_CFG_TESTBUS_ENABLE_MSK BIT(19)
+#define JPEG_V780_CORE_CFG_MODE_MSK BIT(24)
+#define JPEG_V780_CORE_CFG_CGC_DISABLE_MSK BIT(31)
+
+#define JPEG_V780_CMD_HW_START_MSK BIT(0)
+#define JPEG_V780_CMD_HW_STOP_MSK BIT(1)
+#define JPEG_V780_CMD_CLR_RD_PLN0_QUEUE_MSK BIT(4)
+#define JPEG_V780_CMD_CLR_RD_PLN1_QUEUE_MSK BIT(5)
+#define JPEG_V780_CMD_CLR_RD_PLN2_QUEUE_MSK BIT(6)
+#define JPEG_V780_CMD_CLR_WR_PLN0_QUEUE_MSK BIT(8)
+#define JPEG_V780_CMD_CLR_WR_PLN1_QUEUE_MSK BIT(9)
+#define JPEG_V780_CMD_CLR_WR_PLN2_QUEUE_MSK BIT(10)
+#define JPEG_V780_CMD_APPLY_SWC_RD_PARAMS_MSK BIT(11)
+
+#define JPEG_V780_CORE_STATE_STATUS_ENCODE_STATE_MSK BIT(0)
+#define JPEG_V780_CORE_STATE_STATUS_SCALE_STATE_MSK BIT(2)
+#define JPEG_V780_CORE_STATE_STATUS_REALTIME_STATE_MSK BIT(4)
+#define JPEG_V780_CORE_STATE_STATUS_BUS_STATE_MSK BIT(8)
+#define JPEG_V780_CORE_STATE_STATUS_CGC_STATE_MSK BIT(9)
+
+#define JPEG_V780_FE_CFG_BYTE_ORDERING_POS 0
+#define JPEG_V780_FE_CFG_BYTE_ORDERING_MSK \
+ (0xf << JPEG_V780_FE_CFG_BYTE_ORDERING_POS)
+
+#define JPEG_V780_FE_CFG_BURST_LENGTH_MAX_POS 4
+#define JPEG_V780_FE_CFG_BURST_LENGTH_MAX_MSK \
+ (0xf << JPEG_V780_WE_CFG_BURST_LENGTH_MAX_POS)
+
+#define JPEG_V780_FE_CFG_MEMORY_FORMAT_POS 8
+#define JPEG_V780_FE_CFG_MEMORY_FORMAT_MSK \
+ (0x3 << JPEG_V780_WE_CFG_MEMORY_FORMAT_POS)
+
+#define JPEG_V780_FE_CFG_CBCR_ORDER_MSK BIT(12)
+#define JPEG_V780_FE_CFG_BOTTOM_VPAD_EN_MSK BIT(13)
+#define JPEG_V780_FE_CFG_PLN0_EN_MSK BIT(16)
+#define JPEG_V780_FE_CFG_PLN1_EN_MSK BIT(17)
+#define JPEG_V780_FE_CFG_PLN2_EN_MSK BIT(18)
+#define JPEG_V780_FE_CFG_SIXTEEN_MCU_EN_MSK BIT(21)
+#define JPEG_V780_FE_CFG_MCUS_PER_BLOCK_MSK BIT(22)
+#define JPEG_V780_FE_CFG_MAL_BOUNDARY_MSK BIT(24)
+#define JPEG_V780_FE_CFG_MAL_EN_MSK BIT(27)
+
+#define JPEG_V780_PLN_RD_OFFS_OFFSET_POS 0
+#define JPEG_V780_PLN_RD_OFFS_OFFSET_MSK \
+ (0x1fffffff << JPEG_V780_PLN_RD_OFFS_OFFSET_POS)
+
+#define JPEG_V780_PLN_RD_BUFF_SIZE_WIDTH_POS 0
+#define JPEG_V780_PLN_RD_BUFF_SIZE_WIDTH_MSK \
+ (0xffff << JPEG_V780_PLN_RD_BUFF_SIZE_WIDTH_POS)
+
+#define JPEG_V780_PLN_RD_BUFF_SIZE_HEIGHT_POS 16
+#define JPEG_V780_PLN_RD_BUFF_SIZE_HEIGHT_MSK \
+ (0xffff << JPEG_V780_PLN_RD_BUFF_SIZE_HEIGHT_POS)
+
+#define JPEG_V780_PLN_RD_STRIDE_STRIDE_POS 0
+#define JPEG_V780_PLN_RD_STRIDE_STRIDE_MSK \
+ (0xffff << JPEG_V780_PLN_RD_STRIDE_STRIDE_POS)
+
+#define JPEG_V780_PLN_RD_HINIT_FRACTIONAL_POS 0
+#define JPEG_V780_PLN_RD_HINIT_FRACTIONAL_MSK \
+ (0x1fffff << JPEG_V780_PLN_RD_HINIT_FRACTIONAL_POS)
+
+#define JPEG_V780_PLN_RD_VINIT_FRACTIONAL_POS 0
+#define JPEG_V780_PLN_RD_VINIT_FRACTIONAL_MSK \
+ (0x1fffff << JPEG_V780_PLN_RD_VINIT_FRACTIONAL_POS)
+
+#define JPEG_V780_WE_CFG_BYTE_ORDERING_POS 0
+#define JPEG_V780_WE_CFG_BYTE_ORDERING_MSK \
+ (0xf << JPEG_V780_WE_CFG_BYTE_ORDERING_POS)
+
+#define JPEG_V780_WE_CFG_BURST_LENGTH_MAX_POS 4
+#define JPEG_V780_WE_CFG_BURST_LENGTH_MAX_MSK \
+ (0xf << JPEG_V780_WE_CFG_BURST_LENGTH_MAX_POS)
+
+#define JPEG_V780_WE_CFG_MEMORY_FORMAT_POS 8
+#define JPEG_V780_WE_CFG_MEMORY_FORMAT_MSK \
+ (0x3 << JPEG_V780_WE_CFG_MEMORY_FORMAT_POS)
+
+#define JPEG_V780_WE_CFG_CBCR_ORDER_MSK BIT(12)
+#define JPEG_V780_WE_CFG_PLN0_EN_MSK BIT(16)
+#define JPEG_V780_WE_CFG_PLN1_EN_MSK BIT(17)
+#define JPEG_V780_WE_CFG_PLN2_EN_MSK BIT(18)
+#define JPEG_V780_WE_CFG_MAL_BOUNDARY_MSK BIT(24)
+#define JPEG_V780_WE_CFG_MAL_EN_MSK BIT(27)
+#define JPEG_V780_WE_CFG_POP_BUFF_ON_EOS_MSK BIT(28)
+
+#define JPEG_V780_PLN_WR_BUFF_SIZE_WIDTH_POS 0
+#define JPEG_V780_PLN_WR_BUFF_SIZE_WIDTH_MSK \
+ (0xffff << JPEG_V780_PLN_WR_BUFF_SIZE_WIDTH_POS)
+
+#define JPEG_V780_PLN_WR_BUFF_SIZE_HEIGHT_POS 16
+#define JPEG_V780_PLN_WR_BUFF_SIZE_HEIGHT_MSK \
+ (0xffff << JPEG_V780_PLN_WR_BUFF_SIZE_HEIGHT_POS)
+
+#define JPEG_V780_PLN_WR_STRIDE_STRIDE_POS 0
+#define JPEG_V780_PLN_WR_STRIDE_STRIDE_MSK \
+ (0xffff << JPEG_V780_PLN_WR_STRIDE_STRIDE_POS)
+
+#define JPEG_V780_PLN_WR_HINIT_INTEGER_POS 0
+#define JPEG_V780_PLN_WR_HINIT_INTEGER_MSK \
+ (0xffff << JPEG_V780_PLN_WR_HINIT_INTEGER_POS)
+
+#define JPEG_V780_PLN_WR_VINIT_INTEGER_POS 0
+#define JPEG_V780_PLN_WR_VINIT_INTEGER_MSK \
+ (0xffff << JPEG_V780_PLN_WR_VINIT_INTEGER_POS)
+
+#define JPEG_V780_PLN_WR_HSTEP_INTEGER_POS 0
+#define JPEG_V780_PLN_WR_HSTEP_INTEGER_MSK \
+ (0x1ffff << JPEG_V780_PLN_WR_HSTEP_INTEGER_POS)
+
+#define JPEG_V780_PLN_WR_VSTEP_INTEGER_POS 0
+#define JPEG_V780_PLN_WR_VSTEP_INTEGER_MSK \
+ (0x1ffff << JPEG_V780_PLN_WR_VSTEP_INTEGER_POS)
+
+#define JPEG_V780_PLN_WR_BLK_CFG_BLOCKS_PER_COL_POS 0
+#define JPEG_V780_PLN_WR_BLK_CFG_BLOCKS_PER_COL_MSK \
+ (0xffff << JPEG_V780_PLN_WR_BLK_CFG_BLOCKS_PER_COL_POS)
+
+#define JPEG_V780_PLN_WR_BLK_CFG_BLOCKS_PER_ROW_POS 16
+#define JPEG_V780_PLN_WR_BLK_CFG_BLOCKS_PER_ROW_MSK \
+ (0xffff << JPEG_V780_PLN_WR_BLK_CFG_BLOCKS_PER_ROW_POS)
+
+#define JPEG_V780_ENC_CFG_IMAGE_FORMAT_POS 0
+#define JPEG_V780_ENC_CFG_IMAGE_FORMAT_MSK \
+ (0x7 << JPEG_V780_ENC_CFG_IMAGE_FORMAT_POS)
+
+#define JPEG_V780_ENC_CFG_APPLY_EOI_MSK BIT(7)
+#define JPEG_V780_ENC_CFG_HUFFMAN_SEL_MSK BIT(8)
+#define JPEG_V780_ENC_CFG_FSC_ENABLE_MSK BIT(11)
+#define JPEG_V780_ENC_CFG_OUTPUT_DISABLE_MSK BIT(15)
+#define JPEG_V780_ENC_CFG_RST_MARKER_PERIOD_MSK BIT(16)
+
+#define JPEG_V780_ENC_IMG_SIZE_ENCODE_WIDTH_POS 0u
+#define JPEG_V780_ENC_IMG_SIZE_ENCODE_WIDTH_MSK \
+ (0x1fffu << JPEG_V780_ENC_IMG_SIZE_ENCODE_WIDTH_POS)
+
+#define JPEG_V780_ENC_IMG_SIZE_ENCODE_HEIGHT_POS 16u
+#define JPEG_V780_ENC_IMG_SIZE_ENCODE_HEIGHT_MSK \
+ (0x1fffu << JPEG_V780_ENC_IMG_SIZE_ENCODE_HEIGHT_POS)
+
+#define JPEG_V780_OUTPUT_SIZE_STATUS_OUT_SIZE_BYTES_POS 0
+#define JPEG_V780_OUTPUT_SIZE_STATUS_OUT_SIZE_BYTES_MSK \
+ (0x1fffffff << JPEG_V780_OUTPUT_SIZE_STATUS_OUT_SIZE_BYTES_POS)
+
+#define JPEG_V780_SCALE_CFG_HSCALE_ENABLE_MSK BIT(4)
+#define JPEG_V780_SCALE_CFG_VSCALE_ENABLE_MSK BIT(5)
+#define JPEG_V780_SCALE_CFG_UPSAMPLE_EN_MSK BIT(6)
+#define JPEG_V780_SCALE_CFG_SUBSAMPLE_EN_MSK BIT(7)
+#define JPEG_V780_SCALE_CFG_HSCALE_ALGO_MSK BIT(8)
+#define JPEG_V780_SCALE_CFG_VSCALE_ALGO_MSK BIT(9)
+
+#define JPEG_V780_SCALE_CFG_H_SCALE_FIR_ALGO_POS 12u
+#define JPEG_V780_SCALE_CFG_H_SCALE_FIR_ALGO_MSK \
+ (0x3u << JPEG_V780_SCALE_CFG_H_SCALE_FIR_ALGO_POS)
+
+#define JPEG_V780_SCALE_CFG_V_SCALE_FIR_ALGO_POS 16u
+#define JPEG_V780_SCALE_CFG_V_SCALE_FIR_ALGO_MSK \
+ (0x3u << JPEG_V780_SCALE_CFG_V_SCALE_FIR_ALGO_POS)
+
+#define JPEG_V780_SCALE_OUT_CFG_BLOCK_WIDTH_POS 0
+#define JPEG_V780_SCALE_OUT_CFG_BLOCK_WIDTH_MSK \
+ (0xff << JPEG_V780_SCALE_OUT_CFG_BLOCK_WIDTH_POS)
+
+#define JPEG_V780_SCALE_OUT_CFG_BLOCK_HEIGHT_POS 16
+#define JPEG_V780_SCALE_OUT_CFG_BLOCK_HEIGHT_MSK \
+ (0xf << JPEG_V780_SCALE_OUT_CFG_BLOCK_HEIGHT_POS)
+
+#define JPEG_V780_SCALE_PLN_HSTEP_FRACTIONAL_POS 0
+#define JPEG_V780_SCALE_PLN_HSTEP_FRACTIONAL_MSK \
+ (0x1fffff << JPEG_V780_SCALE_PLN_HSTEP_FRACTIONAL_POS)
+
+#define JPEG_V780_SCALE_PLN_HSTEP_INTEGER_POS 21
+#define JPEG_V780_SCALE_PLN_HSTEP_INTEGER_MSK \
+ (0x3f << JPEG_V780_SCALE_PLN_HSTEP_INTEGER_POS)
+
+#define JPEG_V780_SCALE_PLN_VSTEP_FRACTIONAL_POS 0
+#define JPEG_V780_SCALE_PLN_VSTEP_FRACTIONAL_MSK \
+ (0x1fffff << JPEG_V780_SCALE_PLN_VSTEP_FRACTIONAL_POS)
+
+#define JPEG_V780_SCALE_PLN_VSTEP_INTEGER_POS 21
+#define JPEG_V780_SCALE_PLN_VSTEP_INTEGER_MSK \
+ (0x3f << JPEG_V780_SCALE_PLN_VSTEP_INTEGER_POS)
+
+#define JPEG_V780_DMI_CFG_MEM_SEL_POS 0
+#define JPEG_V780_DMI_CFG_MEM_SEL_MSK \
+ (0x7 << JPEG_V780_DMI_CFG_MEM_SEL_POS)
+
+#define JPEG_V780_DMI_CFG_AUTO_INC_EN_MSK BIT(4)
+
+#define JPEG_V780_DMI_ADDR_ADDR_POS 0
+#define JPEG_V780_DMI_ADDR_ADDR_MSK \
+ (0x3ff << JPEG_V780_DMI_ADDR_ADDR_POS)
+
+#define JPEG_V780_TESTBUS_CFG_BUS_SEL_POS 0
+#define JPEG_V780_TESTBUS_CFG_BUS_SEL_MSK \
+ (0x3f << JPEG_V780_TESTBUS_CFG_BUS_SEL_POS)
+
+#define JPEG_V780_FE_VBPAD_CFG_BLOCK_ROW_POS 0
+#define JPEG_V780_FE_VBPAD_CFG_BLOCK_ROW_MSK \
+ (0x1fff << JPEG_V780_FE_VBPAD_CFG_BLOCK_ROW_POS)
+
+#define JPEG_V780_PLN_RD_HINIT_INT_INTEGER_POS 0
+#define JPEG_V780_PLN_RD_HINIT_INT_INTEGER_MSK \
+ (0x1ffff << JPEG_V780_PLN_RD_HINIT_INT_INTEGER_POS)
+
+#define JPEG_V780_PLN_RD_VINIT_INT_INTEGER_POS 0
+#define JPEG_V780_PLN_RD_VINIT_INT_INTEGER_MSK \
+ (0x1ffff << JPEG_V780_PLN_RD_VINIT_INT_INTEGER_POS)
+
+#define JPEG_V780_IRQ_STATUS_SESSION_DONE_MSK BIT(0)
+#define JPEG_V780_IRQ_STATUS_RD_BUF_PLN0_DONE_MSK BIT(4)
+#define JPEG_V780_IRQ_STATUS_RD_BUF_PLN1_DONE_MSK BIT(5)
+#define JPEG_V780_IRQ_STATUS_RD_BUF_PLN2_DONE_MSK BIT(6)
+#define JPEG_V780_IRQ_STATUS_RD_BUF_PLN0_REQ_ATTN_MSK BIT(7)
+#define JPEG_V780_IRQ_STATUS_RD_BUF_PLN1_REQ_ATTN_MSK BIT(8)
+#define JPEG_V780_IRQ_STATUS_RD_BUF_PLN2_REQ_ATTN_MSK BIT(9)
+#define JPEG_V780_IRQ_STATUS_WR_BUF_PLN0_DONE_MSK BIT(10)
+#define JPEG_V780_IRQ_STATUS_WR_BUF_PLN1_DONE_MSK BIT(11)
+#define JPEG_V780_IRQ_STATUS_WR_BUF_PLN2_DONE_MSK BIT(12)
+#define JPEG_V780_IRQ_STATUS_WR_BUF_PLN0_REQ_ATTN_MSK BIT(13)
+#define JPEG_V780_IRQ_STATUS_WR_BUF_PLN1_REQ_ATTN_MSK BIT(14)
+#define JPEG_V780_IRQ_STATUS_WR_BUF_PLN2_REQ_ATTN_MSK BIT(15)
+#define JPEG_V780_IRQ_STATUS_DCD_UNESCAPED_FF_MSK BIT(19)
+#define JPEG_V780_IRQ_STATUS_DCD_HUFFMAN_ERROR_MSK BIT(20)
+#define JPEG_V780_IRQ_STATUS_DCD_COEFF_ERROR_MSK BIT(21)
+#define JPEG_V780_IRQ_STATUS_DCD_MISSING_BITSTUFF_MSK BIT(22)
+#define JPEG_V780_IRQ_STATUS_DCD_SCAN_UNDERFLOW_MSK BIT(23)
+#define JPEG_V780_IRQ_STATUS_DCD_INVALID_RSM_MSK BIT(24)
+#define JPEG_V780_IRQ_STATUS_DCD_INVALID_RSM_SEQ_MSK BIT(25)
+#define JPEG_V780_IRQ_STATUS_DCD_MISSING_RSM_MSK BIT(26)
+#define JPEG_V780_IRQ_STATUS_STOP_ACK_MSK BIT(27)
+#define JPEG_V780_IRQ_STATUS_RESET_ACK_MSK BIT(28)
+
+#define JPEG_V780_IRQ_STATUS_ENABLE_ALL_MSK ~0
+#define JPEG_V780_IRQ_STATUS_DISABLE_ALL_MSK 0
+#define JPEG_V780_IRQ_STATUS_CLEAR_ALL_MSK JPEG_V780_IRQ_STATUS_ENABLE_ALL_MSK
+
+const u32 qcom_v780_jpeg_hw_reg_mask[] = {
+ [JMSK_HW_VER_STEP] = JPEG_V780_HW_VER_STEP_MSK,
+ [JMSK_HW_VER_MINOR] = JPEG_V780_HW_VER_MINOR_MSK,
+ [JMSK_HW_VER_MAJOR] = JPEG_V780_HW_VER_MAJOR_MSK,
+
+ [JMSK_HW_CAP_ENCODE] = JPEG_V780_HW_CAP_ENCODE_MSK,
+ [JMSK_HW_CAP_DECODE] = JPEG_V780_HW_CAP_DECODE_MSK,
+ [JMSK_HW_CAP_UPSCALE] = JPEG_V780_HW_CAP_UPSCALE_MSK,
+ [JMSK_HW_CAP_DOWNSCALE] = JPEG_V780_HW_CAP_DOWNSCALE_MSK,
+
+ [JMSK_RST_CMD_COMMON] =
+ (JPEG_V780_RST_CMD_FE_RESET_MSK |
+ JPEG_V780_RST_CMD_WE_RESET_MSK |
+ JPEG_V780_RST_CMD_ENCODER_RESET_MSK |
+ JPEG_V780_RST_CMD_BLOCK_FORMATTER_RST_MSK |
+ JPEG_V780_RST_CMD_SCALE_RESET_MSK |
+ JPEG_V780_RST_CMD_REGISTER_RESET_MSK |
+ JPEG_V780_RST_CMD_MISR_RESET_MSK |
+ JPEG_V780_RST_CMD_CORE_RESET_MSK |
+ JPEG_V780_RST_CMD_JPEG_V780_DOMAIN_RESET_MSK),
+
+ [JMSK_RST_CMD_FE_RESET] = JPEG_V780_RST_CMD_FE_RESET_MSK,
+ [JMSK_RST_CMD_WE_RESET] = JPEG_V780_RST_CMD_WE_RESET_MSK,
+ [JMSK_RST_CMD_ENCODER_RESET] = JPEG_V780_RST_CMD_ENCODER_RESET_MSK,
+ [JMSK_RST_CMD_DECODER_RESET] = JPEG_V780_RST_CMD_DECODER_RESET_MSK,
+ [JMSK_RST_CMD_BLOCK_FORMATTER_RST] = JPEG_V780_RST_CMD_BLOCK_FORMATTER_RST_MSK,
+ [JMSK_RST_CMD_SCALE_RESET] = JPEG_V780_RST_CMD_SCALE_RESET_MSK,
+ [JMSK_RST_CMD_REGISTER_RESET] = JPEG_V780_RST_CMD_REGISTER_RESET_MSK,
+ [JMSK_RST_CMD_MISR_RESET] = JPEG_V780_RST_CMD_MISR_RESET_MSK,
+ [JMSK_RST_CMD_CORE_RESET] = JPEG_V780_RST_CMD_CORE_RESET_MSK,
+ [JMSK_RST_CMD_JMSK_DOMAIN_RESET] = JPEG_V780_RST_CMD_JPEG_V780_DOMAIN_RESET_MSK,
+ [JMSK_RST_CMD_RESET_BYPASS] = JPEG_V780_RST_CMD_RESET_BYPASS_MSK,
+
+ [JMSK_CORE_CFG_FE_ENABLE] = JPEG_V780_CORE_CFG_FE_ENABLE_MSK,
+ [JMSK_CORE_CFG_WE_ENABLE] = JPEG_V780_CORE_CFG_WE_ENABLE_MSK,
+ [JMSK_CORE_CFG_ENC_ENABLE] = JPEG_V780_CORE_CFG_ENC_ENABLE_MSK,
+ [JMSK_CORE_CFG_SCALE_ENABLE] = JPEG_V780_CORE_CFG_SCALE_ENABLE_MSK,
+ [JMSK_CORE_CFG_TESTBUS_ENABLE] = JPEG_V780_CORE_CFG_TESTBUS_ENABLE_MSK,
+ [JMSK_CORE_CFG_MODE] = JPEG_V780_CORE_CFG_ENC_ENABLE_MSK,
+ [JMSK_CORE_CFG_CGC_DISABLE] = JPEG_V780_CORE_CFG_CGC_DISABLE_MSK,
+
+ [JMSK_CMD_HW_START] = JPEG_V780_CMD_HW_START_MSK,
+ [JMSK_CMD_HW_STOP] = JPEG_V780_CMD_HW_STOP_MSK,
+
+ [JMSK_CMD_CLR_RD_PLNS_QUEUE] =
+ (JPEG_V780_CMD_CLR_RD_PLN0_QUEUE_MSK |
+ JPEG_V780_CMD_CLR_RD_PLN1_QUEUE_MSK |
+ JPEG_V780_CMD_CLR_RD_PLN2_QUEUE_MSK),
+ [JMSK_CMD_CLR_WR_PLNS_QUEUE] =
+ (JPEG_V780_CMD_CLR_WR_PLN0_QUEUE_MSK |
+ JPEG_V780_CMD_CLR_WR_PLN1_QUEUE_MSK |
+ JPEG_V780_CMD_CLR_WR_PLN2_QUEUE_MSK),
+
+ [JMSK_CMD_APPLY_SWC_RD_PARAMS] = JPEG_V780_CMD_APPLY_SWC_RD_PARAMS_MSK,
+
+ [JMSK_CORE_STATUS_ENCODE_STATE] = JPEG_V780_CORE_STATE_STATUS_ENCODE_STATE_MSK,
+ [JMSK_CORE_STATUS_SCALE_STATE] = JPEG_V780_CORE_STATE_STATUS_SCALE_STATE_MSK,
+ [JMSK_CORE_STATUS_RT_STATE] = JPEG_V780_CORE_STATE_STATUS_REALTIME_STATE_MSK,
+ [JMSK_CORE_STATUS_BUS_STATE] = JPEG_V780_CORE_STATE_STATUS_BUS_STATE_MSK,
+ [JMSK_CORE_STATUS_CGC_STATE] = JPEG_V780_CORE_STATE_STATUS_CGC_STATE_MSK,
+
+ [JMSK_IRQ_ENABLE_ALL] = JPEG_V780_IRQ_STATUS_ENABLE_ALL_MSK,
+ [JMSK_IRQ_DISABLE_ALL] = JPEG_V780_IRQ_STATUS_DISABLE_ALL_MSK,
+ [JMSK_IRQ_CLEAR_ALL] = JPEG_V780_IRQ_STATUS_CLEAR_ALL_MSK,
+
+ [JMSK_IRQ_STATUS_SESSION_DONE] = JPEG_V780_IRQ_STATUS_SESSION_DONE_MSK,
+
+ [JMSK_IRQ_STATUS_RD_BUF_PLN0_DONE] = JPEG_V780_IRQ_STATUS_RD_BUF_PLN0_DONE_MSK,
+ [JMSK_IRQ_STATUS_RD_BUF_PLN1_DONE] = JPEG_V780_IRQ_STATUS_RD_BUF_PLN1_DONE_MSK,
+ [JMSK_IRQ_STATUS_RD_BUF_PLN2_DONE] = JPEG_V780_IRQ_STATUS_RD_BUF_PLN2_DONE_MSK,
+ [JMSK_IRQ_STATUS_RD_BUF_PLNS_ATTN] =
+ (JPEG_V780_IRQ_STATUS_RD_BUF_PLN0_REQ_ATTN_MSK |
+ JPEG_V780_IRQ_STATUS_RD_BUF_PLN1_REQ_ATTN_MSK |
+ JPEG_V780_IRQ_STATUS_RD_BUF_PLN2_REQ_ATTN_MSK),
+
+ [JMSK_IRQ_STATUS_WR_BUF_PLN0_DONE] = JPEG_V780_IRQ_STATUS_WR_BUF_PLN0_DONE_MSK,
+ [JMSK_IRQ_STATUS_WR_BUF_PLN1_DONE] = JPEG_V780_IRQ_STATUS_WR_BUF_PLN1_DONE_MSK,
+ [JMSK_IRQ_STATUS_WR_BUF_PLN2_DONE] = JPEG_V780_IRQ_STATUS_WR_BUF_PLN2_DONE_MSK,
+ [JMSK_IRQ_STATUS_WR_BUF_PLNS_ATTN] =
+ (JPEG_V780_IRQ_STATUS_WR_BUF_PLN0_REQ_ATTN_MSK |
+ JPEG_V780_IRQ_STATUS_WR_BUF_PLN1_REQ_ATTN_MSK |
+ JPEG_V780_IRQ_STATUS_WR_BUF_PLN2_REQ_ATTN_MSK),
+
+ [JMSK_IRQ_STATUS_SESSION_ERROR] =
+ (JPEG_V780_IRQ_STATUS_DCD_UNESCAPED_FF_MSK |
+ JPEG_V780_IRQ_STATUS_DCD_HUFFMAN_ERROR_MSK |
+ JPEG_V780_IRQ_STATUS_DCD_COEFF_ERROR_MSK |
+ JPEG_V780_IRQ_STATUS_DCD_MISSING_BITSTUFF_MSK |
+ JPEG_V780_IRQ_STATUS_DCD_SCAN_UNDERFLOW_MSK |
+ JPEG_V780_IRQ_STATUS_DCD_INVALID_RSM_MSK |
+ JPEG_V780_IRQ_STATUS_DCD_INVALID_RSM_SEQ_MSK |
+ JPEG_V780_IRQ_STATUS_DCD_MISSING_RSM_MSK),
+
+ [JMSK_IRQ_STATUS_STOP_ACK] = JPEG_V780_IRQ_STATUS_STOP_ACK_MSK,
+ [JMSK_IRQ_STATUS_RESET_ACK] = JPEG_V780_IRQ_STATUS_RESET_ACK_MSK,
+
+ [JMSK_FE_CFG_BYTE_ORDERING] = JPEG_V780_FE_CFG_BYTE_ORDERING_MSK,
+ [JMSK_FE_CFG_BURST_LENGTH_MAX] = JPEG_V780_FE_CFG_BURST_LENGTH_MAX_MSK,
+ [JMSK_FE_CFG_MEMORY_FORMAT] = JPEG_V780_FE_CFG_MEMORY_FORMAT_MSK,
+ [JMSK_FE_CFG_CBCR_ORDER] = JPEG_V780_FE_CFG_CBCR_ORDER_MSK,
+ [JMSK_FE_CFG_BOTTOM_VPAD_EN] = JPEG_V780_FE_CFG_BOTTOM_VPAD_EN_MSK,
+ [JMSK_FE_CFG_PLN0_EN] = JPEG_V780_FE_CFG_PLN0_EN_MSK,
+ [JMSK_FE_CFG_PLN1_EN] = JPEG_V780_FE_CFG_PLN1_EN_MSK,
+ [JMSK_FE_CFG_PLN2_EN] = JPEG_V780_FE_CFG_PLN2_EN_MSK,
+ [JMSK_FE_CFG_SIXTEEN_MCU_EN] = JPEG_V780_FE_CFG_SIXTEEN_MCU_EN_MSK,
+ [JMSK_FE_CFG_MCUS_PER_BLOCK] = JPEG_V780_FE_CFG_MCUS_PER_BLOCK_MSK,
+ [JMSK_FE_CFG_MAL_BOUNDARY] = JPEG_V780_FE_CFG_MAL_BOUNDARY_MSK,
+ [JMSK_FE_CFG_MAL_EN] = JPEG_V780_FE_CFG_MAL_EN_MSK,
+
+ [JMSK_FE_VBPAD_CFG_BLOCK_ROW] = JPEG_V780_FE_VBPAD_CFG_BLOCK_ROW_MSK,
+
+ [JMSK_PLNS_RD_OFFSET] = JPEG_V780_PLN_RD_OFFS_OFFSET_MSK,
+ [JMSK_PLNS_RD_BUF_SIZE_WIDTH] = JPEG_V780_PLN_RD_BUFF_SIZE_WIDTH_MSK,
+ [JMSK_PLNS_RD_BUF_SIZE_HEIGHT] = JPEG_V780_PLN_RD_BUFF_SIZE_HEIGHT_MSK,
+ [JMSK_PLNS_RD_STRIDE] = JPEG_V780_PLN_RD_STRIDE_STRIDE_MSK,
+ [JMSK_PLNS_RD_HINIT] = JPEG_V780_PLN_RD_HINIT_FRACTIONAL_MSK,
+ [JMSK_PLNS_RD_VINIT] = JPEG_V780_PLN_RD_VINIT_FRACTIONAL_MSK,
+
+ [JMSK_WE_CFG_BYTE_ORDERING] = JPEG_V780_WE_CFG_BYTE_ORDERING_MSK,
+ [JMSK_WE_CFG_BURST_LENGTH_MAX] = JPEG_V780_WE_CFG_BURST_LENGTH_MAX_MSK,
+ [JMSK_WE_CFG_MEMORY_FORMAT] = JPEG_V780_WE_CFG_MEMORY_FORMAT_MSK,
+ [JMSK_WE_CFG_CBCR_ORDER] = JPEG_V780_WE_CFG_CBCR_ORDER_MSK,
+ [JMSK_WE_CFG_PLN0_EN] = JPEG_V780_WE_CFG_PLN0_EN_MSK,
+ [JMSK_WE_CFG_PLN1_EN] = JPEG_V780_WE_CFG_PLN1_EN_MSK,
+ [JMSK_WE_CFG_PLN2_EN] = JPEG_V780_WE_CFG_PLN2_EN_MSK,
+ [JMSK_WE_CFG_MAL_BOUNDARY] = JPEG_V780_WE_CFG_MAL_BOUNDARY_MSK,
+ [JMSK_WE_CFG_MAL_EN] = JPEG_V780_WE_CFG_MAL_EN_MSK,
+ [JMSK_WE_CFG_POP_BUFF_ON_EOS] = JPEG_V780_WE_CFG_POP_BUFF_ON_EOS_MSK,
+
+ [JMSK_PLNS_WR_BUF_SIZE_WIDTH] = JPEG_V780_PLN_WR_BUFF_SIZE_WIDTH_MSK,
+ [JMSK_PLNS_WR_BUF_SIZE_HEIGHT] = JPEG_V780_PLN_WR_BUFF_SIZE_HEIGHT_MSK,
+
+ [JMSK_PLNS_WR_STRIDE] = JPEG_V780_PLN_WR_STRIDE_STRIDE_MSK,
+ [JMSK_PLNS_WR_HINIT] = JPEG_V780_PLN_WR_HINIT_INTEGER_MSK,
+ [JMSK_PLNS_WR_VINIT] = JPEG_V780_PLN_WR_VINIT_INTEGER_MSK,
+ [JMSK_PLNS_WR_HSTEP] = JPEG_V780_PLN_WR_HSTEP_INTEGER_MSK,
+ [JMSK_PLNS_WR_VSTEP] = JPEG_V780_PLN_WR_VSTEP_INTEGER_MSK,
+
+ [JMSK_PLNS_WR_BLOCK_CFG_PER_COL] = JPEG_V780_PLN_WR_BLK_CFG_BLOCKS_PER_COL_MSK,
+ [JMSK_PLNS_WR_BLOCK_CFG_PER_RAW] = JPEG_V780_PLN_WR_BLK_CFG_BLOCKS_PER_ROW_MSK,
+
+ [JMSK_SCALE_CFG_HSCALE_ENABLE] = JPEG_V780_SCALE_CFG_HSCALE_ENABLE_MSK,
+ [JMSK_SCALE_CFG_VSCALE_ENABLE] = JPEG_V780_SCALE_CFG_VSCALE_ENABLE_MSK,
+ [JMSK_SCALE_CFG_UPSAMPLE_EN] = JPEG_V780_SCALE_CFG_UPSAMPLE_EN_MSK,
+ [JMSK_SCALE_CFG_SUBSAMPLE_EN] = JPEG_V780_SCALE_CFG_SUBSAMPLE_EN_MSK,
+ [JMSK_SCALE_CFG_HSCALE_ALGO] = JPEG_V780_SCALE_CFG_HSCALE_ALGO_MSK,
+ [JMSK_SCALE_CFG_VSCALE_ALGO] = JPEG_V780_SCALE_CFG_VSCALE_ALGO_MSK,
+ [JMSK_SCALE_CFG_H_SCALE_FIR_ALGO] = JPEG_V780_SCALE_CFG_H_SCALE_FIR_ALGO_MSK,
+ [JMSK_SCALE_CFG_V_SCALE_FIR_ALGO] = JPEG_V780_SCALE_CFG_V_SCALE_FIR_ALGO_MSK,
+
+ [JMSK_SCALE_PLNS_OUT_CFG_BLK_WIDTH] = JPEG_V780_SCALE_OUT_CFG_BLOCK_WIDTH_MSK,
+ [JMSK_SCALE_PLNS_OUT_CFG_BLK_HEIGHT] = JPEG_V780_SCALE_OUT_CFG_BLOCK_HEIGHT_MSK,
+
+ [JMSK_SCALE_PLNS_HSTEP_FRACTIONAL] = JPEG_V780_SCALE_PLN_HSTEP_FRACTIONAL_MSK,
+ [JMSK_SCALE_PLNS_HSTEP_INTEGER] = JPEG_V780_SCALE_PLN_HSTEP_INTEGER_MSK,
+ [JMSK_SCALE_PLNS_VSTEP_FRACTIONAL] = JPEG_V780_SCALE_PLN_VSTEP_FRACTIONAL_MSK,
+ [JMSK_SCALE_PLNS_VSTEP_INTEGER] = JPEG_V780_SCALE_PLN_VSTEP_INTEGER_MSK,
+
+ [JMSK_ENC_CFG_IMAGE_FORMAT] = JPEG_V780_ENC_CFG_IMAGE_FORMAT_MSK,
+ [JMSK_ENC_CFG_APPLY_EOI] = JPEG_V780_ENC_CFG_APPLY_EOI_MSK,
+ [JMSK_ENC_CFG_HUFFMAN_SEL] = JPEG_V780_ENC_CFG_HUFFMAN_SEL_MSK,
+ [JMSK_ENC_CFG_FSC_ENABLE] = JPEG_V780_ENC_CFG_FSC_ENABLE_MSK,
+ [JMSK_ENC_CFG_OUTPUT_DISABLE] = JPEG_V780_ENC_CFG_OUTPUT_DISABLE_MSK,
+ [JMSK_ENC_CFG_RST_MARKER_PERIOD] = JPEG_V780_ENC_CFG_RST_MARKER_PERIOD_MSK,
+ [JMSK_ENC_IMAGE_SIZE_WIDTH] = JPEG_V780_ENC_IMG_SIZE_ENCODE_WIDTH_MSK,
+ [JMSK_ENC_IMAGE_SIZE_HEIGHT] = JPEG_V780_ENC_IMG_SIZE_ENCODE_HEIGHT_MSK,
+};
+
+const struct qcom_jpeg_reg_offs qcom_v780_jpeg_hw_reg_offs = {
+ .hw_version = 0x000,
+ .hw_capability = 0x004,
+ .reset_cmd = 0x008,
+ .core_cfg = 0x00c,
+ .hw_cmd = 0x010,
+ .int_mask = 0x018,
+ .int_clr = 0x01c,
+ .int_status = 0x020,
+ .enc_core_state = 0x014,
+
+ .fe = {
+ .pntr = { 0x038, 0x044, 0x050 },
+ .offs = { 0x03c, 0x048, 0x054 },
+ .cnsmd = { 0x040, 0x04c, 0x058 },
+ .bsize = { 0x060, 0x068, 0x070 },
+ .stride = { 0x064, 0x06c, 0x08c },
+ .hinit = { 0x074, 0x078, 0x07c },
+ .vinit = { 0x080, 0x084, 0x088 },
+ .pntr_cnt = 0x05c,
+ .vbpad_cfg = 0x2e8
+ },
+ .fe_cfg = 0x024,
+
+ .we = {
+ .pntr = { 0x0cc, 0x0d0, 0x0d4 },
+ .cnsmd = { 0x0d8, 0x0dc, 0x0e0 },
+ .bsize = { 0x0e8, 0x0ec, 0x0f0 },
+ .stride = { 0x0f4, 0x0f8, 0x0fc },
+ .hinit = { 0x100, 0x104, 0x108 },
+ .hstep = { 0x118, 0x11c, 0x120 },
+ .vinit = { 0x10c, 0x110, 0x114 },
+ .vstep = { 0x124, 0x128, 0x12c },
+ .blocks = { 0x130, 0x134, 0x138 },
+ .pntr_cnt = 0x0e4
+ },
+ .we_cfg = 0x0c0,
+
+ .scale = {
+ .hstep = { 0x27c, 0x280, 0x284 },
+ .vstep = { 0x28c, 0x290, 0x294 },
+ },
+ .scale_cfg = 0x26c,
+ .scale_out_cfg = { 0x270, 0x274, 0x278 },
+
+ .enc_cfg = 0x13c,
+ .enc_img_size = 0x140,
+ .enc_out_size = 0x180,
+
+ .dmi_cfg = 0x298,
+ .dmi_data = 0x2a0,
+ .dmi_addr = 0x29c,
+};
+
+#endif /* QCOM_JENC_HW_INFO_V780_H */
--
2.34.1
^ permalink raw reply related [flat|nested] 15+ messages in thread
* [PATCH 3/3] arm64: qcom: dts: qcm6490: Add JPEG encoder DT properties
2026-05-15 11:46 [PATCH 0/3] Subject: [PATCH 0/3] media: qcom: Add Qualcomm JPEG encoder driver Atanas Filipov
2026-05-15 11:46 ` [PATCH 1/3] media: dt-bindings: qcom: add JPEG encoder binding Atanas Filipov
2026-05-15 11:47 ` [PATCH 2/3] qcom: media: jpeg: Add Qualcomm JPEG V4L2 encoder Atanas Filipov
@ 2026-05-15 11:47 ` Atanas Filipov
2026-05-15 12:16 ` Dmitry Baryshkov
` (2 more replies)
2 siblings, 3 replies; 15+ messages in thread
From: Atanas Filipov @ 2026-05-15 11:47 UTC (permalink / raw)
To: Bryan O'Donoghue, Mauro Carvalho Chehab, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Kapatrala Syed,
Hariram Purushothaman, Bjorn Andersson, Konrad Dybcio,
Gjorgji Rosikopulos, afilipov
Cc: linux-media, linux-arm-msm, devicetree, linux-kernel,
Atanas Filipov
Add the required JPEG encoder definitions to the device tree.
Signed-off-by: Atanas Filipov <atanas.filipov@oss.qualcomm.com>
---
arch/arm64/boot/dts/qcom/kodiak.dtsi | 52 ++++++++++++++++++++++++++++++++++++
1 file changed, 52 insertions(+)
diff --git a/arch/arm64/boot/dts/qcom/kodiak.dtsi b/arch/arm64/boot/dts/qcom/kodiak.dtsi
index 6079e67ea829..dbfc6cc051f3 100644
--- a/arch/arm64/boot/dts/qcom/kodiak.dtsi
+++ b/arch/arm64/boot/dts/qcom/kodiak.dtsi
@@ -5198,6 +5198,58 @@ port@4 {
};
};
+ qcom_jpeg_enc: qcom,jpegenc@ac4e000 {
+ cell-index = <0>;
+ compatible = "qcom,qcm6490-jenc";
+
+ reg =
+ <0 0xac4e000 0 0x4000>,
+ <0 0xac40000 0 0x1000>;
+
+ reg-names =
+ "jpeg_regs",
+ "cpas_regs";
+
+ interrupts = <GIC_SPI 474 IRQ_TYPE_EDGE_RISING>;
+ power-domains = <&camcc CAM_CC_TITAN_TOP_GDSC>;
+
+ clocks =
+ <&gcc GCC_CAMERA_HF_AXI_CLK>,
+ <&gcc GCC_CAMERA_SF_AXI_CLK>,
+ <&camcc CAM_CC_CORE_AHB_CLK>,
+ <&camcc CAM_CC_CPAS_AHB_CLK>,
+ <&camcc CAM_CC_CAMNOC_AXI_CLK>,
+ <&camcc CAM_CC_JPEG_CLK>;
+
+ clock-names =
+ "gcc_hf_axi_clk",
+ "gcc_sf_axi_clk",
+ "core_ahb_clk",
+ "cpas_ahb_clk",
+ "camnoc_axi_clk",
+ "jpeg_clk";
+
+ iommus =
+ <&apps_smmu 0x20C0 0x20>,
+ <&apps_smmu 0x20E0 0x20>;
+
+ interconnects =
+ <&gem_noc MASTER_APPSS_PROC 0
+ &cnoc2 SLAVE_CAMERA_CFG 0>,
+ <&mmss_noc MASTER_CAMNOC_HF 0
+ &mc_virt SLAVE_EBI1 0>,
+ <&mmss_noc MASTER_CAMNOC_SF 0
+ &mc_virt SLAVE_EBI1 0>,
+ <&mmss_noc MASTER_CAMNOC_ICP 0
+ &mc_virt SLAVE_EBI1 0>;
+
+ interconnect-names =
+ "cam_ahb",
+ "cam_hf_0_mnoc",
+ "cam_sf_0_mnoc",
+ "cam_sf_icp_mnoc";
+ };
+
camcc: clock-controller@ad00000 {
compatible = "qcom,sc7280-camcc";
reg = <0 0x0ad00000 0 0x10000>;
--
2.34.1
^ permalink raw reply related [flat|nested] 15+ messages in thread
* Re: [PATCH 1/3] media: dt-bindings: qcom: add JPEG encoder binding
2026-05-15 11:46 ` [PATCH 1/3] media: dt-bindings: qcom: add JPEG encoder binding Atanas Filipov
@ 2026-05-15 11:57 ` sashiko-bot
2026-05-15 12:13 ` Dmitry Baryshkov
2026-05-15 12:16 ` Krzysztof Kozlowski
2 siblings, 0 replies; 15+ messages in thread
From: sashiko-bot @ 2026-05-15 11:57 UTC (permalink / raw)
To: Atanas Filipov; +Cc: conor+dt, robh, krzk+dt, devicetree
Thank you for your contribution! Sashiko AI review found 5 potential issue(s) to consider:
- [Medium] `clock-names` is omitted from the `required` list, which can lead to runtime driver probe failures for otherwise valid DT nodes.
- [Low] The `cell-index` property is used in the example but is not defined in the `properties` block, causing a schema validation error.
- [Low] The example uses C preprocessor macros without including the necessary headers, causing `dt_binding_check` compilation to fail.
- [Low] The example uses a non-generic node name (`qcom,jpegenc@ac4e000`).
- [Low] The `reg` property in the example uses 64-bit addresses and sizes without a parent node specifying the cell context, causing a schema validation failure.
--
commit 8198eafe99ce53eb80a55ddd2b50d88c47749ec9
Author: Atanas Filipov <atanas.filipov@oss.qualcomm.com>
media: dt-bindings: qcom: add JPEG encoder binding
Add YAML device tree binding for the Qualcomm JPEG encoder hardware. This
binding is used by the newly added driver and describes all required
resources, including clocks, power domains, IOMMU mappings and interconnect
paths.
> diff --git a/Documentation/devicetree/bindings/media/qcom,jpeg-encoder.yaml b/Documentation/devicetree/bindings/media/qcom,jpeg-encoder.yaml
> new file mode 100644
> index 0000000000000..fac3e654458d3
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/media/qcom,jpeg-encoder.yaml
[ ... ]
> +required:
> + - compatible
> + - reg
> + - clocks
> + - interrupts
> + - power-domains
> + - iommus
> + - interconnects
> + - interconnect-names
Should clock-names be included in this required list?
The binding mandates exactly 6 clocks and defines clock-names, but omits
clock-names from the required list. If a device tree node conforms to the
schema by omitting clock-names, the driver might fail to probe when fetching
clocks by string name.
> +
> +additionalProperties: false
> +
> +examples:
> + - |
Does this example need dt-bindings header includes?
It uses macros like GIC_SPI, IRQ_TYPE_EDGE_RISING, CAM_CC_TITAN_TOP_GDSC, and
GCC_CAMERA_HF_AXI_CLK, but the headers defining them are missing. The device
tree compiler will fail with syntax errors because it expects integer values
rather than string tokens.
> + qcom_jpeg_enc: qcom,jpegenc@ac4e000 {
This isn't a bug, but the node name qcom,jpegenc@ac4e000 does not use a
generic term. Would it be better to use a generic name like
jpeg-encoder@ac4e000 or video-codec@ac4e000 according to standard Device Tree
naming conventions?
> + cell-index = <0>;
Should cell-index be defined in the properties block above?
Because additionalProperties is false at the top level, having cell-index in
the example without defining it in the schema will cause a schema validation
error.
> + compatible = "qcom,qcm6490-jenc";
> + reg =
> + <0 0xac4e000 0 0x4000>,
> + <0 0xac40000 0 0x1000>;
Will this reg property pass validation without a parent node specifying
#address-cells and #size-cells?
Since it uses four cells per entry, dtc will default to 1 for both address
and size, interpreting these 8 cells as 4 separate regions. This would
violate the maxItems: 2 constraint on the reg property.
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260515-qcom-jpeg-v4l2-v1-0-f38c2e1b3555@oss.qualcomm.com?part=1
^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [PATCH 1/3] media: dt-bindings: qcom: add JPEG encoder binding
2026-05-15 11:46 ` [PATCH 1/3] media: dt-bindings: qcom: add JPEG encoder binding Atanas Filipov
2026-05-15 11:57 ` sashiko-bot
@ 2026-05-15 12:13 ` Dmitry Baryshkov
2026-05-15 12:16 ` Krzysztof Kozlowski
2 siblings, 0 replies; 15+ messages in thread
From: Dmitry Baryshkov @ 2026-05-15 12:13 UTC (permalink / raw)
To: Atanas Filipov
Cc: Bryan O'Donoghue, Mauro Carvalho Chehab, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Kapatrala Syed,
Hariram Purushothaman, Bjorn Andersson, Konrad Dybcio,
Gjorgji Rosikopulos, afilipov, linux-media, linux-arm-msm,
devicetree, linux-kernel
On Fri, May 15, 2026 at 02:46:59PM +0300, Atanas Filipov wrote:
> Add YAML device tree binding for the Qualcomm JPEG encoder
> hardware. This binding is used by the newly added driver and
> describes all required resources, including clocks, power domains,
> IOMMU mappings and interconnect paths.
>
> Signed-off-by: Atanas Filipov <atanas.filipov@oss.qualcomm.com>
> ---
> .../bindings/media/qcom,jpeg-encoder.yaml | 122 +++++++++++++++++++++
> 1 file changed, 122 insertions(+)
>
> diff --git a/Documentation/devicetree/bindings/media/qcom,jpeg-encoder.yaml b/Documentation/devicetree/bindings/media/qcom,jpeg-encoder.yaml
> new file mode 100644
> index 000000000000..fac3e654458d
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/media/qcom,jpeg-encoder.yaml
> @@ -0,0 +1,122 @@
> +# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
> +%YAML 1.2
> +---
> +$id: http://devicetree.org/schemas/media/qcom,jpeg-encoder.yaml#
> +$schema: http://devicetree.org/meta-schemas/core.yaml#
> +
> +title: Qualcomm JPEG Encoder
> +
> +maintainers:
> + - Azam Sadiq Pasha Kapatrala Syed <akapatra@quicinc.com>
> + - Hariram Purushothaman <hariramp@quicinc.com>
What is the recommended email domain for Qualcomm submissions? Why are
you nominating some people as maintainers who haven't even touched this
patch?
> +
> +description: |
> + Qualcomm JPEG Encoder is the JPEG encode hardware present in Qualcomm SoCs
> +
> +properties:
> + compatible:
> + items:
> + - enum:
> + - qcom,sc7180-jenc
> + - qcom,sm8250-jenc
> + - qcom,sm7325-jenc
> + - qcom,sc7280-jenc
> + - qcom,qcm6490-jenc
> + - qcom,sm8550-jenc
Is there any difference between JPEG encoder on all these platforms? If
not, add just one primary entry (qcom,sdm845-jenc would sound good) and
then use it as a fallback compatible for all other platforms.
> +
> + reg:
> + maxItems: 2
> +
> + reg-names:
> + items:
> + - const: jpeg-regs
> + - const: cpas-regs
> +
> + interrupts:
> + maxItems: 1
> +
> + clocks:
> + minItems: 6
> + maxItems: 6
> +
> + clock-names:
> + items:
> + - const: gcc_hf_axi_clk
> + - const: gcc_sf_axi_clk
These clocks name the source. Can we have a target-specific clock
name instead? Also, why do you need _clk all over the place? What else
can it be other than the clock?
> + - const: core_ahb_clk
> + - const: cpas_ahb_clk
> + - const: camnoc_axi_clk
> + - const: jpeg_clk
> +
> + power-domains:
> + maxItems: 1
> +
> + iommus:
> + maxItems: 2
> +
> + interconnects:
> + maxItems: 4
> +
> + interconnect-names:
> + items:
> + - const: cam_ahb
> + - const: cam_hf_0_mnoc
> + - const: cam_sf_0_mnoc
> + - const: cam_sf_icp_mnoc
Is this supposed to be a separate node or a child of the camss node?
> +
> +required:
> + - compatible
> + - reg
> + - clocks
> + - interrupts
> + - power-domains
> + - iommus
> + - interconnects
> + - interconnect-names
> +
> +additionalProperties: false
> +
> +examples:
> + - |
> + qcom_jpeg_enc: qcom,jpegenc@ac4e000 {
Drop the label, it's useless.
Do you see any other device tree nodes with the names starting with
qcom,? What should node names look like? Which document covers node
names?
> + cell-index = <0>;
> + compatible = "qcom,qcm6490-jenc";
> + reg =
> + <0 0xac4e000 0 0x4000>,
Do you see other examples having newline after the '=' sign?
> + <0 0xac40000 0 0x1000>;
This points out that this wasn't even validated.
> +
> + interrupts = <GIC_SPI 474 IRQ_TYPE_EDGE_RISING>;
And this won't build as is.
> + power-domains = <&camcc CAM_CC_TITAN_TOP_GDSC>;
> +
> + clock-names =
> + "gcc_hf_axi_clk",
> + "gcc_sf_axi_clk",
> + "core_ahb_clk",
> + "cpas_ahb_clk",
> + "camnoc_axi_clk",
> + "jpeg_clk";
> +
> + clocks =
> + <&gcc GCC_CAMERA_HF_AXI_CLK>,
> + <&gcc GCC_CAMERA_SF_AXI_CLK>,
> + <&camcc CAM_CC_CORE_AHB_CLK>,
> + <&camcc CAM_CC_CPAS_AHB_CLK>,
> + <&camcc CAM_CC_CAMNOC_AXI_CLK>,
> + <&camcc CAM_CC_JPEG_CLK>;
> +
> + iommus =
> + <&apps_smmu 0x20C0 0x20>,
> + <&apps_smmu 0x20E0 0x20>;
> +
> + interconnects =
> + <&gem_noc MASTER_APPSS_PROC 0 &cnoc2 SLAVE_CAMERA_CFG 0>,
> + <&mmss_noc MASTER_CAMNOC_HF 0 &mc_virt SLAVE_EBI1 0>,
> + <&mmss_noc MASTER_CAMNOC_SF 0 &mc_virt SLAVE_EBI1 0>,
> + <&mmss_noc MASTER_CAMNOC_ICP 0 &mc_virt SLAVE_EBI1 0>;
> +
> + interconnect-names =
> + "cam_ahb",
> + "cam_hf_0_mnoc",
> + "cam_sf_0_mnoc",
> + "cam_sf_icp_mnoc";
> + };
>
> --
> 2.34.1
>
--
With best wishes
Dmitry
^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [PATCH 1/3] media: dt-bindings: qcom: add JPEG encoder binding
2026-05-15 11:46 ` [PATCH 1/3] media: dt-bindings: qcom: add JPEG encoder binding Atanas Filipov
2026-05-15 11:57 ` sashiko-bot
2026-05-15 12:13 ` Dmitry Baryshkov
@ 2026-05-15 12:16 ` Krzysztof Kozlowski
2 siblings, 0 replies; 15+ messages in thread
From: Krzysztof Kozlowski @ 2026-05-15 12:16 UTC (permalink / raw)
To: Atanas Filipov, Bryan O'Donoghue, Mauro Carvalho Chehab,
Rob Herring, Krzysztof Kozlowski, Conor Dooley, Kapatrala Syed,
Hariram Purushothaman, Bjorn Andersson, Konrad Dybcio,
Gjorgji Rosikopulos, afilipov
Cc: linux-media, linux-arm-msm, devicetree, linux-kernel
On 15/05/2026 13:46, Atanas Filipov wrote:
> Add YAML device tree binding for the Qualcomm JPEG encoder
> hardware. This binding is used by the newly added driver and
> describes all required resources, including clocks, power domains,
> IOMMU mappings and interconnect paths.
You must send your patchset for internal review to avoid such
trivialities and known issues.
A nit, subject: drop second/last, redundant "bindings". The
"dt-bindings" prefix is already stating that these are bindings.
See also:
https://elixir.bootlin.com/linux/v6.17-rc3/source/Documentation/devicetree/bindings/submitting-patches.rst#L18
>
> Signed-off-by: Atanas Filipov <atanas.filipov@oss.qualcomm.com>
> ---
> .../bindings/media/qcom,jpeg-encoder.yaml | 122 +++++++++++++++++++++
> 1 file changed, 122 insertions(+)
>
> diff --git a/Documentation/devicetree/bindings/media/qcom,jpeg-encoder.yaml b/Documentation/devicetree/bindings/media/qcom,jpeg-encoder.yaml
> new file mode 100644
> index 000000000000..fac3e654458d
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/media/qcom,jpeg-encoder.yaml
Use compatible
> @@ -0,0 +1,122 @@
> +# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
> +%YAML 1.2
> +---
> +$id: http://devicetree.org/schemas/media/qcom,jpeg-encoder.yaml#
> +$schema: http://devicetree.org/meta-schemas/core.yaml#
> +
> +title: Qualcomm JPEG Encoder
> +
> +maintainers:
> + - Azam Sadiq Pasha Kapatrala Syed <akapatra@quicinc.com>
> + - Hariram Purushothaman <hariramp@quicinc.com>
> +
> +description: |
> + Qualcomm JPEG Encoder is the JPEG encode hardware present in Qualcomm SoCs
> +
> +properties:
> + compatible:
> + items:
> + - enum:
> + - qcom,sc7180-jenc
> + - qcom,sm8250-jenc
> + - qcom,sm7325-jenc
> + - qcom,sc7280-jenc
> + - qcom,qcm6490-jenc
> + - qcom,sm8550-jenc
Random order?
Heh, and never actually tested.
> +
> + reg:
> + maxItems: 2
> +
> + reg-names:
> + items:
> + - const: jpeg-regs
> + - const: cpas-regs
Drop regs
> +
> + interrupts:
> + maxItems: 1
> +
> + clocks:
> + minItems: 6
Drop
> + maxItems: 6
> +
> + clock-names:
> + items:
> + - const: gcc_hf_axi_clk
> + - const: gcc_sf_axi_clk
> + - const: core_ahb_clk
> + - const: cpas_ahb_clk
> + - const: camnoc_axi_clk
> + - const: jpeg_clk
Drop _clk. Instead use some useful names.
> +
> + power-domains:
> + maxItems: 1
> +
> + iommus:
> + maxItems: 2
> +
> + interconnects:
> + maxItems: 4
> +
> + interconnect-names:
> + items:
> + - const: cam_ahb
> + - const: cam_hf_0_mnoc
> + - const: cam_sf_0_mnoc
> + - const: cam_sf_icp_mnoc
Use useful names, drop cam
> +
> +required:
> + - compatible
> + - reg
> + - clocks
> + - interrupts
> + - power-domains
> + - iommus
> + - interconnects
> + - interconnect-names
> +
> +additionalProperties: false
> +
> +examples:
> + - |
> + qcom_jpeg_enc: qcom,jpegenc@ac4e000 {
> + cell-index = <0>;
> + compatible = "qcom,qcm6490-jenc";
> + reg =
> + <0 0xac4e000 0 0x4000>,
> + <0 0xac40000 0 0x1000>;
What sort of style is that? No, this does not match upstream at all.
Don't send downstream code.
Qualcomm has extensive internal guides and tools helping in upstreaming,
so I do not understand why you bypass all this to send us downstream -
literally - junk code.
Best regards,
Krzysztof
^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [PATCH 3/3] arm64: qcom: dts: qcm6490: Add JPEG encoder DT properties
2026-05-15 11:47 ` [PATCH 3/3] arm64: qcom: dts: qcm6490: Add JPEG encoder DT properties Atanas Filipov
@ 2026-05-15 12:16 ` Dmitry Baryshkov
2026-05-15 12:17 ` Krzysztof Kozlowski
2026-05-15 12:36 ` sashiko-bot
2 siblings, 0 replies; 15+ messages in thread
From: Dmitry Baryshkov @ 2026-05-15 12:16 UTC (permalink / raw)
To: Atanas Filipov
Cc: Bryan O'Donoghue, Mauro Carvalho Chehab, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Kapatrala Syed,
Hariram Purushothaman, Bjorn Andersson, Konrad Dybcio,
Gjorgji Rosikopulos, afilipov, linux-media, linux-arm-msm,
devicetree, linux-kernel
On Fri, May 15, 2026 at 02:47:01PM +0300, Atanas Filipov wrote:
> Add the required JPEG encoder definitions to the device tree.
>
> Signed-off-by: Atanas Filipov <atanas.filipov@oss.qualcomm.com>
> ---
> arch/arm64/boot/dts/qcom/kodiak.dtsi | 52 ++++++++++++++++++++++++++++++++++++
> 1 file changed, 52 insertions(+)
>
> diff --git a/arch/arm64/boot/dts/qcom/kodiak.dtsi b/arch/arm64/boot/dts/qcom/kodiak.dtsi
> index 6079e67ea829..dbfc6cc051f3 100644
> --- a/arch/arm64/boot/dts/qcom/kodiak.dtsi
> +++ b/arch/arm64/boot/dts/qcom/kodiak.dtsi
> @@ -5198,6 +5198,58 @@ port@4 {
> };
> };
>
> + qcom_jpeg_enc: qcom,jpegenc@ac4e000 {
> + cell-index = <0>;
> + compatible = "qcom,qcm6490-jenc";
Huge, huge NAK. Wrong indentation, wrong name, useless label,
undocumented cell-index, wrong format of other lines, etc.
> +
> + reg =
> + <0 0xac4e000 0 0x4000>,
0x0 instead of just 0.
> + <0 0xac40000 0 0x1000>;
> +
> + reg-names =
> + "jpeg_regs",
> + "cpas_regs";
> +
> + interrupts = <GIC_SPI 474 IRQ_TYPE_EDGE_RISING>;
> + power-domains = <&camcc CAM_CC_TITAN_TOP_GDSC>;
> +
> + clocks =
> + <&gcc GCC_CAMERA_HF_AXI_CLK>,
> + <&gcc GCC_CAMERA_SF_AXI_CLK>,
> + <&camcc CAM_CC_CORE_AHB_CLK>,
> + <&camcc CAM_CC_CPAS_AHB_CLK>,
> + <&camcc CAM_CC_CAMNOC_AXI_CLK>,
> + <&camcc CAM_CC_JPEG_CLK>;
> +
> + clock-names =
> + "gcc_hf_axi_clk",
> + "gcc_sf_axi_clk",
> + "core_ahb_clk",
> + "cpas_ahb_clk",
> + "camnoc_axi_clk",
> + "jpeg_clk";
> +
> + iommus =
> + <&apps_smmu 0x20C0 0x20>,
> + <&apps_smmu 0x20E0 0x20>;
lowercase hex
> +
> + interconnects =
> + <&gem_noc MASTER_APPSS_PROC 0
> + &cnoc2 SLAVE_CAMERA_CFG 0>,
Wrong indentation, use defined values instead of just 0.
> + <&mmss_noc MASTER_CAMNOC_HF 0
> + &mc_virt SLAVE_EBI1 0>,
> + <&mmss_noc MASTER_CAMNOC_SF 0
> + &mc_virt SLAVE_EBI1 0>,
> + <&mmss_noc MASTER_CAMNOC_ICP 0
> + &mc_virt SLAVE_EBI1 0>;
> +
> + interconnect-names =
> + "cam_ahb",
> + "cam_hf_0_mnoc",
> + "cam_sf_0_mnoc",
> + "cam_sf_icp_mnoc";
> + };
> +
> camcc: clock-controller@ad00000 {
> compatible = "qcom,sc7280-camcc";
> reg = <0 0x0ad00000 0 0x10000>;
>
> --
> 2.34.1
>
--
With best wishes
Dmitry
^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [PATCH 3/3] arm64: qcom: dts: qcm6490: Add JPEG encoder DT properties
2026-05-15 11:47 ` [PATCH 3/3] arm64: qcom: dts: qcm6490: Add JPEG encoder DT properties Atanas Filipov
2026-05-15 12:16 ` Dmitry Baryshkov
@ 2026-05-15 12:17 ` Krzysztof Kozlowski
2026-05-15 12:36 ` sashiko-bot
2 siblings, 0 replies; 15+ messages in thread
From: Krzysztof Kozlowski @ 2026-05-15 12:17 UTC (permalink / raw)
To: Atanas Filipov, Bryan O'Donoghue, Mauro Carvalho Chehab,
Rob Herring, Krzysztof Kozlowski, Conor Dooley, Kapatrala Syed,
Hariram Purushothaman, Bjorn Andersson, Konrad Dybcio,
Gjorgji Rosikopulos, afilipov
Cc: linux-media, linux-arm-msm, devicetree, linux-kernel
On 15/05/2026 13:47, Atanas Filipov wrote:
> Add the required JPEG encoder definitions to the device tree.
>
> Signed-off-by: Atanas Filipov <atanas.filipov@oss.qualcomm.com>
> ---
> arch/arm64/boot/dts/qcom/kodiak.dtsi | 52 ++++++++++++++++++++++++++++++++++++
> 1 file changed, 52 insertions(+)
>
> diff --git a/arch/arm64/boot/dts/qcom/kodiak.dtsi b/arch/arm64/boot/dts/qcom/kodiak.dtsi
> index 6079e67ea829..dbfc6cc051f3 100644
> --- a/arch/arm64/boot/dts/qcom/kodiak.dtsi
> +++ b/arch/arm64/boot/dts/qcom/kodiak.dtsi
> @@ -5198,6 +5198,58 @@ port@4 {
> };
> };
>
> + qcom_jpeg_enc: qcom,jpegenc@ac4e000 {
We do not accept downstream code. Please open ANY upstream file and look
for such syntax.
And internal review would tell you that.
NAK
Best regards,
Krzysztof
^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [PATCH 2/3] qcom: media: jpeg: Add Qualcomm JPEG V4L2 encoder
2026-05-15 11:47 ` [PATCH 2/3] qcom: media: jpeg: Add Qualcomm JPEG V4L2 encoder Atanas Filipov
@ 2026-05-15 12:21 ` Krzysztof Kozlowski
[not found] ` <SA1PR02MB11289FA5C2A01466B49C62D4BDD042@SA1PR02MB11289.namprd02.prod.outlook.com>
2026-05-15 12:23 ` sashiko-bot
2026-05-15 13:28 ` Dmitry Baryshkov
2 siblings, 1 reply; 15+ messages in thread
From: Krzysztof Kozlowski @ 2026-05-15 12:21 UTC (permalink / raw)
To: Atanas Filipov, Bryan O'Donoghue, Mauro Carvalho Chehab,
Rob Herring, Krzysztof Kozlowski, Conor Dooley, Kapatrala Syed,
Hariram Purushothaman, Bjorn Andersson, Konrad Dybcio,
Gjorgji Rosikopulos, afilipov
Cc: linux-media, linux-arm-msm, devicetree, linux-kernel
On 15/05/2026 13:47, Atanas Filipov wrote:
> Implementation of a V4L2 JPEG encoder device driver supporting
> Qualcomm SC7180, SM8250, SM7280, and SM8550 chipsets.
>
> Signed-off-by: Atanas Filipov <atanas.filipov@oss.qualcomm.com>
Please use subject prefixes matching the subsystem. You can get them for
example with `git log --oneline -- DIRECTORY_OR_FILE` on the directory
your patch is touching. For bindings, the preferred subjects are
explained here:
https://www.kernel.org/doc/html/latest/devicetree/bindings/submitting-patches.html#i-for-patch-submitters
There is no subsystem "qcom".
> ---
> drivers/media/platform/qcom/Kconfig | 1 +
> drivers/media/platform/qcom/Makefile | 1 +
> drivers/media/platform/qcom/jpeg/Kconfig | 17 +
> drivers/media/platform/qcom/jpeg/Makefile | 9 +
> drivers/media/platform/qcom/jpeg/qcom_jenc_defs.h | 253 ++++
> drivers/media/platform/qcom/jpeg/qcom_jenc_dev.c | 370 +++++
> drivers/media/platform/qcom/jpeg/qcom_jenc_dev.h | 111 ++
> drivers/media/platform/qcom/jpeg/qcom_jenc_hdr.c | 388 +++++
> drivers/media/platform/qcom/jpeg/qcom_jenc_hdr.h | 130 ++
> drivers/media/platform/qcom/jpeg/qcom_jenc_ops.c | 1522 ++++++++++++++++++++
> drivers/media/platform/qcom/jpeg/qcom_jenc_ops.h | 49 +
> drivers/media/platform/qcom/jpeg/qcom_jenc_res.c | 268 ++++
> drivers/media/platform/qcom/jpeg/qcom_jenc_res.h | 70 +
> drivers/media/platform/qcom/jpeg/qcom_jenc_v4l2.c | 1082 ++++++++++++++
> drivers/media/platform/qcom/jpeg/qcom_jenc_v4l2.h | 27 +
> .../platform/qcom/jpeg/qcom_v165_jenc_hw_info.h | 509 +++++++
> .../platform/qcom/jpeg/qcom_v580_jenc_hw_info.h | 509 +++++++
> .../platform/qcom/jpeg/qcom_v680_jenc_hw_info.h | 509 +++++++
> .../platform/qcom/jpeg/qcom_v780_jenc_hw_info.h | 509 +++++++
> 19 files changed, 6334 insertions(+)
>
> diff --git a/drivers/media/platform/qcom/Kconfig b/drivers/media/platform/qcom/Kconfig
> index 4f4d3a68e6e5..f33d53a754a0 100644
> --- a/drivers/media/platform/qcom/Kconfig
> +++ b/drivers/media/platform/qcom/Kconfig
> @@ -5,3 +5,4 @@ comment "Qualcomm media platform drivers"
> source "drivers/media/platform/qcom/camss/Kconfig"
> source "drivers/media/platform/qcom/iris/Kconfig"
> source "drivers/media/platform/qcom/venus/Kconfig"
> +source "drivers/media/platform/qcom/jpeg/Kconfig"
> diff --git a/drivers/media/platform/qcom/Makefile b/drivers/media/platform/qcom/Makefile
> index ea2221a202c0..30c94949e9de 100644
> --- a/drivers/media/platform/qcom/Makefile
> +++ b/drivers/media/platform/qcom/Makefile
> @@ -2,3 +2,4 @@
> obj-y += camss/
> obj-y += iris/
> obj-y += venus/
> +obj-y += jpeg/
Random order. It seems you follow such pattern in multiple places. This
must follow existing ordering.
> diff --git a/drivers/media/platform/qcom/jpeg/Kconfig b/drivers/media/platform/qcom/jpeg/Kconfig
> new file mode 100644
> index 000000000000..51846aeafaf3
> --- /dev/null
> +++ b/drivers/media/platform/qcom/jpeg/Kconfig
> @@ -0,0 +1,17 @@
> +# SPDX-License-Identifier: GPL-2.0-only
> +config VIDEO_QCOM_JENC
> + tristate "Qualcomm V4L2 JPEG Encoder driver"
> + depends on V4L_MEM2MEM_DRIVERS
> + depends on (ARCH_QCOM && IOMMU_DMA) || COMPILE_TEST
> + depends on VIDEO_DEV
> + select VIDEO_V4L2_SUBDEV_API
> + select VIDEOBUF2_DMA_SG
> + select V4L2_MEM2MEM_DEV
> + help
> + Qualcomm JPEG memory-to-memory V4L2 encoder driver.
> +
> + Provides:
> + - qcom-jenc (encode)
> +
> + To compile this driver as a module, choose M here: the
> + module will be called qcom-jenc
> diff --git a/drivers/media/platform/qcom/jpeg/Makefile b/drivers/media/platform/qcom/jpeg/Makefile
> new file mode 100644
> index 000000000000..310f6c3c1f19
> --- /dev/null
> +++ b/drivers/media/platform/qcom/jpeg/Makefile
> @@ -0,0 +1,9 @@
> +# SPDX-License-Identifier: GPL-2.0-only
> +obj-$(CONFIG_VIDEO_QCOM_JENC) += qcom-jenc.o
> +
> +qcom-jenc-objs += \
> + qcom_jenc_dev.o \
> + qcom_jenc_v4l2.o \
> + qcom_jenc_ops.o \
> + qcom_jenc_res.o \
> + qcom_jenc_hdr.o
> diff --git a/drivers/media/platform/qcom/jpeg/qcom_jenc_defs.h b/drivers/media/platform/qcom/jpeg/qcom_jenc_defs.h
> new file mode 100644
> index 000000000000..40e46820c546
> --- /dev/null
> +++ b/drivers/media/platform/qcom/jpeg/qcom_jenc_defs.h
> @@ -0,0 +1,253 @@
> +/* SPDX-License-Identifier: GPL-2.0-only */
> +/*
> + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
> + */
> +
> +#ifndef QCOM_JENC_DEFS_H_
> +#define QCOM_JENC_DEFS_H_
> +
> +#include <linux/types.h>
> +#include <linux/io.h>
> +#include <linux/bitfield.h>
> +#include <linux/videodev2.h>
> +#include <media/videobuf2-core.h>
> +
> +/* Offline JPEG encoder constraints */
> +#define QCOM_JPEG_HW_MAX_WIDTH 9248
> +#define QCOM_JPEG_HW_MAX_HEIGHT 8192
> +#define QCOM_JPEG_HW_MIN_WIDTH 128
> +#define QCOM_JPEG_HW_MIN_HEIGHT 96
> +
> +#define QCOM_JPEG_HW_DEF_HSTEP 16
> +#define QCOM_JPEG_HW_DEF_VSTEP 16
> +
> +#define QCOM_JPEG_HW_DEF_WIDTH 1920
> +#define QCOM_JPEG_HW_DEF_HEIGHT 1080
> +
> +#define QCOM_JPEG_MAX_PLANES 3
> +
> +#define QCOM_JPEG_QUALITY_MIN 1
> +#define QCOM_JPEG_QUALITY_DEF 95
> +#define QCOM_JPEG_QUALITY_MAX 100
> +#define QCOM_JPEG_QUALITY_MID (QCOM_JPEG_QUALITY_MAX / 2)
> +#define QCOM_JPEG_QUALITY_UNT 1
> +
> +enum qcom_jpeg_soc_id {
> + QCOM_V165_SOC_ID = 0,
> + QCOM_V580_SOC_ID,
> + QCOM_V680_SOC_ID,
> + QCOM_V780_SOC_ID,
> + QCOM_UNKNOWN_SOC_ID,
> +};
> +
> +enum qcom_soc_perf_level {
> + QCOM_SOC_PERF_SUSPEND = 0,
> + QCOM_SOC_PERF_LOWSVS,
> + QCOM_SOC_PERF_SVS,
> + QCOM_SOC_PERF_SVS_L1,
> + QCOM_SOC_PERF_NOMINAL,
> + QCOM_SOC_PERF_TURBO,
> + QCOM_SOC_PERF_LEVEL_MAX,
> +};
> +
> +enum qcom_jpeg_mask_id {
> + JMSK_HW_VER_STEP,
> + JMSK_HW_VER_MINOR,
> + JMSK_HW_VER_MAJOR,
> +
> + JMSK_HW_CAP_ENCODE,
> + JMSK_HW_CAP_DECODE,
> + JMSK_HW_CAP_UPSCALE,
> + JMSK_HW_CAP_DOWNSCALE,
> +
> + JMSK_RST_CMD_COMMON,
> + JMSK_RST_CMD_FE_RESET,
> + JMSK_RST_CMD_WE_RESET,
> + JMSK_RST_CMD_ENCODER_RESET,
> + JMSK_RST_CMD_DECODER_RESET,
> + JMSK_RST_CMD_BLOCK_FORMATTER_RST,
> + JMSK_RST_CMD_SCALE_RESET,
> + JMSK_RST_CMD_REGISTER_RESET,
> + JMSK_RST_CMD_MISR_RESET,
> + JMSK_RST_CMD_CORE_RESET,
> + JMSK_RST_CMD_JMSK_DOMAIN_RESET,
> + JMSK_RST_CMD_RESET_BYPASS,
> +
> + JMSK_CMD_HW_START,
> + JMSK_CMD_HW_STOP,
> + JMSK_CMD_CLR_RD_PLNS_QUEUE,
> + JMSK_CMD_CLR_WR_PLNS_QUEUE,
> + JMSK_CMD_APPLY_SWC_RD_PARAMS,
> +
> + JMSK_CORE_CFG_FE_ENABLE,
> + JMSK_CORE_CFG_WE_ENABLE,
> + JMSK_CORE_CFG_ENC_ENABLE,
> + JMSK_CORE_CFG_SCALE_ENABLE,
> + JMSK_CORE_CFG_TESTBUS_ENABLE,
> + JMSK_CORE_CFG_MODE,
> + JMSK_CORE_CFG_CGC_DISABLE,
> +
> + JMSK_CORE_STATUS_ENCODE_STATE,
> + JMSK_CORE_STATUS_SCALE_STATE,
> + JMSK_CORE_STATUS_RT_STATE,
> + JMSK_CORE_STATUS_BUS_STATE,
> + JMSK_CORE_STATUS_CGC_STATE,
> +
> + JMSK_IRQ_ENABLE_ALL,
> + JMSK_IRQ_DISABLE_ALL,
> + JMSK_IRQ_CLEAR_ALL,
> +
> + JMSK_IRQ_STATUS_SESSION_DONE,
> + JMSK_IRQ_STATUS_RD_BUF_PLN0_DONE,
> + JMSK_IRQ_STATUS_RD_BUF_PLN1_DONE,
> + JMSK_IRQ_STATUS_RD_BUF_PLN2_DONE,
> + JMSK_IRQ_STATUS_RD_BUF_PLNS_ATTN,
> + JMSK_IRQ_STATUS_WR_BUF_PLN0_DONE,
> + JMSK_IRQ_STATUS_WR_BUF_PLN1_DONE,
> + JMSK_IRQ_STATUS_WR_BUF_PLN2_DONE,
> + JMSK_IRQ_STATUS_WR_BUF_PLNS_ATTN,
> + JMSK_IRQ_STATUS_SESSION_ERROR,
> + JMSK_IRQ_STATUS_STOP_ACK,
> + JMSK_IRQ_STATUS_RESET_ACK,
> +
> + JMSK_FE_CFG_BYTE_ORDERING,
> + JMSK_FE_CFG_BURST_LENGTH_MAX,
> + JMSK_FE_CFG_MEMORY_FORMAT,
> + JMSK_FE_CFG_CBCR_ORDER,
> + JMSK_FE_CFG_BOTTOM_VPAD_EN,
> + JMSK_FE_CFG_PLN0_EN,
> + JMSK_FE_CFG_PLN1_EN,
> + JMSK_FE_CFG_PLN2_EN,
> + JMSK_FE_CFG_SIXTEEN_MCU_EN,
> + JMSK_FE_CFG_MCUS_PER_BLOCK,
> + JMSK_FE_CFG_MAL_BOUNDARY,
> + JMSK_FE_CFG_MAL_EN,
> +
> + JMSK_FE_VBPAD_CFG_BLOCK_ROW,
> +
> + JMSK_PLNS_RD_OFFSET,
> + JMSK_PLNS_RD_BUF_SIZE_WIDTH,
> + JMSK_PLNS_RD_BUF_SIZE_HEIGHT,
> + JMSK_PLNS_RD_STRIDE,
> + JMSK_PLNS_RD_HINIT,
> + JMSK_PLNS_RD_VINIT,
> +
> + JMSK_WE_CFG_BYTE_ORDERING,
> + JMSK_WE_CFG_BURST_LENGTH_MAX,
> + JMSK_WE_CFG_MEMORY_FORMAT,
> + JMSK_WE_CFG_CBCR_ORDER,
> + JMSK_WE_CFG_PLN0_EN,
> + JMSK_WE_CFG_PLN1_EN,
> + JMSK_WE_CFG_PLN2_EN,
> + JMSK_WE_CFG_MAL_BOUNDARY,
> + JMSK_WE_CFG_MAL_EN,
> + JMSK_WE_CFG_POP_BUFF_ON_EOS,
> +
> + JMSK_PLNS_WR_BUF_SIZE_WIDTH,
> + JMSK_PLNS_WR_BUF_SIZE_HEIGHT,
> +
> + JMSK_PLNS_WR_STRIDE,
> + JMSK_PLNS_WR_HINIT,
> + JMSK_PLNS_WR_VINIT,
> + JMSK_PLNS_WR_HSTEP,
> + JMSK_PLNS_WR_VSTEP,
> + JMSK_PLNS_WR_BLOCK_CFG_PER_COL,
> + JMSK_PLNS_WR_BLOCK_CFG_PER_RAW,
> +
> + JMSK_ENC_CFG_IMAGE_FORMAT,
> + JMSK_ENC_CFG_APPLY_EOI,
> + JMSK_ENC_CFG_HUFFMAN_SEL,
> + JMSK_ENC_CFG_FSC_ENABLE,
> + JMSK_ENC_CFG_OUTPUT_DISABLE,
> + JMSK_ENC_CFG_RST_MARKER_PERIOD,
> + JMSK_ENC_IMAGE_SIZE_WIDTH,
> + JMSK_ENC_IMAGE_SIZE_HEIGHT,
> +
> + JMSK_SCALE_CFG_HSCALE_ENABLE,
> + JMSK_SCALE_CFG_VSCALE_ENABLE,
> + JMSK_SCALE_CFG_UPSAMPLE_EN,
> + JMSK_SCALE_CFG_SUBSAMPLE_EN,
> + JMSK_SCALE_CFG_HSCALE_ALGO,
> + JMSK_SCALE_CFG_VSCALE_ALGO,
> + JMSK_SCALE_CFG_H_SCALE_FIR_ALGO,
> + JMSK_SCALE_CFG_V_SCALE_FIR_ALGO,
> +
> + JMSK_SCALE_PLNS_OUT_CFG_BLK_WIDTH,
> + JMSK_SCALE_PLNS_OUT_CFG_BLK_HEIGHT,
> +
> + JMSK_SCALE_PLNS_HSTEP_FRACTIONAL,
> + JMSK_SCALE_PLNS_HSTEP_INTEGER,
> + JMSK_SCALE_PLNS_VSTEP_FRACTIONAL,
> + JMSK_SCALE_PLNS_VSTEP_INTEGER,
> +
> + JMSK_DMI_CFG,
> + JMSK_DMI_ADDR,
> + JMSK_DMI_DATA,
> +
> + JMSK_TESTBUS_CFG,
> + JMSK_FE_VBPAD_CFG,
> +
> + JMSK_PLN0_RD_HINIT_INT,
> + JMSK_PLN1_RD_HINIT_INT,
> + JMSK_PLN2_RD_HINIT_INT,
> + JMSK_PLN0_RD_VINIT_INT,
> + JMSK_PLN1_RD_VINIT_INT,
> + JMSK_PLN2_RD_VINIT_INT,
> + JMSK_ID_MAX
> +};
> +
> +struct qcom_jpeg_reg_offs {
> + u32 hw_version;
> + u32 hw_capability;
> + u32 reset_cmd;
> + u32 core_cfg;
> + u32 int_mask;
> + u32 int_clr;
> + u32 int_status;
> + u32 hw_cmd;
> + u32 enc_core_state;
> +
> + struct {
> + u32 pntr[QCOM_JPEG_MAX_PLANES];
> + u32 offs[QCOM_JPEG_MAX_PLANES];
> + u32 cnsmd[QCOM_JPEG_MAX_PLANES];
> + u32 bsize[QCOM_JPEG_MAX_PLANES];
> + u32 stride[QCOM_JPEG_MAX_PLANES];
> + u32 hinit[QCOM_JPEG_MAX_PLANES];
> + u32 vinit[QCOM_JPEG_MAX_PLANES];
> + u32 pntr_cnt;
> + u32 vbpad_cfg;
> + } fe;
> + u32 fe_cfg;
> +
> + struct {
> + u32 pntr[QCOM_JPEG_MAX_PLANES];
> + u32 cnsmd[QCOM_JPEG_MAX_PLANES];
> + u32 bsize[QCOM_JPEG_MAX_PLANES];
> + u32 stride[QCOM_JPEG_MAX_PLANES];
> + u32 hinit[QCOM_JPEG_MAX_PLANES];
> + u32 hstep[QCOM_JPEG_MAX_PLANES];
> + u32 vinit[QCOM_JPEG_MAX_PLANES];
> + u32 vstep[QCOM_JPEG_MAX_PLANES];
> + u32 blocks[QCOM_JPEG_MAX_PLANES];
> + u32 pntr_cnt;
> + } we;
> + u32 we_cfg;
> +
> + struct {
> + u32 hstep[QCOM_JPEG_MAX_PLANES];
> + u32 vstep[QCOM_JPEG_MAX_PLANES];
> + } scale;
> + u32 scale_cfg;
> + u32 scale_out_cfg[QCOM_JPEG_MAX_PLANES];
> +
> + u32 enc_cfg;
> + u32 enc_img_size;
> + u32 enc_out_size;
> +
> + u32 dmi_cfg;
> + u32 dmi_data;
> + u32 dmi_addr;
> +} __packed;
> +
> +#endif /* QCOM_JENC_DEFS_H_ */
> diff --git a/drivers/media/platform/qcom/jpeg/qcom_jenc_dev.c b/drivers/media/platform/qcom/jpeg/qcom_jenc_dev.c
> new file mode 100644
> index 000000000000..4ef6bf9fd48d
> --- /dev/null
> +++ b/drivers/media/platform/qcom/jpeg/qcom_jenc_dev.c
> @@ -0,0 +1,370 @@
> +// SPDX-License-Identifier: GPL-2.0-only
> +/*
> + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
> + */
> +
> +#include <linux/clk.h>
> +#include <linux/interrupt.h>
> +#include <linux/module.h>
> +#include <linux/of_device.h>
> +#include <linux/of.h>
> +#include <linux/platform_device.h>
> +#include <linux/pm_runtime.h>
> +#include <linux/slab.h>
> +
> +#include <media/v4l2-mem2mem.h>
> +
> +#include "qcom_jenc_dev.h"
> +
> +#include "qcom_jenc_defs.h"
> +#include "qcom_jenc_ops.h"
> +#include "qcom_jenc_res.h"
> +#include "qcom_jenc_v4l2.h"
> +
> +static int qcom_jpeg_match_data(struct qcom_jenc_dev *jenc)
> +{
> + struct device *dev = jenc->dev;
> + const struct qcom_dev_resources *res;
> +
> + res = device_get_match_data(dev);
> + if (!res)
> + return dev_err_probe(dev, -ENODEV, "unsupported SoC\n");
> +
> + jenc->res = res;
> +
> + return 0;
> +}
> +
> +static int qcom_jpeg_clk_init(struct qcom_jenc_dev *jenc)
> +{
> + const struct qcom_dev_resources *res = jenc->res;
> + int c_idx;
> +
> + jenc->clks = devm_kcalloc(jenc->dev, ARRAY_SIZE(res->clk_names), sizeof(*jenc->clks),
> + GFP_KERNEL);
> + if (!jenc->clks)
> + return -ENOMEM;
> +
> + for (c_idx = 0; c_idx < ARRAY_SIZE(res->clk_names); c_idx++) {
> + if (!res->clk_names[c_idx])
> + break;
> +
> + jenc->clks[c_idx].clk = devm_clk_get(jenc->dev, res->clk_names[c_idx]);
So you just re-implemented clk bulk API, no?
> + if (IS_ERR(jenc->clks[c_idx].clk)) {
Run checkpatch.
> + return dev_err_probe(jenc->dev, PTR_ERR(jenc->clks[c_idx].clk),
> + "failed to get clock %s\n", res->clk_names[c_idx]);
> + }
> +
> + jenc->clks[c_idx].id = res->clk_names[c_idx];
> + jenc->num_clks++;
> + }
> +
> + return 0;
> +}
> +
> +static int qcom_jpeg_clk_rate(struct qcom_jenc_dev *jenc, enum qcom_soc_perf_level level)
> +{
> + const struct qcom_dev_resources *res = jenc->res;
> + const struct qcom_perf_resource *perf = &res->perf_cfg[level];
> + int c_idx;
> + int rc = 0;
> +
> + for (c_idx = 0; c_idx < jenc->num_clks; c_idx++) {
> + /* skip clocks with fixed or default frequency */
> + if (!perf->clk_rate[c_idx])
> + continue;
> +
> + /* setup frequency according to performance level */
> + rc = clk_set_rate(jenc->clks[c_idx].clk, perf->clk_rate[c_idx]);
> + if (rc < 0) {
> + dev_err(jenc->dev, "clock set rate failed: %d\n", rc);
> + return rc;
> + }
> +
> + dev_dbg(jenc->dev, "clock %s current rate: %ld\n",
> + jenc->clks[c_idx].id, clk_get_rate(jenc->clks[c_idx].clk));
> + }
> +
> + return rc;
> +}
> +
> +static int qcom_jpeg_clk_on(struct qcom_jenc_dev *jenc)
> +{
> + int rc;
> +
> + rc = qcom_jpeg_clk_rate(jenc, jenc->perf);
> + if (rc)
> + return rc;
> +
> + rc = clk_bulk_prepare_enable(jenc->num_clks, jenc->clks);
> + if (rc)
> + return rc;
> +
> + return 0;
> +}
> +
> +static void qcom_jpeg_clk_off(struct qcom_jenc_dev *jenc)
> +{
> + clk_bulk_disable_unprepare(jenc->num_clks, jenc->clks);
> +}
> +
> +static int qcom_jpeg_icc_on(struct qcom_jenc_dev *jenc)
> +{
> + const struct qcom_dev_resources *res = jenc->res;
> + int p_idx;
> + int rc;
> +
> + for (p_idx = 0; p_idx < res->num_of_icc; p_idx++) {
> + rc = icc_set_bw(jenc->icc_paths[p_idx], res->icc_res[p_idx].pair.aggr,
> + res->icc_res[p_idx].pair.peak);
> + if (rc) {
> + dev_err(jenc->dev, "%s failed for path %s: %d\n", __func__,
> + res->icc_res[p_idx].icc_id, rc);
> + goto err_icc_set_bw;
> + }
> + }
> +
> + return 0;
> +
> +err_icc_set_bw:
> + while (--p_idx >= 0)
> + icc_set_bw(jenc->icc_paths[p_idx], 0, 0);
> +
> + return rc;
> +}
> +
> +static void qcom_jpeg_icc_off(struct qcom_jenc_dev *jenc)
> +{
> + const struct qcom_dev_resources *res = jenc->res;
> + int p_idx;
> +
> + for (p_idx = 0; p_idx < res->num_of_icc; p_idx++)
> + icc_set_bw(jenc->icc_paths[p_idx], 0, 0);
> +}
> +
> +static int qcom_jpeg_icc_init(struct qcom_jenc_dev *jenc)
> +{
> + const struct qcom_dev_resources *res = jenc->res;
> + int p_idx;
> +
> + jenc->icc_paths = devm_kcalloc(jenc->dev, res->num_of_icc, sizeof(*jenc->icc_paths),
> + GFP_KERNEL);
> + if (!jenc->icc_paths)
> + return -ENOMEM;
> +
> + for (p_idx = 0; p_idx < res->num_of_icc; p_idx++) {
> + jenc->icc_paths[p_idx] = devm_of_icc_get(jenc->dev, res->icc_res[p_idx].icc_id);
> + if (IS_ERR(jenc->icc_paths[p_idx])) {
> + return dev_err_probe(jenc->dev, PTR_ERR(jenc->icc_paths[p_idx]),
> + "failed to get ICC path: %ld\n",
> + PTR_ERR(jenc->icc_paths[p_idx]));
> + }
> + }
> +
> + return 0;
> +}
> +
> +static __maybe_unused int qcom_jpeg_pm_suspend(struct device *dev)
> +{
> + struct qcom_jenc_dev *jenc = dev_get_drvdata(dev);
> +
> + qcom_jpeg_clk_off(jenc);
> +
> + qcom_jpeg_icc_off(jenc);
> +
> + return 0;
> +}
> +
> +static __maybe_unused int qcom_jpeg_pm_resume(struct device *dev)
> +{
> + struct qcom_jenc_dev *jenc = dev_get_drvdata(dev);
> + int rc;
> +
> + rc = qcom_jpeg_icc_on(jenc);
> + if (rc)
> + return rc;
> +
> + return qcom_jpeg_clk_on(jenc);
> +}
> +
> +static __maybe_unused int qcom_jpeg_suspend(struct device *dev)
> +{
> + struct qcom_jenc_dev *jenc = dev_get_drvdata(dev);
> +
> + v4l2_m2m_suspend(jenc->m2m_dev);
> +
> + return pm_runtime_force_suspend(dev);
> +}
> +
> +static __maybe_unused int qcom_jpeg_resume(struct device *dev)
> +{
> + struct qcom_jenc_dev *jenc = dev_get_drvdata(dev);
> + int rc;
> +
> + rc = pm_runtime_force_resume(dev);
> + if (rc)
> + return rc;
> +
> + v4l2_m2m_resume(jenc->m2m_dev);
> +
> + return rc;
> +}
> +
> +static const struct dev_pm_ops qcom_jpeg_pm_ops = {
> + SET_SYSTEM_SLEEP_PM_OPS(qcom_jpeg_suspend, qcom_jpeg_resume)
> + SET_RUNTIME_PM_OPS(qcom_jpeg_pm_suspend, qcom_jpeg_pm_resume, NULL)
> +};
> +
> +static int qcom_jpeg_probe(struct platform_device *pdev)
> +{
> + struct qcom_jenc_dev *jenc;
> + int rc;
> +
> + jenc = devm_kzalloc(&pdev->dev, sizeof(*jenc), GFP_KERNEL);
> + if (!jenc)
> + return -ENOMEM;
> +
> + jenc->dev = &pdev->dev;
> + mutex_init(&jenc->dev_mutex);
> + spin_lock_init(&jenc->hw_lock);
> + init_completion(&jenc->reset_complete);
> + init_completion(&jenc->stop_complete);
> +
> + rc = qcom_jpeg_match_data(jenc);
> + if (rc)
> + return dev_err_probe(jenc->dev, rc, "failed to attach hardware\n");
> +
> + if (!jenc->res->hw_offs || !jenc->res->hw_ops)
> + return dev_err_probe(jenc->dev, -EINVAL, "missing hw resources\n");
> +
> + rc = dma_set_mask_and_coherent(jenc->dev, DMA_BIT_MASK(32));
> + if (rc)
> + return dev_err_probe(jenc->dev, rc, "failed to set DMA mask\n");
> +
> + platform_set_drvdata(pdev, jenc);
> +
> + jenc->jpeg_base = devm_platform_ioremap_resource(pdev, 0);
> + if (IS_ERR(jenc->jpeg_base)) {
> + rc = PTR_ERR(jenc->jpeg_base);
Pointless assignment, drop.
> + return dev_err_probe(jenc->dev, rc, "failed to map JPEG resource\n");
> + }
> +
> + jenc->cpas_base = devm_platform_ioremap_resource(pdev, 1);
> + if (IS_ERR(jenc->cpas_base)) {
> + rc = PTR_ERR(jenc->cpas_base);
> + return dev_err_probe(jenc->dev, rc, "failed to map CPAS resource\n");
> + }
> +
> + rc = qcom_jpeg_clk_init(jenc);
> + if (rc)
> + return dev_err_probe(jenc->dev, rc, "failed to init bulk clocks\n");
Why do you print same errors twice?
> +
> + jenc->irq = platform_get_irq(pdev, 0);
> + if (jenc->irq < 0)
> + return dev_err_probe(jenc->dev, jenc->irq, "failed to get IRQ\n");
> +
> + rc = devm_request_threaded_irq(jenc->dev, jenc->irq,
> + jenc->res->hw_ops->hw_irq_top,
> + jenc->res->hw_ops->hw_irq_bot,
> + IRQF_ONESHOT, dev_name(jenc->dev), jenc);
> + if (rc)
> + return dev_err_probe(jenc->dev, rc, "failed to request IRQ\n");
> +
> + rc = qcom_jpeg_icc_init(jenc);
> + if (rc)
> + return dev_err_probe(jenc->dev, rc, "failed to get ICC resources\n");
> +
> + rc = kfifo_alloc(&jenc->kfifo_inst, sizeof(jenc->enc_status) * VB2_MAX_FRAME, GFP_KERNEL);
> + if (rc) {
> + dev_err(jenc->dev, "failed to allocate kfifo\n");
Allocation errors should never result in error messages.
> + return rc;
> + }
> +
> + spin_lock_init(&jenc->kfifo_lock);
> +
> + rc = v4l2_device_register(jenc->dev, &jenc->v4l2_dev);
> + if (rc) {
> + dev_err(jenc->dev, "failed to register V4L2 device\n");
> + goto err_kfifo_free;
> + }
> +
> + rc = qcom_jpeg_v4l2_register(jenc);
> + if (rc) {
> + dev_err(jenc->dev, "failed to register video device\n");
> + goto err_v4l2_device_unregister;
> + }
> +
> + jenc->perf = QCOM_SOC_PERF_NOMINAL;
> +
> + pm_runtime_enable(jenc->dev);
> +
> + dev_info(jenc->dev, "Qualcomm JPEG encoder registered\n");
> +
> + return 0;
> +
> +err_v4l2_device_unregister:
> + v4l2_device_unregister(&jenc->v4l2_dev);
> +err_kfifo_free:
> + kfifo_free(&jenc->kfifo_inst);
> +
> + return rc;
> +}
> +
> +static void qcom_jpeg_remove(struct platform_device *pdev)
> +{
> + struct qcom_jenc_dev *jenc = platform_get_drvdata(pdev);
> +
> + pm_runtime_disable(&pdev->dev);
> +
> + qcom_jpeg_v4l2_unregister(jenc);
> +
> + v4l2_device_unregister(&jenc->v4l2_dev);
> +
> + kfifo_free(&jenc->kfifo_inst);
> +
> + dev_info(jenc->dev, "Qualcomm JPEG encoder deregistered\n");
Drop, useless.
> +}
> +
> +static const struct of_device_id qcom_jpeg_of_match[] = {
> + {
> + .compatible = "qcom,sc7180-jenc",
> + .data = &qcom_jpeg_v165_drvdata
> + },
> + {
> + .compatible = "qcom,sm8250-jenc",
> + .data = &qcom_jpeg_v580_drvdata
> + },
> + {
> + .compatible = "qcom,sm7325-jenc",
> + .data = &qcom_jpeg_v580_drvdata
> + },
> + {
> + .compatible = "qcom,sc7280-jenc",
> + .data = &qcom_jpeg_v680_drvdata
> + },
> + {
> + .compatible = "qcom,qcm6490-jenc",
> + .data = &qcom_jpeg_v680_drvdata
So devices are compatible? Then express that.
> + },
> + {
> + .compatible = "qcom,sm8550-jenc",
> + .data = &qcom_jpeg_v780_drvdata
> + },
> + { }
> +};
> +MODULE_DEVICE_TABLE(of, qcom_jpeg_of_match);
> +
> +static struct platform_driver qcom_jpeg_platform_driver = {
> + .probe = qcom_jpeg_probe,
> + .remove = qcom_jpeg_remove,
> + .driver = {
> + .name = QCOM_JPEG_ENC_NAME,
> + .of_match_table = qcom_jpeg_of_match,
> + .pm = &qcom_jpeg_pm_ops,
> + },
> +};
> +
> +module_platform_driver(qcom_jpeg_platform_driver);
> +
> +MODULE_DESCRIPTION("QCOM JPEG mem2mem V4L2 encoder");
> +MODULE_LICENSE("GPL");
> diff --git a/drivers/media/platform/qcom/jpeg/qcom_jenc_dev.h b/drivers/media/platform/qcom/jpeg/qcom_jenc_dev.h
> new file mode 100644
> index 000000000000..cf0c1a933163
> --- /dev/null
> +++ b/drivers/media/platform/qcom/jpeg/qcom_jenc_dev.h
> @@ -0,0 +1,111 @@
> +/* SPDX-License-Identifier: GPL-2.0-only */
> +/*
> + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
> + */
> +
> +#ifndef QCOM_JENC_DEV_H
> +#define QCOM_JENC_DEV_H
> +
> +#include <linux/device.h>
> +#include <linux/mutex.h>
> +#include <linux/irqreturn.h>
> +#include <linux/interconnect.h>
> +#include <linux/kfifo.h>
> +#include <linux/irq_work.h>
> +#include <media/videobuf2-core.h>
> +
> +#include <media/v4l2-device.h>
> +#include <media/videobuf2-v4l2.h>
> +#include <media/v4l2-ctrls.h>
> +
> +#include "qcom_jenc_res.h"
> +#include "qcom_jenc_hdr.h"
> +#include "qcom_jenc_defs.h"
Why do you include so many other headers inside header? You ONLY include
what you use. ONLY.
Best regards,
Krzysztof
^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [PATCH 2/3] qcom: media: jpeg: Add Qualcomm JPEG V4L2 encoder
2026-05-15 11:47 ` [PATCH 2/3] qcom: media: jpeg: Add Qualcomm JPEG V4L2 encoder Atanas Filipov
2026-05-15 12:21 ` Krzysztof Kozlowski
@ 2026-05-15 12:23 ` sashiko-bot
2026-05-15 13:28 ` Dmitry Baryshkov
2 siblings, 0 replies; 15+ messages in thread
From: sashiko-bot @ 2026-05-15 12:23 UTC (permalink / raw)
To: Atanas Filipov; +Cc: devicetree, robh, krzk+dt, conor+dt
Thank you for your contribution! Sashiko AI review found 15 potential issue(s) to consider:
- [Critical] Unclocked Hardware Access in VIDIOC_QBUF
- [Critical] DMA Memory Corruption due to Scatter-Gather mismatch
- [High] Out-of-Bounds DMA Hardware Write
- [High] Race Condition in Job Completion (`jpeg_stop` kills next job)
- [High] Unclocked Hardware Access in start_streaming Error Path
- [High] V4L2 Device Registration Race Condition (NULL Dereference)
- [High] Use-After-Free on Driver Unbind
- [High] kfifo Use-After-Free on Unbind
- [High] DMA Memory Corruption on V4L2_ENC_CMD_STOP
- [High] DMA Direction Violation
- [High] Spurious IRQ Crash Risk
- [Medium] Per-Context State Initialization Bug
- [Medium] Threaded IRQ Handler does not loop
- [Medium] Kconfig Dependency Propagation Violation
- [Low] PM Callbacks Dead Code
--
commit 4ae9b8d353b9d9d7104c0c0120d42653b3e58a64
Author: Atanas Filipov <atanas.filipov@oss.qualcomm.com>
Date: Fri May 15 11:47:00 2026 +0000
qcom: media: jpeg: Add Qualcomm JPEG V4L2 encoder
Implementation of a V4L2 JPEG encoder device driver supporting
Qualcomm SC7180, SM8250, SM7280, and SM8550 chipsets.
> diff --git a/drivers/media/platform/qcom/jpeg/Kconfig b/drivers/media/platform/qcom/jpeg/Kconfig
> new file mode 100644
> index 0000000000000..51846aeafaf37
> --- /dev/null
> +++ b/drivers/media/platform/qcom/jpeg/Kconfig
> @@ -0,0 +1,17 @@
> +# SPDX-License-Identifier: GPL-2.0-only
> +config VIDEO_QCOM_JENC
> + tristate "Qualcomm V4L2 JPEG Encoder driver"
> + depends on V4L_MEM2MEM_DRIVERS
> + depends on (ARCH_QCOM && IOMMU_DMA) || COMPILE_TEST
> + depends on VIDEO_DEV
> + select VIDEO_V4L2_SUBDEV_API
This isn't a bug, but selecting VIDEO_V4L2_SUBDEV_API without inheriting its
dependencies (like MEDIA_CONTROLLER) can cause Kconfig warnings and build
failures. Could the dependency be added here?
> diff --git a/drivers/media/platform/qcom/jpeg/qcom_jenc_dev.c b/drivers/media/platform/qcom/jpeg/qcom_jenc_dev.c
> new file mode 100644
> index 0000000000000..4ef6bf9fd48de
> --- /dev/null
> +++ b/drivers/media/platform/qcom/jpeg/qcom_jenc_dev.c
[ ... ]
> +static void qcom_jpeg_remove(struct platform_device *pdev)
> +{
> + struct qcom_jenc_dev *jenc = platform_get_drvdata(pdev);
> +
> + pm_runtime_disable(&pdev->dev);
> +
> + qcom_jpeg_v4l2_unregister(jenc);
> +
> + v4l2_device_unregister(&jenc->v4l2_dev);
> +
> + kfifo_free(&jenc->kfifo_inst);
If an interrupt fires after this point but before devres cleans up the
threaded IRQ handler, can op_jpeg_irq_top push items to this freed kfifo?
Also, since the jenc structure is allocated with devm_kzalloc during probe,
it will be freed when this remove function completes. If userspace still
holds the video device file descriptor open, will v4l2_m2m_ctx_release in
fop_jpeg_file_release access the m2m_dev inside the freed jenc memory later?
[ ... ]
> +static struct platform_driver qcom_jpeg_platform_driver = {
> + .probe = qcom_jpeg_probe,
> + .remove = qcom_jpeg_remove,
> + .driver = {
> + .name = QCOM_JPEG_ENC_NAME,
> + .of_match_table = qcom_jpeg_of_match,
> + .pm = &qcom_jpeg_pm_ops,
This isn't a bug, but should this use the pm_ptr() wrapper to allow the
compiler to optimize out the dev_pm_ops structure when PM features are
disabled?
> diff --git a/drivers/media/platform/qcom/jpeg/qcom_jenc_ops.c b/drivers/media/platform/qcom/jpeg/qcom_jenc_ops.c
> new file mode 100644
> index 0000000000000..92e3c09df3d14
> --- /dev/null
> +++ b/drivers/media/platform/qcom/jpeg/qcom_jenc_ops.c
[ ... ]
> +static int jpeg_store_we_next(struct jenc_context *ectx, struct vb2_buffer *vb2)
> +{
> + struct qcom_jenc_dev *jenc = ectx->jenc;
> + struct qcom_jenc_queue *q = &ectx->bufq[TYPE2QID(vb2->type)];
> + struct qcom_jpeg_buff *frame = &q->buff[vb2->index];
> + struct qc_jfif *mptr;
> + struct sg_table *sgt;
> + dma_addr_t dma;
> +
> + sgt = vb2_dma_sg_plane_desc(vb2, 0);
> + if (WARN_ON_ONCE(!sgt || !sgt->sgl))
> + return -EINVAL;
> +
> + dma = sg_dma_address(sgt->sgl);
Since the driver configures the queues with vb2_dma_sg_memops, userspace can
pass physical memory mapped via scatterlists. Does extracting only the first
scatterlist segment's DMA address cause the hardware to overrun the first
segment if the buffer spans multiple non-contiguous pages?
> + if (WARN_ON_ONCE(!dma))
> + return -EINVAL;
> +
> + mptr = vb2_plane_vaddr(vb2, 0);
> + if (WARN_ON_ONCE(!mptr))
> + return -EINVAL;
> +
> + mutex_lock(&ectx->quality_mutex);
> + if (ectx->quality_programmed != ectx->quality_requested)
> + jpeg_apply_dmi_table(ectx);
This function is called from bop_jpeg_vb2_buf_prepare during VIDIOC_QBUF.
Because VIDIOC_QBUF can be called by userspace before VIDIOC_STREAMON, the
device's PM runtime might be suspended. Will writing directly to the MMIO
registers in jpeg_apply_dmi_table cause a synchronous external abort when the
hardware is unclocked?
> + mutex_unlock(&ectx->quality_mutex);
> +
> + dma += qcom_jenc_header_emit(&ectx->hdr_cache, (void *)mptr,
> + min_t(size_t, vb2->planes[0].length, ectx->hdr_cache.size),
> + q->vf.width, q->vf.height);
By advancing the destination DMA address by the header size, does this allow
the hardware to write past the end of the allocated DMA buffer, since the
length limit programmed into the hardware is still the full sizeimage?
> + qcom_jenc_dqts_emit(&ectx->hdr_cache, (void *)mptr);
> +
> + frame->plns[0].sgt = sgt;
> + frame->plns[0].dma = dma;
> + frame->plns[0].size = vb2_plane_size(vb2, 0);
> +
> + jpeg_dev_access(jenc->dev, frame, DMA_TO_DEVICE);
Since this is the destination capture buffer that is written by the hardware
and read by the CPU, should this use DMA_FROM_DEVICE to maintain cache
coherency?
[ ... ]
> +static irqreturn_t op_jpeg_irq_bot(int irq, void *data)
> +{
> + struct qcom_jenc_dev *jenc = data;
> + const struct qcom_jpeg_reg_offs *offs = jenc->res->hw_offs;
> + u32 irq_status;
> + u32 irq_mask;
> + unsigned long flags;
> + int rc;
> +
> + rc = kfifo_out_spinlocked(&jenc->kfifo_inst, &irq_status, sizeof(irq_status),
> + &jenc->kfifo_lock);
If multiple interrupts push events to the queue, will this only process the
first one and leave the rest stalled until another interrupt arrives? Should
this process the kfifo in a while loop?
> + if (rc != sizeof(irq_status)) {
> + dev_err(jenc->dev, "IRQ status: FIFO empty\n");
> + return IRQ_HANDLED;
> + }
> +
> + irq_mask = jenc->res->hw_mask[JMSK_IRQ_STATUS_SESSION_DONE];
> + if (jpeg_bits_get(irq_mask, irq_status)) {
> + struct jenc_context *ctx = jenc->actx;
> + struct qcom_jenc_queue *dq = &ctx->bufq[JENC_DST_QUEUE];
> + size_t out_size;
> +
> + spin_lock_irqsave(&jenc->hw_lock, flags);
> + jenc->actx = NULL;
> + spin_unlock_irqrestore(&jenc->hw_lock, flags);
> +
> + if (ctx && dq->buff_id >= 0) {
> + struct qcom_jpeg_buff *frame;
> + unsigned long flags;
> +
> + spin_lock_irqsave(&jenc->hw_lock, flags);
> + frame = &dq->buff[dq->buff_id];
> + out_size = jpeg_io_read(jenc, offs->enc_out_size);
> + spin_unlock_irqrestore(&jenc->hw_lock, flags);
> +
> + dev_dbg(jenc->dev, "complete idx:%d addr=0x%llx size=%zu\n",
> + dq->buff_id, frame->plns[0].dma, out_size);
> +
> + jpeg_cpu_access(jenc->dev, frame, DMA_FROM_DEVICE);
> + jenc->enc_hw_irq_cb(ctx, VB2_BUF_STATE_DONE,
> + out_size + JPEG_HEADER_MAX);
> + jpeg_stop(jenc);
The callback enc_hw_irq_cb calls v4l2_m2m_job_finish, which can immediately
unblock the M2M framework to schedule the next job and start the hardware.
Does calling jpeg_stop right after this halt the hardware and kill the newly
scheduled job?
[ ... ]
> +static irqreturn_t op_jpeg_irq_top(int irq, void *data)
> +{
> + struct qcom_jenc_dev *jenc = data;
> + const struct qcom_jpeg_reg_offs *offs = jenc->res->hw_offs;
> + u32 irq_status;
> + u32 irq_mask;
> + unsigned long flags;
> + int rc;
> +
> + spin_lock_irqsave(&jenc->hw_lock, flags);
> +
> + irq_status = jpeg_io_read(jenc, offs->int_status);
If a spurious interrupt arrives while the device is in a runtime-suspended
state (powered off), will reading this register unconditionally cause a bus
fault? Should it check if the device is active first?
[ ... ]
> +static int op_jpeg_acquire(struct jenc_context *ectx, struct vb2_queue *q)
> +{
> + struct qcom_jenc_dev *jenc = ectx->jenc;
> + struct qcom_jenc_queue *sq, *dq;
> + int rc;
> +
> + if (atomic_inc_return(&jenc->ref_count) == 1) {
> + rc = pm_runtime_resume_and_get(jenc->dev);
> + if (rc < 0) {
> + dev_err(jenc->dev, "PM runtime get failed\n");
> + atomic_dec(&jenc->ref_count);
> + return rc;
> + }
> +
> + rc = jpeg_init(jenc);
> + if (rc) {
> + dev_err(jenc->dev, "hardware init failed\n");
> + atomic_dec(&jenc->ref_count);
> + pm_runtime_put(jenc->dev);
> + return rc;
> + }
> +
> + sq = &ectx->bufq[JENC_SRC_QUEUE];
> + sq->sequence = 0;
> + sq->buff_id = -1;
> + dq = &ectx->bufq[JENC_DST_QUEUE];
> + dq->sequence = 0;
> + dq->buff_id = -1;
> + }
Is it intentional to only initialize the context state for the first context?
If a second M2M context starts streaming while ref_count > 1, does its
sequence and buff_id remain uninitialized?
> diff --git a/drivers/media/platform/qcom/jpeg/qcom_jenc_v4l2.c b/drivers/media/platform/qcom/jpeg/qcom_jenc_v4l2.c
> new file mode 100644
> index 0000000000000..8f5e4bd8a36e6
> --- /dev/null
> +++ b/drivers/media/platform/qcom/jpeg/qcom_jenc_v4l2.c
[ ... ]
> +static int bop_jpeg_vb2_start_streaming(struct vb2_queue *q, unsigned int count)
> +{
> + struct jenc_context *ectx = vb2_get_drv_priv(q);
> + struct qcom_jenc_dev *jenc = ectx->jenc;
> + const struct qcom_jpeg_hw_ops *hw = jenc->res->hw_ops;
> + struct qcom_jenc_queue *sq = jpeg_get_bufq(ectx, JENC_SRC_QUEUE);
> + struct qcom_jenc_queue *dq = jpeg_get_bufq(ectx, JENC_DST_QUEUE);
> + u32 hw_caps;
> + u8 pln;
> + int rc;
> +
[ ... ]
> + mutex_lock(&jenc->dev_mutex);
> +
> + ectx->quality_requested = QCOM_JPEG_QUALITY_MAX;
> +
> + rc = hw->hw_acquire(ectx, q);
> +
> + hw->hw_get_cap(jenc, &hw_caps);
If hw_acquire fails to resume the device and returns an error, will
hw_get_cap attempting to read from the unclocked hardware cause a
synchronous external abort?
[ ... ]
> +static int iop_jpeg_encoder_command(struct file *file, void *priv, struct v4l2_encoder_cmd *ec)
> +{
> + struct jenc_context *ectx = jpeg_file2ctx(file);
> + struct vb2_queue *vq;
> +
> + if (ec->cmd == V4L2_ENC_CMD_STOP) {
> + vq = v4l2_m2m_get_src_vq(ectx->fh.m2m_ctx);
> + if (!vb2_is_streaming(vq))
> + return 0;
> +
> + vq = v4l2_m2m_get_dst_vq(ectx->fh.m2m_ctx);
> + if (!vb2_is_streaming(vq))
> + return 0;
> +
> + mutex_lock(&ectx->stop_lock);
> + ectx->is_stopping = true;
> + mutex_unlock(&ectx->stop_lock);
> + jpeg_v4l2_work_stop(ectx->jenc, ectx, VB2_BUF_STATE_ERROR);
> +
> + return 0;
> + }
While jpeg_v4l2_work_stop cleans up buffers, it doesn't appear to halt the
hardware DMA engine. Could the hardware continue writing to the destination
buffer after it has been returned to userspace and potentially reallocated,
causing memory corruption?
[ ... ]
> +int qcom_jpeg_v4l2_register(struct qcom_jenc_dev *jenc)
> +{
> + int rc;
> +
> + mutex_lock(&jenc->dev_mutex);
> +
> + jenc->enc_hw_irq_cb = jpeg_v4l2_process_cb;
> +
> + jenc->m2m_dev = v4l2_m2m_init(&qcom_jpeg_v4l2_m2m_ops);
[ ... ]
> + rc = video_register_device(jenc->vdev, VFL_TYPE_VIDEO, -1);
> + if (rc) {
> + dev_err(jenc->dev, "failed to register video device\n");
> + goto err_video_device_release;
> + }
> +
> + video_set_drvdata(jenc->vdev, jenc);
By calling video_register_device before video_set_drvdata, the video node
becomes visible to userspace immediately. If an application calls open() in
this narrow window, will video_drvdata(file) return NULL and cause a crash
in fop_jpeg_file_open?
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260515-qcom-jpeg-v4l2-v1-0-f38c2e1b3555@oss.qualcomm.com?part=2
^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [PATCH 2/3] qcom: media: jpeg: Add Qualcomm JPEG V4L2 encoder
[not found] ` <SA1PR02MB11289FA5C2A01466B49C62D4BDD042@SA1PR02MB11289.namprd02.prod.outlook.com>
@ 2026-05-15 12:29 ` Krzysztof Kozlowski
0 siblings, 0 replies; 15+ messages in thread
From: Krzysztof Kozlowski @ 2026-05-15 12:29 UTC (permalink / raw)
To: Atanas Filipov (Consultant), Atanas Filipov, Bryan O'Donoghue,
Mauro Carvalho Chehab, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Azam Sadiq Pasha Kapatrala Syed,
Hariram Purushothaman, Bjorn Andersson, Konrad Dybcio,
Gjorgji Rosikopulos (Consultant)
Cc: linux-media@vger.kernel.org, linux-arm-msm@vger.kernel.org,
devicetree@vger.kernel.org, linux-kernel@vger.kernel.org
On 15/05/2026 14:27, Atanas Filipov (Consultant) wrote:
> I'm really sorry, this was a mistake in the B4 automation. Please ignore this patch set.
>
So I just wasted 5 minutes of my time looking at this? I still expect
all review comments to be applied, not just ignored.
Best regards,
Krzysztof
^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [PATCH 3/3] arm64: qcom: dts: qcm6490: Add JPEG encoder DT properties
2026-05-15 11:47 ` [PATCH 3/3] arm64: qcom: dts: qcm6490: Add JPEG encoder DT properties Atanas Filipov
2026-05-15 12:16 ` Dmitry Baryshkov
2026-05-15 12:17 ` Krzysztof Kozlowski
@ 2026-05-15 12:36 ` sashiko-bot
2 siblings, 0 replies; 15+ messages in thread
From: sashiko-bot @ 2026-05-15 12:36 UTC (permalink / raw)
To: Atanas Filipov; +Cc: devicetree, robh, krzk+dt, conor+dt
Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
- [Low] The new device tree node violates generic naming conventions and contains properties that will fail DT schema validation.
--
commit b8074fba99ec8410569dbab1538fc6fc7f0597b9
Author: Atanas Filipov <atanas.filipov@oss.qualcomm.com>
arm64: qcom: dts: qcm6490: Add JPEG encoder DT properties
Add the required JPEG encoder definitions to the device tree.
> diff --git a/arch/arm64/boot/dts/qcom/kodiak.dtsi b/arch/arm64/boot/dts/qcom/kodiak.dtsi
> --- a/arch/arm64/boot/dts/qcom/kodiak.dtsi
> +++ b/arch/arm64/boot/dts/qcom/kodiak.dtsi
[ ... ]
> @@ -5305,6 +5305,58 @@ port@4 {
> };
> };
>
> + qcom_jpeg_enc: qcom,jpegenc@ac4e000 {
This isn't a bug, but does this node name violate generic naming
conventions? Devicetree specifications generally require using generic
names such as jpeg-encoder@ac4e000 or video-codec@ac4e000 instead of
vendor-specific names.
> + cell-index = <0>;
Can this cause a schema validation failure? The cell-index property does
not appear to be defined in the qcom,jpeg-encoder.yaml schema. Since the
schema specifies additionalProperties: false, this undocumented property
will trigger a make dtbs_check validation error.
> + compatible = "qcom,qcm6490-jenc";
> +
> + reg =
> + <0 0xac4e000 0 0x4000>,
> + <0 0xac40000 0 0x1000>;
> +
> + reg-names =
> + "jpeg_regs",
> + "cpas_regs";
Are these reg-names aligned with the schema constraints? It appears they
use underscores, whereas the schema explicitly constrains these items to
use hyphens (jpeg-regs, cpas-regs). This mismatch will cause schema
validation to fail, even though the driver retrieves them safely by index.
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260515-qcom-jpeg-v4l2-v1-0-f38c2e1b3555@oss.qualcomm.com?part=3
^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [PATCH 2/3] qcom: media: jpeg: Add Qualcomm JPEG V4L2 encoder
2026-05-15 11:47 ` [PATCH 2/3] qcom: media: jpeg: Add Qualcomm JPEG V4L2 encoder Atanas Filipov
2026-05-15 12:21 ` Krzysztof Kozlowski
2026-05-15 12:23 ` sashiko-bot
@ 2026-05-15 13:28 ` Dmitry Baryshkov
2026-05-15 13:50 ` Nicolas Dufresne
2 siblings, 1 reply; 15+ messages in thread
From: Dmitry Baryshkov @ 2026-05-15 13:28 UTC (permalink / raw)
To: Atanas Filipov
Cc: Bryan O'Donoghue, Mauro Carvalho Chehab, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Kapatrala Syed,
Hariram Purushothaman, Bjorn Andersson, Konrad Dybcio,
Gjorgji Rosikopulos, afilipov, linux-media, linux-arm-msm,
devicetree, linux-kernel
On Fri, May 15, 2026 at 02:47:00PM +0300, Atanas Filipov wrote:
> Implementation of a V4L2 JPEG encoder device driver supporting
> Qualcomm SC7180, SM8250, SM7280, and SM8550 chipsets.
>
> Signed-off-by: Atanas Filipov <atanas.filipov@oss.qualcomm.com>
> ---
> drivers/media/platform/qcom/Kconfig | 1 +
> drivers/media/platform/qcom/Makefile | 1 +
> drivers/media/platform/qcom/jpeg/Kconfig | 17 +
> drivers/media/platform/qcom/jpeg/Makefile | 9 +
> drivers/media/platform/qcom/jpeg/qcom_jenc_defs.h | 253 ++++
> drivers/media/platform/qcom/jpeg/qcom_jenc_dev.c | 370 +++++
> drivers/media/platform/qcom/jpeg/qcom_jenc_dev.h | 111 ++
> drivers/media/platform/qcom/jpeg/qcom_jenc_hdr.c | 388 +++++
> drivers/media/platform/qcom/jpeg/qcom_jenc_hdr.h | 130 ++
> drivers/media/platform/qcom/jpeg/qcom_jenc_ops.c | 1522 ++++++++++++++++++++
> drivers/media/platform/qcom/jpeg/qcom_jenc_ops.h | 49 +
> drivers/media/platform/qcom/jpeg/qcom_jenc_res.c | 268 ++++
> drivers/media/platform/qcom/jpeg/qcom_jenc_res.h | 70 +
> drivers/media/platform/qcom/jpeg/qcom_jenc_v4l2.c | 1082 ++++++++++++++
> drivers/media/platform/qcom/jpeg/qcom_jenc_v4l2.h | 27 +
> .../platform/qcom/jpeg/qcom_v165_jenc_hw_info.h | 509 +++++++
> .../platform/qcom/jpeg/qcom_v580_jenc_hw_info.h | 509 +++++++
> .../platform/qcom/jpeg/qcom_v680_jenc_hw_info.h | 509 +++++++
> .../platform/qcom/jpeg/qcom_v780_jenc_hw_info.h | 509 +++++++
> 19 files changed, 6334 insertions(+)
>
> diff --git a/drivers/media/platform/qcom/Kconfig b/drivers/media/platform/qcom/Kconfig
> index 4f4d3a68e6e5..f33d53a754a0 100644
> --- a/drivers/media/platform/qcom/Kconfig
> +++ b/drivers/media/platform/qcom/Kconfig
> @@ -5,3 +5,4 @@ comment "Qualcomm media platform drivers"
> source "drivers/media/platform/qcom/camss/Kconfig"
> source "drivers/media/platform/qcom/iris/Kconfig"
> source "drivers/media/platform/qcom/venus/Kconfig"
> +source "drivers/media/platform/qcom/jpeg/Kconfig"
> diff --git a/drivers/media/platform/qcom/Makefile b/drivers/media/platform/qcom/Makefile
> index ea2221a202c0..30c94949e9de 100644
> --- a/drivers/media/platform/qcom/Makefile
> +++ b/drivers/media/platform/qcom/Makefile
> @@ -2,3 +2,4 @@
> obj-y += camss/
> obj-y += iris/
> obj-y += venus/
> +obj-y += jpeg/
> diff --git a/drivers/media/platform/qcom/jpeg/Kconfig b/drivers/media/platform/qcom/jpeg/Kconfig
> new file mode 100644
> index 000000000000..51846aeafaf3
> --- /dev/null
> +++ b/drivers/media/platform/qcom/jpeg/Kconfig
> @@ -0,0 +1,17 @@
> +# SPDX-License-Identifier: GPL-2.0-only
> +config VIDEO_QCOM_JENC
> + tristate "Qualcomm V4L2 JPEG Encoder driver"
> + depends on V4L_MEM2MEM_DRIVERS
> + depends on (ARCH_QCOM && IOMMU_DMA) || COMPILE_TEST
> + depends on VIDEO_DEV
> + select VIDEO_V4L2_SUBDEV_API
> + select VIDEOBUF2_DMA_SG
> + select V4L2_MEM2MEM_DEV
> + help
> + Qualcomm JPEG memory-to-memory V4L2 encoder driver.
> +
> + Provides:
> + - qcom-jenc (encode)
> +
> + To compile this driver as a module, choose M here: the
> + module will be called qcom-jenc
> diff --git a/drivers/media/platform/qcom/jpeg/Makefile b/drivers/media/platform/qcom/jpeg/Makefile
> new file mode 100644
> index 000000000000..310f6c3c1f19
> --- /dev/null
> +++ b/drivers/media/platform/qcom/jpeg/Makefile
> @@ -0,0 +1,9 @@
> +# SPDX-License-Identifier: GPL-2.0-only
> +obj-$(CONFIG_VIDEO_QCOM_JENC) += qcom-jenc.o
> +
> +qcom-jenc-objs += \
> + qcom_jenc_dev.o \
> + qcom_jenc_v4l2.o \
> + qcom_jenc_ops.o \
> + qcom_jenc_res.o \
> + qcom_jenc_hdr.o
> diff --git a/drivers/media/platform/qcom/jpeg/qcom_jenc_defs.h b/drivers/media/platform/qcom/jpeg/qcom_jenc_defs.h
> new file mode 100644
> index 000000000000..40e46820c546
> --- /dev/null
> +++ b/drivers/media/platform/qcom/jpeg/qcom_jenc_defs.h
> @@ -0,0 +1,253 @@
> +/* SPDX-License-Identifier: GPL-2.0-only */
> +/*
> + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
> + */
> +
> +#ifndef QCOM_JENC_DEFS_H_
> +#define QCOM_JENC_DEFS_H_
> +
> +#include <linux/types.h>
> +#include <linux/io.h>
> +#include <linux/bitfield.h>
> +#include <linux/videodev2.h>
> +#include <media/videobuf2-core.h>
Keep the list sorted
> +
> +/* Offline JPEG encoder constraints */
> +#define QCOM_JPEG_HW_MAX_WIDTH 9248
> +#define QCOM_JPEG_HW_MAX_HEIGHT 8192
> +#define QCOM_JPEG_HW_MIN_WIDTH 128
> +#define QCOM_JPEG_HW_MIN_HEIGHT 96
> +
> +#define QCOM_JPEG_HW_DEF_HSTEP 16
> +#define QCOM_JPEG_HW_DEF_VSTEP 16
> +
> +#define QCOM_JPEG_HW_DEF_WIDTH 1920
> +#define QCOM_JPEG_HW_DEF_HEIGHT 1080
> +
> +#define QCOM_JPEG_MAX_PLANES 3
> +
> +#define QCOM_JPEG_QUALITY_MIN 1
> +#define QCOM_JPEG_QUALITY_DEF 95
> +#define QCOM_JPEG_QUALITY_MAX 100
> +#define QCOM_JPEG_QUALITY_MID (QCOM_JPEG_QUALITY_MAX / 2)
> +#define QCOM_JPEG_QUALITY_UNT 1
> +
> +enum qcom_jpeg_soc_id {
> + QCOM_V165_SOC_ID = 0,
> + QCOM_V580_SOC_ID,
> + QCOM_V680_SOC_ID,
> + QCOM_V780_SOC_ID,
> + QCOM_UNKNOWN_SOC_ID,
> +};
> +
> +enum qcom_soc_perf_level {
> + QCOM_SOC_PERF_SUSPEND = 0,
These should be a part of the OPP tables in DT.
> + QCOM_SOC_PERF_LOWSVS,
> + QCOM_SOC_PERF_SVS,
> + QCOM_SOC_PERF_SVS_L1,
> + QCOM_SOC_PERF_NOMINAL,
> + QCOM_SOC_PERF_TURBO,
> + QCOM_SOC_PERF_LEVEL_MAX,
> +};
> +
> +enum qcom_jpeg_mask_id {
> + JMSK_HW_VER_STEP,
> + JMSK_HW_VER_MINOR,
> + JMSK_HW_VER_MAJOR,
> +
> + JMSK_HW_CAP_ENCODE,
> + JMSK_HW_CAP_DECODE,
> + JMSK_HW_CAP_UPSCALE,
> + JMSK_HW_CAP_DOWNSCALE,
> +
> + JMSK_RST_CMD_COMMON,
> + JMSK_RST_CMD_FE_RESET,
> + JMSK_RST_CMD_WE_RESET,
> + JMSK_RST_CMD_ENCODER_RESET,
> + JMSK_RST_CMD_DECODER_RESET,
> + JMSK_RST_CMD_BLOCK_FORMATTER_RST,
> + JMSK_RST_CMD_SCALE_RESET,
> + JMSK_RST_CMD_REGISTER_RESET,
> + JMSK_RST_CMD_MISR_RESET,
> + JMSK_RST_CMD_CORE_RESET,
> + JMSK_RST_CMD_JMSK_DOMAIN_RESET,
> + JMSK_RST_CMD_RESET_BYPASS,
> +
> + JMSK_CMD_HW_START,
> + JMSK_CMD_HW_STOP,
> + JMSK_CMD_CLR_RD_PLNS_QUEUE,
> + JMSK_CMD_CLR_WR_PLNS_QUEUE,
> + JMSK_CMD_APPLY_SWC_RD_PARAMS,
> +
> + JMSK_CORE_CFG_FE_ENABLE,
> + JMSK_CORE_CFG_WE_ENABLE,
> + JMSK_CORE_CFG_ENC_ENABLE,
> + JMSK_CORE_CFG_SCALE_ENABLE,
> + JMSK_CORE_CFG_TESTBUS_ENABLE,
> + JMSK_CORE_CFG_MODE,
> + JMSK_CORE_CFG_CGC_DISABLE,
> +
> + JMSK_CORE_STATUS_ENCODE_STATE,
> + JMSK_CORE_STATUS_SCALE_STATE,
> + JMSK_CORE_STATUS_RT_STATE,
> + JMSK_CORE_STATUS_BUS_STATE,
> + JMSK_CORE_STATUS_CGC_STATE,
> +
> + JMSK_IRQ_ENABLE_ALL,
> + JMSK_IRQ_DISABLE_ALL,
> + JMSK_IRQ_CLEAR_ALL,
> +
> + JMSK_IRQ_STATUS_SESSION_DONE,
> + JMSK_IRQ_STATUS_RD_BUF_PLN0_DONE,
> + JMSK_IRQ_STATUS_RD_BUF_PLN1_DONE,
> + JMSK_IRQ_STATUS_RD_BUF_PLN2_DONE,
> + JMSK_IRQ_STATUS_RD_BUF_PLNS_ATTN,
> + JMSK_IRQ_STATUS_WR_BUF_PLN0_DONE,
> + JMSK_IRQ_STATUS_WR_BUF_PLN1_DONE,
> + JMSK_IRQ_STATUS_WR_BUF_PLN2_DONE,
> + JMSK_IRQ_STATUS_WR_BUF_PLNS_ATTN,
> + JMSK_IRQ_STATUS_SESSION_ERROR,
> + JMSK_IRQ_STATUS_STOP_ACK,
> + JMSK_IRQ_STATUS_RESET_ACK,
> +
> + JMSK_FE_CFG_BYTE_ORDERING,
> + JMSK_FE_CFG_BURST_LENGTH_MAX,
> + JMSK_FE_CFG_MEMORY_FORMAT,
> + JMSK_FE_CFG_CBCR_ORDER,
> + JMSK_FE_CFG_BOTTOM_VPAD_EN,
> + JMSK_FE_CFG_PLN0_EN,
> + JMSK_FE_CFG_PLN1_EN,
> + JMSK_FE_CFG_PLN2_EN,
> + JMSK_FE_CFG_SIXTEEN_MCU_EN,
> + JMSK_FE_CFG_MCUS_PER_BLOCK,
> + JMSK_FE_CFG_MAL_BOUNDARY,
> + JMSK_FE_CFG_MAL_EN,
> +
> + JMSK_FE_VBPAD_CFG_BLOCK_ROW,
> +
> + JMSK_PLNS_RD_OFFSET,
> + JMSK_PLNS_RD_BUF_SIZE_WIDTH,
> + JMSK_PLNS_RD_BUF_SIZE_HEIGHT,
> + JMSK_PLNS_RD_STRIDE,
> + JMSK_PLNS_RD_HINIT,
> + JMSK_PLNS_RD_VINIT,
> +
> + JMSK_WE_CFG_BYTE_ORDERING,
> + JMSK_WE_CFG_BURST_LENGTH_MAX,
> + JMSK_WE_CFG_MEMORY_FORMAT,
> + JMSK_WE_CFG_CBCR_ORDER,
> + JMSK_WE_CFG_PLN0_EN,
> + JMSK_WE_CFG_PLN1_EN,
> + JMSK_WE_CFG_PLN2_EN,
> + JMSK_WE_CFG_MAL_BOUNDARY,
> + JMSK_WE_CFG_MAL_EN,
> + JMSK_WE_CFG_POP_BUFF_ON_EOS,
> +
> + JMSK_PLNS_WR_BUF_SIZE_WIDTH,
> + JMSK_PLNS_WR_BUF_SIZE_HEIGHT,
> +
> + JMSK_PLNS_WR_STRIDE,
> + JMSK_PLNS_WR_HINIT,
> + JMSK_PLNS_WR_VINIT,
> + JMSK_PLNS_WR_HSTEP,
> + JMSK_PLNS_WR_VSTEP,
> + JMSK_PLNS_WR_BLOCK_CFG_PER_COL,
> + JMSK_PLNS_WR_BLOCK_CFG_PER_RAW,
> +
> + JMSK_ENC_CFG_IMAGE_FORMAT,
> + JMSK_ENC_CFG_APPLY_EOI,
> + JMSK_ENC_CFG_HUFFMAN_SEL,
> + JMSK_ENC_CFG_FSC_ENABLE,
> + JMSK_ENC_CFG_OUTPUT_DISABLE,
> + JMSK_ENC_CFG_RST_MARKER_PERIOD,
> + JMSK_ENC_IMAGE_SIZE_WIDTH,
> + JMSK_ENC_IMAGE_SIZE_HEIGHT,
> +
> + JMSK_SCALE_CFG_HSCALE_ENABLE,
> + JMSK_SCALE_CFG_VSCALE_ENABLE,
> + JMSK_SCALE_CFG_UPSAMPLE_EN,
> + JMSK_SCALE_CFG_SUBSAMPLE_EN,
> + JMSK_SCALE_CFG_HSCALE_ALGO,
> + JMSK_SCALE_CFG_VSCALE_ALGO,
> + JMSK_SCALE_CFG_H_SCALE_FIR_ALGO,
> + JMSK_SCALE_CFG_V_SCALE_FIR_ALGO,
> +
> + JMSK_SCALE_PLNS_OUT_CFG_BLK_WIDTH,
> + JMSK_SCALE_PLNS_OUT_CFG_BLK_HEIGHT,
> +
> + JMSK_SCALE_PLNS_HSTEP_FRACTIONAL,
> + JMSK_SCALE_PLNS_HSTEP_INTEGER,
> + JMSK_SCALE_PLNS_VSTEP_FRACTIONAL,
> + JMSK_SCALE_PLNS_VSTEP_INTEGER,
> +
> + JMSK_DMI_CFG,
> + JMSK_DMI_ADDR,
> + JMSK_DMI_DATA,
> +
> + JMSK_TESTBUS_CFG,
> + JMSK_FE_VBPAD_CFG,
> +
> + JMSK_PLN0_RD_HINIT_INT,
> + JMSK_PLN1_RD_HINIT_INT,
> + JMSK_PLN2_RD_HINIT_INT,
> + JMSK_PLN0_RD_VINIT_INT,
> + JMSK_PLN1_RD_VINIT_INT,
> + JMSK_PLN2_RD_VINIT_INT,
> + JMSK_ID_MAX
> +};
> +
> +struct qcom_jpeg_reg_offs {
> + u32 hw_version;
> + u32 hw_capability;
> + u32 reset_cmd;
> + u32 core_cfg;
> + u32 int_mask;
> + u32 int_clr;
> + u32 int_status;
> + u32 hw_cmd;
> + u32 enc_core_state;
> +
> + struct {
> + u32 pntr[QCOM_JPEG_MAX_PLANES];
> + u32 offs[QCOM_JPEG_MAX_PLANES];
> + u32 cnsmd[QCOM_JPEG_MAX_PLANES];
> + u32 bsize[QCOM_JPEG_MAX_PLANES];
> + u32 stride[QCOM_JPEG_MAX_PLANES];
> + u32 hinit[QCOM_JPEG_MAX_PLANES];
> + u32 vinit[QCOM_JPEG_MAX_PLANES];
> + u32 pntr_cnt;
> + u32 vbpad_cfg;
> + } fe;
> + u32 fe_cfg;
> +
> + struct {
> + u32 pntr[QCOM_JPEG_MAX_PLANES];
> + u32 cnsmd[QCOM_JPEG_MAX_PLANES];
> + u32 bsize[QCOM_JPEG_MAX_PLANES];
> + u32 stride[QCOM_JPEG_MAX_PLANES];
> + u32 hinit[QCOM_JPEG_MAX_PLANES];
> + u32 hstep[QCOM_JPEG_MAX_PLANES];
> + u32 vinit[QCOM_JPEG_MAX_PLANES];
> + u32 vstep[QCOM_JPEG_MAX_PLANES];
> + u32 blocks[QCOM_JPEG_MAX_PLANES];
> + u32 pntr_cnt;
> + } we;
> + u32 we_cfg;
> +
> + struct {
> + u32 hstep[QCOM_JPEG_MAX_PLANES];
> + u32 vstep[QCOM_JPEG_MAX_PLANES];
> + } scale;
> + u32 scale_cfg;
> + u32 scale_out_cfg[QCOM_JPEG_MAX_PLANES];
> +
> + u32 enc_cfg;
> + u32 enc_img_size;
> + u32 enc_out_size;
> +
> + u32 dmi_cfg;
> + u32 dmi_data;
> + u32 dmi_addr;
> +} __packed;
> +
> +#endif /* QCOM_JENC_DEFS_H_ */
> diff --git a/drivers/media/platform/qcom/jpeg/qcom_jenc_dev.c b/drivers/media/platform/qcom/jpeg/qcom_jenc_dev.c
> new file mode 100644
> index 000000000000..4ef6bf9fd48d
> --- /dev/null
> +++ b/drivers/media/platform/qcom/jpeg/qcom_jenc_dev.c
> @@ -0,0 +1,370 @@
> +// SPDX-License-Identifier: GPL-2.0-only
> +/*
> + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
> + */
> +
> +#include <linux/clk.h>
> +#include <linux/interrupt.h>
> +#include <linux/module.h>
> +#include <linux/of_device.h>
> +#include <linux/of.h>
> +#include <linux/platform_device.h>
> +#include <linux/pm_runtime.h>
> +#include <linux/slab.h>
> +
> +#include <media/v4l2-mem2mem.h>
> +
> +#include "qcom_jenc_dev.h"
> +
> +#include "qcom_jenc_defs.h"
> +#include "qcom_jenc_ops.h"
> +#include "qcom_jenc_res.h"
> +#include "qcom_jenc_v4l2.h"
> +
> +static int qcom_jpeg_match_data(struct qcom_jenc_dev *jenc)
> +{
> + struct device *dev = jenc->dev;
> + const struct qcom_dev_resources *res;
> +
> + res = device_get_match_data(dev);
> + if (!res)
> + return dev_err_probe(dev, -ENODEV, "unsupported SoC\n");
> +
> + jenc->res = res;
> +
> + return 0;
Useless wrapper, inline it.
> +}
> +
> +static int qcom_jpeg_clk_init(struct qcom_jenc_dev *jenc)
> +{
> + const struct qcom_dev_resources *res = jenc->res;
> + int c_idx;
> +
> + jenc->clks = devm_kcalloc(jenc->dev, ARRAY_SIZE(res->clk_names), sizeof(*jenc->clks),
> + GFP_KERNEL);
> + if (!jenc->clks)
> + return -ENOMEM;
> +
> + for (c_idx = 0; c_idx < ARRAY_SIZE(res->clk_names); c_idx++) {
> + if (!res->clk_names[c_idx])
> + break;
> +
> + jenc->clks[c_idx].clk = devm_clk_get(jenc->dev, res->clk_names[c_idx]);
> + if (IS_ERR(jenc->clks[c_idx].clk)) {
> + return dev_err_probe(jenc->dev, PTR_ERR(jenc->clks[c_idx].clk),
> + "failed to get clock %s\n", res->clk_names[c_idx]);
> + }
> +
> + jenc->clks[c_idx].id = res->clk_names[c_idx];
> + jenc->num_clks++;
> + }
> +
Use bulk clock API instead of manually implementing those.
> + return 0;
> +}
> +
> +static int qcom_jpeg_clk_rate(struct qcom_jenc_dev *jenc, enum qcom_soc_perf_level level)
> +{
> + const struct qcom_dev_resources *res = jenc->res;
> + const struct qcom_perf_resource *perf = &res->perf_cfg[level];
> + int c_idx;
> + int rc = 0;
> +
> + for (c_idx = 0; c_idx < jenc->num_clks; c_idx++) {
> + /* skip clocks with fixed or default frequency */
> + if (!perf->clk_rate[c_idx])
> + continue;
> +
> + /* setup frequency according to performance level */
> + rc = clk_set_rate(jenc->clks[c_idx].clk, perf->clk_rate[c_idx]);
> + if (rc < 0) {
> + dev_err(jenc->dev, "clock set rate failed: %d\n", rc);
> + return rc;
> + }
> +
> + dev_dbg(jenc->dev, "clock %s current rate: %ld\n",
> + jenc->clks[c_idx].id, clk_get_rate(jenc->clks[c_idx].clk));
People have invented OPP tables. Please use those instead.
> + }
> +
> + return rc;
> +}
> +
[...]
> +
> +static int qcom_jpeg_probe(struct platform_device *pdev)
> +{
> + struct qcom_jenc_dev *jenc;
> + int rc;
> +
> + jenc = devm_kzalloc(&pdev->dev, sizeof(*jenc), GFP_KERNEL);
> + if (!jenc)
> + return -ENOMEM;
> +
> + jenc->dev = &pdev->dev;
> + mutex_init(&jenc->dev_mutex);
> + spin_lock_init(&jenc->hw_lock);
> + init_completion(&jenc->reset_complete);
> + init_completion(&jenc->stop_complete);
> +
> + rc = qcom_jpeg_match_data(jenc);
> + if (rc)
> + return dev_err_probe(jenc->dev, rc, "failed to attach hardware\n");
> +
> + if (!jenc->res->hw_offs || !jenc->res->hw_ops)
> + return dev_err_probe(jenc->dev, -EINVAL, "missing hw resources\n");
> +
> + rc = dma_set_mask_and_coherent(jenc->dev, DMA_BIT_MASK(32));
> + if (rc)
> + return dev_err_probe(jenc->dev, rc, "failed to set DMA mask\n");
> +
> + platform_set_drvdata(pdev, jenc);
> +
> + jenc->jpeg_base = devm_platform_ioremap_resource(pdev, 0);
> + if (IS_ERR(jenc->jpeg_base)) {
> + rc = PTR_ERR(jenc->jpeg_base);
> + return dev_err_probe(jenc->dev, rc, "failed to map JPEG resource\n");
> + }
> +
> + jenc->cpas_base = devm_platform_ioremap_resource(pdev, 1);
> + if (IS_ERR(jenc->cpas_base)) {
> + rc = PTR_ERR(jenc->cpas_base);
> + return dev_err_probe(jenc->dev, rc, "failed to map CPAS resource\n");
> + }
> +
> + rc = qcom_jpeg_clk_init(jenc);
> + if (rc)
> + return dev_err_probe(jenc->dev, rc, "failed to init bulk clocks\n");
> +
> + jenc->irq = platform_get_irq(pdev, 0);
> + if (jenc->irq < 0)
> + return dev_err_probe(jenc->dev, jenc->irq, "failed to get IRQ\n");
> +
> + rc = devm_request_threaded_irq(jenc->dev, jenc->irq,
> + jenc->res->hw_ops->hw_irq_top,
> + jenc->res->hw_ops->hw_irq_bot,
> + IRQF_ONESHOT, dev_name(jenc->dev), jenc);
> + if (rc)
> + return dev_err_probe(jenc->dev, rc, "failed to request IRQ\n");
> +
> + rc = qcom_jpeg_icc_init(jenc);
> + if (rc)
> + return dev_err_probe(jenc->dev, rc, "failed to get ICC resources\n");
> +
> + rc = kfifo_alloc(&jenc->kfifo_inst, sizeof(jenc->enc_status) * VB2_MAX_FRAME, GFP_KERNEL);
> + if (rc) {
> + dev_err(jenc->dev, "failed to allocate kfifo\n");
> + return rc;
> + }
> +
> + spin_lock_init(&jenc->kfifo_lock);
> +
> + rc = v4l2_device_register(jenc->dev, &jenc->v4l2_dev);
> + if (rc) {
> + dev_err(jenc->dev, "failed to register V4L2 device\n");
> + goto err_kfifo_free;
> + }
> +
> + rc = qcom_jpeg_v4l2_register(jenc);
> + if (rc) {
> + dev_err(jenc->dev, "failed to register video device\n");
> + goto err_v4l2_device_unregister;
> + }
> +
> + jenc->perf = QCOM_SOC_PERF_NOMINAL;
> +
> + pm_runtime_enable(jenc->dev);
devm_pm_runtime_enable()
> +
> + dev_info(jenc->dev, "Qualcomm JPEG encoder registered\n");
> +
> + return 0;
> +
> +err_v4l2_device_unregister:
> + v4l2_device_unregister(&jenc->v4l2_dev);
> +err_kfifo_free:
> + kfifo_free(&jenc->kfifo_inst);
> +
> + return rc;
> +}
> +
> +static void qcom_jpeg_remove(struct platform_device *pdev)
> +{
> + struct qcom_jenc_dev *jenc = platform_get_drvdata(pdev);
> +
> + pm_runtime_disable(&pdev->dev);
> +
> + qcom_jpeg_v4l2_unregister(jenc);
> +
> + v4l2_device_unregister(&jenc->v4l2_dev);
> +
> + kfifo_free(&jenc->kfifo_inst);
> +
> + dev_info(jenc->dev, "Qualcomm JPEG encoder deregistered\n");
Don't spam the logs with useless info.
> +}
> +
> +static const struct of_device_id qcom_jpeg_of_match[] = {
> + {
> + .compatible = "qcom,sc7180-jenc",
> + .data = &qcom_jpeg_v165_drvdata
> + },
> + {
> + .compatible = "qcom,sm8250-jenc",
> + .data = &qcom_jpeg_v580_drvdata
> + },
> + {
> + .compatible = "qcom,sm7325-jenc",
> + .data = &qcom_jpeg_v580_drvdata
Don't regisger multiple entries for compatible devices. Use fallback
compats instead.
> + },
> + {
> + .compatible = "qcom,sc7280-jenc",
> + .data = &qcom_jpeg_v680_drvdata
> + },
> + {
> + .compatible = "qcom,qcm6490-jenc",
> + .data = &qcom_jpeg_v680_drvdata
> + },
> + {
> + .compatible = "qcom,sm8550-jenc",
> + .data = &qcom_jpeg_v780_drvdata
> + },
> + { }
> +};
> +MODULE_DEVICE_TABLE(of, qcom_jpeg_of_match);
> +
> +static struct platform_driver qcom_jpeg_platform_driver = {
> + .probe = qcom_jpeg_probe,
> + .remove = qcom_jpeg_remove,
> + .driver = {
> + .name = QCOM_JPEG_ENC_NAME,
> + .of_match_table = qcom_jpeg_of_match,
> + .pm = &qcom_jpeg_pm_ops,
> + },
> +};
> +
> +module_platform_driver(qcom_jpeg_platform_driver);
> +
> +MODULE_DESCRIPTION("QCOM JPEG mem2mem V4L2 encoder");
> +MODULE_LICENSE("GPL");
[...]
> +
> +int qcom_jenc_header_init(struct qcom_jenc_header *c, u32 fourcc)
> +{
> + int rc;
> + struct jpeg_header_buf b = {
> + .ptr = c->data,
> + .size = sizeof(c->data),
> + .pos = 0,
> + };
> +
> + c->sof_offset = 0;
> + c->dqt_one_offs = 0;
> + c->dqt_two_offs = 0;
> +
> + rc = jb_put_mem(&b, &soi_app0, sizeof(soi_app0));
> + if (rc)
> + return rc;
> +
> + if (fourcc != V4L2_PIX_FMT_GREY) {
> + rc = jb_put_mem(&b, &dqt_chroma_hdr, sizeof(dqt_chroma_hdr));
> + if (rc)
> + return rc;
> +
> + /* Store the offset of the first DQT table for later use. */
> + c->dqt_one_offs = b.pos;
> + rc = jb_put_mem(&b, &dqt_luma_data, sizeof(dqt_luma_data));
> + if (rc)
> + return rc;
> +
> + /* Store the offset of the second DQT table for later use. */
> + c->dqt_two_offs = b.pos;
> + rc = jb_put_mem(&b, &dqt_chroma_data, sizeof(dqt_chroma_data));
> + if (rc)
> + return rc;
> + } else {
> + rc = jb_put_mem(&b, &dqt_luma_hdr, sizeof(dqt_luma_hdr));
> + if (rc)
> + return rc;
> +
> + /* Store the offset of the first DQT table for later use. */
> + c->dqt_one_offs = b.pos;
> + rc = jb_put_mem(&b, &dqt_luma_data, sizeof(dqt_luma_data));
> + if (rc)
> + return rc;
> + }
Do we absolutely need to do this in the kernel? Can we have defer that
to the userspace using V4L2 encoders? Are there any other JPEG encoders
handling JPEG headers in the kernel code?
> +
> + /* Store the offset of the SOF record for later use. */
> + c->sof_offset = b.pos;
> +
> + if (fourcc != V4L2_PIX_FMT_GREY) {
> + rc = jb_put_mem(&b, &sof0_color_hdr, sizeof(sof0_color_hdr));
> + if (rc)
> + return rc;
> + rc = jb_put_mem(&b, &sof0_color_data, sizeof(sof0_color_data));
> + if (rc)
> + return rc;
> + rc = jb_put_mem(&b, &coeff_color_hdr, sizeof(coeff_color_hdr));
> + if (rc)
> + return rc;
> + rc = jb_put_mem(&b, &luma_dc_coeff, sizeof(luma_dc_coeff));
> + if (rc)
> + return rc;
> + rc = jb_put_mem(&b, &luma_ac_coeff, sizeof(luma_ac_coeff));
> + if (rc)
> + return rc;
> + rc = jb_put_mem(&b, &chroma_dc_coeff, sizeof(chroma_dc_coeff));
> + if (rc)
> + return rc;
> + rc = jb_put_mem(&b, &chroma_ac_coeff, sizeof(chroma_ac_coeff));
> + if (rc)
> + return rc;
> + rc = jb_put_mem(&b, &sos_color_hdr, sizeof(sos_color_hdr));
> + if (rc)
> + return rc;
> + rc = jb_put_mem(&b, &sos_color_data, sizeof(sos_color_data));
> + if (rc)
> + return rc;
> + } else {
> + rc = jb_put_mem(&b, &sof0_mono_hdr, sizeof(sof0_mono_hdr));
> + if (rc)
> + return rc;
> + rc = jb_put_mem(&b, &sof0_mono_data, sizeof(sof0_mono_data));
> + if (rc)
> + return rc;
> + rc = jb_put_mem(&b, &coeff_mono_hdr, sizeof(coeff_mono_hdr));
> + if (rc)
> + return rc;
> + rc = jb_put_mem(&b, &luma_dc_coeff, sizeof(luma_dc_coeff));
> + if (rc)
> + return rc;
> + rc = jb_put_mem(&b, &luma_ac_coeff, sizeof(luma_ac_coeff));
> + if (rc)
> + return rc;
> + rc = jb_put_mem(&b, &sos_mono_hdr, sizeof(sos_mono_hdr));
> + if (rc)
> + return rc;
> + rc = jb_put_mem(&b, &sos_mono_data, sizeof(sos_mono_data));
> + if (rc)
> + return rc;
> + }
> +
> + c->size = b.pos;
> +
> + return 0;
> +}
> +
> +void qcom_jenc_dqts_emit(const struct qcom_jenc_header *c, u8 *dst)
> +{
> + /* Propagate DQT tables into the JPEG header */
> + if (c->dqt_one_offs) {
> + u32 one_offs = c->dqt_one_offs + sizeof(dqt_luma_data.index);
> +
> + memcpy(dst + one_offs, &c->data[one_offs], sizeof(dqt_luma_data.value));
> + }
> +
> + if (c->dqt_two_offs) {
> + u32 two_offs = c->dqt_two_offs + sizeof(dqt_chroma_data.index);
> +
> + memcpy(dst + two_offs, &c->data[two_offs], sizeof(dqt_chroma_data.value));
> + }
> +}
> +
> +u32 qcom_jenc_header_emit(const struct qcom_jenc_header *c, u8 *dst, u32 dst_size, u16 width,
> + u16 height)
> +{
> + /* Copy JFIF into JPEG header and update actual image size */
> + if (dst_size < c->size)
> + return 0;
> +
> + memcpy(dst, c->data, c->size);
> +
> + /* Update output image size */
> + patch_u16be(dst, c->sof_offset + JFIF_HEADER_WIDTH_OFFS, width);
> + patch_u16be(dst, c->sof_offset + JFIF_HEADER_HEIGHT_OFFS, height);
> +
> + return c->size;
> +}
> diff --git a/drivers/media/platform/qcom/jpeg/qcom_jenc_hdr.h b/drivers/media/platform/qcom/jpeg/qcom_jenc_hdr.h
> new file mode 100644
> index 000000000000..0c5fcc69e7cd
> --- /dev/null
> +++ b/drivers/media/platform/qcom/jpeg/qcom_jenc_hdr.h
> @@ -0,0 +1,130 @@
> +/* SPDX-License-Identifier: GPL-2.0-only */
> +/*
> + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
> + */
> +
> +#ifndef QCOM_JENC_HDR_H
> +#define QCOM_JENC_HDR_H
> +
> +#include <linux/types.h>
> +
> +#include "qcom_jenc_defs.h"
> +
> +#define JPEG_QDT_LENGTH 64
> +#define JPEG_HEADER_MAX 1024
> +
> +struct qcom_jenc_header {
> + u8 data[JPEG_HEADER_MAX];
> + u32 size;
> + u32 sof_offset;
> + u32 dqt_one_offs;
> + u32 dqt_two_offs;
> +};
> +
> +struct jpeg_record_hdr {
> + u8 marker[2];
> + u8 length[2];
> +} __packed;
> +
> +struct jpeg_dqt_header {
> + u8 index;
> + u8 value[JPEG_QDT_LENGTH];
> +} __packed;
> +
> +struct jpeg_soi_app0 {
> + u8 soi[2];
> + u8 app0_marker[2];
> + u8 app0_length[2];
> + u8 jfif_id[5];
> + u8 version[2];
> + u8 units;
> + u8 density_x[2];
> + u8 density_y[2];
> + u8 thumb_x;
> + u8 thumb_y;
> +} __packed;
> +
> +struct jpeg_sof0_mono {
> + u8 precision;
> + u8 height[2];
> + u8 width[2];
> + u8 components;
> +
> + u8 y_id;
> + u8 y_sampling;
> + u8 y_qtable;
> +} __packed;
> +
> +struct jpeg_sof0_color {
> + u8 precision;
> + u8 height[2];
> + u8 width[2];
> + u8 components;
> +
> + u8 y_id;
> + u8 y_sampling;
> + u8 y_qtable;
> +
> + u8 cb_id;
> + u8 cb_sampling;
> + u8 cb_qtable;
> +
> + u8 cr_id;
> + u8 cr_sampling;
> + u8 cr_qtable;
> +} __packed;
> +
> +struct jpeg_dc_coeff_desc {
> + u8 index;
> + u8 bits[16];
> + u8 values[12];
> +} __packed;
> +
> +struct jpeg_ac_coeff_desc {
> + u8 index;
> + u8 bits[16];
> + u8 values[162];
> +} __packed;
> +
> +struct jpeg_sos_hdr {
> + u8 sos_marker[2];
> + u8 sos_length[2];
> + u8 components;
> +} __packed;
> +
> +struct jpeg_sos_mono {
> + u8 components;
> +
> + u8 y_id;
> + u8 y_tables;
> +
> + u8 spectral[2];
> + u8 approx;
> +} __packed;
> +
> +struct jpeg_sos_color {
> + u8 components;
> +
> + u8 y_id;
> + u8 y_tables;
> +
> + u8 cb_id;
> + u8 cb_tables;
> +
> + u8 cr_id;
> + u8 cr_tables;
> +
> + u8 spectral[2];
> + u8 approx;
> +} __packed;
> +
> +struct jenc_context;
> +
> +int qcom_jenc_header_init(struct qcom_jenc_header *c, u32 fourcc);
> +
> +void qcom_jenc_dqts_emit(const struct qcom_jenc_header *c, u8 *dst);
> +
> +u32 qcom_jenc_header_emit(const struct qcom_jenc_header *c, u8 *dst, u32 dst_size, u16 width,
> + u16 height);
> +
> +#endif /* QCOM_JENC_HDR_H */
> diff --git a/drivers/media/platform/qcom/jpeg/qcom_jenc_ops.c b/drivers/media/platform/qcom/jpeg/qcom_jenc_ops.c
> new file mode 100644
> index 000000000000..92e3c09df3d1
> --- /dev/null
> +++ b/drivers/media/platform/qcom/jpeg/qcom_jenc_ops.c
> @@ -0,0 +1,1522 @@
> +// SPDX-License-Identifier: GPL-2.0-only
> +/*
> + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
> + */
> +
> +#include <asm/div64.h>
> +#include <linux/pm_runtime.h>
> +
> +#include <media/v4l2-common.h>
> +#include <media/v4l2-mem2mem.h>
> +#include <media/videobuf2-dma-sg.h>
> +#include <media/videobuf2-dma-contig.h>
> +
> +#include "qcom_jenc_dev.h"
> +#include "qcom_jenc_ops.h"
> +#include "qcom_jenc_defs.h"
> +
> +#define JPEG_RESET_TIMEOUT_MS 300
> +#define JPEG_STOP_TIMEOUT_MS 200
> +
> +#define JPEG_DQT_SHIFT 20
> +#define JPEG_Q5_21_SHIFT 21
> +
> +#define JPEG_MCU_BLOCK_8 8
> +#define JPEG_MCU_BLOCK_16 16
> +#define JPEG_MCU_BLOCK_128 128
> +#define JPEG_MCU_BLOCK_256 256
> +
> +#define JPEG_DEFAULT_SCALE_STEP 0x200000
> +
> +#define JPEG_U32_CLR (0U)
> +#define JPEG_U32_SET (~0U)
> +
> +/*
> + * JPEG | V4L2
> + * ---- | -------
> + * H1V1 | GREY
> + * H1V2 | YUV422M
> + * H2V1 | NV16M
> + * H2V2 | NV12M
> + */
> +enum qcom_jpeg_encode_fmt {
> + JPEG_ENCODE_H1V1 = 0,
> + JPEG_ENCODE_H1V2,
> + JPEG_ENCODE_H2V1,
> + JPEG_ENCODE_H2V2,
> + JPEG_ENCODE_MONO,
> +};
> +
> +enum qcom_jpeg_memory_fmt {
> + JPEG_MEM_FMT_PLANAR = 0x0,
> + JPEG_MEM_FMT_PPLANAR = 0x1,
> + JPEG_MEM_FMT_MONO = 0x2,
> + JPEG_MEM_FMT_COEFFICIENT = 0x3
> +};
> +
> +enum jpeg_mal_bounds {
> + JPEG_CFG_MAL_BOUND_32_BYTES = 0x0,
> + JPEG_CFG_MAL_BOUND_64_BYTES = 0x1,
> + JPEG_CFG_MAL_BOUND_128_BYTES = 0x2,
> + JPEG_CFG_MAL_BOUND_256_BYTES = 0x3,
> + JPEG_CFG_MAL_BOUND_512_BYTES = 0x4,
> + JPEG_CFG_MAL_BOUND_1K_BYTES = 0x5,
> + JPEG_CFG_MAL_BOUND_2K_BYTES = 0x6,
> + JPEG_CFG_MAL_BOUND_4K_BYTES = 0x7
> +};
> +
> +struct qcom_jpeg_scale_blocks {
> + u8 w_block[QCOM_JPEG_MAX_PLANES];
> + u8 h_block[QCOM_JPEG_MAX_PLANES];
> +};
> +
> +struct qcom_jpeg_mal_boundary {
> + u32 bytes;
> + int boundary;
> +};
> +
> +struct qcom_jpeg_formats {
> + u32 fourcc;
> + enum qcom_jpeg_encode_fmt encode;
> + enum qcom_jpeg_memory_fmt memory;
> +};
> +
> +/*
> + * Luminance quantization table defined by CCITT T.81.
> + * See: https://www.w3.org/Graphics/JPEG/itu-t81.pdf
> + */
> +static const u8 t81k1_dct_luma_table[JPEG_QDT_LENGTH] = {
> + 16, 11, 10, 16, 24, 40, 51, 61,
> + 12, 12, 14, 19, 26, 58, 60, 55,
> + 14, 13, 16, 24, 40, 57, 69, 56,
> + 14, 17, 22, 29, 51, 87, 80, 62,
> + 18, 22, 37, 56, 68, 109, 103, 77,
> + 24, 35, 55, 64, 81, 104, 113, 92,
> + 49, 64, 78, 87, 103, 121, 120, 101,
> + 72, 92, 95, 98, 112, 100, 103, 99
> +};
> +
> +/*
> + * Chrominance quantization table defined by CCITT T.81.
> + * See: https://www.w3.org/Graphics/JPEG/itu-t81.pdf
> + */
> +static const u8 t81k2_dct_chroma_table[JPEG_QDT_LENGTH] = {
> + 17, 18, 24, 47, 99, 99, 99, 99,
> + 18, 21, 26, 66, 99, 99, 99, 99,
> + 24, 26, 56, 99, 99, 99, 99, 99,
> + 47, 66, 99, 99, 99, 99, 99, 99,
> + 99, 99, 99, 99, 99, 99, 99, 99,
> + 99, 99, 99, 99, 99, 99, 99, 99,
> + 99, 99, 99, 99, 99, 99, 99, 99,
> + 99, 99, 99, 99, 99, 99, 99, 99
> +};
> +
> +/*
> + * Zig-zag scan order for quantized DCT coefficients
> + * as defined by CCITT T.81.
> + * See: https://www.w3.org/Graphics/JPEG/itu-t81.pdf
> + */
> +static const u8 t81a6_dct_zig_zag_table[] = {
> + 0, 1, 5, 6, 14, 15, 27, 28,
> + 2, 4, 7, 13, 16, 26, 29, 42,
> + 3, 8, 12, 17, 25, 30, 41, 43,
> + 9, 11, 18, 24, 31, 40, 44, 53,
> + 10, 19, 23, 32, 39, 45, 52, 54,
> + 20, 22, 33, 38, 46, 51, 55, 60,
> + 21, 34, 37, 47, 50, 56, 59, 61,
> + 35, 36, 48, 49, 57, 58, 62, 63
> +};
> +
> +static const u8 jpeg_mcu_per_ratio[] = {
> + 0, /* MCU = 1, Ratio < 2x */
> + 3, /* MCU = 0, 2x <= Ratio < 4x */
> + 2, /* MCU = 0, 4x <= Ratio < 8x */
> + 1, /* MCU = 0, 8x <= Ratio < 16x */
> + 0, /* MCU = 0, Ratio > 16x */
> +};
> +
> +static const struct qcom_jpeg_formats jpeg_encode_fmt[] = {
> + {
> + .fourcc = V4L2_PIX_FMT_GREY,
> + .encode = JPEG_ENCODE_MONO,
> + .memory = JPEG_MEM_FMT_MONO
> + },
> + {
> + .fourcc = V4L2_PIX_FMT_JPEG,
> + .encode = JPEG_ENCODE_H1V1,
> + .memory = JPEG_MEM_FMT_PPLANAR
> + },
> + {
> + .fourcc = V4L2_PIX_FMT_YUV422M,
> + .encode = JPEG_ENCODE_H1V2,
> + .memory = JPEG_MEM_FMT_PLANAR
> + },
> + {
> + .fourcc = V4L2_PIX_FMT_YVU422M,
> + .encode = JPEG_ENCODE_H1V2,
> + .memory = JPEG_MEM_FMT_PLANAR
> + },
> + {
> + .fourcc = V4L2_PIX_FMT_NV16M,
> + .encode = JPEG_ENCODE_H2V1,
> + .memory = JPEG_MEM_FMT_PPLANAR
> + },
> + {
> + .fourcc = V4L2_PIX_FMT_NV61M,
> + .encode = JPEG_ENCODE_H2V1,
> + .memory = JPEG_MEM_FMT_PPLANAR
> + },
> + {
> + .fourcc = V4L2_PIX_FMT_NV12M,
> + .encode = JPEG_ENCODE_H2V2,
> + .memory = JPEG_MEM_FMT_PPLANAR
> + },
> + {
> + .fourcc = V4L2_PIX_FMT_NV21M,
> + .encode = JPEG_ENCODE_H2V2,
> + .memory = JPEG_MEM_FMT_PPLANAR
> + }
> +};
> +
> +static const struct qcom_jpeg_mal_boundary jpeg_mal_bounds[] = {
> + { .bytes = 32, .boundary = JPEG_CFG_MAL_BOUND_32_BYTES },
> + { .bytes = 64, .boundary = JPEG_CFG_MAL_BOUND_64_BYTES },
> + { .bytes = 128, .boundary = JPEG_CFG_MAL_BOUND_128_BYTES },
> + { .bytes = 256, .boundary = JPEG_CFG_MAL_BOUND_256_BYTES },
> + { .bytes = 512, .boundary = JPEG_CFG_MAL_BOUND_512_BYTES },
> + { .bytes = 1024, .boundary = JPEG_CFG_MAL_BOUND_1K_BYTES },
> + { .bytes = 4096, .boundary = JPEG_CFG_MAL_BOUND_4K_BYTES }
> +};
> +
> +static const struct qcom_jpeg_scale_blocks jpeg_mcu_blocks[] = {
> + [JPEG_ENCODE_H1V1] = {
> + .w_block = { JPEG_MCU_BLOCK_8, JPEG_MCU_BLOCK_8, JPEG_MCU_BLOCK_8 },
> + .h_block = { JPEG_MCU_BLOCK_8, JPEG_MCU_BLOCK_8, JPEG_MCU_BLOCK_8 },
> + },
> + [JPEG_ENCODE_H1V2] = {
> + .w_block = { JPEG_MCU_BLOCK_8, JPEG_MCU_BLOCK_8, JPEG_MCU_BLOCK_8 },
> + .h_block = { JPEG_MCU_BLOCK_16, JPEG_MCU_BLOCK_8, JPEG_MCU_BLOCK_8 },
> + },
> + [JPEG_ENCODE_H2V1] = {
> + .w_block = { JPEG_MCU_BLOCK_16, JPEG_MCU_BLOCK_8, JPEG_MCU_BLOCK_8 },
> + .h_block = { JPEG_MCU_BLOCK_8, JPEG_MCU_BLOCK_8, JPEG_MCU_BLOCK_8 },
> + },
> + [JPEG_ENCODE_H2V2] = {
> + .w_block = { JPEG_MCU_BLOCK_16, JPEG_MCU_BLOCK_8, JPEG_MCU_BLOCK_8 },
> + .h_block = { JPEG_MCU_BLOCK_16, JPEG_MCU_BLOCK_8, JPEG_MCU_BLOCK_8 },
> + },
> + [JPEG_ENCODE_MONO] = {
> + .w_block = { JPEG_MCU_BLOCK_8 },
> + .h_block = { JPEG_MCU_BLOCK_8 }
> + },
> +};
> +
> +static inline int jpeg_get_memory_fmt(u32 fourcc)
> +{
> + u32 fi;
> +
> + for (fi = 0; fi < ARRAY_SIZE(jpeg_encode_fmt); fi++) {
> + if (jpeg_encode_fmt[fi].fourcc == fourcc)
> + return jpeg_encode_fmt[fi].memory;
> + }
> +
> + return -EINVAL;
> +}
> +
> +static inline int jpeg_get_encode_fmt(u32 fourcc)
> +{
> + u32 fi;
> +
> + for (fi = 0; fi < ARRAY_SIZE(jpeg_encode_fmt); fi++) {
> + if (jpeg_encode_fmt[fi].fourcc == fourcc)
> + return jpeg_encode_fmt[fi].encode;
> + }
> +
> + return -EINVAL;
> +}
> +
> +static inline int jpeg_get_mal_boundary(u32 width, const struct qcom_jpeg_mal_boundary *table,
> + u32 count)
> +{
> + u32 bi;
> +
> + if (!table || !count)
> + return -EINVAL;
> +
> + for (bi = 0; bi < count; bi++) {
> + if (table[bi].bytes > width)
> + break;
> + }
> +
> + if (!bi)
> + return table[0].boundary;
> +
> + return table[bi - 1].boundary;
> +}
> +
> +static inline u8 jpeg_get_mcu_per_block(u32 src_size, u32 dst_size)
> +{
> + u8 h_rto;
> +
> + if (!src_size || !dst_size)
> + return 0;
> +
> + /* Calculate scale factor */
> + h_rto = max(src_size, dst_size) / min(src_size, dst_size);
> +
> + if (h_rto >= 0 && h_rto < 2)
> + return jpeg_mcu_per_ratio[0];
> + else if (h_rto >= 2 && h_rto < 4)
> + return jpeg_mcu_per_ratio[1];
> + else if (h_rto >= 4 && h_rto < 8)
> + return jpeg_mcu_per_ratio[2];
> + else if (h_rto >= 8 && h_rto < 16)
> + return jpeg_mcu_per_ratio[3];
> +
> + return jpeg_mcu_per_ratio[4];
> +}
> +
> +static inline int jpeg_get_mcu_geometry(enum qcom_jpeg_encode_fmt fmt, u32 width, u32 height,
> + u32 *blk_w, u32 *blk_h, u32 *mcu_cols, u32 *mcu_rows)
> +{
> + const struct qcom_jpeg_scale_blocks *blks;
> + u32 bw = 0, bh = 0;
> + u8 pln;
> +
> + if (!width || !height)
> + return -EINVAL;
> +
> + blks = &jpeg_mcu_blocks[fmt];
> +
> + for (pln = 0; pln < QCOM_JPEG_MAX_PLANES; pln++) {
> + bw = max(bw, blks->w_block[pln]);
> + bh = max(bh, blks->h_block[pln]);
> + }
> +
> + if (!bw || !bh)
> + return -EINVAL;
> +
> + if (blk_w)
> + *blk_w = bw;
> + if (blk_h)
> + *blk_h = bh;
> +
> + if (mcu_cols)
> + *mcu_cols = ALIGN(width, bw) / bw;
> +
> + if (mcu_rows)
> + *mcu_rows = ALIGN(height, bh) / bh;
> +
> + return 0;
> +}
> +
> +/* Integer part of scale */
> +static inline s32 jpeg_calc_scale_int(u32 in_width, u32 out_width)
> +{
> + if (!out_width)
> + return 0;
> +
> + return (s32)(in_width / out_width);
> +}
> +
> +/* Fractional part od scale */
> +static inline u32 jpeg_calc_scale_frac(u32 in_width, u32 out_width)
> +{
> + u32 remainder = in_width % out_width;
> +
> + if (!out_width)
> + return 0;
> +
> + /* 64-bit to avoid overflow during shift */
> + return (u32)(((u64)remainder << JPEG_Q5_21_SHIFT) / out_width);
> +}
> +
> +static inline s32 jpeg_calc_q5_21(s32 int_part, u32 frac_part)
> +{
> + return ((s32)((u32)int_part << JPEG_Q5_21_SHIFT)) | (frac_part & ((1u << 21) - 1));
> +}
> +
> +static inline u32 jpeg_io_read(struct qcom_jenc_dev *jenc, u32 offset)
> +{
> + u32 data;
> +
> + rmb(); /* Preventing concurrency read/write interference */
> + data = readl_relaxed(jenc->jpeg_base + offset);
> +
> + return data;
> +}
> +
> +static inline void jpeg_io_write(struct qcom_jenc_dev *jenc, u32 offset, u32 value)
> +{
> + wmb(); /* Preventing concurrency read/write interference */
> + writel_relaxed(value, jenc->jpeg_base + offset);
> +}
> +
> +/*
> + * Runtime bitfield helpers (for non-constant masks).
> + *
> + * Requirements:
> + * - mask must be non-zero
> + * - mask must be contiguous (e.g. 0x7u << n)
> + */
> +
> +static inline u32 jpeg_bits_get(u32 mask, u32 reg)
> +{
> + return (reg & mask) >> __builtin_ctz(mask);
> +}
> +
> +static inline u32 jpeg_bits_set(u32 mask, u32 val)
> +{
> + return (val << __builtin_ctz(mask)) & mask;
> +}
> +
> +static inline u32 jpeg_rd_bits(struct qcom_jenc_dev *jenc, u32 offs, enum qcom_jpeg_mask_id mid)
> +{
> + u32 reg = jpeg_io_read(jenc, offs);
> + u32 mask = jenc->res->hw_mask[mid];
> +
> + return jpeg_bits_get(mask, reg);
> +}
> +
> +/*
> + * Read-modify-write (for R/W registers)
> + */
> +static inline void jpeg_rw_bits(struct qcom_jenc_dev *jenc, u32 offs, enum qcom_jpeg_mask_id mid,
> + u32 val)
> +{
> + u32 reg = jpeg_io_read(jenc, offs);
> + u32 mask = jenc->res->hw_mask[mid];
> +
> + reg &= ~mask;
> + reg |= jpeg_bits_set(mask, val);
> +
> + jpeg_io_write(jenc, offs, reg);
> +}
> +
> +/*
> + * Write-only variant (for write only registers)
> + */
> +static inline void jpeg_wo_bits(struct qcom_jenc_dev *jenc, u32 offs, enum qcom_jpeg_mask_id mid,
> + u32 val)
> +{
> + u32 mask = jenc->res->hw_mask[mid];
> +
> + jpeg_io_write(jenc, offs, jpeg_bits_set(mask, val));
> +}
> +
> +static u8 jpeg_calculate_dqt(struct jenc_context *ectx, u8 dqt_value)
> +{
> + u64 ratio;
> + u8 calc_val;
> +
> + ratio = (QCOM_JPEG_QUALITY_MAX - ectx->quality_requested) << JPEG_DQT_SHIFT;
> + ratio = max_t(u64, 1, ratio);
> + do_div(ratio, QCOM_JPEG_QUALITY_MID);
> +
> + calc_val = DIV64_U64_ROUND_CLOSEST(ratio * dqt_value, 1LU << JPEG_DQT_SHIFT);
> +
> + return max_t(u8, 1, calc_val);
> +}
> +
> +static void jpeg_apply_dmi_table(struct jenc_context *ectx)
> +{
> + const struct qcom_jpeg_reg_offs *offs = ectx->jenc->res->hw_offs;
> + u32 pcfg = { 0x00000011 };
> + u32 addr = { 0x00000000 };
> + u8 *base;
> + u8 dqt_val, idx;
> + u32 reg_val;
> + int i;
> +
> + /* DMI upload start sequence */
> + jpeg_io_write(ectx->jenc, offs->dmi_addr, addr);
> + jpeg_io_write(ectx->jenc, offs->dmi_cfg, pcfg);
> +
> + /* DMI Luma upload */
> + base = &ectx->hdr_cache.data[ectx->hdr_cache.dqt_one_offs + 1];
> + for (i = 0; i < ARRAY_SIZE(t81k1_dct_luma_table); i++) {
> + dqt_val = jpeg_calculate_dqt(ectx, t81k1_dct_luma_table[i]);
> + /*
> + * Store the luma to be propagated to the JPEG header at a later stage.
> + * If offs == 0, no DQT is present in the header and the write
> + * should be skipped.
> + */
> + if (ectx->hdr_cache.dqt_one_offs) {
> + idx = t81a6_dct_zig_zag_table[i];
> + /* Perform reordering to arrange transformed DQT in a zigzag pattern */
> + base[idx] = dqt_val;
> + }
> + /* The calculated DQT value cannot be less than 1 */
> + reg_val = div_u64(U16_MAX + 1U, dqt_val);
> + jpeg_io_write(ectx->jenc, offs->dmi_data, clamp_t(u32, reg_val, 0, U16_MAX));
> + }
> +
> + /* DMI Chroma upload */
> + base = &ectx->hdr_cache.data[ectx->hdr_cache.dqt_two_offs + 1];
> + for (i = 0; i < ARRAY_SIZE(t81k2_dct_chroma_table); i++) {
> + dqt_val = jpeg_calculate_dqt(ectx, t81k2_dct_chroma_table[i]);
> + /*
> + * Store the chroma to be propagated to the JPEG header at a later stage.
> + * If offs == 0, no DQT is present in the header and the write
> + * should be skipped.
> + */
> + if (ectx->hdr_cache.dqt_two_offs) {
> + idx = t81a6_dct_zig_zag_table[i];
> + /* Perform reordering to arrange transformed DQT in a zigzag pattern */
> + base[idx] = dqt_val;
> + }
> + /* The calculated DQT value cannot be less than 1 */
> + reg_val = div_u64(U16_MAX + 1U, dqt_val);
> + jpeg_io_write(ectx->jenc, offs->dmi_data, clamp_t(u32, reg_val, 0, U16_MAX));
> + }
> +
> + /* DMI upload end sequence */
> + jpeg_io_write(ectx->jenc, offs->dmi_cfg, addr);
> +
> + ectx->quality_programmed = ectx->quality_requested;
> +
> + dev_dbg(ectx->dev, "%s: ctx=%p quality_programmed=%d\n", __func__, ectx,
> + ectx->quality_programmed);
> +}
> +
> +static void jpeg_cpu_access(struct device *dev, struct qcom_jpeg_buff *frame,
> + enum dma_data_direction direction)
> +{
> + u8 pln;
> +
> + for (pln = 0; pln < QCOM_JPEG_MAX_PLANES; pln++) {
> + struct sg_table *sgt = frame->plns[pln].sgt;
> +
> + if (!frame->plns[pln].dma || !sgt)
> + break;
> +
> + dma_sync_sg_for_cpu(dev, sgt->sgl, sgt->orig_nents, direction);
> + }
> +}
> +
> +static void jpeg_dev_access(struct device *dev, struct qcom_jpeg_buff *frame,
> + enum dma_data_direction direction)
> +{
> + u8 pln;
> +
> + for (pln = 0; pln < QCOM_JPEG_MAX_PLANES; pln++) {
> + struct sg_table *sgt = frame->plns[pln].sgt;
> +
> + if (!frame->plns[pln].dma || !sgt)
> + continue;
> +
> + dma_sync_sg_for_device(dev, sgt->sgl, sgt->orig_nents, direction);
> + }
> +}
> +
> +static int jpeg_init(struct qcom_jenc_dev *jenc)
> +{
> + const struct qcom_jpeg_reg_offs *offs;
> + void __iomem *mem_base;
> + unsigned long rtime;
> + u32 hw_ver;
> +
> + if (!jenc || !jenc->dev || !jenc->jpeg_base || !jenc->res->hw_offs) {
How can jenc be NULL here? Or any other field?
> + pr_err("encoder HW init failed\n");
dev_err.
> + return -EINVAL;
> + }
> +
> + offs = jenc->res->hw_offs;
> + mem_base = jenc->jpeg_base;
> +
> + jpeg_wo_bits(jenc, offs->int_clr, JMSK_IRQ_CLEAR_ALL, JPEG_U32_SET);
> + jpeg_rw_bits(jenc, offs->int_mask, JMSK_IRQ_STATUS_RESET_ACK, JPEG_U32_SET);
> +
> + reinit_completion(&jenc->reset_complete);
> +
> + jpeg_wo_bits(jenc, offs->reset_cmd, JMSK_RST_CMD_COMMON, JPEG_U32_SET);
> +
> + rtime = wait_for_completion_timeout(&jenc->reset_complete,
> + msecs_to_jiffies(JPEG_RESET_TIMEOUT_MS));
> + if (!rtime) {
> + dev_err(jenc->dev, "encoder HW reset timeout\n");
> + disable_irq(jenc->irq);
> + return -ETIME;
> + }
> +
> + hw_ver = jpeg_io_read(jenc, offs->hw_version);
> + dev_info(jenc->dev, "JPEG HW encoder version %d.%d.%d\n",
No useless log spamming.
> + jpeg_bits_get(jenc->res->hw_mask[JMSK_HW_VER_MAJOR], hw_ver),
> + jpeg_bits_get(jenc->res->hw_mask[JMSK_HW_VER_MINOR], hw_ver),
> + jpeg_bits_get(jenc->res->hw_mask[JMSK_HW_VER_STEP], hw_ver));
> +
> + jpeg_wo_bits(jenc, offs->hw_cmd, JMSK_CMD_CLR_RD_PLNS_QUEUE, JPEG_U32_SET);
> + jpeg_wo_bits(jenc, offs->hw_cmd, JMSK_CMD_CLR_RD_PLNS_QUEUE, JPEG_U32_CLR);
> +
> + jpeg_wo_bits(jenc, offs->hw_cmd, JMSK_CMD_CLR_WR_PLNS_QUEUE, JPEG_U32_SET);
> + jpeg_wo_bits(jenc, offs->hw_cmd, JMSK_CMD_CLR_WR_PLNS_QUEUE, JPEG_U32_CLR);
> +
> + jpeg_wo_bits(jenc, offs->int_clr, JMSK_IRQ_CLEAR_ALL, JPEG_U32_SET);
> + jpeg_rw_bits(jenc, offs->int_mask, JMSK_IRQ_ENABLE_ALL, JPEG_U32_SET);
> +
> + return 0;
> +}
> +
> +static int jpeg_exec(struct qcom_jenc_dev *jenc)
> +{
> + const struct qcom_jpeg_reg_offs *offs = jenc->res->hw_offs;
> +
> + jpeg_wo_bits(jenc, offs->hw_cmd, JMSK_CMD_HW_START, 1);
> +
> + return 0;
> +}
> +
> +static void jpeg_stop(struct qcom_jenc_dev *jenc)
> +{
> + const struct qcom_jpeg_reg_offs *offs = jenc->res->hw_offs;
> +
> + jpeg_wo_bits(jenc, offs->hw_cmd, JMSK_CMD_HW_START, 0);
> +
> + jpeg_wo_bits(jenc, offs->hw_cmd, JMSK_CMD_CLR_RD_PLNS_QUEUE, JPEG_U32_SET);
> + jpeg_wo_bits(jenc, offs->hw_cmd, JMSK_CMD_CLR_RD_PLNS_QUEUE, JPEG_U32_CLR);
> +
> + jpeg_wo_bits(jenc, offs->hw_cmd, JMSK_CMD_CLR_WR_PLNS_QUEUE, JPEG_U32_SET);
> + jpeg_wo_bits(jenc, offs->hw_cmd, JMSK_CMD_CLR_WR_PLNS_QUEUE, JPEG_U32_CLR);
> +
> + jpeg_wo_bits(jenc, offs->int_clr, JMSK_IRQ_CLEAR_ALL, JPEG_U32_SET);
> + jpeg_rw_bits(jenc, offs->int_mask, JMSK_IRQ_ENABLE_ALL, JPEG_U32_SET);
> +}
> +
> +static int jpeg_deinit(struct qcom_jenc_dev *jenc)
> +{
> + const struct qcom_jpeg_reg_offs *offs = jenc->res->hw_offs;
> + unsigned long rtime;
> +
> + jpeg_wo_bits(jenc, offs->int_clr, JMSK_IRQ_CLEAR_ALL, JPEG_U32_SET);
> + jpeg_rw_bits(jenc, offs->int_mask, JMSK_IRQ_STATUS_STOP_ACK, JPEG_U32_SET);
> +
> + jpeg_wo_bits(jenc, offs->hw_cmd, JMSK_CMD_HW_STOP, 1);
> +
> + reinit_completion(&jenc->stop_complete);
> + rtime = wait_for_completion_timeout(&jenc->stop_complete,
> + msecs_to_jiffies(JPEG_STOP_TIMEOUT_MS));
> + if (!rtime) {
> + dev_err(jenc->dev, "encoder HW stop timeout\n");
> + return -ETIME;
> + }
> +
> + jpeg_rw_bits(jenc, offs->int_mask, JMSK_IRQ_DISABLE_ALL, JPEG_U32_CLR);
> + jpeg_rw_bits(jenc, offs->int_clr, JMSK_IRQ_CLEAR_ALL, JPEG_U32_SET);
> +
> + return 0;
> +}
> +
> +static int jpeg_apply_fe_addr(struct jenc_context *ectx, struct qcom_jenc_queue *q,
> + struct vb2_buffer *vb)
> +{
> + struct qcom_jenc_dev *jenc = ectx->jenc;
> + const struct qcom_jpeg_reg_offs *offs = jenc->res->hw_offs;
> + struct qcom_jpeg_buff *frame = &q->buff[vb->index];
> + struct v4l2_pix_format_mplane *fmt = &q->vf;
> + u8 pln = 0;
> +
> + if (WARN_ON_ONCE(!frame->plns[pln].dma))
> + return -EPERM;
> +
> + for (pln = 0; pln < fmt->num_planes; pln++) {
> + if (!frame->plns[pln].sgt || !frame->plns[pln].sgt->sgl)
> + break;
> +
> + jpeg_io_write(jenc, offs->fe.pntr[pln], frame->plns[pln].dma);
> + jpeg_io_write(jenc, offs->fe.offs[pln], 0);
> +
> + dev_dbg(jenc->dev, "%s: pln=%d addr=0x%llx idx:%d\n", __func__,
> + pln, frame->plns[pln].dma, vb->index);
> + }
> +
> + q->buff_id = vb->index;
> +
> + jpeg_dev_access(jenc->dev, frame, DMA_TO_DEVICE);
> +
> + return 0;
> +}
> +
> +static int jpeg_store_fe_next(struct jenc_context *ectx, struct vb2_buffer *vb2)
> +{
> + struct qcom_jenc_queue *q = &ectx->bufq[TYPE2QID(vb2->type)];
> + struct qcom_jpeg_buff *buff = &q->buff[vb2->index];
> + u8 pln = 0;
> +
> + buff->plns[pln].sgt = vb2_dma_sg_plane_desc(vb2, pln);
> + if (WARN_ON_ONCE(!buff->plns[pln].sgt))
> + return -EINVAL;
> +
> + if (WARN_ON_ONCE(!buff->plns[pln].sgt->sgl))
> + return -EINVAL;
> +
> + buff->plns[pln].dma = sg_dma_address(buff->plns[pln].sgt->sgl);
> + if (WARN_ON_ONCE(!buff->plns[pln].dma))
> + return -EINVAL;
> +
> + buff->plns[pln].size = vb2_plane_size(vb2, pln);
> + if (WARN_ON_ONCE(!buff->plns[pln].size))
> + return -EINVAL;
> +
> + for (pln = 1; pln < q->vf.num_planes; pln++) {
> + buff->plns[pln].sgt = vb2_dma_sg_plane_desc(vb2, pln);
> + if (WARN_ON_ONCE(!buff->plns[pln].sgt || !buff->plns[pln].sgt->sgl))
> + return -EINVAL;
> +
> + buff->plns[pln].dma = sg_dma_address(buff->plns[pln].sgt->sgl);
> + if (WARN_ON_ONCE(!buff->plns[pln].dma))
> + return -EINVAL;
> +
> + buff->plns[pln].size = vb2_plane_size(vb2, pln);
> + if (WARN_ON_ONCE(!buff->plns[pln].size))
> + return -EINVAL;
> + }
> +
> + return 0;
> +}
> +
> +static int jpeg_setup_fe_size(struct jenc_context *ectx, struct qcom_jenc_queue *q)
> +{
> + struct qcom_jenc_dev *jenc = ectx->jenc;
> + struct v4l2_pix_format_mplane *sfmt = &q->vf;
> + const struct qcom_jpeg_reg_offs *offs = jenc->res->hw_offs;
> + u8 pln;
> +
> + for (pln = 0; pln < QCOM_JPEG_MAX_PLANES; pln++) {
> + jpeg_rw_bits(jenc, offs->fe.bsize[pln], JMSK_PLNS_RD_BUF_SIZE_WIDTH, 0);
> + jpeg_rw_bits(jenc, offs->fe.bsize[pln], JMSK_PLNS_RD_BUF_SIZE_HEIGHT, 0);
> + jpeg_rw_bits(jenc, offs->fe.bsize[pln], JMSK_PLNS_RD_STRIDE, 0);
> + }
> +
> + for (pln = 0; pln < sfmt->num_planes; pln++) {
> + jpeg_rw_bits(jenc, offs->fe.bsize[pln], JMSK_PLNS_RD_BUF_SIZE_WIDTH,
> + sfmt->width - 1);
> + jpeg_rw_bits(jenc, offs->fe.bsize[pln], JMSK_PLNS_RD_BUF_SIZE_HEIGHT,
> + sfmt->height - 1);
> + jpeg_rw_bits(jenc, offs->fe.stride[pln], JMSK_PLNS_RD_STRIDE,
> + sfmt->plane_fmt[pln].bytesperline);
> +
> + dev_dbg(ectx->dev, "%s: ctx=%p pln=%d width=%d height=%d stride=%d\n",
> + __func__, ectx, pln,
> + jpeg_rd_bits(jenc, offs->fe.bsize[pln], JMSK_PLNS_RD_BUF_SIZE_WIDTH),
> + jpeg_rd_bits(jenc, offs->fe.bsize[pln], JMSK_PLNS_RD_BUF_SIZE_HEIGHT),
> + jpeg_rd_bits(jenc, offs->fe.stride[pln], JMSK_PLNS_RD_STRIDE));
> + }
> +
> + return 0;
> +}
> +
> +static int jpeg_setup_fe_hinit(struct jenc_context *ectx, struct qcom_jenc_queue *q)
> +{
> + struct qcom_jenc_dev *jenc = ectx->jenc;
> + struct v4l2_pix_format_mplane *sfmt = &q->vf;
> + const struct qcom_jpeg_reg_offs *offs = jenc->res->hw_offs;
> + u8 pln;
> +
> + if (!sfmt->width) {
> + dev_err(ectx->dev, "%s: invalid source width=%d\n", __func__, sfmt->width);
> + return -EINVAL;
> + }
> +
> + for (pln = 0; pln < QCOM_JPEG_MAX_PLANES; pln++)
> + jpeg_io_write(jenc, offs->fe.hinit[pln], 0);
> +
> + return 0;
> +}
> +
> +static int jpeg_setup_fe_vinit(struct jenc_context *ectx, struct qcom_jenc_queue *q)
> +{
> + struct qcom_jenc_dev *jenc = ectx->jenc;
> + struct v4l2_pix_format_mplane *sfmt = &q->vf;
> + const struct qcom_jpeg_reg_offs *offs = jenc->res->hw_offs;
> + u8 pln;
> +
> + if (!sfmt->height) {
> + dev_err(ectx->dev, "%s: invalid source height=%d\n", __func__, sfmt->height);
> + return -EINVAL;
> + }
> +
> + for (pln = 0; pln < QCOM_JPEG_MAX_PLANES; pln++)
> + jpeg_io_write(jenc, offs->fe.vinit[pln], 0);
> +
> + return 0;
> +}
> +
> +static int jpeg_setup_fe_params(struct jenc_context *ectx, struct qcom_jenc_queue *q)
> +{
> + struct qcom_jenc_dev *jenc = ectx->jenc;
> + struct v4l2_pix_format_mplane *sfmt = &q->vf;
> + struct v4l2_pix_format_mplane *dfmt = &ectx->bufq[JENC_DST_QUEUE].vf;
> + const struct qcom_jpeg_reg_offs *offs = jenc->res->hw_offs;
> + u8 expected_planes, pln;
> + int rval;
> +
> + jpeg_rw_bits(jenc, offs->fe_cfg, JMSK_FE_CFG_MAL_EN, 1);
> + jpeg_rw_bits(jenc, offs->fe_cfg, JMSK_FE_CFG_BOTTOM_VPAD_EN, 1);
> +
> + rval = jpeg_get_memory_fmt(sfmt->pixelformat);
> + if (rval < 0) {
> + dev_err(ectx->dev, "%s: invalid memory format for v4l2 format:0x%x\n",
> + __func__, sfmt->pixelformat);
> + return -EINVAL;
> + }
> +
> + switch (rval) {
> + case JPEG_MEM_FMT_MONO:
> + expected_planes = 1;
> + break;
> + case JPEG_MEM_FMT_PPLANAR:
> + expected_planes = 2;
> + break;
> + case JPEG_MEM_FMT_PLANAR:
> + expected_planes = 3;
> + break;
> + default:
> + return -EINVAL;
> + }
> +
> + if (sfmt->num_planes != expected_planes) {
> + dev_err(ectx->dev, "%s: plane mismatch fmt=%u expected=%u got=%u\n",
> + __func__, rval, expected_planes, sfmt->num_planes);
> + return -EINVAL;
> + }
> +
> + jpeg_rw_bits(jenc, offs->fe_cfg, JMSK_FE_CFG_MEMORY_FORMAT, rval);
> +
> + jpeg_rw_bits(jenc, offs->fe_cfg, JMSK_FE_CFG_PLN0_EN, 0);
> + jpeg_rw_bits(jenc, offs->fe_cfg, JMSK_FE_CFG_PLN1_EN, 0);
> + jpeg_rw_bits(jenc, offs->fe_cfg, JMSK_FE_CFG_PLN2_EN, 0);
> +
> + if (sfmt->width == dfmt->width && sfmt->height == dfmt->height) {
> + /* No scaling */
> + jpeg_rw_bits(jenc, offs->fe_cfg, JMSK_FE_CFG_SIXTEEN_MCU_EN, 1);
> + jpeg_rw_bits(jenc, offs->fe_cfg, JMSK_FE_CFG_MCUS_PER_BLOCK, 0);
> + } else {
> + u8 mcu_per_blks;
> +
> + /* Scaling */
> + jpeg_rw_bits(jenc, offs->fe_cfg, JMSK_FE_CFG_SIXTEEN_MCU_EN, 0);
> + /* get value according to image width */
> + mcu_per_blks = jpeg_get_mcu_per_block(sfmt->width, dfmt->width);
> + /* get value according to image height assign the bigger */
> + mcu_per_blks = max_t(u8, mcu_per_blks,
> + jpeg_get_mcu_per_block(sfmt->height, dfmt->height));
> +
> + jpeg_rw_bits(jenc, offs->fe_cfg, JMSK_FE_CFG_MCUS_PER_BLOCK, mcu_per_blks);
> + }
> +
> + dev_dbg(ectx->dev, "%s: sixteen MCU enabled=%d, %d MCU per blocks\n", __func__,
> + jpeg_rd_bits(jenc, offs->fe_cfg, JMSK_FE_CFG_SIXTEEN_MCU_EN),
> + jpeg_rd_bits(jenc, offs->fe_cfg, JMSK_FE_CFG_MCUS_PER_BLOCK));
> +
> + rval = jpeg_get_mal_boundary(sfmt->width, jpeg_mal_bounds, ARRAY_SIZE(jpeg_mal_bounds));
> + if (rval < 0) {
> + dev_err(ectx->dev, "%s: failed to get FE mal boundary width=%u\n", __func__,
> + sfmt->width);
> + return -EINVAL;
> + }
> + jpeg_rw_bits(jenc, offs->fe_cfg, JMSK_FE_CFG_MAL_BOUNDARY, rval);
> +
> + dev_dbg(ectx->dev, "%s: optimal FE mal boundary=%d\n", __func__,
> + jpeg_rd_bits(jenc, offs->fe_cfg, JMSK_FE_CFG_MAL_BOUNDARY));
> +
> + rval = jpeg_get_encode_fmt(sfmt->pixelformat);
> + if (rval < 0) {
> + dev_err(ectx->dev, "%s: unsupported encode format fourcc=0x%x\n",
> + __func__, sfmt->pixelformat);
> + return -EINVAL;
> + }
> +
> + switch (rval) {
> + case JPEG_ENCODE_MONO:
> + case JPEG_ENCODE_H1V1:
> + case JPEG_ENCODE_H2V1:
> + jpeg_rw_bits(jenc, offs->fe.vbpad_cfg, JMSK_FE_VBPAD_CFG_BLOCK_ROW,
> + DIV_ROUND_UP(sfmt->height, JPEG_MCU_BLOCK_8));
> + break;
> + case JPEG_ENCODE_H1V2:
> + case JPEG_ENCODE_H2V2:
> + jpeg_rw_bits(jenc, offs->fe.vbpad_cfg, JMSK_FE_VBPAD_CFG_BLOCK_ROW,
> + DIV_ROUND_UP(sfmt->height, JPEG_MCU_BLOCK_16));
> + break;
> + default:
> + dev_err(ectx->dev, "%s: unsupported encode format fourcc=0x%x\n", __func__, rval);
> + return -EINVAL;
> + }
> +
> + if (sfmt->pixelformat == V4L2_PIX_FMT_NV21 || sfmt->pixelformat == V4L2_PIX_FMT_NV61)
> + jpeg_rw_bits(jenc, offs->fe_cfg, JMSK_FE_CFG_CBCR_ORDER, 1);
> + else
> + jpeg_rw_bits(jenc, offs->fe_cfg, JMSK_FE_CFG_CBCR_ORDER, 0);
> +
> + for (pln = 0; pln < sfmt->num_planes; pln++) {
> + if (sfmt->width && sfmt->height) {
> + switch (pln) {
> + case 0:
> + jpeg_rw_bits(jenc, offs->fe_cfg, JMSK_FE_CFG_PLN0_EN, 1);
> + break;
> + case 1:
> + jpeg_rw_bits(jenc, offs->fe_cfg, JMSK_FE_CFG_PLN1_EN, 1);
> + break;
> + case 2:
> + jpeg_rw_bits(jenc, offs->fe_cfg, JMSK_FE_CFG_PLN2_EN, 1);
> + break;
> + }
> + }
> + }
> +
> + jpeg_rw_bits(jenc, offs->core_cfg, JMSK_CORE_CFG_FE_ENABLE, 1);
> +
> + return 0;
> +}
> +
> +static int jpeg_setup_fe(struct jenc_context *ectx, struct qcom_jenc_queue *q)
> +{
> + int rc;
> +
> + rc = jpeg_setup_fe_size(ectx, q);
> + if (rc)
> + return rc;
> +
> + rc = jpeg_setup_fe_hinit(ectx, q);
> + if (rc)
> + return rc;
> +
> + rc = jpeg_setup_fe_vinit(ectx, q);
> + if (rc)
> + return rc;
> +
> + rc = jpeg_setup_fe_params(ectx, q);
> + if (rc)
> + return rc;
> +
> + return 0;
> +}
> +
> +static int jpeg_apply_we_addr(struct jenc_context *ectx, struct qcom_jenc_queue *q,
> + struct vb2_buffer *vb)
> +{
> + struct qcom_jenc_dev *jenc = ectx->jenc;
> + const struct qcom_jpeg_reg_offs *offs = jenc->res->hw_offs;
> + struct qcom_jpeg_buff *frame = &q->buff[vb->index];
> + u8 pln = 0;
> +
> + if (WARN_ON_ONCE(!frame->plns[pln].dma))
> + return -EPERM;
> +
> + jpeg_io_write(jenc, offs->we.pntr[pln], frame->plns[pln].dma);
> +
> + dev_dbg(jenc->dev, "%s: pln=%d addr=0x%llx idx:%d\n", __func__,
> + pln, frame->plns[pln].dma, vb->index);
> +
> + q->buff_id = vb->index;
> +
> + return 0;
> +}
> +
> +static int jpeg_store_we_next(struct jenc_context *ectx, struct vb2_buffer *vb2)
> +{
> + struct qcom_jenc_dev *jenc = ectx->jenc;
> + struct qcom_jenc_queue *q = &ectx->bufq[TYPE2QID(vb2->type)];
> + struct qcom_jpeg_buff *frame = &q->buff[vb2->index];
> + struct qc_jfif *mptr;
> + struct sg_table *sgt;
> + dma_addr_t dma;
> +
> + sgt = vb2_dma_sg_plane_desc(vb2, 0);
> + if (WARN_ON_ONCE(!sgt || !sgt->sgl))
> + return -EINVAL;
> +
> + dma = sg_dma_address(sgt->sgl);
> + if (WARN_ON_ONCE(!dma))
> + return -EINVAL;
> +
> + mptr = vb2_plane_vaddr(vb2, 0);
> + if (WARN_ON_ONCE(!mptr))
> + return -EINVAL;
> +
> + mutex_lock(&ectx->quality_mutex);
> + if (ectx->quality_programmed != ectx->quality_requested)
> + jpeg_apply_dmi_table(ectx);
> + mutex_unlock(&ectx->quality_mutex);
> +
> + dma += qcom_jenc_header_emit(&ectx->hdr_cache, (void *)mptr,
> + min_t(size_t, vb2->planes[0].length, ectx->hdr_cache.size),
> + q->vf.width, q->vf.height);
> + qcom_jenc_dqts_emit(&ectx->hdr_cache, (void *)mptr);
> +
> + frame->plns[0].sgt = sgt;
> + frame->plns[0].dma = dma;
> + frame->plns[0].size = vb2_plane_size(vb2, 0);
> +
> + jpeg_dev_access(jenc->dev, frame, DMA_TO_DEVICE);
> +
> + return 0;
> +}
> +
> +static int jpeg_setup_we_size(struct jenc_context *ectx, struct qcom_jenc_queue *q)
> +{
> + struct qcom_jenc_dev *jenc = ectx->jenc;
> + const struct qcom_jpeg_reg_offs *offs = jenc->res->hw_offs;
> + struct v4l2_pix_format_mplane *dfmt = &q->vf;
> + u8 pln;
> +
> + if (!dfmt->plane_fmt[0].sizeimage) {
> + dev_err(ectx->dev, "%s: invalid destination buffer size=0\n", __func__);
> + return -EINVAL;
> + }
> +
> + for (pln = 0; pln < QCOM_JPEG_MAX_PLANES; pln++)
> + jpeg_rw_bits(jenc, offs->we.stride[pln], JMSK_PLNS_WR_STRIDE, 0);
> +
> + jpeg_io_write(jenc, offs->we.bsize[0], dfmt->plane_fmt[0].sizeimage);
> +
> + dev_dbg(ectx->dev, "%s: ctx=%p size=%u\n", __func__,
> + ectx, dfmt->plane_fmt[0].sizeimage);
> +
> + return 0;
> +}
> +
> +static int jpeg_setup_we_hinit(struct jenc_context *ectx, struct qcom_jenc_queue *q)
> +{
> + struct qcom_jenc_dev *jenc = ectx->jenc;
> + const struct qcom_jpeg_reg_offs *offs = jenc->res->hw_offs;
> + struct v4l2_pix_format_mplane *dfmt = &q->vf;
> + u8 pln;
> +
> + if (!dfmt->width) {
> + dev_err(ectx->dev, "%s: invalid destination width=%d\n", __func__, dfmt->width);
> + return -EINVAL;
> + }
> +
> + for (pln = 0; pln < QCOM_JPEG_MAX_PLANES; pln++) {
> + jpeg_rw_bits(jenc, offs->we.hinit[pln], JMSK_PLNS_WR_HINIT, 0);
> + jpeg_rw_bits(jenc, offs->we.hstep[pln], JMSK_PLNS_WR_HSTEP, 0);
> + }
> +
> + jpeg_rw_bits(jenc, offs->we.hstep[0], JMSK_PLNS_WR_HSTEP, dfmt->width);
> +
> + dev_dbg(ectx->dev, "%s: ctx=%p hstep=%u\n", __func__, ectx,
> + jpeg_rd_bits(jenc, offs->we.hstep[0], JMSK_PLNS_WR_HSTEP));
> +
> + return 0;
> +}
> +
> +static int jpeg_setup_we_vinit(struct jenc_context *ectx, struct qcom_jenc_queue *q)
> +{
> + struct qcom_jenc_dev *jenc = ectx->jenc;
> + const struct qcom_jpeg_reg_offs *offs = jenc->res->hw_offs;
> + struct v4l2_pix_format_mplane *dfmt = &q->vf;
> + u8 pln;
> +
> + if (!dfmt->height) {
> + dev_err(ectx->dev, "%s: invalid destination height=%d\n", __func__, dfmt->height);
> + return -EINVAL;
> + }
> +
> + for (pln = 0; pln < QCOM_JPEG_MAX_PLANES; pln++) {
> + jpeg_rw_bits(jenc, offs->we.vinit[pln], JMSK_PLNS_WR_VINIT, 0);
> + jpeg_rw_bits(jenc, offs->we.vstep[pln], JMSK_PLNS_WR_VSTEP, 0);
> + }
> +
> + jpeg_rw_bits(jenc, offs->we.vstep[0], JMSK_PLNS_WR_VSTEP, dfmt->height);
> +
> + dev_dbg(ectx->dev, "%s: ctx=%p vstep=%u\n", __func__, ectx,
> + jpeg_rd_bits(jenc, offs->we.vstep[0], JMSK_PLNS_WR_VSTEP));
> +
> + return 0;
> +}
> +
> +static int jpeg_setup_we_params(struct jenc_context *ectx, struct qcom_jenc_queue *q)
> +{
> + struct qcom_jenc_dev *jenc = ectx->jenc;
> + const struct qcom_jpeg_reg_offs *offs = jenc->res->hw_offs;
> + struct v4l2_pix_format_mplane *dfmt = &q->vf;
> + u32 blk_w, blk_h, mcu_cols, mcu_rows;
> + int rval;
> +
> + rval = jpeg_get_memory_fmt(dfmt->pixelformat);
> + if (rval < 0) {
> + dev_err(ectx->dev, "%s: invalid memory format for v4l2 format:0x%x\n",
> + __func__, dfmt->pixelformat);
> + return -EINVAL;
> + }
> + jpeg_rw_bits(jenc, offs->we_cfg, JMSK_WE_CFG_MEMORY_FORMAT, rval);
> +
> + rval = jpeg_get_mal_boundary(dfmt->width, jpeg_mal_bounds, ARRAY_SIZE(jpeg_mal_bounds));
> + if (rval < 0) {
> + dev_err(ectx->dev, "%s: failed to get WE mal boundary width=%u\n",
> + __func__, dfmt->width);
> + return -EINVAL;
> + }
> + jpeg_rw_bits(jenc, offs->we_cfg, JMSK_WE_CFG_MAL_BOUNDARY, rval);
> +
> + dev_dbg(ectx->dev, "%s: optimal WE mal boundary=%d\n", __func__,
> + jpeg_rd_bits(jenc, offs->we_cfg, JMSK_WE_CFG_MAL_BOUNDARY));
> +
> + rval = jpeg_get_encode_fmt(dfmt->pixelformat);
> + if (rval < 0) {
> + dev_err(ectx->dev, "%s: unsupported encode format fourcc=0x%x\n",
> + __func__, dfmt->pixelformat);
> + return rval;
> + }
> +
> + rval = jpeg_get_mcu_geometry(rval, dfmt->width, dfmt->height, &blk_w, &blk_h,
> + &mcu_cols, &mcu_rows);
> + if (rval < 0) {
> + dev_err(ectx->dev, "%s: invalid MCU geometry mcu_cols=%d mcu_rows=%d\n",
> + __func__, mcu_cols, mcu_rows);
> + return rval;
> + }
> +
> + dev_dbg(ectx->dev, "%s blk_w=%u blk_h=%u cols=%u rows=%u\n", __func__,
> + blk_w, blk_h, mcu_cols, mcu_rows);
> +
> + jpeg_rw_bits(jenc, offs->we.blocks[0], JMSK_PLNS_WR_BLOCK_CFG_PER_RAW, mcu_rows - 1);
> + jpeg_rw_bits(jenc, offs->we.blocks[0], JMSK_PLNS_WR_BLOCK_CFG_PER_COL, mcu_cols - 1);
> +
> + jpeg_rw_bits(jenc, offs->we_cfg, JMSK_WE_CFG_CBCR_ORDER, 1);
> + jpeg_rw_bits(jenc, offs->we_cfg, JMSK_WE_CFG_MAL_EN, 1);
> + jpeg_rw_bits(jenc, offs->we_cfg, JMSK_WE_CFG_POP_BUFF_ON_EOS, 1);
> + jpeg_rw_bits(jenc, offs->we_cfg, JMSK_WE_CFG_PLN0_EN, 1);
> +
> + jpeg_rw_bits(jenc, offs->core_cfg, JMSK_CORE_CFG_MODE, 1);
> + jpeg_rw_bits(jenc, offs->core_cfg, JMSK_CORE_CFG_WE_ENABLE, 1);
> +
> + return 0;
> +}
> +
> +static int jpeg_setup_we(struct jenc_context *ectx, struct qcom_jenc_queue *q)
> +{
> + int rc;
> +
> + rc = jpeg_setup_we_size(ectx, q);
> + if (rc)
> + return rc;
> +
> + rc = jpeg_setup_we_hinit(ectx, q);
> + if (rc)
> + return rc;
> +
> + rc = jpeg_setup_we_vinit(ectx, q);
> + if (rc)
> + return rc;
> +
> + return jpeg_setup_we_params(ectx, q);
> +}
> +
> +static int jpeg_setup_scale(struct jenc_context *ectx)
> +{
> + struct qcom_jenc_dev *jenc = ectx->jenc;
> + const struct qcom_jpeg_reg_offs *offs = jenc->res->hw_offs;
> + struct qcom_jenc_queue *sq = &ectx->bufq[JENC_SRC_QUEUE];
> + struct qcom_jenc_queue *dq = &ectx->bufq[JENC_DST_QUEUE];
> + struct v4l2_pix_format_mplane *sfmt = &sq->vf;
> + struct v4l2_pix_format_mplane *dfmt = &dq->vf;
> + u32 blk_w, blk_h, mcu_cols, mcu_rows;
> + int rval;
> + u8 pln;
> +
> + jpeg_rw_bits(jenc, offs->reset_cmd, JMSK_RST_CMD_SCALE_RESET, 1);
> +
> + /* explicit no scaling */
> + jpeg_rw_bits(jenc, offs->scale_cfg, JMSK_SCALE_CFG_HSCALE_ENABLE, 0);
> + jpeg_rw_bits(jenc, offs->scale_cfg, JMSK_SCALE_CFG_VSCALE_ENABLE, 0);
> +
> + for (pln = 0; pln < QCOM_JPEG_MAX_PLANES; pln++) {
> + jpeg_io_write(jenc, offs->scale.hstep[pln], JPEG_DEFAULT_SCALE_STEP);
> + jpeg_io_write(jenc, offs->scale.vstep[pln], JPEG_DEFAULT_SCALE_STEP);
> + }
> +
> + if (jpeg_rd_bits(jenc, offs->scale_cfg, JMSK_SCALE_CFG_HSCALE_ENABLE)) {
> + for (pln = 0; pln < sq->vf.num_planes; pln++) {
> + jpeg_rw_bits(jenc, offs->scale.hstep[pln],
> + JMSK_SCALE_PLNS_HSTEP_INTEGER,
> + jpeg_calc_scale_int(sfmt->width, dfmt->width));
> + jpeg_rw_bits(jenc, offs->scale.hstep[pln],
> + JMSK_SCALE_PLNS_HSTEP_FRACTIONAL,
> + jpeg_calc_scale_frac(sfmt->width, dfmt->width));
> +
> + dev_dbg(ectx->dev, "%s: ctx=%p hint=%d hfrac=%d\n",
> + __func__, ectx,
> + jpeg_rd_bits(jenc, offs->scale.hstep[pln],
> + JMSK_SCALE_PLNS_HSTEP_INTEGER),
> + jpeg_rd_bits(jenc, offs->scale.hstep[pln],
> + JMSK_SCALE_PLNS_HSTEP_FRACTIONAL));
> + }
> + }
> +
> + if (jpeg_rd_bits(jenc, offs->scale_cfg, JMSK_SCALE_CFG_VSCALE_ENABLE)) {
> + for (pln = 0; pln < sq->vf.num_planes; pln++) {
> + jpeg_rw_bits(jenc, offs->scale.vstep[pln],
> + JMSK_SCALE_PLNS_VSTEP_INTEGER,
> + jpeg_calc_scale_int(sfmt->height, dfmt->height));
> + jpeg_rw_bits(jenc, offs->scale.vstep[pln],
> + JMSK_SCALE_PLNS_VSTEP_FRACTIONAL,
> + jpeg_calc_scale_frac(sfmt->height, dfmt->height));
> +
> + dev_dbg(ectx->dev, "%s: ctx=%p vint=%d vfrac=%d\n",
> + __func__, ectx,
> + jpeg_rd_bits(jenc, offs->scale.vstep[pln],
> + JMSK_SCALE_PLNS_VSTEP_INTEGER),
> + jpeg_rd_bits(jenc, offs->scale.vstep[pln],
> + JMSK_SCALE_PLNS_VSTEP_FRACTIONAL));
> + }
> + }
> +
> + rval = jpeg_get_encode_fmt(sfmt->pixelformat);
> + if (rval < 0) {
> + dev_err(ectx->dev, "%s: unsupported encode format fourcc=0x%x\n",
> + __func__, sfmt->pixelformat);
> + return -EINVAL;
> + }
> +
> + rval = jpeg_get_mcu_geometry(rval, dfmt->width, dfmt->height, &blk_w, &blk_h,
> + &mcu_cols, &mcu_rows);
> + if (rval < 0) {
> + dev_err(ectx->dev, "%s: invalid MCU geometry blk_w=%d blk_h=%d\n",
> + __func__, blk_w, blk_h);
> + return -EINVAL;
> + }
> +
> + dev_dbg(ectx->dev, "%s blk_w=%u blk_h=%u cols=%u rows=%u\n", __func__, blk_w, blk_h,
> + mcu_cols, mcu_rows);
> +
> + for (pln = 0; pln < sq->vf.num_planes; pln++) {
> + jpeg_rw_bits(jenc, offs->scale_out_cfg[pln],
> + JMSK_SCALE_PLNS_OUT_CFG_BLK_WIDTH, mcu_cols - 1);
> + jpeg_rw_bits(jenc, offs->scale_out_cfg[pln],
> + JMSK_SCALE_PLNS_OUT_CFG_BLK_HEIGHT, mcu_rows - 1);
> + }
> +
> + dev_dbg(ectx->dev, "%s: ctx=%p scale src=%ux%u dst=%ux%u enable=%d/%d\n",
> + __func__, ectx, sfmt->width, sfmt->height, dfmt->width, dfmt->height,
> + jpeg_rd_bits(jenc, offs->scale_cfg, JMSK_SCALE_CFG_HSCALE_ENABLE),
> + jpeg_rd_bits(jenc, offs->scale_cfg, JMSK_SCALE_CFG_VSCALE_ENABLE));
> +
> + /* Disabled, but must be configured */
> + jpeg_rw_bits(jenc, offs->core_cfg, JMSK_CORE_CFG_SCALE_ENABLE, 0);
> +
> + return 0;
> +}
> +
> +static int jpeg_setup_encode(struct jenc_context *ectx)
> +{
> + struct qcom_jenc_dev *jenc = ectx->jenc;
> + struct qcom_jenc_queue *sq = &ectx->bufq[JENC_SRC_QUEUE];
> + struct v4l2_pix_format_mplane *sfmt = &sq->vf;
> + const struct qcom_jpeg_reg_offs *offs = jenc->res->hw_offs;
> + u32 blk_w, blk_h, mcu_cols, mcu_rows;
> + int rval;
> +
> + if (!sfmt->width || !sfmt->height)
> + return -EINVAL;
> +
> + jpeg_rw_bits(jenc, offs->reset_cmd, JMSK_RST_CMD_ENCODER_RESET, 1);
> +
> + rval = jpeg_get_encode_fmt(sfmt->pixelformat);
> + if (rval < 0) {
> + dev_err(ectx->dev, "%s: unsupported encode format fourcc=0x%x\n",
> + __func__, sfmt->pixelformat);
> + return -EINVAL;
> + }
> + jpeg_rw_bits(jenc, offs->enc_cfg, JMSK_ENC_CFG_IMAGE_FORMAT, rval);
> +
> + rval = jpeg_get_mcu_geometry(rval, sfmt->width, sfmt->height, &blk_w, &blk_h,
> + &mcu_cols, &mcu_rows);
> + if (rval < 0) {
> + dev_err(ectx->dev, "%s: invalid MCU geometry mcu_cols=%d mcu_rows=%d\n",
> + __func__, mcu_cols, mcu_rows);
> + return -EINVAL;
> + }
> +
> + dev_dbg(ectx->dev, "%s blk_w=%u blk_h=%u cols=%u rows=%u\n", __func__,
> + blk_w, blk_h, mcu_cols, mcu_rows);
> +
> + jpeg_rw_bits(jenc, offs->enc_img_size, JMSK_ENC_IMAGE_SIZE_WIDTH, mcu_cols - 1);
> + jpeg_rw_bits(jenc, offs->enc_img_size, JMSK_ENC_IMAGE_SIZE_HEIGHT, mcu_rows - 1);
> +
> + dev_dbg(ectx->dev, "%s: ctx=%p width=%d height=%d\n", __func__, ectx,
> + jpeg_rd_bits(jenc, offs->enc_img_size, JMSK_ENC_IMAGE_SIZE_WIDTH),
> + jpeg_rd_bits(jenc, offs->enc_img_size, JMSK_ENC_IMAGE_SIZE_HEIGHT));
> +
> + jpeg_rw_bits(jenc, offs->enc_cfg, JMSK_ENC_CFG_APPLY_EOI, 1);
> + jpeg_rw_bits(jenc, offs->core_cfg, JMSK_CORE_CFG_ENC_ENABLE, 1);
> +
> + return 0;
> +}
> +
> +static irqreturn_t op_jpeg_irq_bot(int irq, void *data)
> +{
> + struct qcom_jenc_dev *jenc = data;
> + const struct qcom_jpeg_reg_offs *offs = jenc->res->hw_offs;
> + u32 irq_status;
> + u32 irq_mask;
> + unsigned long flags;
> + int rc;
> +
> + rc = kfifo_out_spinlocked(&jenc->kfifo_inst, &irq_status, sizeof(irq_status),
> + &jenc->kfifo_lock);
> + if (rc != sizeof(irq_status)) {
> + dev_err(jenc->dev, "IRQ status: FIFO empty\n");
> + return IRQ_HANDLED;
> + }
> +
> + irq_mask = jenc->res->hw_mask[JMSK_IRQ_STATUS_SESSION_DONE];
> + if (jpeg_bits_get(irq_mask, irq_status)) {
> + struct jenc_context *ctx = jenc->actx;
> + struct qcom_jenc_queue *dq = &ctx->bufq[JENC_DST_QUEUE];
> + size_t out_size;
> +
> + spin_lock_irqsave(&jenc->hw_lock, flags);
> + jenc->actx = NULL;
> + spin_unlock_irqrestore(&jenc->hw_lock, flags);
> +
> + if (ctx && dq->buff_id >= 0) {
> + struct qcom_jpeg_buff *frame;
> + unsigned long flags;
> +
> + spin_lock_irqsave(&jenc->hw_lock, flags);
> + frame = &dq->buff[dq->buff_id];
> + out_size = jpeg_io_read(jenc, offs->enc_out_size);
> + spin_unlock_irqrestore(&jenc->hw_lock, flags);
> +
> + dev_dbg(jenc->dev, "complete idx:%d addr=0x%llx size=%zu\n",
> + dq->buff_id, frame->plns[0].dma, out_size);
> +
> + jpeg_cpu_access(jenc->dev, frame, DMA_FROM_DEVICE);
> + jenc->enc_hw_irq_cb(ctx, VB2_BUF_STATE_DONE,
> + out_size + JPEG_HEADER_MAX);
> + jpeg_stop(jenc);
> + }
> + }
> +
> + irq_mask = jenc->res->hw_mask[JMSK_IRQ_STATUS_SESSION_ERROR];
> + if (jpeg_bits_get(irq_mask, irq_status)) {
> + struct jenc_context *ctx = jenc->actx;
> +
> + spin_lock_irqsave(&jenc->hw_lock, flags);
> + jenc->actx = NULL;
> + spin_unlock_irqrestore(&jenc->hw_lock, flags);
> +
> + dev_err(jenc->dev, "encoder hardware failure=0x%x\n",
> + jpeg_bits_get(JMSK_IRQ_STATUS_SESSION_ERROR, irq_status));
> + if (ctx)
> + jenc->enc_hw_irq_cb(ctx, VB2_BUF_STATE_ERROR, 0);
> +
> + jpeg_stop(jenc);
> + }
> +
> + return IRQ_HANDLED;
> +}
> +
> +static irqreturn_t op_jpeg_irq_top(int irq, void *data)
> +{
> + struct qcom_jenc_dev *jenc = data;
> + const struct qcom_jpeg_reg_offs *offs = jenc->res->hw_offs;
> + u32 irq_status;
> + u32 irq_mask;
> + unsigned long flags;
> + int rc;
> +
> + spin_lock_irqsave(&jenc->hw_lock, flags);
> +
> + irq_status = jpeg_io_read(jenc, offs->int_status);
> + jpeg_wo_bits(jenc, offs->int_clr, JMSK_IRQ_CLEAR_ALL, irq_status);
> +
> + irq_mask = jenc->res->hw_mask[JMSK_IRQ_STATUS_RESET_ACK];
> + if (jpeg_bits_get(irq_mask, irq_status)) {
> + complete(&jenc->reset_complete);
> + spin_unlock_irqrestore(&jenc->hw_lock, flags);
> + return IRQ_HANDLED;
> + }
> +
> + irq_mask = jenc->res->hw_mask[JMSK_IRQ_STATUS_STOP_ACK];
> + if (jpeg_bits_get(irq_mask, irq_status)) {
> + complete(&jenc->stop_complete);
> + dev_dbg(jenc->dev, "hardware stop acknowledged\n");
> + spin_unlock_irqrestore(&jenc->hw_lock, flags);
> + return IRQ_HANDLED;
> + }
> +
> + rc = kfifo_in(&jenc->kfifo_inst, &irq_status, sizeof(irq_status));
> + if (rc != sizeof(irq_status))
> + dev_err(jenc->dev, "IRQ status: FIFO full\n");
> +
> + spin_unlock_irqrestore(&jenc->hw_lock, flags);
> +
> + return IRQ_WAKE_THREAD;
> +}
> +
> +static void op_jpeg_get_hw_caps(struct qcom_jenc_dev *jenc, u32 *caps)
> +{
> + const struct qcom_jpeg_reg_offs *offs = jenc->res->hw_offs;
> + u32 hw_caps;
> +
> + hw_caps = jpeg_io_read(jenc, offs->hw_capability);
> + dev_dbg(jenc->dev, "CAPS: encode=%d decode=%d upscale=%d downscale=%d\n",
> + jpeg_bits_get(jenc->res->hw_mask[JMSK_HW_CAP_ENCODE], hw_caps),
> + jpeg_bits_get(jenc->res->hw_mask[JMSK_HW_CAP_DECODE], hw_caps),
> + jpeg_bits_get(jenc->res->hw_mask[JMSK_HW_CAP_UPSCALE], hw_caps),
> + jpeg_bits_get(jenc->res->hw_mask[JMSK_HW_CAP_DOWNSCALE], hw_caps));
> +
> + *caps = hw_caps;
> +}
> +
> +static struct qcom_jenc_queue *op_jpeg_get_buff_queue(struct jenc_context *ectx,
> + enum qcom_enc_qid id)
> +{
> + return &ectx->bufq[id];
> +}
> +
> +static int op_jpeg_queue_setup(struct jenc_context *ectx, enum qcom_enc_qid id)
> +{
> + int rc;
> +
> + if (id == JENC_SRC_QUEUE) {
> + struct qcom_jenc_queue *q = &ectx->bufq[id];
> +
> + rc = qcom_jenc_header_init(&ectx->hdr_cache, q->vf.pixelformat);
> + if (rc) {
> + dev_err(ectx->dev, "JFIF header init failed\n");
> + return rc;
> + }
> + }
> +
> + return 0;
> +}
> +
> +static int op_jpeg_buffer_prepare(struct jenc_context *ectx, struct vb2_buffer *vb2)
> +{
> + int rc;
> +
> + if (V4L2_TYPE_IS_OUTPUT(vb2->type)) {
> + rc = jpeg_store_fe_next(ectx, vb2);
> + if (rc)
> + dev_err(ectx->dev, "%s: cannot set up fetch addr\n", __func__);
> + } else {
> + rc = jpeg_store_we_next(ectx, vb2);
> + if (rc)
> + dev_err(ectx->dev, "%s: cannot set up write addr\n", __func__);
> + }
> +
> + return rc;
> +}
> +
> +static int op_jpeg_process_exec(struct qcom_jenc_dev *jenc, struct jenc_context *ectx,
> + struct vb2_buffer *vb)
> +{
> + struct qcom_jenc_queue *sq = &ectx->bufq[JENC_SRC_QUEUE];
> + struct qcom_jenc_queue *dq = &ectx->bufq[JENC_DST_QUEUE];
> + unsigned long flags;
> + int rc;
> +
> + spin_lock_irqsave(&jenc->hw_lock, flags);
> + jenc->actx = ectx;
> + spin_unlock_irqrestore(&jenc->hw_lock, flags);
> +
> + if (V4L2_TYPE_IS_OUTPUT(vb->type)) {
> + rc = jpeg_setup_fe(ectx, sq);
> + if (rc)
> + return rc;
> +
> + jpeg_apply_fe_addr(ectx, sq, vb);
> +
> + } else {
> + rc = jpeg_setup_we(ectx, dq);
> + if (rc)
> + return rc;
> +
> + jpeg_apply_we_addr(ectx, dq, vb);
> + }
> +
> + if (sq->sequence == dq->sequence) {
> + rc = jpeg_setup_scale(ectx);
> + if (rc)
> + return rc;
> +
> + rc = jpeg_setup_encode(ectx);
> + if (rc)
> + return rc;
> +
> + jpeg_exec(jenc);
> + }
> +
> + return 0;
> +}
> +
> +static int op_jpeg_prepare(struct qcom_jenc_dev *jenc)
> +{
> + const struct qcom_jpeg_reg_offs *offs = jenc->res->hw_offs;
> +
> + jpeg_rw_bits(jenc, offs->reset_cmd, JMSK_RST_CMD_DECODER_RESET, 1);
> + jpeg_rw_bits(jenc, offs->reset_cmd, JMSK_RST_CMD_BLOCK_FORMATTER_RST, 1);
> + jpeg_rw_bits(jenc, offs->reset_cmd, JMSK_RST_CMD_CORE_RESET, 1);
> +
> + return 0;
> +}
> +
> +static int op_jpeg_acquire(struct jenc_context *ectx, struct vb2_queue *q)
> +{
> + struct qcom_jenc_dev *jenc = ectx->jenc;
> + struct qcom_jenc_queue *sq, *dq;
> + int rc;
> +
> + if (atomic_inc_return(&jenc->ref_count) == 1) {
> + rc = pm_runtime_resume_and_get(jenc->dev);
> + if (rc < 0) {
> + dev_err(jenc->dev, "PM runtime get failed\n");
> + atomic_dec(&jenc->ref_count);
> + return rc;
> + }
> +
> + rc = jpeg_init(jenc);
> + if (rc) {
> + dev_err(jenc->dev, "hardware init failed\n");
> + atomic_dec(&jenc->ref_count);
> + pm_runtime_put(jenc->dev);
> + return rc;
> + }
> +
> + sq = &ectx->bufq[JENC_SRC_QUEUE];
> + sq->sequence = 0;
> + sq->buff_id = -1;
> + dq = &ectx->bufq[JENC_DST_QUEUE];
> + dq->sequence = 0;
> + dq->buff_id = -1;
> + }
> +
> + return 0;
> +}
> +
> +static int op_jpeg_release(struct jenc_context *ectx, struct vb2_queue *q)
> +{
> + struct qcom_jenc_dev *jenc = ectx->jenc;
> + int rc;
> +
> + if (!atomic_dec_if_positive(&jenc->ref_count)) {
> + rc = jpeg_deinit(jenc);
> + if (rc)
> + dev_err(jenc->dev, "hardware exit failed\n");
> +
> + rc = pm_runtime_put_sync(jenc->dev);
> + if (rc < 0)
> + dev_err(jenc->dev, "PM runtime put failed\n");
> +
> + dev_dbg(jenc->dev, "JPEG HW encoder released\n");
> + }
> +
> + return 0;
> +}
> +
> +const struct qcom_jpeg_hw_ops qcom_jpeg_default_ops = {
> + .hw_get_cap = op_jpeg_get_hw_caps,
> + .hw_acquire = op_jpeg_acquire,
> + .hw_release = op_jpeg_release,
> + .hw_prepare = op_jpeg_prepare,
> + .get_queue = op_jpeg_get_buff_queue,
> + .queue_setup = op_jpeg_queue_setup,
> + .buf_prepare = op_jpeg_buffer_prepare,
> + .process_exec = op_jpeg_process_exec,
> + .hw_irq_top = op_jpeg_irq_top,
> + .hw_irq_bot = op_jpeg_irq_bot
> +};
> diff --git a/drivers/media/platform/qcom/jpeg/qcom_jenc_ops.h b/drivers/media/platform/qcom/jpeg/qcom_jenc_ops.h
> new file mode 100644
> index 000000000000..751a045a3486
> --- /dev/null
> +++ b/drivers/media/platform/qcom/jpeg/qcom_jenc_ops.h
> @@ -0,0 +1,49 @@
> +/* SPDX-License-Identifier: GPL-2.0-only */
> +/*
> + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
> + */
> +
> +#ifndef QCOM_JENC_OPS_H
> +#define QCOM_JENC_OPS_H
> +
> +#include <linux/types.h>
> +#include <linux/device.h>
> +#include <media/videobuf2-core.h>
> +
> +#include "qcom_jenc_dev.h"
> +
> +/*
> + * JENC encoder hardware operations.
> + */
> +struct qcom_jpeg_hw_ops {
> + void (*hw_get_cap)
> + (struct qcom_jenc_dev *jenc_dev, u32 *hw_caps);
> +
> + int (*hw_acquire)
> + (struct jenc_context *ectx, struct vb2_queue *queue);
> +
> + int (*hw_release)
> + (struct jenc_context *ectx, struct vb2_queue *queue);
> +
> + int (*hw_prepare)
> + (struct qcom_jenc_dev *jenc);
> +
> + struct qcom_jenc_queue * (*get_queue)
> + (struct jenc_context *ectx, enum qcom_enc_qid id);
> +
> + int (*queue_setup)
> + (struct jenc_context *ectx, enum qcom_enc_qid id);
> +
> + int (*buf_prepare)
> + (struct jenc_context *ectx, struct vb2_buffer *vb2);
> +
> + int (*process_exec)
> + (struct qcom_jenc_dev *jenc, struct jenc_context *ectx, struct vb2_buffer *vb2);
> +
> + irqreturn_t (*hw_irq_top)(int irq_num, void *data);
> + irqreturn_t (*hw_irq_bot)(int irq_num, void *data);
> +};
> +
> +extern const struct qcom_jpeg_hw_ops qcom_jpeg_default_ops;
> +
> +#endif /* QCOM_JENC_OPS_H */
> diff --git a/drivers/media/platform/qcom/jpeg/qcom_jenc_res.c b/drivers/media/platform/qcom/jpeg/qcom_jenc_res.c
> new file mode 100644
> index 000000000000..c935ea690837
> --- /dev/null
> +++ b/drivers/media/platform/qcom/jpeg/qcom_jenc_res.c
> @@ -0,0 +1,268 @@
> +// SPDX-License-Identifier: GPL-2.0-only
> +/*
> + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
> + */
> +
> +#include <linux/clk.h>
> +
> +#include "qcom_jenc_ops.h"
> +#include "qcom_jenc_res.h"
> +
> +#include "qcom_v165_jenc_hw_info.h"
> +#include "qcom_v580_jenc_hw_info.h"
> +#include "qcom_v680_jenc_hw_info.h"
> +#include "qcom_v780_jenc_hw_info.h"
> +
> +#define QCOM_PERF_ROW(_axi_rate, _jpeg_rate) \
> +{ \
> + .clk_rate = { \
> + [JPEG_CAMNOC_AXI_CLK] = (_axi_rate), \
> + [JPEG_CORE_CLK] = (_jpeg_rate), \
> + }, \
> +}
> +
> +/*
> + * Baseline AXI clock rates shared across v165/v580, reused by later
> + * derivatives where the hardware does not change these domains.
> + */
> +static const u64 cnoc_axi_clk_base[] = {
> + [QCOM_SOC_PERF_SUSPEND] = 19200000,
> + [QCOM_SOC_PERF_LOWSVS] = 300000000,
> + [QCOM_SOC_PERF_SVS] = 300000000,
> + [QCOM_SOC_PERF_SVS_L1] = 300000000,
> + [QCOM_SOC_PERF_NOMINAL] = 400000000,
> + [QCOM_SOC_PERF_TURBO] = 400000000,
> +};
> +
> +/*
> + * Derivative with an improved CAMNOC AXI frequency range
> + */
> +static const u64 cnoc_axi_clk_v680[] = {
> + [QCOM_SOC_PERF_SUSPEND] = 19200000,
> + [QCOM_SOC_PERF_LOWSVS] = 150000000,
> + [QCOM_SOC_PERF_SVS] = 240000000,
> + [QCOM_SOC_PERF_SVS_L1] = 320000000,
> + [QCOM_SOC_PERF_NOMINAL] = 400000000,
> + [QCOM_SOC_PERF_TURBO] = 480000000,
> +};
> +
> +/*
> + * Baseline JPEG clock rates shared across v165/v680, reused by later
> + * derivatives where the hardware does not change these domains.
> + */
> +static const u64 qcom_jpeg_clk_base[] = {
> + [QCOM_SOC_PERF_SUSPEND] = 19200000,
> + [QCOM_SOC_PERF_LOWSVS] = 300000000,
> + [QCOM_SOC_PERF_SVS] = 400000000,
> + [QCOM_SOC_PERF_SVS_L1] = 480000000,
> + [QCOM_SOC_PERF_NOMINAL] = 600000000,
> + [QCOM_SOC_PERF_TURBO] = 600000000,
> +};
> +
> +/*
> + * Derivative with an improved maximum JPEG frequency
> + */
> +static const u64 qcom_jpeg_clk_v780[] = {
> + [QCOM_SOC_PERF_SUSPEND] = 19200000,
> + [QCOM_SOC_PERF_LOWSVS] = 200000000,
> + [QCOM_SOC_PERF_SVS] = 200000000,
> + [QCOM_SOC_PERF_SVS_L1] = 400000000,
> + [QCOM_SOC_PERF_NOMINAL] = 480000000,
> + [QCOM_SOC_PERF_TURBO] = 785000000,
> +};
> +
> +static const struct qcom_perf_resource qcom_perf_rates_base[] = {
> + [QCOM_SOC_PERF_SUSPEND] =
> + QCOM_PERF_ROW(cnoc_axi_clk_base[QCOM_SOC_PERF_SUSPEND],
> + qcom_jpeg_clk_base[QCOM_SOC_PERF_SUSPEND]),
> +
> + [QCOM_SOC_PERF_LOWSVS] =
> + QCOM_PERF_ROW(cnoc_axi_clk_base[QCOM_SOC_PERF_LOWSVS],
> + qcom_jpeg_clk_base[QCOM_SOC_PERF_LOWSVS]),
> +
> + [QCOM_SOC_PERF_SVS] =
> + QCOM_PERF_ROW(cnoc_axi_clk_base[QCOM_SOC_PERF_SVS],
> + qcom_jpeg_clk_base[QCOM_SOC_PERF_SVS]),
> +
> + [QCOM_SOC_PERF_SVS_L1] =
> + QCOM_PERF_ROW(cnoc_axi_clk_base[QCOM_SOC_PERF_SVS_L1],
> + qcom_jpeg_clk_base[QCOM_SOC_PERF_SVS_L1]),
> +
> + [QCOM_SOC_PERF_NOMINAL] =
> + QCOM_PERF_ROW(cnoc_axi_clk_base[QCOM_SOC_PERF_NOMINAL],
> + qcom_jpeg_clk_base[QCOM_SOC_PERF_NOMINAL]),
> +
> + [QCOM_SOC_PERF_TURBO] =
> + QCOM_PERF_ROW(cnoc_axi_clk_base[QCOM_SOC_PERF_TURBO],
> + qcom_jpeg_clk_base[QCOM_SOC_PERF_TURBO]),
> +};
> +
> +static const struct qcom_perf_resource qcom_perf_rates_v680[] = {
> + [QCOM_SOC_PERF_SUSPEND] =
> + QCOM_PERF_ROW(cnoc_axi_clk_v680[QCOM_SOC_PERF_SUSPEND],
> + qcom_jpeg_clk_base[QCOM_SOC_PERF_SUSPEND]),
> +
> + [QCOM_SOC_PERF_LOWSVS] =
> + QCOM_PERF_ROW(cnoc_axi_clk_v680[QCOM_SOC_PERF_LOWSVS],
> + qcom_jpeg_clk_base[QCOM_SOC_PERF_LOWSVS]),
> +
> + [QCOM_SOC_PERF_SVS] =
> + QCOM_PERF_ROW(cnoc_axi_clk_v680[QCOM_SOC_PERF_SVS],
> + qcom_jpeg_clk_base[QCOM_SOC_PERF_SVS]),
> +
> + [QCOM_SOC_PERF_SVS_L1] =
> + QCOM_PERF_ROW(cnoc_axi_clk_v680[QCOM_SOC_PERF_SVS_L1],
> + qcom_jpeg_clk_base[QCOM_SOC_PERF_SVS_L1]),
> +
> + [QCOM_SOC_PERF_NOMINAL] =
> + QCOM_PERF_ROW(cnoc_axi_clk_v680[QCOM_SOC_PERF_NOMINAL],
> + qcom_jpeg_clk_base[QCOM_SOC_PERF_NOMINAL]),
> +
> + [QCOM_SOC_PERF_TURBO] =
> + QCOM_PERF_ROW(cnoc_axi_clk_v680[QCOM_SOC_PERF_TURBO],
> + qcom_jpeg_clk_base[QCOM_SOC_PERF_TURBO]),
> +};
> +
> +static const struct qcom_perf_resource qcom_perf_rates_v780[] = {
> + [QCOM_SOC_PERF_SUSPEND] =
> + QCOM_PERF_ROW(cnoc_axi_clk_base[QCOM_SOC_PERF_SUSPEND],
> + qcom_jpeg_clk_v780[QCOM_SOC_PERF_SUSPEND]),
> +
> + [QCOM_SOC_PERF_LOWSVS] =
> + QCOM_PERF_ROW(cnoc_axi_clk_base[QCOM_SOC_PERF_LOWSVS],
> + qcom_jpeg_clk_v780[QCOM_SOC_PERF_LOWSVS]),
> +
> + [QCOM_SOC_PERF_SVS] =
> + QCOM_PERF_ROW(cnoc_axi_clk_base[QCOM_SOC_PERF_SVS],
> + qcom_jpeg_clk_v780[QCOM_SOC_PERF_SVS]),
> +
> + [QCOM_SOC_PERF_SVS_L1] =
> + QCOM_PERF_ROW(cnoc_axi_clk_base[QCOM_SOC_PERF_SVS_L1],
> + qcom_jpeg_clk_v780[QCOM_SOC_PERF_SVS_L1]),
> +
> + [QCOM_SOC_PERF_NOMINAL] =
> + QCOM_PERF_ROW(cnoc_axi_clk_base[QCOM_SOC_PERF_NOMINAL],
> + qcom_jpeg_clk_v780[QCOM_SOC_PERF_NOMINAL]),
> +
> + [QCOM_SOC_PERF_TURBO] =
> + QCOM_PERF_ROW(cnoc_axi_clk_base[QCOM_SOC_PERF_TURBO],
> + qcom_jpeg_clk_v780[QCOM_SOC_PERF_TURBO]),
> +};
> +
> +static const struct qcom_icc_resource qcom_jpeg_default_icc[] = {
> + {
> + .icc_id = "cam_ahb",
> + .pair = { 38400, 76800 }
> + },
> + {
> + .icc_id = "cam_hf_0_mnoc",
> + .pair = { 2097152, 2097152 }
> + },
> + {
> + .icc_id = "cam_sf_0_mnoc",
> + .pair = { 0, 2097152 }
> + },
> + {
> + .icc_id = "cam_sf_icp_mnoc",
> + .pair = { 2097152, 2097152 }
> + },
> +};
> +
> +static const struct qcom_mem_resource qcom_jpeg_default_mem[] = {
> + {
> + .map_id = 0,
> + .res_id = "JPEG"
> + },
> + {
> + .map_id = 1,
> + .res_id = "CPAS"
> + }
> +};
You don't even use these in the driver
> +
> +/*
> + * Resources for T165, T170 JPEG version and derivatives
> + */
> +const struct qcom_dev_resources qcom_jpeg_v165_drvdata = {
> + .hw_ops = &qcom_jpeg_default_ops,
> + .hw_offs = &qcom_v165_jpeg_hw_reg_offs,
> + .hw_mask = &qcom_v165_jpeg_hw_reg_mask[0],
> + .icc_res = qcom_jpeg_default_icc,
> + .num_of_icc = ARRAY_SIZE(qcom_jpeg_default_icc),
> + .mem_res = qcom_jpeg_default_mem,
> + .num_of_mem = ARRAY_SIZE(qcom_jpeg_default_mem),
> + .perf_cfg = qcom_perf_rates_base,
> + .clk_names = {
> + [JPEG_CAMNOC_AXI_CLK] = "camnoc_axi_clk",
> + [JPEG_CORE_CLK] = "jpeg_clk",
> + [JPEG_CORE_AHB_CLK] = "core_ahb_clk",
> + [JPEG_CPAS_AHB_CLK] = "cpas_ahb_clk",
> + [JPEG_GCC_HF_AXI] = "gcc_hf_axi_clk",
> + [JPEG_GCC_SF_AXI] = "gcc_sf_axi_clk",
> + }
> +};
> +
> +/*
> + * Resources for T480, T580 JPEG version and derivatives
> + */
> +const struct qcom_dev_resources qcom_jpeg_v580_drvdata = {
> + .hw_ops = &qcom_jpeg_default_ops,
> + .hw_offs = &qcom_v580_jpeg_hw_reg_offs,
> + .hw_mask = &qcom_v580_jpeg_hw_reg_mask[0],
> + .icc_res = qcom_jpeg_default_icc,
> + .num_of_icc = ARRAY_SIZE(qcom_jpeg_default_icc),
> + .mem_res = qcom_jpeg_default_mem,
> + .num_of_mem = ARRAY_SIZE(qcom_jpeg_default_mem),
> + .perf_cfg = qcom_perf_rates_base,
> + .clk_names = {
> + [JPEG_CAMNOC_AXI_CLK] = "camnoc_axi_clk",
> + [JPEG_CORE_CLK] = "jpeg_clk",
> + [JPEG_CORE_AHB_CLK] = "core_ahb_clk",
> + [JPEG_CPAS_AHB_CLK] = "cpas_ahb_clk",
> + [JPEG_GCC_HF_AXI] = "gcc_hf_axi_clk",
> + [JPEG_GCC_SF_AXI] = "gcc_sf_axi_clk",
> + }
> +};
> +
> +/*
> + * Resources for T680 JPEG version and derivatives
> + */
> +const struct qcom_dev_resources qcom_jpeg_v680_drvdata = {
> + .hw_ops = &qcom_jpeg_default_ops,
All hw_ops are the same, remove them from the struct.
> + .hw_offs = &qcom_v680_jpeg_hw_reg_offs,
> + .hw_mask = &qcom_v680_jpeg_hw_reg_mask[0],
> + .icc_res = qcom_jpeg_default_icc,
> + .num_of_icc = ARRAY_SIZE(qcom_jpeg_default_icc),
> + .mem_res = qcom_jpeg_default_mem,
> + .num_of_mem = ARRAY_SIZE(qcom_jpeg_default_mem),
> + .perf_cfg = qcom_perf_rates_v680,
> + .clk_names = {
> + [JPEG_CAMNOC_AXI_CLK] = "camnoc_axi_clk",
> + [JPEG_CORE_CLK] = "jpeg_clk",
> + [JPEG_CORE_AHB_CLK] = "core_ahb_clk",
> + [JPEG_CPAS_AHB_CLK] = "cpas_ahb_clk",
> + [JPEG_GCC_HF_AXI] = "gcc_hf_axi_clk",
> + [JPEG_GCC_SF_AXI] = "gcc_sf_axi_clk",
> + }
Nope. You don't really need all those clock names here. Use
devm_clk_bulk_get_all().
> +};
> +
> +/*
> + * Resources for T780 JPEG version and derivatives
> + */
> +const struct qcom_dev_resources qcom_jpeg_v780_drvdata = {
> + .hw_ops = &qcom_jpeg_default_ops,
> + .hw_offs = &qcom_v780_jpeg_hw_reg_offs,
> + .hw_mask = &qcom_v780_jpeg_hw_reg_mask[0],
> + .icc_res = qcom_jpeg_default_icc,
> + .num_of_icc = ARRAY_SIZE(qcom_jpeg_default_icc),
> + .mem_res = qcom_jpeg_default_mem,
> + .num_of_mem = ARRAY_SIZE(qcom_jpeg_default_mem),
> + .perf_cfg = qcom_perf_rates_v780,
> + .clk_names = {
> + [JPEG_CAMNOC_AXI_CLK] = "camnoc_axi_clk",
> + [JPEG_CORE_CLK] = "jpeg_clk",
> + [JPEG_CORE_AHB_CLK] = "core_ahb_clk",
> + [JPEG_CPAS_AHB_CLK] = "cpas_ahb_clk",
> + [JPEG_GCC_HF_AXI] = "gcc_hf_axi_clk",
> + [JPEG_GCC_SF_AXI] = "gcc_sf_axi_clk",
> + }
> +};
> diff --git a/drivers/media/platform/qcom/jpeg/qcom_v165_jenc_hw_info.h b/drivers/media/platform/qcom/jpeg/qcom_v165_jenc_hw_info.h
> new file mode 100644
> index 000000000000..16e4eae04d5f
> --- /dev/null
> +++ b/drivers/media/platform/qcom/jpeg/qcom_v165_jenc_hw_info.h
> @@ -0,0 +1,509 @@
> +/* SPDX-License-Identifier: GPL-2.0-only */
> +/*
> + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
> + */
> +
> +#ifndef QCOM_JENC_HW_INFO_V165_H
> +#define QCOM_JENC_HW_INFO_V165_H
> +
> +#include "qcom_jenc_defs.h"
> +
> +#define JPEG_V165_HW_VER_STEP_POS 0
> +#define JPEG_V165_HW_VER_STEP_MSK \
> + (0xffff << JPEG_V165_HW_VER_STEP_POS)
Use GENMASK instead.
> +
> +#define JPEG_V165_HW_VER_MINOR_POS 16
> +#define JPEG_V165_HW_VER_MINOR_MSK \
> + (0x0fff << JPEG_V165_HW_VER_MINOR_POS)
> +
> +#define JPEG_V165_HW_VER_MAJOR_POS 28
> +#define JPEG_V165_HW_VER_MAJOR_MSK \
> + (0xf << JPEG_V165_HW_VER_MAJOR_POS)
> +
> +#define JPEG_V165_HW_CAP_ENCODE_MSK BIT(0)
> +#define JPEG_V165_HW_CAP_DECODE_MSK BIT(1)
Stop declaring bits and pieces which are common to all platforms as
platform-specific. Get them handled in the code directly without this
extra intervention. Ideally, get one(!) of the platforms merged first
and then implement corresponding differences for all other platforms.
--
With best wishes
Dmitry
^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [PATCH 2/3] qcom: media: jpeg: Add Qualcomm JPEG V4L2 encoder
2026-05-15 13:28 ` Dmitry Baryshkov
@ 2026-05-15 13:50 ` Nicolas Dufresne
0 siblings, 0 replies; 15+ messages in thread
From: Nicolas Dufresne @ 2026-05-15 13:50 UTC (permalink / raw)
To: Dmitry Baryshkov, Atanas Filipov
Cc: Bryan O'Donoghue, Mauro Carvalho Chehab, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Kapatrala Syed,
Hariram Purushothaman, Bjorn Andersson, Konrad Dybcio,
Gjorgji Rosikopulos, afilipov, linux-media, linux-arm-msm,
devicetree, linux-kernel
[-- Attachment #1: Type: text/plain, Size: 93855 bytes --]
Le vendredi 15 mai 2026 à 16:28 +0300, Dmitry Baryshkov a écrit :
> On Fri, May 15, 2026 at 02:47:00PM +0300, Atanas Filipov wrote:
> > Implementation of a V4L2 JPEG encoder device driver supporting
> > Qualcomm SC7180, SM8250, SM7280, and SM8550 chipsets.
> >
> > Signed-off-by: Atanas Filipov <atanas.filipov@oss.qualcomm.com>
> > ---
> > drivers/media/platform/qcom/Kconfig | 1 +
> > drivers/media/platform/qcom/Makefile | 1 +
> > drivers/media/platform/qcom/jpeg/Kconfig | 17 +
> > drivers/media/platform/qcom/jpeg/Makefile | 9 +
> > drivers/media/platform/qcom/jpeg/qcom_jenc_defs.h | 253 ++++
> > drivers/media/platform/qcom/jpeg/qcom_jenc_dev.c | 370 +++++
> > drivers/media/platform/qcom/jpeg/qcom_jenc_dev.h | 111 ++
> > drivers/media/platform/qcom/jpeg/qcom_jenc_hdr.c | 388 +++++
> > drivers/media/platform/qcom/jpeg/qcom_jenc_hdr.h | 130 ++
> > drivers/media/platform/qcom/jpeg/qcom_jenc_ops.c | 1522 ++++++++++++++++++++
> > drivers/media/platform/qcom/jpeg/qcom_jenc_ops.h | 49 +
> > drivers/media/platform/qcom/jpeg/qcom_jenc_res.c | 268 ++++
> > drivers/media/platform/qcom/jpeg/qcom_jenc_res.h | 70 +
> > drivers/media/platform/qcom/jpeg/qcom_jenc_v4l2.c | 1082 ++++++++++++++
> > drivers/media/platform/qcom/jpeg/qcom_jenc_v4l2.h | 27 +
> > .../platform/qcom/jpeg/qcom_v165_jenc_hw_info.h | 509 +++++++
> > .../platform/qcom/jpeg/qcom_v580_jenc_hw_info.h | 509 +++++++
> > .../platform/qcom/jpeg/qcom_v680_jenc_hw_info.h | 509 +++++++
> > .../platform/qcom/jpeg/qcom_v780_jenc_hw_info.h | 509 +++++++
> > 19 files changed, 6334 insertions(+)
> >
> > diff --git a/drivers/media/platform/qcom/Kconfig b/drivers/media/platform/qcom/Kconfig
> > index 4f4d3a68e6e5..f33d53a754a0 100644
> > --- a/drivers/media/platform/qcom/Kconfig
> > +++ b/drivers/media/platform/qcom/Kconfig
> > @@ -5,3 +5,4 @@ comment "Qualcomm media platform drivers"
> > source "drivers/media/platform/qcom/camss/Kconfig"
> > source "drivers/media/platform/qcom/iris/Kconfig"
> > source "drivers/media/platform/qcom/venus/Kconfig"
> > +source "drivers/media/platform/qcom/jpeg/Kconfig"
> > diff --git a/drivers/media/platform/qcom/Makefile b/drivers/media/platform/qcom/Makefile
> > index ea2221a202c0..30c94949e9de 100644
> > --- a/drivers/media/platform/qcom/Makefile
> > +++ b/drivers/media/platform/qcom/Makefile
> > @@ -2,3 +2,4 @@
> > obj-y += camss/
> > obj-y += iris/
> > obj-y += venus/
> > +obj-y += jpeg/
> > diff --git a/drivers/media/platform/qcom/jpeg/Kconfig b/drivers/media/platform/qcom/jpeg/Kconfig
> > new file mode 100644
> > index 000000000000..51846aeafaf3
> > --- /dev/null
> > +++ b/drivers/media/platform/qcom/jpeg/Kconfig
> > @@ -0,0 +1,17 @@
> > +# SPDX-License-Identifier: GPL-2.0-only
> > +config VIDEO_QCOM_JENC
> > + tristate "Qualcomm V4L2 JPEG Encoder driver"
> > + depends on V4L_MEM2MEM_DRIVERS
> > + depends on (ARCH_QCOM && IOMMU_DMA) || COMPILE_TEST
> > + depends on VIDEO_DEV
> > + select VIDEO_V4L2_SUBDEV_API
> > + select VIDEOBUF2_DMA_SG
> > + select V4L2_MEM2MEM_DEV
> > + help
> > + Qualcomm JPEG memory-to-memory V4L2 encoder driver.
> > +
> > + Provides:
> > + - qcom-jenc (encode)
> > +
> > + To compile this driver as a module, choose M here: the
> > + module will be called qcom-jenc
> > diff --git a/drivers/media/platform/qcom/jpeg/Makefile b/drivers/media/platform/qcom/jpeg/Makefile
> > new file mode 100644
> > index 000000000000..310f6c3c1f19
> > --- /dev/null
> > +++ b/drivers/media/platform/qcom/jpeg/Makefile
> > @@ -0,0 +1,9 @@
> > +# SPDX-License-Identifier: GPL-2.0-only
> > +obj-$(CONFIG_VIDEO_QCOM_JENC) += qcom-jenc.o
> > +
> > +qcom-jenc-objs += \
> > + qcom_jenc_dev.o \
> > + qcom_jenc_v4l2.o \
> > + qcom_jenc_ops.o \
> > + qcom_jenc_res.o \
> > + qcom_jenc_hdr.o
> > diff --git a/drivers/media/platform/qcom/jpeg/qcom_jenc_defs.h b/drivers/media/platform/qcom/jpeg/qcom_jenc_defs.h
> > new file mode 100644
> > index 000000000000..40e46820c546
> > --- /dev/null
> > +++ b/drivers/media/platform/qcom/jpeg/qcom_jenc_defs.h
> > @@ -0,0 +1,253 @@
> > +/* SPDX-License-Identifier: GPL-2.0-only */
> > +/*
> > + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
> > + */
> > +
> > +#ifndef QCOM_JENC_DEFS_H_
> > +#define QCOM_JENC_DEFS_H_
> > +
> > +#include <linux/types.h>
> > +#include <linux/io.h>
> > +#include <linux/bitfield.h>
> > +#include <linux/videodev2.h>
> > +#include <media/videobuf2-core.h>
>
> Keep the list sorted
>
> > +
> > +/* Offline JPEG encoder constraints */
> > +#define QCOM_JPEG_HW_MAX_WIDTH 9248
> > +#define QCOM_JPEG_HW_MAX_HEIGHT 8192
> > +#define QCOM_JPEG_HW_MIN_WIDTH 128
> > +#define QCOM_JPEG_HW_MIN_HEIGHT 96
> > +
> > +#define QCOM_JPEG_HW_DEF_HSTEP 16
> > +#define QCOM_JPEG_HW_DEF_VSTEP 16
> > +
> > +#define QCOM_JPEG_HW_DEF_WIDTH 1920
> > +#define QCOM_JPEG_HW_DEF_HEIGHT 1080
> > +
> > +#define QCOM_JPEG_MAX_PLANES 3
> > +
> > +#define QCOM_JPEG_QUALITY_MIN 1
> > +#define QCOM_JPEG_QUALITY_DEF 95
> > +#define QCOM_JPEG_QUALITY_MAX 100
> > +#define QCOM_JPEG_QUALITY_MID (QCOM_JPEG_QUALITY_MAX / 2)
> > +#define QCOM_JPEG_QUALITY_UNT 1
> > +
> > +enum qcom_jpeg_soc_id {
> > + QCOM_V165_SOC_ID = 0,
> > + QCOM_V580_SOC_ID,
> > + QCOM_V680_SOC_ID,
> > + QCOM_V780_SOC_ID,
> > + QCOM_UNKNOWN_SOC_ID,
> > +};
> > +
> > +enum qcom_soc_perf_level {
> > + QCOM_SOC_PERF_SUSPEND = 0,
>
> These should be a part of the OPP tables in DT.
>
> > + QCOM_SOC_PERF_LOWSVS,
> > + QCOM_SOC_PERF_SVS,
> > + QCOM_SOC_PERF_SVS_L1,
> > + QCOM_SOC_PERF_NOMINAL,
> > + QCOM_SOC_PERF_TURBO,
> > + QCOM_SOC_PERF_LEVEL_MAX,
> > +};
> > +
> > +enum qcom_jpeg_mask_id {
> > + JMSK_HW_VER_STEP,
> > + JMSK_HW_VER_MINOR,
> > + JMSK_HW_VER_MAJOR,
> > +
> > + JMSK_HW_CAP_ENCODE,
> > + JMSK_HW_CAP_DECODE,
> > + JMSK_HW_CAP_UPSCALE,
> > + JMSK_HW_CAP_DOWNSCALE,
> > +
> > + JMSK_RST_CMD_COMMON,
> > + JMSK_RST_CMD_FE_RESET,
> > + JMSK_RST_CMD_WE_RESET,
> > + JMSK_RST_CMD_ENCODER_RESET,
> > + JMSK_RST_CMD_DECODER_RESET,
> > + JMSK_RST_CMD_BLOCK_FORMATTER_RST,
> > + JMSK_RST_CMD_SCALE_RESET,
> > + JMSK_RST_CMD_REGISTER_RESET,
> > + JMSK_RST_CMD_MISR_RESET,
> > + JMSK_RST_CMD_CORE_RESET,
> > + JMSK_RST_CMD_JMSK_DOMAIN_RESET,
> > + JMSK_RST_CMD_RESET_BYPASS,
> > +
> > + JMSK_CMD_HW_START,
> > + JMSK_CMD_HW_STOP,
> > + JMSK_CMD_CLR_RD_PLNS_QUEUE,
> > + JMSK_CMD_CLR_WR_PLNS_QUEUE,
> > + JMSK_CMD_APPLY_SWC_RD_PARAMS,
> > +
> > + JMSK_CORE_CFG_FE_ENABLE,
> > + JMSK_CORE_CFG_WE_ENABLE,
> > + JMSK_CORE_CFG_ENC_ENABLE,
> > + JMSK_CORE_CFG_SCALE_ENABLE,
> > + JMSK_CORE_CFG_TESTBUS_ENABLE,
> > + JMSK_CORE_CFG_MODE,
> > + JMSK_CORE_CFG_CGC_DISABLE,
> > +
> > + JMSK_CORE_STATUS_ENCODE_STATE,
> > + JMSK_CORE_STATUS_SCALE_STATE,
> > + JMSK_CORE_STATUS_RT_STATE,
> > + JMSK_CORE_STATUS_BUS_STATE,
> > + JMSK_CORE_STATUS_CGC_STATE,
> > +
> > + JMSK_IRQ_ENABLE_ALL,
> > + JMSK_IRQ_DISABLE_ALL,
> > + JMSK_IRQ_CLEAR_ALL,
> > +
> > + JMSK_IRQ_STATUS_SESSION_DONE,
> > + JMSK_IRQ_STATUS_RD_BUF_PLN0_DONE,
> > + JMSK_IRQ_STATUS_RD_BUF_PLN1_DONE,
> > + JMSK_IRQ_STATUS_RD_BUF_PLN2_DONE,
> > + JMSK_IRQ_STATUS_RD_BUF_PLNS_ATTN,
> > + JMSK_IRQ_STATUS_WR_BUF_PLN0_DONE,
> > + JMSK_IRQ_STATUS_WR_BUF_PLN1_DONE,
> > + JMSK_IRQ_STATUS_WR_BUF_PLN2_DONE,
> > + JMSK_IRQ_STATUS_WR_BUF_PLNS_ATTN,
> > + JMSK_IRQ_STATUS_SESSION_ERROR,
> > + JMSK_IRQ_STATUS_STOP_ACK,
> > + JMSK_IRQ_STATUS_RESET_ACK,
> > +
> > + JMSK_FE_CFG_BYTE_ORDERING,
> > + JMSK_FE_CFG_BURST_LENGTH_MAX,
> > + JMSK_FE_CFG_MEMORY_FORMAT,
> > + JMSK_FE_CFG_CBCR_ORDER,
> > + JMSK_FE_CFG_BOTTOM_VPAD_EN,
> > + JMSK_FE_CFG_PLN0_EN,
> > + JMSK_FE_CFG_PLN1_EN,
> > + JMSK_FE_CFG_PLN2_EN,
> > + JMSK_FE_CFG_SIXTEEN_MCU_EN,
> > + JMSK_FE_CFG_MCUS_PER_BLOCK,
> > + JMSK_FE_CFG_MAL_BOUNDARY,
> > + JMSK_FE_CFG_MAL_EN,
> > +
> > + JMSK_FE_VBPAD_CFG_BLOCK_ROW,
> > +
> > + JMSK_PLNS_RD_OFFSET,
> > + JMSK_PLNS_RD_BUF_SIZE_WIDTH,
> > + JMSK_PLNS_RD_BUF_SIZE_HEIGHT,
> > + JMSK_PLNS_RD_STRIDE,
> > + JMSK_PLNS_RD_HINIT,
> > + JMSK_PLNS_RD_VINIT,
> > +
> > + JMSK_WE_CFG_BYTE_ORDERING,
> > + JMSK_WE_CFG_BURST_LENGTH_MAX,
> > + JMSK_WE_CFG_MEMORY_FORMAT,
> > + JMSK_WE_CFG_CBCR_ORDER,
> > + JMSK_WE_CFG_PLN0_EN,
> > + JMSK_WE_CFG_PLN1_EN,
> > + JMSK_WE_CFG_PLN2_EN,
> > + JMSK_WE_CFG_MAL_BOUNDARY,
> > + JMSK_WE_CFG_MAL_EN,
> > + JMSK_WE_CFG_POP_BUFF_ON_EOS,
> > +
> > + JMSK_PLNS_WR_BUF_SIZE_WIDTH,
> > + JMSK_PLNS_WR_BUF_SIZE_HEIGHT,
> > +
> > + JMSK_PLNS_WR_STRIDE,
> > + JMSK_PLNS_WR_HINIT,
> > + JMSK_PLNS_WR_VINIT,
> > + JMSK_PLNS_WR_HSTEP,
> > + JMSK_PLNS_WR_VSTEP,
> > + JMSK_PLNS_WR_BLOCK_CFG_PER_COL,
> > + JMSK_PLNS_WR_BLOCK_CFG_PER_RAW,
> > +
> > + JMSK_ENC_CFG_IMAGE_FORMAT,
> > + JMSK_ENC_CFG_APPLY_EOI,
> > + JMSK_ENC_CFG_HUFFMAN_SEL,
> > + JMSK_ENC_CFG_FSC_ENABLE,
> > + JMSK_ENC_CFG_OUTPUT_DISABLE,
> > + JMSK_ENC_CFG_RST_MARKER_PERIOD,
> > + JMSK_ENC_IMAGE_SIZE_WIDTH,
> > + JMSK_ENC_IMAGE_SIZE_HEIGHT,
> > +
> > + JMSK_SCALE_CFG_HSCALE_ENABLE,
> > + JMSK_SCALE_CFG_VSCALE_ENABLE,
> > + JMSK_SCALE_CFG_UPSAMPLE_EN,
> > + JMSK_SCALE_CFG_SUBSAMPLE_EN,
> > + JMSK_SCALE_CFG_HSCALE_ALGO,
> > + JMSK_SCALE_CFG_VSCALE_ALGO,
> > + JMSK_SCALE_CFG_H_SCALE_FIR_ALGO,
> > + JMSK_SCALE_CFG_V_SCALE_FIR_ALGO,
> > +
> > + JMSK_SCALE_PLNS_OUT_CFG_BLK_WIDTH,
> > + JMSK_SCALE_PLNS_OUT_CFG_BLK_HEIGHT,
> > +
> > + JMSK_SCALE_PLNS_HSTEP_FRACTIONAL,
> > + JMSK_SCALE_PLNS_HSTEP_INTEGER,
> > + JMSK_SCALE_PLNS_VSTEP_FRACTIONAL,
> > + JMSK_SCALE_PLNS_VSTEP_INTEGER,
> > +
> > + JMSK_DMI_CFG,
> > + JMSK_DMI_ADDR,
> > + JMSK_DMI_DATA,
> > +
> > + JMSK_TESTBUS_CFG,
> > + JMSK_FE_VBPAD_CFG,
> > +
> > + JMSK_PLN0_RD_HINIT_INT,
> > + JMSK_PLN1_RD_HINIT_INT,
> > + JMSK_PLN2_RD_HINIT_INT,
> > + JMSK_PLN0_RD_VINIT_INT,
> > + JMSK_PLN1_RD_VINIT_INT,
> > + JMSK_PLN2_RD_VINIT_INT,
> > + JMSK_ID_MAX
> > +};
> > +
> > +struct qcom_jpeg_reg_offs {
> > + u32 hw_version;
> > + u32 hw_capability;
> > + u32 reset_cmd;
> > + u32 core_cfg;
> > + u32 int_mask;
> > + u32 int_clr;
> > + u32 int_status;
> > + u32 hw_cmd;
> > + u32 enc_core_state;
> > +
> > + struct {
> > + u32 pntr[QCOM_JPEG_MAX_PLANES];
> > + u32 offs[QCOM_JPEG_MAX_PLANES];
> > + u32 cnsmd[QCOM_JPEG_MAX_PLANES];
> > + u32 bsize[QCOM_JPEG_MAX_PLANES];
> > + u32 stride[QCOM_JPEG_MAX_PLANES];
> > + u32 hinit[QCOM_JPEG_MAX_PLANES];
> > + u32 vinit[QCOM_JPEG_MAX_PLANES];
> > + u32 pntr_cnt;
> > + u32 vbpad_cfg;
> > + } fe;
> > + u32 fe_cfg;
> > +
> > + struct {
> > + u32 pntr[QCOM_JPEG_MAX_PLANES];
> > + u32 cnsmd[QCOM_JPEG_MAX_PLANES];
> > + u32 bsize[QCOM_JPEG_MAX_PLANES];
> > + u32 stride[QCOM_JPEG_MAX_PLANES];
> > + u32 hinit[QCOM_JPEG_MAX_PLANES];
> > + u32 hstep[QCOM_JPEG_MAX_PLANES];
> > + u32 vinit[QCOM_JPEG_MAX_PLANES];
> > + u32 vstep[QCOM_JPEG_MAX_PLANES];
> > + u32 blocks[QCOM_JPEG_MAX_PLANES];
> > + u32 pntr_cnt;
> > + } we;
> > + u32 we_cfg;
> > +
> > + struct {
> > + u32 hstep[QCOM_JPEG_MAX_PLANES];
> > + u32 vstep[QCOM_JPEG_MAX_PLANES];
> > + } scale;
> > + u32 scale_cfg;
> > + u32 scale_out_cfg[QCOM_JPEG_MAX_PLANES];
> > +
> > + u32 enc_cfg;
> > + u32 enc_img_size;
> > + u32 enc_out_size;
> > +
> > + u32 dmi_cfg;
> > + u32 dmi_data;
> > + u32 dmi_addr;
> > +} __packed;
> > +
> > +#endif /* QCOM_JENC_DEFS_H_ */
> > diff --git a/drivers/media/platform/qcom/jpeg/qcom_jenc_dev.c b/drivers/media/platform/qcom/jpeg/qcom_jenc_dev.c
> > new file mode 100644
> > index 000000000000..4ef6bf9fd48d
> > --- /dev/null
> > +++ b/drivers/media/platform/qcom/jpeg/qcom_jenc_dev.c
> > @@ -0,0 +1,370 @@
> > +// SPDX-License-Identifier: GPL-2.0-only
> > +/*
> > + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
> > + */
> > +
> > +#include <linux/clk.h>
> > +#include <linux/interrupt.h>
> > +#include <linux/module.h>
> > +#include <linux/of_device.h>
> > +#include <linux/of.h>
> > +#include <linux/platform_device.h>
> > +#include <linux/pm_runtime.h>
> > +#include <linux/slab.h>
> > +
> > +#include <media/v4l2-mem2mem.h>
> > +
> > +#include "qcom_jenc_dev.h"
> > +
> > +#include "qcom_jenc_defs.h"
> > +#include "qcom_jenc_ops.h"
> > +#include "qcom_jenc_res.h"
> > +#include "qcom_jenc_v4l2.h"
> > +
> > +static int qcom_jpeg_match_data(struct qcom_jenc_dev *jenc)
> > +{
> > + struct device *dev = jenc->dev;
> > + const struct qcom_dev_resources *res;
> > +
> > + res = device_get_match_data(dev);
> > + if (!res)
> > + return dev_err_probe(dev, -ENODEV, "unsupported SoC\n");
> > +
> > + jenc->res = res;
> > +
> > + return 0;
>
> Useless wrapper, inline it.
>
> > +}
> > +
> > +static int qcom_jpeg_clk_init(struct qcom_jenc_dev *jenc)
> > +{
> > + const struct qcom_dev_resources *res = jenc->res;
> > + int c_idx;
> > +
> > + jenc->clks = devm_kcalloc(jenc->dev, ARRAY_SIZE(res->clk_names), sizeof(*jenc->clks),
> > + GFP_KERNEL);
> > + if (!jenc->clks)
> > + return -ENOMEM;
> > +
> > + for (c_idx = 0; c_idx < ARRAY_SIZE(res->clk_names); c_idx++) {
> > + if (!res->clk_names[c_idx])
> > + break;
> > +
> > + jenc->clks[c_idx].clk = devm_clk_get(jenc->dev, res->clk_names[c_idx]);
> > + if (IS_ERR(jenc->clks[c_idx].clk)) {
> > + return dev_err_probe(jenc->dev, PTR_ERR(jenc->clks[c_idx].clk),
> > + "failed to get clock %s\n", res->clk_names[c_idx]);
> > + }
> > +
> > + jenc->clks[c_idx].id = res->clk_names[c_idx];
> > + jenc->num_clks++;
> > + }
> > +
>
> Use bulk clock API instead of manually implementing those.
>
> > + return 0;
> > +}
> > +
> > +static int qcom_jpeg_clk_rate(struct qcom_jenc_dev *jenc, enum qcom_soc_perf_level level)
> > +{
> > + const struct qcom_dev_resources *res = jenc->res;
> > + const struct qcom_perf_resource *perf = &res->perf_cfg[level];
> > + int c_idx;
> > + int rc = 0;
> > +
> > + for (c_idx = 0; c_idx < jenc->num_clks; c_idx++) {
> > + /* skip clocks with fixed or default frequency */
> > + if (!perf->clk_rate[c_idx])
> > + continue;
> > +
> > + /* setup frequency according to performance level */
> > + rc = clk_set_rate(jenc->clks[c_idx].clk, perf->clk_rate[c_idx]);
> > + if (rc < 0) {
> > + dev_err(jenc->dev, "clock set rate failed: %d\n", rc);
> > + return rc;
> > + }
> > +
> > + dev_dbg(jenc->dev, "clock %s current rate: %ld\n",
> > + jenc->clks[c_idx].id, clk_get_rate(jenc->clks[c_idx].clk));
>
> People have invented OPP tables. Please use those instead.
>
> > + }
> > +
> > + return rc;
> > +}
> > +
>
> [...]
>
> > +
> > +static int qcom_jpeg_probe(struct platform_device *pdev)
> > +{
> > + struct qcom_jenc_dev *jenc;
> > + int rc;
> > +
> > + jenc = devm_kzalloc(&pdev->dev, sizeof(*jenc), GFP_KERNEL);
> > + if (!jenc)
> > + return -ENOMEM;
> > +
> > + jenc->dev = &pdev->dev;
> > + mutex_init(&jenc->dev_mutex);
> > + spin_lock_init(&jenc->hw_lock);
> > + init_completion(&jenc->reset_complete);
> > + init_completion(&jenc->stop_complete);
> > +
> > + rc = qcom_jpeg_match_data(jenc);
> > + if (rc)
> > + return dev_err_probe(jenc->dev, rc, "failed to attach hardware\n");
> > +
> > + if (!jenc->res->hw_offs || !jenc->res->hw_ops)
> > + return dev_err_probe(jenc->dev, -EINVAL, "missing hw resources\n");
> > +
> > + rc = dma_set_mask_and_coherent(jenc->dev, DMA_BIT_MASK(32));
> > + if (rc)
> > + return dev_err_probe(jenc->dev, rc, "failed to set DMA mask\n");
> > +
> > + platform_set_drvdata(pdev, jenc);
> > +
> > + jenc->jpeg_base = devm_platform_ioremap_resource(pdev, 0);
> > + if (IS_ERR(jenc->jpeg_base)) {
> > + rc = PTR_ERR(jenc->jpeg_base);
> > + return dev_err_probe(jenc->dev, rc, "failed to map JPEG resource\n");
> > + }
> > +
> > + jenc->cpas_base = devm_platform_ioremap_resource(pdev, 1);
> > + if (IS_ERR(jenc->cpas_base)) {
> > + rc = PTR_ERR(jenc->cpas_base);
> > + return dev_err_probe(jenc->dev, rc, "failed to map CPAS resource\n");
> > + }
> > +
> > + rc = qcom_jpeg_clk_init(jenc);
> > + if (rc)
> > + return dev_err_probe(jenc->dev, rc, "failed to init bulk clocks\n");
> > +
> > + jenc->irq = platform_get_irq(pdev, 0);
> > + if (jenc->irq < 0)
> > + return dev_err_probe(jenc->dev, jenc->irq, "failed to get IRQ\n");
> > +
> > + rc = devm_request_threaded_irq(jenc->dev, jenc->irq,
> > + jenc->res->hw_ops->hw_irq_top,
> > + jenc->res->hw_ops->hw_irq_bot,
> > + IRQF_ONESHOT, dev_name(jenc->dev), jenc);
> > + if (rc)
> > + return dev_err_probe(jenc->dev, rc, "failed to request IRQ\n");
> > +
> > + rc = qcom_jpeg_icc_init(jenc);
> > + if (rc)
> > + return dev_err_probe(jenc->dev, rc, "failed to get ICC resources\n");
> > +
> > + rc = kfifo_alloc(&jenc->kfifo_inst, sizeof(jenc->enc_status) * VB2_MAX_FRAME, GFP_KERNEL);
> > + if (rc) {
> > + dev_err(jenc->dev, "failed to allocate kfifo\n");
> > + return rc;
> > + }
> > +
> > + spin_lock_init(&jenc->kfifo_lock);
> > +
> > + rc = v4l2_device_register(jenc->dev, &jenc->v4l2_dev);
> > + if (rc) {
> > + dev_err(jenc->dev, "failed to register V4L2 device\n");
> > + goto err_kfifo_free;
> > + }
> > +
> > + rc = qcom_jpeg_v4l2_register(jenc);
> > + if (rc) {
> > + dev_err(jenc->dev, "failed to register video device\n");
> > + goto err_v4l2_device_unregister;
> > + }
> > +
> > + jenc->perf = QCOM_SOC_PERF_NOMINAL;
> > +
> > + pm_runtime_enable(jenc->dev);
>
> devm_pm_runtime_enable()
>
> > +
> > + dev_info(jenc->dev, "Qualcomm JPEG encoder registered\n");
> > +
> > + return 0;
> > +
> > +err_v4l2_device_unregister:
> > + v4l2_device_unregister(&jenc->v4l2_dev);
> > +err_kfifo_free:
> > + kfifo_free(&jenc->kfifo_inst);
> > +
> > + return rc;
> > +}
> > +
> > +static void qcom_jpeg_remove(struct platform_device *pdev)
> > +{
> > + struct qcom_jenc_dev *jenc = platform_get_drvdata(pdev);
> > +
> > + pm_runtime_disable(&pdev->dev);
> > +
> > + qcom_jpeg_v4l2_unregister(jenc);
> > +
> > + v4l2_device_unregister(&jenc->v4l2_dev);
> > +
> > + kfifo_free(&jenc->kfifo_inst);
> > +
> > + dev_info(jenc->dev, "Qualcomm JPEG encoder deregistered\n");
>
> Don't spam the logs with useless info.
>
> > +}
> > +
> > +static const struct of_device_id qcom_jpeg_of_match[] = {
> > + {
> > + .compatible = "qcom,sc7180-jenc",
> > + .data = &qcom_jpeg_v165_drvdata
> > + },
> > + {
> > + .compatible = "qcom,sm8250-jenc",
> > + .data = &qcom_jpeg_v580_drvdata
> > + },
> > + {
> > + .compatible = "qcom,sm7325-jenc",
> > + .data = &qcom_jpeg_v580_drvdata
>
> Don't regisger multiple entries for compatible devices. Use fallback
> compats instead.
>
> > + },
> > + {
> > + .compatible = "qcom,sc7280-jenc",
> > + .data = &qcom_jpeg_v680_drvdata
> > + },
> > + {
> > + .compatible = "qcom,qcm6490-jenc",
> > + .data = &qcom_jpeg_v680_drvdata
> > + },
> > + {
> > + .compatible = "qcom,sm8550-jenc",
> > + .data = &qcom_jpeg_v780_drvdata
> > + },
> > + { }
> > +};
> > +MODULE_DEVICE_TABLE(of, qcom_jpeg_of_match);
> > +
> > +static struct platform_driver qcom_jpeg_platform_driver = {
> > + .probe = qcom_jpeg_probe,
> > + .remove = qcom_jpeg_remove,
> > + .driver = {
> > + .name = QCOM_JPEG_ENC_NAME,
> > + .of_match_table = qcom_jpeg_of_match,
> > + .pm = &qcom_jpeg_pm_ops,
> > + },
> > +};
> > +
> > +module_platform_driver(qcom_jpeg_platform_driver);
> > +
> > +MODULE_DESCRIPTION("QCOM JPEG mem2mem V4L2 encoder");
> > +MODULE_LICENSE("GPL");
>
> [...]
>
> > +
> > +int qcom_jenc_header_init(struct qcom_jenc_header *c, u32 fourcc)
> > +{
> > + int rc;
> > + struct jpeg_header_buf b = {
> > + .ptr = c->data,
> > + .size = sizeof(c->data),
> > + .pos = 0,
> > + };
> > +
> > + c->sof_offset = 0;
> > + c->dqt_one_offs = 0;
> > + c->dqt_two_offs = 0;
> > +
> > + rc = jb_put_mem(&b, &soi_app0, sizeof(soi_app0));
> > + if (rc)
> > + return rc;
> > +
> > + if (fourcc != V4L2_PIX_FMT_GREY) {
> > + rc = jb_put_mem(&b, &dqt_chroma_hdr, sizeof(dqt_chroma_hdr));
> > + if (rc)
> > + return rc;
> > +
> > + /* Store the offset of the first DQT table for later use. */
> > + c->dqt_one_offs = b.pos;
> > + rc = jb_put_mem(&b, &dqt_luma_data, sizeof(dqt_luma_data));
> > + if (rc)
> > + return rc;
> > +
> > + /* Store the offset of the second DQT table for later use. */
> > + c->dqt_two_offs = b.pos;
> > + rc = jb_put_mem(&b, &dqt_chroma_data, sizeof(dqt_chroma_data));
> > + if (rc)
> > + return rc;
> > + } else {
> > + rc = jb_put_mem(&b, &dqt_luma_hdr, sizeof(dqt_luma_hdr));
> > + if (rc)
> > + return rc;
> > +
> > + /* Store the offset of the first DQT table for later use. */
> > + c->dqt_one_offs = b.pos;
> > + rc = jb_put_mem(&b, &dqt_luma_data, sizeof(dqt_luma_data));
> > + if (rc)
> > + return rc;
> > + }
>
> Do we absolutely need to do this in the kernel? Can we have defer that
> to the userspace using V4L2 encoders? Are there any other JPEG encoders
> handling JPEG headers in the kernel code?
Yes, see drivers/media/platform/verisilicon/hantro_jpeg.c (though its using
shortcuts compare to this. In any case, make an implementation for v4l2-jpeg,
then use it, and port hantro to show it is portable.
Stop using your own structure to represent a jpeg headers, v4l2-jpeg already
have that.
cheers,
Nicolas
>
> > +
> > + /* Store the offset of the SOF record for later use. */
> > + c->sof_offset = b.pos;
> > +
> > + if (fourcc != V4L2_PIX_FMT_GREY) {
> > + rc = jb_put_mem(&b, &sof0_color_hdr, sizeof(sof0_color_hdr));
> > + if (rc)
> > + return rc;
> > + rc = jb_put_mem(&b, &sof0_color_data, sizeof(sof0_color_data));
> > + if (rc)
> > + return rc;
> > + rc = jb_put_mem(&b, &coeff_color_hdr, sizeof(coeff_color_hdr));
> > + if (rc)
> > + return rc;
> > + rc = jb_put_mem(&b, &luma_dc_coeff, sizeof(luma_dc_coeff));
> > + if (rc)
> > + return rc;
> > + rc = jb_put_mem(&b, &luma_ac_coeff, sizeof(luma_ac_coeff));
> > + if (rc)
> > + return rc;
> > + rc = jb_put_mem(&b, &chroma_dc_coeff, sizeof(chroma_dc_coeff));
> > + if (rc)
> > + return rc;
> > + rc = jb_put_mem(&b, &chroma_ac_coeff, sizeof(chroma_ac_coeff));
> > + if (rc)
> > + return rc;
> > + rc = jb_put_mem(&b, &sos_color_hdr, sizeof(sos_color_hdr));
> > + if (rc)
> > + return rc;
> > + rc = jb_put_mem(&b, &sos_color_data, sizeof(sos_color_data));
> > + if (rc)
> > + return rc;
> > + } else {
> > + rc = jb_put_mem(&b, &sof0_mono_hdr, sizeof(sof0_mono_hdr));
> > + if (rc)
> > + return rc;
> > + rc = jb_put_mem(&b, &sof0_mono_data, sizeof(sof0_mono_data));
> > + if (rc)
> > + return rc;
> > + rc = jb_put_mem(&b, &coeff_mono_hdr, sizeof(coeff_mono_hdr));
> > + if (rc)
> > + return rc;
> > + rc = jb_put_mem(&b, &luma_dc_coeff, sizeof(luma_dc_coeff));
> > + if (rc)
> > + return rc;
> > + rc = jb_put_mem(&b, &luma_ac_coeff, sizeof(luma_ac_coeff));
> > + if (rc)
> > + return rc;
> > + rc = jb_put_mem(&b, &sos_mono_hdr, sizeof(sos_mono_hdr));
> > + if (rc)
> > + return rc;
> > + rc = jb_put_mem(&b, &sos_mono_data, sizeof(sos_mono_data));
> > + if (rc)
> > + return rc;
> > + }
> > +
> > + c->size = b.pos;
> > +
> > + return 0;
> > +}
> > +
> > +void qcom_jenc_dqts_emit(const struct qcom_jenc_header *c, u8 *dst)
> > +{
> > + /* Propagate DQT tables into the JPEG header */
> > + if (c->dqt_one_offs) {
> > + u32 one_offs = c->dqt_one_offs + sizeof(dqt_luma_data.index);
> > +
> > + memcpy(dst + one_offs, &c->data[one_offs], sizeof(dqt_luma_data.value));
> > + }
> > +
> > + if (c->dqt_two_offs) {
> > + u32 two_offs = c->dqt_two_offs + sizeof(dqt_chroma_data.index);
> > +
> > + memcpy(dst + two_offs, &c->data[two_offs], sizeof(dqt_chroma_data.value));
> > + }
> > +}
> > +
> > +u32 qcom_jenc_header_emit(const struct qcom_jenc_header *c, u8 *dst, u32 dst_size, u16 width,
> > + u16 height)
> > +{
> > + /* Copy JFIF into JPEG header and update actual image size */
> > + if (dst_size < c->size)
> > + return 0;
> > +
> > + memcpy(dst, c->data, c->size);
> > +
> > + /* Update output image size */
> > + patch_u16be(dst, c->sof_offset + JFIF_HEADER_WIDTH_OFFS, width);
> > + patch_u16be(dst, c->sof_offset + JFIF_HEADER_HEIGHT_OFFS, height);
> > +
> > + return c->size;
> > +}
> > diff --git a/drivers/media/platform/qcom/jpeg/qcom_jenc_hdr.h b/drivers/media/platform/qcom/jpeg/qcom_jenc_hdr.h
> > new file mode 100644
> > index 000000000000..0c5fcc69e7cd
> > --- /dev/null
> > +++ b/drivers/media/platform/qcom/jpeg/qcom_jenc_hdr.h
> > @@ -0,0 +1,130 @@
> > +/* SPDX-License-Identifier: GPL-2.0-only */
> > +/*
> > + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
> > + */
> > +
> > +#ifndef QCOM_JENC_HDR_H
> > +#define QCOM_JENC_HDR_H
> > +
> > +#include <linux/types.h>
> > +
> > +#include "qcom_jenc_defs.h"
> > +
> > +#define JPEG_QDT_LENGTH 64
> > +#define JPEG_HEADER_MAX 1024
> > +
> > +struct qcom_jenc_header {
> > + u8 data[JPEG_HEADER_MAX];
> > + u32 size;
> > + u32 sof_offset;
> > + u32 dqt_one_offs;
> > + u32 dqt_two_offs;
> > +};
> > +
> > +struct jpeg_record_hdr {
> > + u8 marker[2];
> > + u8 length[2];
> > +} __packed;
> > +
> > +struct jpeg_dqt_header {
> > + u8 index;
> > + u8 value[JPEG_QDT_LENGTH];
> > +} __packed;
> > +
> > +struct jpeg_soi_app0 {
> > + u8 soi[2];
> > + u8 app0_marker[2];
> > + u8 app0_length[2];
> > + u8 jfif_id[5];
> > + u8 version[2];
> > + u8 units;
> > + u8 density_x[2];
> > + u8 density_y[2];
> > + u8 thumb_x;
> > + u8 thumb_y;
> > +} __packed;
> > +
> > +struct jpeg_sof0_mono {
> > + u8 precision;
> > + u8 height[2];
> > + u8 width[2];
> > + u8 components;
> > +
> > + u8 y_id;
> > + u8 y_sampling;
> > + u8 y_qtable;
> > +} __packed;
> > +
> > +struct jpeg_sof0_color {
> > + u8 precision;
> > + u8 height[2];
> > + u8 width[2];
> > + u8 components;
> > +
> > + u8 y_id;
> > + u8 y_sampling;
> > + u8 y_qtable;
> > +
> > + u8 cb_id;
> > + u8 cb_sampling;
> > + u8 cb_qtable;
> > +
> > + u8 cr_id;
> > + u8 cr_sampling;
> > + u8 cr_qtable;
> > +} __packed;
> > +
> > +struct jpeg_dc_coeff_desc {
> > + u8 index;
> > + u8 bits[16];
> > + u8 values[12];
> > +} __packed;
> > +
> > +struct jpeg_ac_coeff_desc {
> > + u8 index;
> > + u8 bits[16];
> > + u8 values[162];
> > +} __packed;
> > +
> > +struct jpeg_sos_hdr {
> > + u8 sos_marker[2];
> > + u8 sos_length[2];
> > + u8 components;
> > +} __packed;
> > +
> > +struct jpeg_sos_mono {
> > + u8 components;
> > +
> > + u8 y_id;
> > + u8 y_tables;
> > +
> > + u8 spectral[2];
> > + u8 approx;
> > +} __packed;
> > +
> > +struct jpeg_sos_color {
> > + u8 components;
> > +
> > + u8 y_id;
> > + u8 y_tables;
> > +
> > + u8 cb_id;
> > + u8 cb_tables;
> > +
> > + u8 cr_id;
> > + u8 cr_tables;
> > +
> > + u8 spectral[2];
> > + u8 approx;
> > +} __packed;
> > +
> > +struct jenc_context;
> > +
> > +int qcom_jenc_header_init(struct qcom_jenc_header *c, u32 fourcc);
> > +
> > +void qcom_jenc_dqts_emit(const struct qcom_jenc_header *c, u8 *dst);
> > +
> > +u32 qcom_jenc_header_emit(const struct qcom_jenc_header *c, u8 *dst, u32 dst_size, u16 width,
> > + u16 height);
> > +
> > +#endif /* QCOM_JENC_HDR_H */
> > diff --git a/drivers/media/platform/qcom/jpeg/qcom_jenc_ops.c b/drivers/media/platform/qcom/jpeg/qcom_jenc_ops.c
> > new file mode 100644
> > index 000000000000..92e3c09df3d1
> > --- /dev/null
> > +++ b/drivers/media/platform/qcom/jpeg/qcom_jenc_ops.c
> > @@ -0,0 +1,1522 @@
> > +// SPDX-License-Identifier: GPL-2.0-only
> > +/*
> > + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
> > + */
> > +
> > +#include <asm/div64.h>
> > +#include <linux/pm_runtime.h>
> > +
> > +#include <media/v4l2-common.h>
> > +#include <media/v4l2-mem2mem.h>
> > +#include <media/videobuf2-dma-sg.h>
> > +#include <media/videobuf2-dma-contig.h>
> > +
> > +#include "qcom_jenc_dev.h"
> > +#include "qcom_jenc_ops.h"
> > +#include "qcom_jenc_defs.h"
> > +
> > +#define JPEG_RESET_TIMEOUT_MS 300
> > +#define JPEG_STOP_TIMEOUT_MS 200
> > +
> > +#define JPEG_DQT_SHIFT 20
> > +#define JPEG_Q5_21_SHIFT 21
> > +
> > +#define JPEG_MCU_BLOCK_8 8
> > +#define JPEG_MCU_BLOCK_16 16
> > +#define JPEG_MCU_BLOCK_128 128
> > +#define JPEG_MCU_BLOCK_256 256
> > +
> > +#define JPEG_DEFAULT_SCALE_STEP 0x200000
> > +
> > +#define JPEG_U32_CLR (0U)
> > +#define JPEG_U32_SET (~0U)
> > +
> > +/*
> > + * JPEG | V4L2
> > + * ---- | -------
> > + * H1V1 | GREY
> > + * H1V2 | YUV422M
> > + * H2V1 | NV16M
> > + * H2V2 | NV12M
> > + */
> > +enum qcom_jpeg_encode_fmt {
> > + JPEG_ENCODE_H1V1 = 0,
> > + JPEG_ENCODE_H1V2,
> > + JPEG_ENCODE_H2V1,
> > + JPEG_ENCODE_H2V2,
> > + JPEG_ENCODE_MONO,
> > +};
> > +
> > +enum qcom_jpeg_memory_fmt {
> > + JPEG_MEM_FMT_PLANAR = 0x0,
> > + JPEG_MEM_FMT_PPLANAR = 0x1,
> > + JPEG_MEM_FMT_MONO = 0x2,
> > + JPEG_MEM_FMT_COEFFICIENT = 0x3
> > +};
> > +
> > +enum jpeg_mal_bounds {
> > + JPEG_CFG_MAL_BOUND_32_BYTES = 0x0,
> > + JPEG_CFG_MAL_BOUND_64_BYTES = 0x1,
> > + JPEG_CFG_MAL_BOUND_128_BYTES = 0x2,
> > + JPEG_CFG_MAL_BOUND_256_BYTES = 0x3,
> > + JPEG_CFG_MAL_BOUND_512_BYTES = 0x4,
> > + JPEG_CFG_MAL_BOUND_1K_BYTES = 0x5,
> > + JPEG_CFG_MAL_BOUND_2K_BYTES = 0x6,
> > + JPEG_CFG_MAL_BOUND_4K_BYTES = 0x7
> > +};
> > +
> > +struct qcom_jpeg_scale_blocks {
> > + u8 w_block[QCOM_JPEG_MAX_PLANES];
> > + u8 h_block[QCOM_JPEG_MAX_PLANES];
> > +};
> > +
> > +struct qcom_jpeg_mal_boundary {
> > + u32 bytes;
> > + int boundary;
> > +};
> > +
> > +struct qcom_jpeg_formats {
> > + u32 fourcc;
> > + enum qcom_jpeg_encode_fmt encode;
> > + enum qcom_jpeg_memory_fmt memory;
> > +};
> > +
> > +/*
> > + * Luminance quantization table defined by CCITT T.81.
> > + * See: https://www.w3.org/Graphics/JPEG/itu-t81.pdf
> > + */
> > +static const u8 t81k1_dct_luma_table[JPEG_QDT_LENGTH] = {
> > + 16, 11, 10, 16, 24, 40, 51, 61,
> > + 12, 12, 14, 19, 26, 58, 60, 55,
> > + 14, 13, 16, 24, 40, 57, 69, 56,
> > + 14, 17, 22, 29, 51, 87, 80, 62,
> > + 18, 22, 37, 56, 68, 109, 103, 77,
> > + 24, 35, 55, 64, 81, 104, 113, 92,
> > + 49, 64, 78, 87, 103, 121, 120, 101,
> > + 72, 92, 95, 98, 112, 100, 103, 99
> > +};
> > +
> > +/*
> > + * Chrominance quantization table defined by CCITT T.81.
> > + * See: https://www.w3.org/Graphics/JPEG/itu-t81.pdf
> > + */
> > +static const u8 t81k2_dct_chroma_table[JPEG_QDT_LENGTH] = {
> > + 17, 18, 24, 47, 99, 99, 99, 99,
> > + 18, 21, 26, 66, 99, 99, 99, 99,
> > + 24, 26, 56, 99, 99, 99, 99, 99,
> > + 47, 66, 99, 99, 99, 99, 99, 99,
> > + 99, 99, 99, 99, 99, 99, 99, 99,
> > + 99, 99, 99, 99, 99, 99, 99, 99,
> > + 99, 99, 99, 99, 99, 99, 99, 99,
> > + 99, 99, 99, 99, 99, 99, 99, 99
> > +};
> > +
> > +/*
> > + * Zig-zag scan order for quantized DCT coefficients
> > + * as defined by CCITT T.81.
> > + * See: https://www.w3.org/Graphics/JPEG/itu-t81.pdf
> > + */
> > +static const u8 t81a6_dct_zig_zag_table[] = {
> > + 0, 1, 5, 6, 14, 15, 27, 28,
> > + 2, 4, 7, 13, 16, 26, 29, 42,
> > + 3, 8, 12, 17, 25, 30, 41, 43,
> > + 9, 11, 18, 24, 31, 40, 44, 53,
> > + 10, 19, 23, 32, 39, 45, 52, 54,
> > + 20, 22, 33, 38, 46, 51, 55, 60,
> > + 21, 34, 37, 47, 50, 56, 59, 61,
> > + 35, 36, 48, 49, 57, 58, 62, 63
> > +};
> > +
> > +static const u8 jpeg_mcu_per_ratio[] = {
> > + 0, /* MCU = 1, Ratio < 2x */
> > + 3, /* MCU = 0, 2x <= Ratio < 4x */
> > + 2, /* MCU = 0, 4x <= Ratio < 8x */
> > + 1, /* MCU = 0, 8x <= Ratio < 16x */
> > + 0, /* MCU = 0, Ratio > 16x */
> > +};
> > +
> > +static const struct qcom_jpeg_formats jpeg_encode_fmt[] = {
> > + {
> > + .fourcc = V4L2_PIX_FMT_GREY,
> > + .encode = JPEG_ENCODE_MONO,
> > + .memory = JPEG_MEM_FMT_MONO
> > + },
> > + {
> > + .fourcc = V4L2_PIX_FMT_JPEG,
> > + .encode = JPEG_ENCODE_H1V1,
> > + .memory = JPEG_MEM_FMT_PPLANAR
> > + },
> > + {
> > + .fourcc = V4L2_PIX_FMT_YUV422M,
> > + .encode = JPEG_ENCODE_H1V2,
> > + .memory = JPEG_MEM_FMT_PLANAR
> > + },
> > + {
> > + .fourcc = V4L2_PIX_FMT_YVU422M,
> > + .encode = JPEG_ENCODE_H1V2,
> > + .memory = JPEG_MEM_FMT_PLANAR
> > + },
> > + {
> > + .fourcc = V4L2_PIX_FMT_NV16M,
> > + .encode = JPEG_ENCODE_H2V1,
> > + .memory = JPEG_MEM_FMT_PPLANAR
> > + },
> > + {
> > + .fourcc = V4L2_PIX_FMT_NV61M,
> > + .encode = JPEG_ENCODE_H2V1,
> > + .memory = JPEG_MEM_FMT_PPLANAR
> > + },
> > + {
> > + .fourcc = V4L2_PIX_FMT_NV12M,
> > + .encode = JPEG_ENCODE_H2V2,
> > + .memory = JPEG_MEM_FMT_PPLANAR
> > + },
> > + {
> > + .fourcc = V4L2_PIX_FMT_NV21M,
> > + .encode = JPEG_ENCODE_H2V2,
> > + .memory = JPEG_MEM_FMT_PPLANAR
> > + }
> > +};
> > +
> > +static const struct qcom_jpeg_mal_boundary jpeg_mal_bounds[] = {
> > + { .bytes = 32, .boundary = JPEG_CFG_MAL_BOUND_32_BYTES },
> > + { .bytes = 64, .boundary = JPEG_CFG_MAL_BOUND_64_BYTES },
> > + { .bytes = 128, .boundary = JPEG_CFG_MAL_BOUND_128_BYTES },
> > + { .bytes = 256, .boundary = JPEG_CFG_MAL_BOUND_256_BYTES },
> > + { .bytes = 512, .boundary = JPEG_CFG_MAL_BOUND_512_BYTES },
> > + { .bytes = 1024, .boundary = JPEG_CFG_MAL_BOUND_1K_BYTES },
> > + { .bytes = 4096, .boundary = JPEG_CFG_MAL_BOUND_4K_BYTES }
> > +};
> > +
> > +static const struct qcom_jpeg_scale_blocks jpeg_mcu_blocks[] = {
> > + [JPEG_ENCODE_H1V1] = {
> > + .w_block = { JPEG_MCU_BLOCK_8, JPEG_MCU_BLOCK_8, JPEG_MCU_BLOCK_8 },
> > + .h_block = { JPEG_MCU_BLOCK_8, JPEG_MCU_BLOCK_8, JPEG_MCU_BLOCK_8 },
> > + },
> > + [JPEG_ENCODE_H1V2] = {
> > + .w_block = { JPEG_MCU_BLOCK_8, JPEG_MCU_BLOCK_8, JPEG_MCU_BLOCK_8 },
> > + .h_block = { JPEG_MCU_BLOCK_16, JPEG_MCU_BLOCK_8, JPEG_MCU_BLOCK_8 },
> > + },
> > + [JPEG_ENCODE_H2V1] = {
> > + .w_block = { JPEG_MCU_BLOCK_16, JPEG_MCU_BLOCK_8, JPEG_MCU_BLOCK_8 },
> > + .h_block = { JPEG_MCU_BLOCK_8, JPEG_MCU_BLOCK_8, JPEG_MCU_BLOCK_8 },
> > + },
> > + [JPEG_ENCODE_H2V2] = {
> > + .w_block = { JPEG_MCU_BLOCK_16, JPEG_MCU_BLOCK_8, JPEG_MCU_BLOCK_8 },
> > + .h_block = { JPEG_MCU_BLOCK_16, JPEG_MCU_BLOCK_8, JPEG_MCU_BLOCK_8 },
> > + },
> > + [JPEG_ENCODE_MONO] = {
> > + .w_block = { JPEG_MCU_BLOCK_8 },
> > + .h_block = { JPEG_MCU_BLOCK_8 }
> > + },
> > +};
> > +
> > +static inline int jpeg_get_memory_fmt(u32 fourcc)
> > +{
> > + u32 fi;
> > +
> > + for (fi = 0; fi < ARRAY_SIZE(jpeg_encode_fmt); fi++) {
> > + if (jpeg_encode_fmt[fi].fourcc == fourcc)
> > + return jpeg_encode_fmt[fi].memory;
> > + }
> > +
> > + return -EINVAL;
> > +}
> > +
> > +static inline int jpeg_get_encode_fmt(u32 fourcc)
> > +{
> > + u32 fi;
> > +
> > + for (fi = 0; fi < ARRAY_SIZE(jpeg_encode_fmt); fi++) {
> > + if (jpeg_encode_fmt[fi].fourcc == fourcc)
> > + return jpeg_encode_fmt[fi].encode;
> > + }
> > +
> > + return -EINVAL;
> > +}
> > +
> > +static inline int jpeg_get_mal_boundary(u32 width, const struct qcom_jpeg_mal_boundary *table,
> > + u32 count)
> > +{
> > + u32 bi;
> > +
> > + if (!table || !count)
> > + return -EINVAL;
> > +
> > + for (bi = 0; bi < count; bi++) {
> > + if (table[bi].bytes > width)
> > + break;
> > + }
> > +
> > + if (!bi)
> > + return table[0].boundary;
> > +
> > + return table[bi - 1].boundary;
> > +}
> > +
> > +static inline u8 jpeg_get_mcu_per_block(u32 src_size, u32 dst_size)
> > +{
> > + u8 h_rto;
> > +
> > + if (!src_size || !dst_size)
> > + return 0;
> > +
> > + /* Calculate scale factor */
> > + h_rto = max(src_size, dst_size) / min(src_size, dst_size);
> > +
> > + if (h_rto >= 0 && h_rto < 2)
> > + return jpeg_mcu_per_ratio[0];
> > + else if (h_rto >= 2 && h_rto < 4)
> > + return jpeg_mcu_per_ratio[1];
> > + else if (h_rto >= 4 && h_rto < 8)
> > + return jpeg_mcu_per_ratio[2];
> > + else if (h_rto >= 8 && h_rto < 16)
> > + return jpeg_mcu_per_ratio[3];
> > +
> > + return jpeg_mcu_per_ratio[4];
> > +}
> > +
> > +static inline int jpeg_get_mcu_geometry(enum qcom_jpeg_encode_fmt fmt, u32 width, u32 height,
> > + u32 *blk_w, u32 *blk_h, u32 *mcu_cols, u32 *mcu_rows)
> > +{
> > + const struct qcom_jpeg_scale_blocks *blks;
> > + u32 bw = 0, bh = 0;
> > + u8 pln;
> > +
> > + if (!width || !height)
> > + return -EINVAL;
> > +
> > + blks = &jpeg_mcu_blocks[fmt];
> > +
> > + for (pln = 0; pln < QCOM_JPEG_MAX_PLANES; pln++) {
> > + bw = max(bw, blks->w_block[pln]);
> > + bh = max(bh, blks->h_block[pln]);
> > + }
> > +
> > + if (!bw || !bh)
> > + return -EINVAL;
> > +
> > + if (blk_w)
> > + *blk_w = bw;
> > + if (blk_h)
> > + *blk_h = bh;
> > +
> > + if (mcu_cols)
> > + *mcu_cols = ALIGN(width, bw) / bw;
> > +
> > + if (mcu_rows)
> > + *mcu_rows = ALIGN(height, bh) / bh;
> > +
> > + return 0;
> > +}
> > +
> > +/* Integer part of scale */
> > +static inline s32 jpeg_calc_scale_int(u32 in_width, u32 out_width)
> > +{
> > + if (!out_width)
> > + return 0;
> > +
> > + return (s32)(in_width / out_width);
> > +}
> > +
> > +/* Fractional part od scale */
> > +static inline u32 jpeg_calc_scale_frac(u32 in_width, u32 out_width)
> > +{
> > + u32 remainder = in_width % out_width;
> > +
> > + if (!out_width)
> > + return 0;
> > +
> > + /* 64-bit to avoid overflow during shift */
> > + return (u32)(((u64)remainder << JPEG_Q5_21_SHIFT) / out_width);
> > +}
> > +
> > +static inline s32 jpeg_calc_q5_21(s32 int_part, u32 frac_part)
> > +{
> > + return ((s32)((u32)int_part << JPEG_Q5_21_SHIFT)) | (frac_part & ((1u << 21) - 1));
> > +}
> > +
> > +static inline u32 jpeg_io_read(struct qcom_jenc_dev *jenc, u32 offset)
> > +{
> > + u32 data;
> > +
> > + rmb(); /* Preventing concurrency read/write interference */
> > + data = readl_relaxed(jenc->jpeg_base + offset);
> > +
> > + return data;
> > +}
> > +
> > +static inline void jpeg_io_write(struct qcom_jenc_dev *jenc, u32 offset, u32 value)
> > +{
> > + wmb(); /* Preventing concurrency read/write interference */
> > + writel_relaxed(value, jenc->jpeg_base + offset);
> > +}
> > +
> > +/*
> > + * Runtime bitfield helpers (for non-constant masks).
> > + *
> > + * Requirements:
> > + * - mask must be non-zero
> > + * - mask must be contiguous (e.g. 0x7u << n)
> > + */
> > +
> > +static inline u32 jpeg_bits_get(u32 mask, u32 reg)
> > +{
> > + return (reg & mask) >> __builtin_ctz(mask);
> > +}
> > +
> > +static inline u32 jpeg_bits_set(u32 mask, u32 val)
> > +{
> > + return (val << __builtin_ctz(mask)) & mask;
> > +}
> > +
> > +static inline u32 jpeg_rd_bits(struct qcom_jenc_dev *jenc, u32 offs, enum qcom_jpeg_mask_id mid)
> > +{
> > + u32 reg = jpeg_io_read(jenc, offs);
> > + u32 mask = jenc->res->hw_mask[mid];
> > +
> > + return jpeg_bits_get(mask, reg);
> > +}
> > +
> > +/*
> > + * Read-modify-write (for R/W registers)
> > + */
> > +static inline void jpeg_rw_bits(struct qcom_jenc_dev *jenc, u32 offs, enum qcom_jpeg_mask_id mid,
> > + u32 val)
> > +{
> > + u32 reg = jpeg_io_read(jenc, offs);
> > + u32 mask = jenc->res->hw_mask[mid];
> > +
> > + reg &= ~mask;
> > + reg |= jpeg_bits_set(mask, val);
> > +
> > + jpeg_io_write(jenc, offs, reg);
> > +}
> > +
> > +/*
> > + * Write-only variant (for write only registers)
> > + */
> > +static inline void jpeg_wo_bits(struct qcom_jenc_dev *jenc, u32 offs, enum qcom_jpeg_mask_id mid,
> > + u32 val)
> > +{
> > + u32 mask = jenc->res->hw_mask[mid];
> > +
> > + jpeg_io_write(jenc, offs, jpeg_bits_set(mask, val));
> > +}
> > +
> > +static u8 jpeg_calculate_dqt(struct jenc_context *ectx, u8 dqt_value)
> > +{
> > + u64 ratio;
> > + u8 calc_val;
> > +
> > + ratio = (QCOM_JPEG_QUALITY_MAX - ectx->quality_requested) << JPEG_DQT_SHIFT;
> > + ratio = max_t(u64, 1, ratio);
> > + do_div(ratio, QCOM_JPEG_QUALITY_MID);
> > +
> > + calc_val = DIV64_U64_ROUND_CLOSEST(ratio * dqt_value, 1LU << JPEG_DQT_SHIFT);
> > +
> > + return max_t(u8, 1, calc_val);
> > +}
> > +
> > +static void jpeg_apply_dmi_table(struct jenc_context *ectx)
> > +{
> > + const struct qcom_jpeg_reg_offs *offs = ectx->jenc->res->hw_offs;
> > + u32 pcfg = { 0x00000011 };
> > + u32 addr = { 0x00000000 };
> > + u8 *base;
> > + u8 dqt_val, idx;
> > + u32 reg_val;
> > + int i;
> > +
> > + /* DMI upload start sequence */
> > + jpeg_io_write(ectx->jenc, offs->dmi_addr, addr);
> > + jpeg_io_write(ectx->jenc, offs->dmi_cfg, pcfg);
> > +
> > + /* DMI Luma upload */
> > + base = &ectx->hdr_cache.data[ectx->hdr_cache.dqt_one_offs + 1];
> > + for (i = 0; i < ARRAY_SIZE(t81k1_dct_luma_table); i++) {
> > + dqt_val = jpeg_calculate_dqt(ectx, t81k1_dct_luma_table[i]);
> > + /*
> > + * Store the luma to be propagated to the JPEG header at a later stage.
> > + * If offs == 0, no DQT is present in the header and the write
> > + * should be skipped.
> > + */
> > + if (ectx->hdr_cache.dqt_one_offs) {
> > + idx = t81a6_dct_zig_zag_table[i];
> > + /* Perform reordering to arrange transformed DQT in a zigzag pattern */
> > + base[idx] = dqt_val;
> > + }
> > + /* The calculated DQT value cannot be less than 1 */
> > + reg_val = div_u64(U16_MAX + 1U, dqt_val);
> > + jpeg_io_write(ectx->jenc, offs->dmi_data, clamp_t(u32, reg_val, 0, U16_MAX));
> > + }
> > +
> > + /* DMI Chroma upload */
> > + base = &ectx->hdr_cache.data[ectx->hdr_cache.dqt_two_offs + 1];
> > + for (i = 0; i < ARRAY_SIZE(t81k2_dct_chroma_table); i++) {
> > + dqt_val = jpeg_calculate_dqt(ectx, t81k2_dct_chroma_table[i]);
> > + /*
> > + * Store the chroma to be propagated to the JPEG header at a later stage.
> > + * If offs == 0, no DQT is present in the header and the write
> > + * should be skipped.
> > + */
> > + if (ectx->hdr_cache.dqt_two_offs) {
> > + idx = t81a6_dct_zig_zag_table[i];
> > + /* Perform reordering to arrange transformed DQT in a zigzag pattern */
> > + base[idx] = dqt_val;
> > + }
> > + /* The calculated DQT value cannot be less than 1 */
> > + reg_val = div_u64(U16_MAX + 1U, dqt_val);
> > + jpeg_io_write(ectx->jenc, offs->dmi_data, clamp_t(u32, reg_val, 0, U16_MAX));
> > + }
> > +
> > + /* DMI upload end sequence */
> > + jpeg_io_write(ectx->jenc, offs->dmi_cfg, addr);
> > +
> > + ectx->quality_programmed = ectx->quality_requested;
> > +
> > + dev_dbg(ectx->dev, "%s: ctx=%p quality_programmed=%d\n", __func__, ectx,
> > + ectx->quality_programmed);
> > +}
> > +
> > +static void jpeg_cpu_access(struct device *dev, struct qcom_jpeg_buff *frame,
> > + enum dma_data_direction direction)
> > +{
> > + u8 pln;
> > +
> > + for (pln = 0; pln < QCOM_JPEG_MAX_PLANES; pln++) {
> > + struct sg_table *sgt = frame->plns[pln].sgt;
> > +
> > + if (!frame->plns[pln].dma || !sgt)
> > + break;
> > +
> > + dma_sync_sg_for_cpu(dev, sgt->sgl, sgt->orig_nents, direction);
> > + }
> > +}
> > +
> > +static void jpeg_dev_access(struct device *dev, struct qcom_jpeg_buff *frame,
> > + enum dma_data_direction direction)
> > +{
> > + u8 pln;
> > +
> > + for (pln = 0; pln < QCOM_JPEG_MAX_PLANES; pln++) {
> > + struct sg_table *sgt = frame->plns[pln].sgt;
> > +
> > + if (!frame->plns[pln].dma || !sgt)
> > + continue;
> > +
> > + dma_sync_sg_for_device(dev, sgt->sgl, sgt->orig_nents, direction);
> > + }
> > +}
> > +
> > +static int jpeg_init(struct qcom_jenc_dev *jenc)
> > +{
> > + const struct qcom_jpeg_reg_offs *offs;
> > + void __iomem *mem_base;
> > + unsigned long rtime;
> > + u32 hw_ver;
> > +
> > + if (!jenc || !jenc->dev || !jenc->jpeg_base || !jenc->res->hw_offs) {
>
> How can jenc be NULL here? Or any other field?
>
> > + pr_err("encoder HW init failed\n");
>
> dev_err.
>
> > + return -EINVAL;
> > + }
> > +
> > + offs = jenc->res->hw_offs;
> > + mem_base = jenc->jpeg_base;
> > +
> > + jpeg_wo_bits(jenc, offs->int_clr, JMSK_IRQ_CLEAR_ALL, JPEG_U32_SET);
> > + jpeg_rw_bits(jenc, offs->int_mask, JMSK_IRQ_STATUS_RESET_ACK, JPEG_U32_SET);
> > +
> > + reinit_completion(&jenc->reset_complete);
> > +
> > + jpeg_wo_bits(jenc, offs->reset_cmd, JMSK_RST_CMD_COMMON, JPEG_U32_SET);
> > +
> > + rtime = wait_for_completion_timeout(&jenc->reset_complete,
> > + msecs_to_jiffies(JPEG_RESET_TIMEOUT_MS));
> > + if (!rtime) {
> > + dev_err(jenc->dev, "encoder HW reset timeout\n");
> > + disable_irq(jenc->irq);
> > + return -ETIME;
> > + }
> > +
> > + hw_ver = jpeg_io_read(jenc, offs->hw_version);
> > + dev_info(jenc->dev, "JPEG HW encoder version %d.%d.%d\n",
>
> No useless log spamming.
>
> > + jpeg_bits_get(jenc->res->hw_mask[JMSK_HW_VER_MAJOR], hw_ver),
> > + jpeg_bits_get(jenc->res->hw_mask[JMSK_HW_VER_MINOR], hw_ver),
> > + jpeg_bits_get(jenc->res->hw_mask[JMSK_HW_VER_STEP], hw_ver));
> > +
> > + jpeg_wo_bits(jenc, offs->hw_cmd, JMSK_CMD_CLR_RD_PLNS_QUEUE, JPEG_U32_SET);
> > + jpeg_wo_bits(jenc, offs->hw_cmd, JMSK_CMD_CLR_RD_PLNS_QUEUE, JPEG_U32_CLR);
> > +
> > + jpeg_wo_bits(jenc, offs->hw_cmd, JMSK_CMD_CLR_WR_PLNS_QUEUE, JPEG_U32_SET);
> > + jpeg_wo_bits(jenc, offs->hw_cmd, JMSK_CMD_CLR_WR_PLNS_QUEUE, JPEG_U32_CLR);
> > +
> > + jpeg_wo_bits(jenc, offs->int_clr, JMSK_IRQ_CLEAR_ALL, JPEG_U32_SET);
> > + jpeg_rw_bits(jenc, offs->int_mask, JMSK_IRQ_ENABLE_ALL, JPEG_U32_SET);
> > +
> > + return 0;
> > +}
> > +
> > +static int jpeg_exec(struct qcom_jenc_dev *jenc)
> > +{
> > + const struct qcom_jpeg_reg_offs *offs = jenc->res->hw_offs;
> > +
> > + jpeg_wo_bits(jenc, offs->hw_cmd, JMSK_CMD_HW_START, 1);
> > +
> > + return 0;
> > +}
> > +
> > +static void jpeg_stop(struct qcom_jenc_dev *jenc)
> > +{
> > + const struct qcom_jpeg_reg_offs *offs = jenc->res->hw_offs;
> > +
> > + jpeg_wo_bits(jenc, offs->hw_cmd, JMSK_CMD_HW_START, 0);
> > +
> > + jpeg_wo_bits(jenc, offs->hw_cmd, JMSK_CMD_CLR_RD_PLNS_QUEUE, JPEG_U32_SET);
> > + jpeg_wo_bits(jenc, offs->hw_cmd, JMSK_CMD_CLR_RD_PLNS_QUEUE, JPEG_U32_CLR);
> > +
> > + jpeg_wo_bits(jenc, offs->hw_cmd, JMSK_CMD_CLR_WR_PLNS_QUEUE, JPEG_U32_SET);
> > + jpeg_wo_bits(jenc, offs->hw_cmd, JMSK_CMD_CLR_WR_PLNS_QUEUE, JPEG_U32_CLR);
> > +
> > + jpeg_wo_bits(jenc, offs->int_clr, JMSK_IRQ_CLEAR_ALL, JPEG_U32_SET);
> > + jpeg_rw_bits(jenc, offs->int_mask, JMSK_IRQ_ENABLE_ALL, JPEG_U32_SET);
> > +}
> > +
> > +static int jpeg_deinit(struct qcom_jenc_dev *jenc)
> > +{
> > + const struct qcom_jpeg_reg_offs *offs = jenc->res->hw_offs;
> > + unsigned long rtime;
> > +
> > + jpeg_wo_bits(jenc, offs->int_clr, JMSK_IRQ_CLEAR_ALL, JPEG_U32_SET);
> > + jpeg_rw_bits(jenc, offs->int_mask, JMSK_IRQ_STATUS_STOP_ACK, JPEG_U32_SET);
> > +
> > + jpeg_wo_bits(jenc, offs->hw_cmd, JMSK_CMD_HW_STOP, 1);
> > +
> > + reinit_completion(&jenc->stop_complete);
> > + rtime = wait_for_completion_timeout(&jenc->stop_complete,
> > + msecs_to_jiffies(JPEG_STOP_TIMEOUT_MS));
> > + if (!rtime) {
> > + dev_err(jenc->dev, "encoder HW stop timeout\n");
> > + return -ETIME;
> > + }
> > +
> > + jpeg_rw_bits(jenc, offs->int_mask, JMSK_IRQ_DISABLE_ALL, JPEG_U32_CLR);
> > + jpeg_rw_bits(jenc, offs->int_clr, JMSK_IRQ_CLEAR_ALL, JPEG_U32_SET);
> > +
> > + return 0;
> > +}
> > +
> > +static int jpeg_apply_fe_addr(struct jenc_context *ectx, struct qcom_jenc_queue *q,
> > + struct vb2_buffer *vb)
> > +{
> > + struct qcom_jenc_dev *jenc = ectx->jenc;
> > + const struct qcom_jpeg_reg_offs *offs = jenc->res->hw_offs;
> > + struct qcom_jpeg_buff *frame = &q->buff[vb->index];
> > + struct v4l2_pix_format_mplane *fmt = &q->vf;
> > + u8 pln = 0;
> > +
> > + if (WARN_ON_ONCE(!frame->plns[pln].dma))
> > + return -EPERM;
> > +
> > + for (pln = 0; pln < fmt->num_planes; pln++) {
> > + if (!frame->plns[pln].sgt || !frame->plns[pln].sgt->sgl)
> > + break;
> > +
> > + jpeg_io_write(jenc, offs->fe.pntr[pln], frame->plns[pln].dma);
> > + jpeg_io_write(jenc, offs->fe.offs[pln], 0);
> > +
> > + dev_dbg(jenc->dev, "%s: pln=%d addr=0x%llx idx:%d\n", __func__,
> > + pln, frame->plns[pln].dma, vb->index);
> > + }
> > +
> > + q->buff_id = vb->index;
> > +
> > + jpeg_dev_access(jenc->dev, frame, DMA_TO_DEVICE);
> > +
> > + return 0;
> > +}
> > +
> > +static int jpeg_store_fe_next(struct jenc_context *ectx, struct vb2_buffer *vb2)
> > +{
> > + struct qcom_jenc_queue *q = &ectx->bufq[TYPE2QID(vb2->type)];
> > + struct qcom_jpeg_buff *buff = &q->buff[vb2->index];
> > + u8 pln = 0;
> > +
> > + buff->plns[pln].sgt = vb2_dma_sg_plane_desc(vb2, pln);
> > + if (WARN_ON_ONCE(!buff->plns[pln].sgt))
> > + return -EINVAL;
> > +
> > + if (WARN_ON_ONCE(!buff->plns[pln].sgt->sgl))
> > + return -EINVAL;
> > +
> > + buff->plns[pln].dma = sg_dma_address(buff->plns[pln].sgt->sgl);
> > + if (WARN_ON_ONCE(!buff->plns[pln].dma))
> > + return -EINVAL;
> > +
> > + buff->plns[pln].size = vb2_plane_size(vb2, pln);
> > + if (WARN_ON_ONCE(!buff->plns[pln].size))
> > + return -EINVAL;
> > +
> > + for (pln = 1; pln < q->vf.num_planes; pln++) {
> > + buff->plns[pln].sgt = vb2_dma_sg_plane_desc(vb2, pln);
> > + if (WARN_ON_ONCE(!buff->plns[pln].sgt || !buff->plns[pln].sgt->sgl))
> > + return -EINVAL;
> > +
> > + buff->plns[pln].dma = sg_dma_address(buff->plns[pln].sgt->sgl);
> > + if (WARN_ON_ONCE(!buff->plns[pln].dma))
> > + return -EINVAL;
> > +
> > + buff->plns[pln].size = vb2_plane_size(vb2, pln);
> > + if (WARN_ON_ONCE(!buff->plns[pln].size))
> > + return -EINVAL;
> > + }
> > +
> > + return 0;
> > +}
> > +
> > +static int jpeg_setup_fe_size(struct jenc_context *ectx, struct qcom_jenc_queue *q)
> > +{
> > + struct qcom_jenc_dev *jenc = ectx->jenc;
> > + struct v4l2_pix_format_mplane *sfmt = &q->vf;
> > + const struct qcom_jpeg_reg_offs *offs = jenc->res->hw_offs;
> > + u8 pln;
> > +
> > + for (pln = 0; pln < QCOM_JPEG_MAX_PLANES; pln++) {
> > + jpeg_rw_bits(jenc, offs->fe.bsize[pln], JMSK_PLNS_RD_BUF_SIZE_WIDTH, 0);
> > + jpeg_rw_bits(jenc, offs->fe.bsize[pln], JMSK_PLNS_RD_BUF_SIZE_HEIGHT, 0);
> > + jpeg_rw_bits(jenc, offs->fe.bsize[pln], JMSK_PLNS_RD_STRIDE, 0);
> > + }
> > +
> > + for (pln = 0; pln < sfmt->num_planes; pln++) {
> > + jpeg_rw_bits(jenc, offs->fe.bsize[pln], JMSK_PLNS_RD_BUF_SIZE_WIDTH,
> > + sfmt->width - 1);
> > + jpeg_rw_bits(jenc, offs->fe.bsize[pln], JMSK_PLNS_RD_BUF_SIZE_HEIGHT,
> > + sfmt->height - 1);
> > + jpeg_rw_bits(jenc, offs->fe.stride[pln], JMSK_PLNS_RD_STRIDE,
> > + sfmt->plane_fmt[pln].bytesperline);
> > +
> > + dev_dbg(ectx->dev, "%s: ctx=%p pln=%d width=%d height=%d stride=%d\n",
> > + __func__, ectx, pln,
> > + jpeg_rd_bits(jenc, offs->fe.bsize[pln], JMSK_PLNS_RD_BUF_SIZE_WIDTH),
> > + jpeg_rd_bits(jenc, offs->fe.bsize[pln], JMSK_PLNS_RD_BUF_SIZE_HEIGHT),
> > + jpeg_rd_bits(jenc, offs->fe.stride[pln], JMSK_PLNS_RD_STRIDE));
> > + }
> > +
> > + return 0;
> > +}
> > +
> > +static int jpeg_setup_fe_hinit(struct jenc_context *ectx, struct qcom_jenc_queue *q)
> > +{
> > + struct qcom_jenc_dev *jenc = ectx->jenc;
> > + struct v4l2_pix_format_mplane *sfmt = &q->vf;
> > + const struct qcom_jpeg_reg_offs *offs = jenc->res->hw_offs;
> > + u8 pln;
> > +
> > + if (!sfmt->width) {
> > + dev_err(ectx->dev, "%s: invalid source width=%d\n", __func__, sfmt->width);
> > + return -EINVAL;
> > + }
> > +
> > + for (pln = 0; pln < QCOM_JPEG_MAX_PLANES; pln++)
> > + jpeg_io_write(jenc, offs->fe.hinit[pln], 0);
> > +
> > + return 0;
> > +}
> > +
> > +static int jpeg_setup_fe_vinit(struct jenc_context *ectx, struct qcom_jenc_queue *q)
> > +{
> > + struct qcom_jenc_dev *jenc = ectx->jenc;
> > + struct v4l2_pix_format_mplane *sfmt = &q->vf;
> > + const struct qcom_jpeg_reg_offs *offs = jenc->res->hw_offs;
> > + u8 pln;
> > +
> > + if (!sfmt->height) {
> > + dev_err(ectx->dev, "%s: invalid source height=%d\n", __func__, sfmt->height);
> > + return -EINVAL;
> > + }
> > +
> > + for (pln = 0; pln < QCOM_JPEG_MAX_PLANES; pln++)
> > + jpeg_io_write(jenc, offs->fe.vinit[pln], 0);
> > +
> > + return 0;
> > +}
> > +
> > +static int jpeg_setup_fe_params(struct jenc_context *ectx, struct qcom_jenc_queue *q)
> > +{
> > + struct qcom_jenc_dev *jenc = ectx->jenc;
> > + struct v4l2_pix_format_mplane *sfmt = &q->vf;
> > + struct v4l2_pix_format_mplane *dfmt = &ectx->bufq[JENC_DST_QUEUE].vf;
> > + const struct qcom_jpeg_reg_offs *offs = jenc->res->hw_offs;
> > + u8 expected_planes, pln;
> > + int rval;
> > +
> > + jpeg_rw_bits(jenc, offs->fe_cfg, JMSK_FE_CFG_MAL_EN, 1);
> > + jpeg_rw_bits(jenc, offs->fe_cfg, JMSK_FE_CFG_BOTTOM_VPAD_EN, 1);
> > +
> > + rval = jpeg_get_memory_fmt(sfmt->pixelformat);
> > + if (rval < 0) {
> > + dev_err(ectx->dev, "%s: invalid memory format for v4l2 format:0x%x\n",
> > + __func__, sfmt->pixelformat);
> > + return -EINVAL;
> > + }
> > +
> > + switch (rval) {
> > + case JPEG_MEM_FMT_MONO:
> > + expected_planes = 1;
> > + break;
> > + case JPEG_MEM_FMT_PPLANAR:
> > + expected_planes = 2;
> > + break;
> > + case JPEG_MEM_FMT_PLANAR:
> > + expected_planes = 3;
> > + break;
> > + default:
> > + return -EINVAL;
> > + }
> > +
> > + if (sfmt->num_planes != expected_planes) {
> > + dev_err(ectx->dev, "%s: plane mismatch fmt=%u expected=%u got=%u\n",
> > + __func__, rval, expected_planes, sfmt->num_planes);
> > + return -EINVAL;
> > + }
> > +
> > + jpeg_rw_bits(jenc, offs->fe_cfg, JMSK_FE_CFG_MEMORY_FORMAT, rval);
> > +
> > + jpeg_rw_bits(jenc, offs->fe_cfg, JMSK_FE_CFG_PLN0_EN, 0);
> > + jpeg_rw_bits(jenc, offs->fe_cfg, JMSK_FE_CFG_PLN1_EN, 0);
> > + jpeg_rw_bits(jenc, offs->fe_cfg, JMSK_FE_CFG_PLN2_EN, 0);
> > +
> > + if (sfmt->width == dfmt->width && sfmt->height == dfmt->height) {
> > + /* No scaling */
> > + jpeg_rw_bits(jenc, offs->fe_cfg, JMSK_FE_CFG_SIXTEEN_MCU_EN, 1);
> > + jpeg_rw_bits(jenc, offs->fe_cfg, JMSK_FE_CFG_MCUS_PER_BLOCK, 0);
> > + } else {
> > + u8 mcu_per_blks;
> > +
> > + /* Scaling */
> > + jpeg_rw_bits(jenc, offs->fe_cfg, JMSK_FE_CFG_SIXTEEN_MCU_EN, 0);
> > + /* get value according to image width */
> > + mcu_per_blks = jpeg_get_mcu_per_block(sfmt->width, dfmt->width);
> > + /* get value according to image height assign the bigger */
> > + mcu_per_blks = max_t(u8, mcu_per_blks,
> > + jpeg_get_mcu_per_block(sfmt->height, dfmt->height));
> > +
> > + jpeg_rw_bits(jenc, offs->fe_cfg, JMSK_FE_CFG_MCUS_PER_BLOCK, mcu_per_blks);
> > + }
> > +
> > + dev_dbg(ectx->dev, "%s: sixteen MCU enabled=%d, %d MCU per blocks\n", __func__,
> > + jpeg_rd_bits(jenc, offs->fe_cfg, JMSK_FE_CFG_SIXTEEN_MCU_EN),
> > + jpeg_rd_bits(jenc, offs->fe_cfg, JMSK_FE_CFG_MCUS_PER_BLOCK));
> > +
> > + rval = jpeg_get_mal_boundary(sfmt->width, jpeg_mal_bounds, ARRAY_SIZE(jpeg_mal_bounds));
> > + if (rval < 0) {
> > + dev_err(ectx->dev, "%s: failed to get FE mal boundary width=%u\n", __func__,
> > + sfmt->width);
> > + return -EINVAL;
> > + }
> > + jpeg_rw_bits(jenc, offs->fe_cfg, JMSK_FE_CFG_MAL_BOUNDARY, rval);
> > +
> > + dev_dbg(ectx->dev, "%s: optimal FE mal boundary=%d\n", __func__,
> > + jpeg_rd_bits(jenc, offs->fe_cfg, JMSK_FE_CFG_MAL_BOUNDARY));
> > +
> > + rval = jpeg_get_encode_fmt(sfmt->pixelformat);
> > + if (rval < 0) {
> > + dev_err(ectx->dev, "%s: unsupported encode format fourcc=0x%x\n",
> > + __func__, sfmt->pixelformat);
> > + return -EINVAL;
> > + }
> > +
> > + switch (rval) {
> > + case JPEG_ENCODE_MONO:
> > + case JPEG_ENCODE_H1V1:
> > + case JPEG_ENCODE_H2V1:
> > + jpeg_rw_bits(jenc, offs->fe.vbpad_cfg, JMSK_FE_VBPAD_CFG_BLOCK_ROW,
> > + DIV_ROUND_UP(sfmt->height, JPEG_MCU_BLOCK_8));
> > + break;
> > + case JPEG_ENCODE_H1V2:
> > + case JPEG_ENCODE_H2V2:
> > + jpeg_rw_bits(jenc, offs->fe.vbpad_cfg, JMSK_FE_VBPAD_CFG_BLOCK_ROW,
> > + DIV_ROUND_UP(sfmt->height, JPEG_MCU_BLOCK_16));
> > + break;
> > + default:
> > + dev_err(ectx->dev, "%s: unsupported encode format fourcc=0x%x\n", __func__, rval);
> > + return -EINVAL;
> > + }
> > +
> > + if (sfmt->pixelformat == V4L2_PIX_FMT_NV21 || sfmt->pixelformat == V4L2_PIX_FMT_NV61)
> > + jpeg_rw_bits(jenc, offs->fe_cfg, JMSK_FE_CFG_CBCR_ORDER, 1);
> > + else
> > + jpeg_rw_bits(jenc, offs->fe_cfg, JMSK_FE_CFG_CBCR_ORDER, 0);
> > +
> > + for (pln = 0; pln < sfmt->num_planes; pln++) {
> > + if (sfmt->width && sfmt->height) {
> > + switch (pln) {
> > + case 0:
> > + jpeg_rw_bits(jenc, offs->fe_cfg, JMSK_FE_CFG_PLN0_EN, 1);
> > + break;
> > + case 1:
> > + jpeg_rw_bits(jenc, offs->fe_cfg, JMSK_FE_CFG_PLN1_EN, 1);
> > + break;
> > + case 2:
> > + jpeg_rw_bits(jenc, offs->fe_cfg, JMSK_FE_CFG_PLN2_EN, 1);
> > + break;
> > + }
> > + }
> > + }
> > +
> > + jpeg_rw_bits(jenc, offs->core_cfg, JMSK_CORE_CFG_FE_ENABLE, 1);
> > +
> > + return 0;
> > +}
> > +
> > +static int jpeg_setup_fe(struct jenc_context *ectx, struct qcom_jenc_queue *q)
> > +{
> > + int rc;
> > +
> > + rc = jpeg_setup_fe_size(ectx, q);
> > + if (rc)
> > + return rc;
> > +
> > + rc = jpeg_setup_fe_hinit(ectx, q);
> > + if (rc)
> > + return rc;
> > +
> > + rc = jpeg_setup_fe_vinit(ectx, q);
> > + if (rc)
> > + return rc;
> > +
> > + rc = jpeg_setup_fe_params(ectx, q);
> > + if (rc)
> > + return rc;
> > +
> > + return 0;
> > +}
> > +
> > +static int jpeg_apply_we_addr(struct jenc_context *ectx, struct qcom_jenc_queue *q,
> > + struct vb2_buffer *vb)
> > +{
> > + struct qcom_jenc_dev *jenc = ectx->jenc;
> > + const struct qcom_jpeg_reg_offs *offs = jenc->res->hw_offs;
> > + struct qcom_jpeg_buff *frame = &q->buff[vb->index];
> > + u8 pln = 0;
> > +
> > + if (WARN_ON_ONCE(!frame->plns[pln].dma))
> > + return -EPERM;
> > +
> > + jpeg_io_write(jenc, offs->we.pntr[pln], frame->plns[pln].dma);
> > +
> > + dev_dbg(jenc->dev, "%s: pln=%d addr=0x%llx idx:%d\n", __func__,
> > + pln, frame->plns[pln].dma, vb->index);
> > +
> > + q->buff_id = vb->index;
> > +
> > + return 0;
> > +}
> > +
> > +static int jpeg_store_we_next(struct jenc_context *ectx, struct vb2_buffer *vb2)
> > +{
> > + struct qcom_jenc_dev *jenc = ectx->jenc;
> > + struct qcom_jenc_queue *q = &ectx->bufq[TYPE2QID(vb2->type)];
> > + struct qcom_jpeg_buff *frame = &q->buff[vb2->index];
> > + struct qc_jfif *mptr;
> > + struct sg_table *sgt;
> > + dma_addr_t dma;
> > +
> > + sgt = vb2_dma_sg_plane_desc(vb2, 0);
> > + if (WARN_ON_ONCE(!sgt || !sgt->sgl))
> > + return -EINVAL;
> > +
> > + dma = sg_dma_address(sgt->sgl);
> > + if (WARN_ON_ONCE(!dma))
> > + return -EINVAL;
> > +
> > + mptr = vb2_plane_vaddr(vb2, 0);
> > + if (WARN_ON_ONCE(!mptr))
> > + return -EINVAL;
> > +
> > + mutex_lock(&ectx->quality_mutex);
> > + if (ectx->quality_programmed != ectx->quality_requested)
> > + jpeg_apply_dmi_table(ectx);
> > + mutex_unlock(&ectx->quality_mutex);
> > +
> > + dma += qcom_jenc_header_emit(&ectx->hdr_cache, (void *)mptr,
> > + min_t(size_t, vb2->planes[0].length, ectx->hdr_cache.size),
> > + q->vf.width, q->vf.height);
> > + qcom_jenc_dqts_emit(&ectx->hdr_cache, (void *)mptr);
> > +
> > + frame->plns[0].sgt = sgt;
> > + frame->plns[0].dma = dma;
> > + frame->plns[0].size = vb2_plane_size(vb2, 0);
> > +
> > + jpeg_dev_access(jenc->dev, frame, DMA_TO_DEVICE);
> > +
> > + return 0;
> > +}
> > +
> > +static int jpeg_setup_we_size(struct jenc_context *ectx, struct qcom_jenc_queue *q)
> > +{
> > + struct qcom_jenc_dev *jenc = ectx->jenc;
> > + const struct qcom_jpeg_reg_offs *offs = jenc->res->hw_offs;
> > + struct v4l2_pix_format_mplane *dfmt = &q->vf;
> > + u8 pln;
> > +
> > + if (!dfmt->plane_fmt[0].sizeimage) {
> > + dev_err(ectx->dev, "%s: invalid destination buffer size=0\n", __func__);
> > + return -EINVAL;
> > + }
> > +
> > + for (pln = 0; pln < QCOM_JPEG_MAX_PLANES; pln++)
> > + jpeg_rw_bits(jenc, offs->we.stride[pln], JMSK_PLNS_WR_STRIDE, 0);
> > +
> > + jpeg_io_write(jenc, offs->we.bsize[0], dfmt->plane_fmt[0].sizeimage);
> > +
> > + dev_dbg(ectx->dev, "%s: ctx=%p size=%u\n", __func__,
> > + ectx, dfmt->plane_fmt[0].sizeimage);
> > +
> > + return 0;
> > +}
> > +
> > +static int jpeg_setup_we_hinit(struct jenc_context *ectx, struct qcom_jenc_queue *q)
> > +{
> > + struct qcom_jenc_dev *jenc = ectx->jenc;
> > + const struct qcom_jpeg_reg_offs *offs = jenc->res->hw_offs;
> > + struct v4l2_pix_format_mplane *dfmt = &q->vf;
> > + u8 pln;
> > +
> > + if (!dfmt->width) {
> > + dev_err(ectx->dev, "%s: invalid destination width=%d\n", __func__, dfmt->width);
> > + return -EINVAL;
> > + }
> > +
> > + for (pln = 0; pln < QCOM_JPEG_MAX_PLANES; pln++) {
> > + jpeg_rw_bits(jenc, offs->we.hinit[pln], JMSK_PLNS_WR_HINIT, 0);
> > + jpeg_rw_bits(jenc, offs->we.hstep[pln], JMSK_PLNS_WR_HSTEP, 0);
> > + }
> > +
> > + jpeg_rw_bits(jenc, offs->we.hstep[0], JMSK_PLNS_WR_HSTEP, dfmt->width);
> > +
> > + dev_dbg(ectx->dev, "%s: ctx=%p hstep=%u\n", __func__, ectx,
> > + jpeg_rd_bits(jenc, offs->we.hstep[0], JMSK_PLNS_WR_HSTEP));
> > +
> > + return 0;
> > +}
> > +
> > +static int jpeg_setup_we_vinit(struct jenc_context *ectx, struct qcom_jenc_queue *q)
> > +{
> > + struct qcom_jenc_dev *jenc = ectx->jenc;
> > + const struct qcom_jpeg_reg_offs *offs = jenc->res->hw_offs;
> > + struct v4l2_pix_format_mplane *dfmt = &q->vf;
> > + u8 pln;
> > +
> > + if (!dfmt->height) {
> > + dev_err(ectx->dev, "%s: invalid destination height=%d\n", __func__, dfmt->height);
> > + return -EINVAL;
> > + }
> > +
> > + for (pln = 0; pln < QCOM_JPEG_MAX_PLANES; pln++) {
> > + jpeg_rw_bits(jenc, offs->we.vinit[pln], JMSK_PLNS_WR_VINIT, 0);
> > + jpeg_rw_bits(jenc, offs->we.vstep[pln], JMSK_PLNS_WR_VSTEP, 0);
> > + }
> > +
> > + jpeg_rw_bits(jenc, offs->we.vstep[0], JMSK_PLNS_WR_VSTEP, dfmt->height);
> > +
> > + dev_dbg(ectx->dev, "%s: ctx=%p vstep=%u\n", __func__, ectx,
> > + jpeg_rd_bits(jenc, offs->we.vstep[0], JMSK_PLNS_WR_VSTEP));
> > +
> > + return 0;
> > +}
> > +
> > +static int jpeg_setup_we_params(struct jenc_context *ectx, struct qcom_jenc_queue *q)
> > +{
> > + struct qcom_jenc_dev *jenc = ectx->jenc;
> > + const struct qcom_jpeg_reg_offs *offs = jenc->res->hw_offs;
> > + struct v4l2_pix_format_mplane *dfmt = &q->vf;
> > + u32 blk_w, blk_h, mcu_cols, mcu_rows;
> > + int rval;
> > +
> > + rval = jpeg_get_memory_fmt(dfmt->pixelformat);
> > + if (rval < 0) {
> > + dev_err(ectx->dev, "%s: invalid memory format for v4l2 format:0x%x\n",
> > + __func__, dfmt->pixelformat);
> > + return -EINVAL;
> > + }
> > + jpeg_rw_bits(jenc, offs->we_cfg, JMSK_WE_CFG_MEMORY_FORMAT, rval);
> > +
> > + rval = jpeg_get_mal_boundary(dfmt->width, jpeg_mal_bounds, ARRAY_SIZE(jpeg_mal_bounds));
> > + if (rval < 0) {
> > + dev_err(ectx->dev, "%s: failed to get WE mal boundary width=%u\n",
> > + __func__, dfmt->width);
> > + return -EINVAL;
> > + }
> > + jpeg_rw_bits(jenc, offs->we_cfg, JMSK_WE_CFG_MAL_BOUNDARY, rval);
> > +
> > + dev_dbg(ectx->dev, "%s: optimal WE mal boundary=%d\n", __func__,
> > + jpeg_rd_bits(jenc, offs->we_cfg, JMSK_WE_CFG_MAL_BOUNDARY));
> > +
> > + rval = jpeg_get_encode_fmt(dfmt->pixelformat);
> > + if (rval < 0) {
> > + dev_err(ectx->dev, "%s: unsupported encode format fourcc=0x%x\n",
> > + __func__, dfmt->pixelformat);
> > + return rval;
> > + }
> > +
> > + rval = jpeg_get_mcu_geometry(rval, dfmt->width, dfmt->height, &blk_w, &blk_h,
> > + &mcu_cols, &mcu_rows);
> > + if (rval < 0) {
> > + dev_err(ectx->dev, "%s: invalid MCU geometry mcu_cols=%d mcu_rows=%d\n",
> > + __func__, mcu_cols, mcu_rows);
> > + return rval;
> > + }
> > +
> > + dev_dbg(ectx->dev, "%s blk_w=%u blk_h=%u cols=%u rows=%u\n", __func__,
> > + blk_w, blk_h, mcu_cols, mcu_rows);
> > +
> > + jpeg_rw_bits(jenc, offs->we.blocks[0], JMSK_PLNS_WR_BLOCK_CFG_PER_RAW, mcu_rows - 1);
> > + jpeg_rw_bits(jenc, offs->we.blocks[0], JMSK_PLNS_WR_BLOCK_CFG_PER_COL, mcu_cols - 1);
> > +
> > + jpeg_rw_bits(jenc, offs->we_cfg, JMSK_WE_CFG_CBCR_ORDER, 1);
> > + jpeg_rw_bits(jenc, offs->we_cfg, JMSK_WE_CFG_MAL_EN, 1);
> > + jpeg_rw_bits(jenc, offs->we_cfg, JMSK_WE_CFG_POP_BUFF_ON_EOS, 1);
> > + jpeg_rw_bits(jenc, offs->we_cfg, JMSK_WE_CFG_PLN0_EN, 1);
> > +
> > + jpeg_rw_bits(jenc, offs->core_cfg, JMSK_CORE_CFG_MODE, 1);
> > + jpeg_rw_bits(jenc, offs->core_cfg, JMSK_CORE_CFG_WE_ENABLE, 1);
> > +
> > + return 0;
> > +}
> > +
> > +static int jpeg_setup_we(struct jenc_context *ectx, struct qcom_jenc_queue *q)
> > +{
> > + int rc;
> > +
> > + rc = jpeg_setup_we_size(ectx, q);
> > + if (rc)
> > + return rc;
> > +
> > + rc = jpeg_setup_we_hinit(ectx, q);
> > + if (rc)
> > + return rc;
> > +
> > + rc = jpeg_setup_we_vinit(ectx, q);
> > + if (rc)
> > + return rc;
> > +
> > + return jpeg_setup_we_params(ectx, q);
> > +}
> > +
> > +static int jpeg_setup_scale(struct jenc_context *ectx)
> > +{
> > + struct qcom_jenc_dev *jenc = ectx->jenc;
> > + const struct qcom_jpeg_reg_offs *offs = jenc->res->hw_offs;
> > + struct qcom_jenc_queue *sq = &ectx->bufq[JENC_SRC_QUEUE];
> > + struct qcom_jenc_queue *dq = &ectx->bufq[JENC_DST_QUEUE];
> > + struct v4l2_pix_format_mplane *sfmt = &sq->vf;
> > + struct v4l2_pix_format_mplane *dfmt = &dq->vf;
> > + u32 blk_w, blk_h, mcu_cols, mcu_rows;
> > + int rval;
> > + u8 pln;
> > +
> > + jpeg_rw_bits(jenc, offs->reset_cmd, JMSK_RST_CMD_SCALE_RESET, 1);
> > +
> > + /* explicit no scaling */
> > + jpeg_rw_bits(jenc, offs->scale_cfg, JMSK_SCALE_CFG_HSCALE_ENABLE, 0);
> > + jpeg_rw_bits(jenc, offs->scale_cfg, JMSK_SCALE_CFG_VSCALE_ENABLE, 0);
> > +
> > + for (pln = 0; pln < QCOM_JPEG_MAX_PLANES; pln++) {
> > + jpeg_io_write(jenc, offs->scale.hstep[pln], JPEG_DEFAULT_SCALE_STEP);
> > + jpeg_io_write(jenc, offs->scale.vstep[pln], JPEG_DEFAULT_SCALE_STEP);
> > + }
> > +
> > + if (jpeg_rd_bits(jenc, offs->scale_cfg, JMSK_SCALE_CFG_HSCALE_ENABLE)) {
> > + for (pln = 0; pln < sq->vf.num_planes; pln++) {
> > + jpeg_rw_bits(jenc, offs->scale.hstep[pln],
> > + JMSK_SCALE_PLNS_HSTEP_INTEGER,
> > + jpeg_calc_scale_int(sfmt->width, dfmt->width));
> > + jpeg_rw_bits(jenc, offs->scale.hstep[pln],
> > + JMSK_SCALE_PLNS_HSTEP_FRACTIONAL,
> > + jpeg_calc_scale_frac(sfmt->width, dfmt->width));
> > +
> > + dev_dbg(ectx->dev, "%s: ctx=%p hint=%d hfrac=%d\n",
> > + __func__, ectx,
> > + jpeg_rd_bits(jenc, offs->scale.hstep[pln],
> > + JMSK_SCALE_PLNS_HSTEP_INTEGER),
> > + jpeg_rd_bits(jenc, offs->scale.hstep[pln],
> > + JMSK_SCALE_PLNS_HSTEP_FRACTIONAL));
> > + }
> > + }
> > +
> > + if (jpeg_rd_bits(jenc, offs->scale_cfg, JMSK_SCALE_CFG_VSCALE_ENABLE)) {
> > + for (pln = 0; pln < sq->vf.num_planes; pln++) {
> > + jpeg_rw_bits(jenc, offs->scale.vstep[pln],
> > + JMSK_SCALE_PLNS_VSTEP_INTEGER,
> > + jpeg_calc_scale_int(sfmt->height, dfmt->height));
> > + jpeg_rw_bits(jenc, offs->scale.vstep[pln],
> > + JMSK_SCALE_PLNS_VSTEP_FRACTIONAL,
> > + jpeg_calc_scale_frac(sfmt->height, dfmt->height));
> > +
> > + dev_dbg(ectx->dev, "%s: ctx=%p vint=%d vfrac=%d\n",
> > + __func__, ectx,
> > + jpeg_rd_bits(jenc, offs->scale.vstep[pln],
> > + JMSK_SCALE_PLNS_VSTEP_INTEGER),
> > + jpeg_rd_bits(jenc, offs->scale.vstep[pln],
> > + JMSK_SCALE_PLNS_VSTEP_FRACTIONAL));
> > + }
> > + }
> > +
> > + rval = jpeg_get_encode_fmt(sfmt->pixelformat);
> > + if (rval < 0) {
> > + dev_err(ectx->dev, "%s: unsupported encode format fourcc=0x%x\n",
> > + __func__, sfmt->pixelformat);
> > + return -EINVAL;
> > + }
> > +
> > + rval = jpeg_get_mcu_geometry(rval, dfmt->width, dfmt->height, &blk_w, &blk_h,
> > + &mcu_cols, &mcu_rows);
> > + if (rval < 0) {
> > + dev_err(ectx->dev, "%s: invalid MCU geometry blk_w=%d blk_h=%d\n",
> > + __func__, blk_w, blk_h);
> > + return -EINVAL;
> > + }
> > +
> > + dev_dbg(ectx->dev, "%s blk_w=%u blk_h=%u cols=%u rows=%u\n", __func__, blk_w, blk_h,
> > + mcu_cols, mcu_rows);
> > +
> > + for (pln = 0; pln < sq->vf.num_planes; pln++) {
> > + jpeg_rw_bits(jenc, offs->scale_out_cfg[pln],
> > + JMSK_SCALE_PLNS_OUT_CFG_BLK_WIDTH, mcu_cols - 1);
> > + jpeg_rw_bits(jenc, offs->scale_out_cfg[pln],
> > + JMSK_SCALE_PLNS_OUT_CFG_BLK_HEIGHT, mcu_rows - 1);
> > + }
> > +
> > + dev_dbg(ectx->dev, "%s: ctx=%p scale src=%ux%u dst=%ux%u enable=%d/%d\n",
> > + __func__, ectx, sfmt->width, sfmt->height, dfmt->width, dfmt->height,
> > + jpeg_rd_bits(jenc, offs->scale_cfg, JMSK_SCALE_CFG_HSCALE_ENABLE),
> > + jpeg_rd_bits(jenc, offs->scale_cfg, JMSK_SCALE_CFG_VSCALE_ENABLE));
> > +
> > + /* Disabled, but must be configured */
> > + jpeg_rw_bits(jenc, offs->core_cfg, JMSK_CORE_CFG_SCALE_ENABLE, 0);
> > +
> > + return 0;
> > +}
> > +
> > +static int jpeg_setup_encode(struct jenc_context *ectx)
> > +{
> > + struct qcom_jenc_dev *jenc = ectx->jenc;
> > + struct qcom_jenc_queue *sq = &ectx->bufq[JENC_SRC_QUEUE];
> > + struct v4l2_pix_format_mplane *sfmt = &sq->vf;
> > + const struct qcom_jpeg_reg_offs *offs = jenc->res->hw_offs;
> > + u32 blk_w, blk_h, mcu_cols, mcu_rows;
> > + int rval;
> > +
> > + if (!sfmt->width || !sfmt->height)
> > + return -EINVAL;
> > +
> > + jpeg_rw_bits(jenc, offs->reset_cmd, JMSK_RST_CMD_ENCODER_RESET, 1);
> > +
> > + rval = jpeg_get_encode_fmt(sfmt->pixelformat);
> > + if (rval < 0) {
> > + dev_err(ectx->dev, "%s: unsupported encode format fourcc=0x%x\n",
> > + __func__, sfmt->pixelformat);
> > + return -EINVAL;
> > + }
> > + jpeg_rw_bits(jenc, offs->enc_cfg, JMSK_ENC_CFG_IMAGE_FORMAT, rval);
> > +
> > + rval = jpeg_get_mcu_geometry(rval, sfmt->width, sfmt->height, &blk_w, &blk_h,
> > + &mcu_cols, &mcu_rows);
> > + if (rval < 0) {
> > + dev_err(ectx->dev, "%s: invalid MCU geometry mcu_cols=%d mcu_rows=%d\n",
> > + __func__, mcu_cols, mcu_rows);
> > + return -EINVAL;
> > + }
> > +
> > + dev_dbg(ectx->dev, "%s blk_w=%u blk_h=%u cols=%u rows=%u\n", __func__,
> > + blk_w, blk_h, mcu_cols, mcu_rows);
> > +
> > + jpeg_rw_bits(jenc, offs->enc_img_size, JMSK_ENC_IMAGE_SIZE_WIDTH, mcu_cols - 1);
> > + jpeg_rw_bits(jenc, offs->enc_img_size, JMSK_ENC_IMAGE_SIZE_HEIGHT, mcu_rows - 1);
> > +
> > + dev_dbg(ectx->dev, "%s: ctx=%p width=%d height=%d\n", __func__, ectx,
> > + jpeg_rd_bits(jenc, offs->enc_img_size, JMSK_ENC_IMAGE_SIZE_WIDTH),
> > + jpeg_rd_bits(jenc, offs->enc_img_size, JMSK_ENC_IMAGE_SIZE_HEIGHT));
> > +
> > + jpeg_rw_bits(jenc, offs->enc_cfg, JMSK_ENC_CFG_APPLY_EOI, 1);
> > + jpeg_rw_bits(jenc, offs->core_cfg, JMSK_CORE_CFG_ENC_ENABLE, 1);
> > +
> > + return 0;
> > +}
> > +
> > +static irqreturn_t op_jpeg_irq_bot(int irq, void *data)
> > +{
> > + struct qcom_jenc_dev *jenc = data;
> > + const struct qcom_jpeg_reg_offs *offs = jenc->res->hw_offs;
> > + u32 irq_status;
> > + u32 irq_mask;
> > + unsigned long flags;
> > + int rc;
> > +
> > + rc = kfifo_out_spinlocked(&jenc->kfifo_inst, &irq_status, sizeof(irq_status),
> > + &jenc->kfifo_lock);
> > + if (rc != sizeof(irq_status)) {
> > + dev_err(jenc->dev, "IRQ status: FIFO empty\n");
> > + return IRQ_HANDLED;
> > + }
> > +
> > + irq_mask = jenc->res->hw_mask[JMSK_IRQ_STATUS_SESSION_DONE];
> > + if (jpeg_bits_get(irq_mask, irq_status)) {
> > + struct jenc_context *ctx = jenc->actx;
> > + struct qcom_jenc_queue *dq = &ctx->bufq[JENC_DST_QUEUE];
> > + size_t out_size;
> > +
> > + spin_lock_irqsave(&jenc->hw_lock, flags);
> > + jenc->actx = NULL;
> > + spin_unlock_irqrestore(&jenc->hw_lock, flags);
> > +
> > + if (ctx && dq->buff_id >= 0) {
> > + struct qcom_jpeg_buff *frame;
> > + unsigned long flags;
> > +
> > + spin_lock_irqsave(&jenc->hw_lock, flags);
> > + frame = &dq->buff[dq->buff_id];
> > + out_size = jpeg_io_read(jenc, offs->enc_out_size);
> > + spin_unlock_irqrestore(&jenc->hw_lock, flags);
> > +
> > + dev_dbg(jenc->dev, "complete idx:%d addr=0x%llx size=%zu\n",
> > + dq->buff_id, frame->plns[0].dma, out_size);
> > +
> > + jpeg_cpu_access(jenc->dev, frame, DMA_FROM_DEVICE);
> > + jenc->enc_hw_irq_cb(ctx, VB2_BUF_STATE_DONE,
> > + out_size + JPEG_HEADER_MAX);
> > + jpeg_stop(jenc);
> > + }
> > + }
> > +
> > + irq_mask = jenc->res->hw_mask[JMSK_IRQ_STATUS_SESSION_ERROR];
> > + if (jpeg_bits_get(irq_mask, irq_status)) {
> > + struct jenc_context *ctx = jenc->actx;
> > +
> > + spin_lock_irqsave(&jenc->hw_lock, flags);
> > + jenc->actx = NULL;
> > + spin_unlock_irqrestore(&jenc->hw_lock, flags);
> > +
> > + dev_err(jenc->dev, "encoder hardware failure=0x%x\n",
> > + jpeg_bits_get(JMSK_IRQ_STATUS_SESSION_ERROR, irq_status));
> > + if (ctx)
> > + jenc->enc_hw_irq_cb(ctx, VB2_BUF_STATE_ERROR, 0);
> > +
> > + jpeg_stop(jenc);
> > + }
> > +
> > + return IRQ_HANDLED;
> > +}
> > +
> > +static irqreturn_t op_jpeg_irq_top(int irq, void *data)
> > +{
> > + struct qcom_jenc_dev *jenc = data;
> > + const struct qcom_jpeg_reg_offs *offs = jenc->res->hw_offs;
> > + u32 irq_status;
> > + u32 irq_mask;
> > + unsigned long flags;
> > + int rc;
> > +
> > + spin_lock_irqsave(&jenc->hw_lock, flags);
> > +
> > + irq_status = jpeg_io_read(jenc, offs->int_status);
> > + jpeg_wo_bits(jenc, offs->int_clr, JMSK_IRQ_CLEAR_ALL, irq_status);
> > +
> > + irq_mask = jenc->res->hw_mask[JMSK_IRQ_STATUS_RESET_ACK];
> > + if (jpeg_bits_get(irq_mask, irq_status)) {
> > + complete(&jenc->reset_complete);
> > + spin_unlock_irqrestore(&jenc->hw_lock, flags);
> > + return IRQ_HANDLED;
> > + }
> > +
> > + irq_mask = jenc->res->hw_mask[JMSK_IRQ_STATUS_STOP_ACK];
> > + if (jpeg_bits_get(irq_mask, irq_status)) {
> > + complete(&jenc->stop_complete);
> > + dev_dbg(jenc->dev, "hardware stop acknowledged\n");
> > + spin_unlock_irqrestore(&jenc->hw_lock, flags);
> > + return IRQ_HANDLED;
> > + }
> > +
> > + rc = kfifo_in(&jenc->kfifo_inst, &irq_status, sizeof(irq_status));
> > + if (rc != sizeof(irq_status))
> > + dev_err(jenc->dev, "IRQ status: FIFO full\n");
> > +
> > + spin_unlock_irqrestore(&jenc->hw_lock, flags);
> > +
> > + return IRQ_WAKE_THREAD;
> > +}
> > +
> > +static void op_jpeg_get_hw_caps(struct qcom_jenc_dev *jenc, u32 *caps)
> > +{
> > + const struct qcom_jpeg_reg_offs *offs = jenc->res->hw_offs;
> > + u32 hw_caps;
> > +
> > + hw_caps = jpeg_io_read(jenc, offs->hw_capability);
> > + dev_dbg(jenc->dev, "CAPS: encode=%d decode=%d upscale=%d downscale=%d\n",
> > + jpeg_bits_get(jenc->res->hw_mask[JMSK_HW_CAP_ENCODE], hw_caps),
> > + jpeg_bits_get(jenc->res->hw_mask[JMSK_HW_CAP_DECODE], hw_caps),
> > + jpeg_bits_get(jenc->res->hw_mask[JMSK_HW_CAP_UPSCALE], hw_caps),
> > + jpeg_bits_get(jenc->res->hw_mask[JMSK_HW_CAP_DOWNSCALE], hw_caps));
> > +
> > + *caps = hw_caps;
> > +}
> > +
> > +static struct qcom_jenc_queue *op_jpeg_get_buff_queue(struct jenc_context *ectx,
> > + enum qcom_enc_qid id)
> > +{
> > + return &ectx->bufq[id];
> > +}
> > +
> > +static int op_jpeg_queue_setup(struct jenc_context *ectx, enum qcom_enc_qid id)
> > +{
> > + int rc;
> > +
> > + if (id == JENC_SRC_QUEUE) {
> > + struct qcom_jenc_queue *q = &ectx->bufq[id];
> > +
> > + rc = qcom_jenc_header_init(&ectx->hdr_cache, q->vf.pixelformat);
> > + if (rc) {
> > + dev_err(ectx->dev, "JFIF header init failed\n");
> > + return rc;
> > + }
> > + }
> > +
> > + return 0;
> > +}
> > +
> > +static int op_jpeg_buffer_prepare(struct jenc_context *ectx, struct vb2_buffer *vb2)
> > +{
> > + int rc;
> > +
> > + if (V4L2_TYPE_IS_OUTPUT(vb2->type)) {
> > + rc = jpeg_store_fe_next(ectx, vb2);
> > + if (rc)
> > + dev_err(ectx->dev, "%s: cannot set up fetch addr\n", __func__);
> > + } else {
> > + rc = jpeg_store_we_next(ectx, vb2);
> > + if (rc)
> > + dev_err(ectx->dev, "%s: cannot set up write addr\n", __func__);
> > + }
> > +
> > + return rc;
> > +}
> > +
> > +static int op_jpeg_process_exec(struct qcom_jenc_dev *jenc, struct jenc_context *ectx,
> > + struct vb2_buffer *vb)
> > +{
> > + struct qcom_jenc_queue *sq = &ectx->bufq[JENC_SRC_QUEUE];
> > + struct qcom_jenc_queue *dq = &ectx->bufq[JENC_DST_QUEUE];
> > + unsigned long flags;
> > + int rc;
> > +
> > + spin_lock_irqsave(&jenc->hw_lock, flags);
> > + jenc->actx = ectx;
> > + spin_unlock_irqrestore(&jenc->hw_lock, flags);
> > +
> > + if (V4L2_TYPE_IS_OUTPUT(vb->type)) {
> > + rc = jpeg_setup_fe(ectx, sq);
> > + if (rc)
> > + return rc;
> > +
> > + jpeg_apply_fe_addr(ectx, sq, vb);
> > +
> > + } else {
> > + rc = jpeg_setup_we(ectx, dq);
> > + if (rc)
> > + return rc;
> > +
> > + jpeg_apply_we_addr(ectx, dq, vb);
> > + }
> > +
> > + if (sq->sequence == dq->sequence) {
> > + rc = jpeg_setup_scale(ectx);
> > + if (rc)
> > + return rc;
> > +
> > + rc = jpeg_setup_encode(ectx);
> > + if (rc)
> > + return rc;
> > +
> > + jpeg_exec(jenc);
> > + }
> > +
> > + return 0;
> > +}
> > +
> > +static int op_jpeg_prepare(struct qcom_jenc_dev *jenc)
> > +{
> > + const struct qcom_jpeg_reg_offs *offs = jenc->res->hw_offs;
> > +
> > + jpeg_rw_bits(jenc, offs->reset_cmd, JMSK_RST_CMD_DECODER_RESET, 1);
> > + jpeg_rw_bits(jenc, offs->reset_cmd, JMSK_RST_CMD_BLOCK_FORMATTER_RST, 1);
> > + jpeg_rw_bits(jenc, offs->reset_cmd, JMSK_RST_CMD_CORE_RESET, 1);
> > +
> > + return 0;
> > +}
> > +
> > +static int op_jpeg_acquire(struct jenc_context *ectx, struct vb2_queue *q)
> > +{
> > + struct qcom_jenc_dev *jenc = ectx->jenc;
> > + struct qcom_jenc_queue *sq, *dq;
> > + int rc;
> > +
> > + if (atomic_inc_return(&jenc->ref_count) == 1) {
> > + rc = pm_runtime_resume_and_get(jenc->dev);
> > + if (rc < 0) {
> > + dev_err(jenc->dev, "PM runtime get failed\n");
> > + atomic_dec(&jenc->ref_count);
> > + return rc;
> > + }
> > +
> > + rc = jpeg_init(jenc);
> > + if (rc) {
> > + dev_err(jenc->dev, "hardware init failed\n");
> > + atomic_dec(&jenc->ref_count);
> > + pm_runtime_put(jenc->dev);
> > + return rc;
> > + }
> > +
> > + sq = &ectx->bufq[JENC_SRC_QUEUE];
> > + sq->sequence = 0;
> > + sq->buff_id = -1;
> > + dq = &ectx->bufq[JENC_DST_QUEUE];
> > + dq->sequence = 0;
> > + dq->buff_id = -1;
> > + }
> > +
> > + return 0;
> > +}
> > +
> > +static int op_jpeg_release(struct jenc_context *ectx, struct vb2_queue *q)
> > +{
> > + struct qcom_jenc_dev *jenc = ectx->jenc;
> > + int rc;
> > +
> > + if (!atomic_dec_if_positive(&jenc->ref_count)) {
> > + rc = jpeg_deinit(jenc);
> > + if (rc)
> > + dev_err(jenc->dev, "hardware exit failed\n");
> > +
> > + rc = pm_runtime_put_sync(jenc->dev);
> > + if (rc < 0)
> > + dev_err(jenc->dev, "PM runtime put failed\n");
> > +
> > + dev_dbg(jenc->dev, "JPEG HW encoder released\n");
> > + }
> > +
> > + return 0;
> > +}
> > +
> > +const struct qcom_jpeg_hw_ops qcom_jpeg_default_ops = {
> > + .hw_get_cap = op_jpeg_get_hw_caps,
> > + .hw_acquire = op_jpeg_acquire,
> > + .hw_release = op_jpeg_release,
> > + .hw_prepare = op_jpeg_prepare,
> > + .get_queue = op_jpeg_get_buff_queue,
> > + .queue_setup = op_jpeg_queue_setup,
> > + .buf_prepare = op_jpeg_buffer_prepare,
> > + .process_exec = op_jpeg_process_exec,
> > + .hw_irq_top = op_jpeg_irq_top,
> > + .hw_irq_bot = op_jpeg_irq_bot
> > +};
> > diff --git a/drivers/media/platform/qcom/jpeg/qcom_jenc_ops.h b/drivers/media/platform/qcom/jpeg/qcom_jenc_ops.h
> > new file mode 100644
> > index 000000000000..751a045a3486
> > --- /dev/null
> > +++ b/drivers/media/platform/qcom/jpeg/qcom_jenc_ops.h
> > @@ -0,0 +1,49 @@
> > +/* SPDX-License-Identifier: GPL-2.0-only */
> > +/*
> > + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
> > + */
> > +
> > +#ifndef QCOM_JENC_OPS_H
> > +#define QCOM_JENC_OPS_H
> > +
> > +#include <linux/types.h>
> > +#include <linux/device.h>
> > +#include <media/videobuf2-core.h>
> > +
> > +#include "qcom_jenc_dev.h"
> > +
> > +/*
> > + * JENC encoder hardware operations.
> > + */
> > +struct qcom_jpeg_hw_ops {
> > + void (*hw_get_cap)
> > + (struct qcom_jenc_dev *jenc_dev, u32 *hw_caps);
> > +
> > + int (*hw_acquire)
> > + (struct jenc_context *ectx, struct vb2_queue *queue);
> > +
> > + int (*hw_release)
> > + (struct jenc_context *ectx, struct vb2_queue *queue);
> > +
> > + int (*hw_prepare)
> > + (struct qcom_jenc_dev *jenc);
> > +
> > + struct qcom_jenc_queue * (*get_queue)
> > + (struct jenc_context *ectx, enum qcom_enc_qid id);
> > +
> > + int (*queue_setup)
> > + (struct jenc_context *ectx, enum qcom_enc_qid id);
> > +
> > + int (*buf_prepare)
> > + (struct jenc_context *ectx, struct vb2_buffer *vb2);
> > +
> > + int (*process_exec)
> > + (struct qcom_jenc_dev *jenc, struct jenc_context *ectx, struct vb2_buffer *vb2);
> > +
> > + irqreturn_t (*hw_irq_top)(int irq_num, void *data);
> > + irqreturn_t (*hw_irq_bot)(int irq_num, void *data);
> > +};
> > +
> > +extern const struct qcom_jpeg_hw_ops qcom_jpeg_default_ops;
> > +
> > +#endif /* QCOM_JENC_OPS_H */
> > diff --git a/drivers/media/platform/qcom/jpeg/qcom_jenc_res.c b/drivers/media/platform/qcom/jpeg/qcom_jenc_res.c
> > new file mode 100644
> > index 000000000000..c935ea690837
> > --- /dev/null
> > +++ b/drivers/media/platform/qcom/jpeg/qcom_jenc_res.c
> > @@ -0,0 +1,268 @@
> > +// SPDX-License-Identifier: GPL-2.0-only
> > +/*
> > + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
> > + */
> > +
> > +#include <linux/clk.h>
> > +
> > +#include "qcom_jenc_ops.h"
> > +#include "qcom_jenc_res.h"
> > +
> > +#include "qcom_v165_jenc_hw_info.h"
> > +#include "qcom_v580_jenc_hw_info.h"
> > +#include "qcom_v680_jenc_hw_info.h"
> > +#include "qcom_v780_jenc_hw_info.h"
> > +
> > +#define QCOM_PERF_ROW(_axi_rate, _jpeg_rate) \
> > +{ \
> > + .clk_rate = { \
> > + [JPEG_CAMNOC_AXI_CLK] = (_axi_rate), \
> > + [JPEG_CORE_CLK] = (_jpeg_rate), \
> > + }, \
> > +}
> > +
> > +/*
> > + * Baseline AXI clock rates shared across v165/v580, reused by later
> > + * derivatives where the hardware does not change these domains.
> > + */
> > +static const u64 cnoc_axi_clk_base[] = {
> > + [QCOM_SOC_PERF_SUSPEND] = 19200000,
> > + [QCOM_SOC_PERF_LOWSVS] = 300000000,
> > + [QCOM_SOC_PERF_SVS] = 300000000,
> > + [QCOM_SOC_PERF_SVS_L1] = 300000000,
> > + [QCOM_SOC_PERF_NOMINAL] = 400000000,
> > + [QCOM_SOC_PERF_TURBO] = 400000000,
> > +};
> > +
> > +/*
> > + * Derivative with an improved CAMNOC AXI frequency range
> > + */
> > +static const u64 cnoc_axi_clk_v680[] = {
> > + [QCOM_SOC_PERF_SUSPEND] = 19200000,
> > + [QCOM_SOC_PERF_LOWSVS] = 150000000,
> > + [QCOM_SOC_PERF_SVS] = 240000000,
> > + [QCOM_SOC_PERF_SVS_L1] = 320000000,
> > + [QCOM_SOC_PERF_NOMINAL] = 400000000,
> > + [QCOM_SOC_PERF_TURBO] = 480000000,
> > +};
> > +
> > +/*
> > + * Baseline JPEG clock rates shared across v165/v680, reused by later
> > + * derivatives where the hardware does not change these domains.
> > + */
> > +static const u64 qcom_jpeg_clk_base[] = {
> > + [QCOM_SOC_PERF_SUSPEND] = 19200000,
> > + [QCOM_SOC_PERF_LOWSVS] = 300000000,
> > + [QCOM_SOC_PERF_SVS] = 400000000,
> > + [QCOM_SOC_PERF_SVS_L1] = 480000000,
> > + [QCOM_SOC_PERF_NOMINAL] = 600000000,
> > + [QCOM_SOC_PERF_TURBO] = 600000000,
> > +};
> > +
> > +/*
> > + * Derivative with an improved maximum JPEG frequency
> > + */
> > +static const u64 qcom_jpeg_clk_v780[] = {
> > + [QCOM_SOC_PERF_SUSPEND] = 19200000,
> > + [QCOM_SOC_PERF_LOWSVS] = 200000000,
> > + [QCOM_SOC_PERF_SVS] = 200000000,
> > + [QCOM_SOC_PERF_SVS_L1] = 400000000,
> > + [QCOM_SOC_PERF_NOMINAL] = 480000000,
> > + [QCOM_SOC_PERF_TURBO] = 785000000,
> > +};
> > +
> > +static const struct qcom_perf_resource qcom_perf_rates_base[] = {
> > + [QCOM_SOC_PERF_SUSPEND] =
> > + QCOM_PERF_ROW(cnoc_axi_clk_base[QCOM_SOC_PERF_SUSPEND],
> > + qcom_jpeg_clk_base[QCOM_SOC_PERF_SUSPEND]),
> > +
> > + [QCOM_SOC_PERF_LOWSVS] =
> > + QCOM_PERF_ROW(cnoc_axi_clk_base[QCOM_SOC_PERF_LOWSVS],
> > + qcom_jpeg_clk_base[QCOM_SOC_PERF_LOWSVS]),
> > +
> > + [QCOM_SOC_PERF_SVS] =
> > + QCOM_PERF_ROW(cnoc_axi_clk_base[QCOM_SOC_PERF_SVS],
> > + qcom_jpeg_clk_base[QCOM_SOC_PERF_SVS]),
> > +
> > + [QCOM_SOC_PERF_SVS_L1] =
> > + QCOM_PERF_ROW(cnoc_axi_clk_base[QCOM_SOC_PERF_SVS_L1],
> > + qcom_jpeg_clk_base[QCOM_SOC_PERF_SVS_L1]),
> > +
> > + [QCOM_SOC_PERF_NOMINAL] =
> > + QCOM_PERF_ROW(cnoc_axi_clk_base[QCOM_SOC_PERF_NOMINAL],
> > + qcom_jpeg_clk_base[QCOM_SOC_PERF_NOMINAL]),
> > +
> > + [QCOM_SOC_PERF_TURBO] =
> > + QCOM_PERF_ROW(cnoc_axi_clk_base[QCOM_SOC_PERF_TURBO],
> > + qcom_jpeg_clk_base[QCOM_SOC_PERF_TURBO]),
> > +};
> > +
> > +static const struct qcom_perf_resource qcom_perf_rates_v680[] = {
> > + [QCOM_SOC_PERF_SUSPEND] =
> > + QCOM_PERF_ROW(cnoc_axi_clk_v680[QCOM_SOC_PERF_SUSPEND],
> > + qcom_jpeg_clk_base[QCOM_SOC_PERF_SUSPEND]),
> > +
> > + [QCOM_SOC_PERF_LOWSVS] =
> > + QCOM_PERF_ROW(cnoc_axi_clk_v680[QCOM_SOC_PERF_LOWSVS],
> > + qcom_jpeg_clk_base[QCOM_SOC_PERF_LOWSVS]),
> > +
> > + [QCOM_SOC_PERF_SVS] =
> > + QCOM_PERF_ROW(cnoc_axi_clk_v680[QCOM_SOC_PERF_SVS],
> > + qcom_jpeg_clk_base[QCOM_SOC_PERF_SVS]),
> > +
> > + [QCOM_SOC_PERF_SVS_L1] =
> > + QCOM_PERF_ROW(cnoc_axi_clk_v680[QCOM_SOC_PERF_SVS_L1],
> > + qcom_jpeg_clk_base[QCOM_SOC_PERF_SVS_L1]),
> > +
> > + [QCOM_SOC_PERF_NOMINAL] =
> > + QCOM_PERF_ROW(cnoc_axi_clk_v680[QCOM_SOC_PERF_NOMINAL],
> > + qcom_jpeg_clk_base[QCOM_SOC_PERF_NOMINAL]),
> > +
> > + [QCOM_SOC_PERF_TURBO] =
> > + QCOM_PERF_ROW(cnoc_axi_clk_v680[QCOM_SOC_PERF_TURBO],
> > + qcom_jpeg_clk_base[QCOM_SOC_PERF_TURBO]),
> > +};
> > +
> > +static const struct qcom_perf_resource qcom_perf_rates_v780[] = {
> > + [QCOM_SOC_PERF_SUSPEND] =
> > + QCOM_PERF_ROW(cnoc_axi_clk_base[QCOM_SOC_PERF_SUSPEND],
> > + qcom_jpeg_clk_v780[QCOM_SOC_PERF_SUSPEND]),
> > +
> > + [QCOM_SOC_PERF_LOWSVS] =
> > + QCOM_PERF_ROW(cnoc_axi_clk_base[QCOM_SOC_PERF_LOWSVS],
> > + qcom_jpeg_clk_v780[QCOM_SOC_PERF_LOWSVS]),
> > +
> > + [QCOM_SOC_PERF_SVS] =
> > + QCOM_PERF_ROW(cnoc_axi_clk_base[QCOM_SOC_PERF_SVS],
> > + qcom_jpeg_clk_v780[QCOM_SOC_PERF_SVS]),
> > +
> > + [QCOM_SOC_PERF_SVS_L1] =
> > + QCOM_PERF_ROW(cnoc_axi_clk_base[QCOM_SOC_PERF_SVS_L1],
> > + qcom_jpeg_clk_v780[QCOM_SOC_PERF_SVS_L1]),
> > +
> > + [QCOM_SOC_PERF_NOMINAL] =
> > + QCOM_PERF_ROW(cnoc_axi_clk_base[QCOM_SOC_PERF_NOMINAL],
> > + qcom_jpeg_clk_v780[QCOM_SOC_PERF_NOMINAL]),
> > +
> > + [QCOM_SOC_PERF_TURBO] =
> > + QCOM_PERF_ROW(cnoc_axi_clk_base[QCOM_SOC_PERF_TURBO],
> > + qcom_jpeg_clk_v780[QCOM_SOC_PERF_TURBO]),
> > +};
> > +
> > +static const struct qcom_icc_resource qcom_jpeg_default_icc[] = {
> > + {
> > + .icc_id = "cam_ahb",
> > + .pair = { 38400, 76800 }
> > + },
> > + {
> > + .icc_id = "cam_hf_0_mnoc",
> > + .pair = { 2097152, 2097152 }
> > + },
> > + {
> > + .icc_id = "cam_sf_0_mnoc",
> > + .pair = { 0, 2097152 }
> > + },
> > + {
> > + .icc_id = "cam_sf_icp_mnoc",
> > + .pair = { 2097152, 2097152 }
> > + },
> > +};
> > +
> > +static const struct qcom_mem_resource qcom_jpeg_default_mem[] = {
> > + {
> > + .map_id = 0,
> > + .res_id = "JPEG"
> > + },
> > + {
> > + .map_id = 1,
> > + .res_id = "CPAS"
> > + }
> > +};
>
> You don't even use these in the driver
>
> > +
> > +/*
> > + * Resources for T165, T170 JPEG version and derivatives
> > + */
> > +const struct qcom_dev_resources qcom_jpeg_v165_drvdata = {
> > + .hw_ops = &qcom_jpeg_default_ops,
> > + .hw_offs = &qcom_v165_jpeg_hw_reg_offs,
> > + .hw_mask = &qcom_v165_jpeg_hw_reg_mask[0],
> > + .icc_res = qcom_jpeg_default_icc,
> > + .num_of_icc = ARRAY_SIZE(qcom_jpeg_default_icc),
> > + .mem_res = qcom_jpeg_default_mem,
> > + .num_of_mem = ARRAY_SIZE(qcom_jpeg_default_mem),
> > + .perf_cfg = qcom_perf_rates_base,
> > + .clk_names = {
> > + [JPEG_CAMNOC_AXI_CLK] = "camnoc_axi_clk",
> > + [JPEG_CORE_CLK] = "jpeg_clk",
> > + [JPEG_CORE_AHB_CLK] = "core_ahb_clk",
> > + [JPEG_CPAS_AHB_CLK] = "cpas_ahb_clk",
> > + [JPEG_GCC_HF_AXI] = "gcc_hf_axi_clk",
> > + [JPEG_GCC_SF_AXI] = "gcc_sf_axi_clk",
> > + }
> > +};
> > +
> > +/*
> > + * Resources for T480, T580 JPEG version and derivatives
> > + */
> > +const struct qcom_dev_resources qcom_jpeg_v580_drvdata = {
> > + .hw_ops = &qcom_jpeg_default_ops,
> > + .hw_offs = &qcom_v580_jpeg_hw_reg_offs,
> > + .hw_mask = &qcom_v580_jpeg_hw_reg_mask[0],
> > + .icc_res = qcom_jpeg_default_icc,
> > + .num_of_icc = ARRAY_SIZE(qcom_jpeg_default_icc),
> > + .mem_res = qcom_jpeg_default_mem,
> > + .num_of_mem = ARRAY_SIZE(qcom_jpeg_default_mem),
> > + .perf_cfg = qcom_perf_rates_base,
> > + .clk_names = {
> > + [JPEG_CAMNOC_AXI_CLK] = "camnoc_axi_clk",
> > + [JPEG_CORE_CLK] = "jpeg_clk",
> > + [JPEG_CORE_AHB_CLK] = "core_ahb_clk",
> > + [JPEG_CPAS_AHB_CLK] = "cpas_ahb_clk",
> > + [JPEG_GCC_HF_AXI] = "gcc_hf_axi_clk",
> > + [JPEG_GCC_SF_AXI] = "gcc_sf_axi_clk",
> > + }
> > +};
> > +
> > +/*
> > + * Resources for T680 JPEG version and derivatives
> > + */
> > +const struct qcom_dev_resources qcom_jpeg_v680_drvdata = {
> > + .hw_ops = &qcom_jpeg_default_ops,
>
> All hw_ops are the same, remove them from the struct.
>
> > + .hw_offs = &qcom_v680_jpeg_hw_reg_offs,
> > + .hw_mask = &qcom_v680_jpeg_hw_reg_mask[0],
> > + .icc_res = qcom_jpeg_default_icc,
> > + .num_of_icc = ARRAY_SIZE(qcom_jpeg_default_icc),
> > + .mem_res = qcom_jpeg_default_mem,
> > + .num_of_mem = ARRAY_SIZE(qcom_jpeg_default_mem),
> > + .perf_cfg = qcom_perf_rates_v680,
> > + .clk_names = {
> > + [JPEG_CAMNOC_AXI_CLK] = "camnoc_axi_clk",
> > + [JPEG_CORE_CLK] = "jpeg_clk",
> > + [JPEG_CORE_AHB_CLK] = "core_ahb_clk",
> > + [JPEG_CPAS_AHB_CLK] = "cpas_ahb_clk",
> > + [JPEG_GCC_HF_AXI] = "gcc_hf_axi_clk",
> > + [JPEG_GCC_SF_AXI] = "gcc_sf_axi_clk",
> > + }
>
> Nope. You don't really need all those clock names here. Use
> devm_clk_bulk_get_all().
>
> > +};
> > +
> > +/*
> > + * Resources for T780 JPEG version and derivatives
> > + */
> > +const struct qcom_dev_resources qcom_jpeg_v780_drvdata = {
> > + .hw_ops = &qcom_jpeg_default_ops,
> > + .hw_offs = &qcom_v780_jpeg_hw_reg_offs,
> > + .hw_mask = &qcom_v780_jpeg_hw_reg_mask[0],
> > + .icc_res = qcom_jpeg_default_icc,
> > + .num_of_icc = ARRAY_SIZE(qcom_jpeg_default_icc),
> > + .mem_res = qcom_jpeg_default_mem,
> > + .num_of_mem = ARRAY_SIZE(qcom_jpeg_default_mem),
> > + .perf_cfg = qcom_perf_rates_v780,
> > + .clk_names = {
> > + [JPEG_CAMNOC_AXI_CLK] = "camnoc_axi_clk",
> > + [JPEG_CORE_CLK] = "jpeg_clk",
> > + [JPEG_CORE_AHB_CLK] = "core_ahb_clk",
> > + [JPEG_CPAS_AHB_CLK] = "cpas_ahb_clk",
> > + [JPEG_GCC_HF_AXI] = "gcc_hf_axi_clk",
> > + [JPEG_GCC_SF_AXI] = "gcc_sf_axi_clk",
> > + }
> > +};
>
>
> > diff --git a/drivers/media/platform/qcom/jpeg/qcom_v165_jenc_hw_info.h b/drivers/media/platform/qcom/jpeg/qcom_v165_jenc_hw_info.h
> > new file mode 100644
> > index 000000000000..16e4eae04d5f
> > --- /dev/null
> > +++ b/drivers/media/platform/qcom/jpeg/qcom_v165_jenc_hw_info.h
> > @@ -0,0 +1,509 @@
> > +/* SPDX-License-Identifier: GPL-2.0-only */
> > +/*
> > + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
> > + */
> > +
> > +#ifndef QCOM_JENC_HW_INFO_V165_H
> > +#define QCOM_JENC_HW_INFO_V165_H
> > +
> > +#include "qcom_jenc_defs.h"
> > +
> > +#define JPEG_V165_HW_VER_STEP_POS 0
> > +#define JPEG_V165_HW_VER_STEP_MSK \
> > + (0xffff << JPEG_V165_HW_VER_STEP_POS)
>
> Use GENMASK instead.
>
> > +
> > +#define JPEG_V165_HW_VER_MINOR_POS 16
> > +#define JPEG_V165_HW_VER_MINOR_MSK \
> > + (0x0fff << JPEG_V165_HW_VER_MINOR_POS)
> > +
> > +#define JPEG_V165_HW_VER_MAJOR_POS 28
> > +#define JPEG_V165_HW_VER_MAJOR_MSK \
> > + (0xf << JPEG_V165_HW_VER_MAJOR_POS)
> > +
> > +#define JPEG_V165_HW_CAP_ENCODE_MSK BIT(0)
> > +#define JPEG_V165_HW_CAP_DECODE_MSK BIT(1)
>
> Stop declaring bits and pieces which are common to all platforms as
> platform-specific. Get them handled in the code directly without this
> extra intervention. Ideally, get one(!) of the platforms merged first
> and then implement corresponding differences for all other platforms.
>
[-- Attachment #2: This is a digitally signed message part --]
[-- Type: application/pgp-signature, Size: 228 bytes --]
^ permalink raw reply [flat|nested] 15+ messages in thread
end of thread, other threads:[~2026-05-15 13:50 UTC | newest]
Thread overview: 15+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-05-15 11:46 [PATCH 0/3] Subject: [PATCH 0/3] media: qcom: Add Qualcomm JPEG encoder driver Atanas Filipov
2026-05-15 11:46 ` [PATCH 1/3] media: dt-bindings: qcom: add JPEG encoder binding Atanas Filipov
2026-05-15 11:57 ` sashiko-bot
2026-05-15 12:13 ` Dmitry Baryshkov
2026-05-15 12:16 ` Krzysztof Kozlowski
2026-05-15 11:47 ` [PATCH 2/3] qcom: media: jpeg: Add Qualcomm JPEG V4L2 encoder Atanas Filipov
2026-05-15 12:21 ` Krzysztof Kozlowski
[not found] ` <SA1PR02MB11289FA5C2A01466B49C62D4BDD042@SA1PR02MB11289.namprd02.prod.outlook.com>
2026-05-15 12:29 ` Krzysztof Kozlowski
2026-05-15 12:23 ` sashiko-bot
2026-05-15 13:28 ` Dmitry Baryshkov
2026-05-15 13:50 ` Nicolas Dufresne
2026-05-15 11:47 ` [PATCH 3/3] arm64: qcom: dts: qcm6490: Add JPEG encoder DT properties Atanas Filipov
2026-05-15 12:16 ` Dmitry Baryshkov
2026-05-15 12:17 ` Krzysztof Kozlowski
2026-05-15 12:36 ` sashiko-bot
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox