Add Qualcomm JPEG V4L2 encoder for SM8250 and SC7280
Subsystems (5)
v8 cover Add Qualcomm JPEG V4L2 encoder for SM8250 and SC7280
The goal is to upstream a standards-based JPEG encode path using the V4L2 M2M framework, with DT-described hardware resources and SoC DTS integration.
The JPEG encoder is a standalone hardware IP within the camera subsystem. It is modelled as a peer node of CAMSS directly under the SoC bus, with all resources self-described in its own device tree node (power-domains, clocks, interconnects, iommus). This follows the consensus reached in the v4 review thread (Bryan O'Donoghue, Konrad Dybcio, Gjorgji Rosikopulos).
Supported compatibles:
- qcom,sm8250-jpeg-enc
- qcom,sc7280-jpeg-enc
Driver scope and design choices:
- uses the standard V4L2 mem2mem and vb2 framework
- the JPEG header is written by a common v4l2-jpeg helper
- all resources come from DT (clocks, interconnects, iommu, power-domains)
- power is managed with power-domains (SM8250: TITAN_TOP_GDSC, MX, MMCX; SC7280: TITAN_TOP_GDSC, CX) and the OPP framework
- the driver selects the core clock for each job from the image size; the OPP table votes the SoC rails and the DDR bandwidth
Note on the camera NoC AXI clock (camnoc_axi): several camera blocks share this clock. For now there is no upstream driver that aggregates their votes, so the driver does this: while the encoder is powered, it sets a minimum rate on the camera NoC AXI clock source with clk_set_rate_range(). The minimum is 300 MHz on SM8250 and 150 MHz on SC7280, the lowest levels. Another user of the clock cannot set a lower rate. The series does not depend on the camcc icc-clk series.
Functional validation:
- tested with v4l2-ctl and GStreamer (v4l2jpegenc) on RB5 (SM8250) and RB3 Gen2 (QCS6490)
- v4l2-compliance passes
- throughput and DDR traffic measured for each OPP on both boards; the OPP bandwidth values and the reference throughput come from these measurements
Known limitations:
- no scaling
- width and height must be multiples of 16
- the camera NoC AXI clock has a fixed minimum rate; its bandwidth is not aggregated with the other camera blocks (see the note above)
Changes since v7:
Binding (dt-bindings: media: qcom: Add JPEG encoder binding):
- Dropped the camnoc_axi_src clock. It is the parent of camnoc_axi, not a clock of the block. The core clock is now the first clock. (Rob, Bryan)
Driver (media: qcom: jpeg: Add Qualcomm JPEG V4L2 encoder):
- The camera NoC AXI clock source is now taken with clk_get_parent() from camnoc_axi. (Rob)
DTS (arm64: dts: qcom: sm8250, kodiak):
- Dropped the camnoc_axi_src clock; the core clock is first. (Rob)
Changes since v6:
Series:
- Added SC7280 (Kodiak) support and RB3 Gen2.
- Split the driver patch into media/jpeg.h constants, a common v4l2-jpeg header writer and the driver. (Dmitry)
- The SoC nodes are disabled by default and enabled per board (new
qrb5165-rb5 and qcs6490-rb3gen2 patches).
- No dependency on the camcc icc-clk series any more.
Binding (dt-bindings: media: qcom: Add JPEG encoder binding):
- Added qcom,sc7280-jpeg-enc (titan_top and cx power domains).
- New clock names: core, bus, config, camnoc_axi. (Dmitry)
- Added the camnoc_axi_src clock.
- SM8250 power domains: titan_top, mx, mmcx. (Dmitry)
media/jpeg.h (media: jpeg: Add JPEG baseline and JFIF APP0 constants):
- New patch with the standard JPEG/JFIF values. (Dmitry)
v4l2-jpeg (media: v4l2-jpeg: Add a baseline JPEG header writer):
- New patch with a common header writer; the qcom JFIF header code is removed from the driver. (Dmitry)
Driver (media: qcom: jpeg: Add Qualcomm JPEG V4L2 encoder):
- Added SC7280 support.
- Power domains are attached with devm_pm_domain_attach_list(); the OPP table votes the SoC rails with required-opps. (Dmitry)
- Fixed the clock/OPP order in runtime PM. (Dmitry)
- Minimum camera NoC AXI rate with clk_set_rate_range().
- The core clock is selected from a measured reference throughput.
- GENMASK()/BIT() with FIELD_GET()/FIELD_PREP(). (Dmitry)
- JFIF tables from the common V4L2 JPEG helpers. (Dmitry)
- qcom_jenc_v420_* names; removed the qcom_jpeg_hw_ops table. (Dmitry)
- Removed the custom performance controls. G/S_PARM is not used either; the driver selects the clock and bandwidth itself. (Dmitry, Gjorgji)
DTS (arm64: dts: qcom: sm8250, kodiak):
- required-opps on every OPP for the power domains. (Dmitry)
- Interconnect on the mmss_noc camnoc SF path to EBI; added the camnoc_axi_src clock.
- OPP bandwidth values from measured DDR traffic.
- New kodiak node for SC7280.
Changes since v5:
Binding (dt-bindings: media: qcom,sm8250-jpeg-enc):
- Removed GCC_CAMERA_HF_AXI_CLK (hf_axi) clock and hf-mnoc interconnect path. The JPEG encoder uses only the SF CAMNOC port; the HF port is for real-time capture pipelines. (Loic Poulain)
- Added RPMHPD_MMCX and RPMHPD_MX to power-domains. (bod)
- Added power-domain-names property with entries "titan_top", "mmcx", "mx".
- Added power-domain-names to the required list.
DTS (arm64: dts: qcom: sm8250):
- Removed GCC_CAMERA_HF_AXI_CLK (hf_axi) clock and hf-mnoc interconnect path from jpeg-encoder node. (Loic Poulain)
- Added RPMHPD_MMCX and RPMHPD_MX to power-domains. (bod)
- Added power-domain-names = "titan_top", "mmcx", "mx".
Changes since v4:
Architecture:
- Dropped patch 1/5 (devm_of_platform_populate in camss.c) entirely. JPEG is now a peer node of CAMSS, not a child node. (bod)
- Dropped patch 2/5 (camss binding unevaluatedProperties). (krzk, bod)
- Moved jpeg-encoder DTS node from camss@ to soc@ level. (bod)
Binding (dt-bindings: media: qcom,sm8250-jpeg-enc):
- Renamed binding file from qcom,jpeg-encoder.yaml to qcom,sm8250-jpeg-enc.yaml to match compatible string convention.
- Renamed compatible from qcom,sm8250-jenc to qcom,sm8250-jpeg-enc for readability. (Bjorn Andersson)
- Added power-domains property and required entry. (bod)
- Added iommus description with SID value 0x2040 for SM8250. (bod)
- Dropped soc{} wrapper from example; node is directly under soc. (Dmitry)
- Added Gjorgji Rosikopulos as co-maintainer.
- Patch order corrected: binding before driver before DTS. (krzk)
Driver (media: qcom: jpeg):
- Removed <linux/mod_devicetable.h> include. (Uwe Kleine-Koenig)
- Removed dev_dbg calls from OPP clock selection path. (Dmitry)
- Removed camss_dev field and pm_runtime_resume_and_get(camss_dev); PM is now managed independently via power-domains. (Dmitry)
- Removed incorrect device_link_add() to parent; not needed in peer node model.
- Moved file-local defines out of qcom_jenc_defs.h to their respective .c files. (Dmitry)
- Fixed dev_pm_opp_put() placement: called before rc check. (Dmitry)
- Replaced _DEFINE_DEV_PM_OPS() with SYSTEM_SLEEP_PM_OPS() + RUNTIME_PM_OPS() macros, consistent with other media drivers. (Frank Li)
- Fixed Kconfig source order to alphabetical. (krzk)
- Updated compatible string in driver match table to qcom,sm8250-jpeg-enc.
DTS (arm64: dts: qcom: sm8250):
- Added status = "disabled" to jpeg-encoder node.
- Used 0x0 instead of bare 0 for zero cells in reg property. (Dmitry)
- Dropped opp-peak-kBps and opp-avg-kBps from OPP table; no upstream aggregation mechanism available yet.
Changes since v3:
CAMSS binding (dt-bindings: media: qcom,sm8250-camss):
- Added as new patch 2/5; allows #address-cells, #size-cells, ranges, and child nodes using unevaluatedProperties: false.
Binding (dt-bindings: media: qcom,jpeg-encoder):
- Dropped soc and camss wrapper nodes from example. (Dmitry)
- Removed opp-level from all OPP table entries. (Dmitry)
CAMSS (media: qcom: camss):
- Replaced patch 1/4 with Bryan O'Donoghue's original upstream commit.
Driver (media: qcom: jpeg):
- Cleaned up driver patch commit. (bod)
DTS (arm64: dts: qcom: sm8250):
- Restored camss interconnect-names to original values.
Changes since v2:
Binding (dt-bindings: media: qcom,jpeg-encoder):
- IOMMU stream IDs documented in binding description. (bod)
- Dropped "Properties documented:" section from commit message. (krzk)
- Dropped clocks minItems constraint. (krzk)
- Renamed clock-names to match hardware signal names. (krzk)
- Renamed interconnect-names to reflect path topology. (krzk, Dmitry)
DTS (arm64: dts: qcom: sm8250):
- Removed cell-index; use lowercase hex. (Dmitry)
- Moved jpeg-encoder node into the camss block as a child node. (bod)
Driver (media: qcom: jpeg):
- Sort obj-y entries alphabetically in qcom/Makefile. (krzk)
- Use devm_mutex_init() instead of mutex_init(). (Frank Li)
Changes since v1:
Binding (dt-bindings: media: qcom,jpeg-encoder):
- Removed qcm6490 and sm8550 compatible strings; SM8250 only.
- Fixed clock-names block in the binding example.
- Dropped reg-names: with a single reg entry it is unnecessary.
- Removed description literal block scalar (|).
- Dropped _clk suffix from clock-names.
- Added iommus description in the properties section.
Driver (media: qcom: jpeg):
- Migrated to devm_clk_bulk_get_all().
- Migrated to the OPP framework for clock rate management.
- Switched to RUNTIME_PM_OPS() and SYSTEM_SLEEP_PM_OPS() macros.
- platform_set_drvdata() moved to immediately after allocation.
- .pm uses pm_ptr().
Atanas Filipov (8):
dt-bindings: media: qcom: Add JPEG encoder binding
media: jpeg: Add JPEG baseline and JFIF APP0 constants
media: v4l2-jpeg: Add a baseline JPEG header writer
media: qcom: jpeg: Add Qualcomm JPEG V4L2 encoder
arm64: dts: qcom: sm8250: Add JPEG encoder node
arm64: dts: qcom: qrb5165-rb5: Enable JPEG encoder
arm64: dts: qcom: kodiak: Add JPEG encoder node
arm64: dts: qcom: qcs6490-rb3gen2: Enable JPEG encoder
.../bindings/media/qcom,sm8250-jpeg-enc.yaml | 190 ++ arch/arm64/boot/dts/qcom/kodiak.dtsi | 67 + arch/arm64/boot/dts/qcom/qcs6490-rb3gen2.dts | 4 + arch/arm64/boot/dts/qcom/qrb5165-rb5.dts | 4 + arch/arm64/boot/dts/qcom/sm8250.dtsi | 72 + drivers/media/platform/qcom/Kconfig | 1 + drivers/media/platform/qcom/Makefile | 1 + drivers/media/platform/qcom/jpeg/Kconfig | 15 + drivers/media/platform/qcom/jpeg/Makefile | 7 + .../media/platform/qcom/jpeg/qcom_jenc_dev.c | 379 ++++ .../media/platform/qcom/jpeg/qcom_jenc_dev.h | 122 ++ .../media/platform/qcom/jpeg/qcom_jenc_v420.c | 1541 +++++++++++++++++ .../media/platform/qcom/jpeg/qcom_jenc_v420.h | 45 + .../qcom/jpeg/qcom_jenc_v420_hw_info.h | 215 +++ .../media/platform/qcom/jpeg/qcom_jenc_v4l2.c | 1175 +++++++++++++ .../media/platform/qcom/jpeg/qcom_jenc_v4l2.h | 13 + drivers/media/v4l2-core/v4l2-jpeg.c | 165 ++ include/media/jpeg.h | 79 + include/media/v4l2-jpeg.h | 31 + 19 files changed, 4126 insertions(+) create mode 100644 Documentation/devicetree/bindings/media/qcom,sm8250-jpeg-enc.yaml create mode 100644 drivers/media/platform/qcom/jpeg/Kconfig create mode 100644 drivers/media/platform/qcom/jpeg/Makefile create mode 100644 drivers/media/platform/qcom/jpeg/qcom_jenc_dev.c create mode 100644 drivers/media/platform/qcom/jpeg/qcom_jenc_dev.h create mode 100644 drivers/media/platform/qcom/jpeg/qcom_jenc_v420.c create mode 100644 drivers/media/platform/qcom/jpeg/qcom_jenc_v420.h create mode 100644 drivers/media/platform/qcom/jpeg/qcom_jenc_v420_hw_info.h create mode 100644 drivers/media/platform/qcom/jpeg/qcom_jenc_v4l2.c create mode 100644 drivers/media/platform/qcom/jpeg/qcom_jenc_v4l2.h
base-commit: 630059a5a632377b9b7b487baccde92b7ae1dd47
Signature · 1 line
2.34.1
PATCH v8 1/8 dt-bindings: media: qcom: Add JPEG encoder binding
Add device-tree binding for the Qualcomm JPEG encoder hardware block present in SM8250 (Kona) and SC7280 (Kodiak) SoCs.
The JPEG encoder is a standalone hardware IP within the camera subsystem that performs JPEG compression in memory-to-memory fashion. It is separate from the CAMSS ISP pipeline and has its own register space, interrupt, clocks, power domains, IOMMU stream, and interconnect path.
--- .../bindings/media/qcom,sm8250-jpeg-enc.yaml | 190 ++++++++++++++++++ 1 file changed, 190 insertions(+) create mode 100644 Documentation/devicetree/bindings/media/qcom,sm8250-jpeg-enc.yaml
Documentation/devicetree/bindings/media/qcom,sm8250-jpeg-enc.yaml new file +190 -0
@@ -0,0 +1,190 @@ +# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/media/qcom,sm8250-jpeg-enc.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Qualcomm JPEG Encoder + +maintainers: + - Atanas Filipov <[email protected]> + +description: + Qualcomm JPEG Encoder is the JPEG encode hardware present in Qualcomm SoCs. + The encoder is a standalone hardware IP within the camera subsystem that + performs JPEG compression in memory-to-memory fashion. + +properties: + compatible: + enum: + - qcom,sc7280-jpeg-enc + - qcom,sm8250-jpeg-enc + + reg: + maxItems: 1 + + interrupts: + maxItems: 1 + + clocks: + maxItems: 5 + + clock-names: + items: + - const: core + - const: bus + - const: config + - const: cpas + - const: camnoc_axi + + power-domains: + minItems: 2 + maxItems: 3 + + power-domain-names: + minItems: 2 + maxItems: 3 + + interconnects: + maxItems: 1 + + interconnect-names: + items: + - const: camnoc + + iommus: + description: + SMMU stream ID for the JPEG hardware. + maxItems: 1 + + operating-points-v2: true + + opp-table: + type: object + +required: + - compatible + - reg + - clocks + - clock-names + - interrupts + - power-domains + - power-domain-names + - interconnects + - interconnect-names + - iommus + - operating-points-v2 + +allOf: + - if: + properties: + compatible: + contains: + const: qcom,sc7280-jpeg-enc + then: + properties: + power-domains: + items: + - description: Titan top GDSC + - description: CX power domain + power-domain-names: + items: + - const: titan_top + - const: cx + + - if: + properties: + compatible: + contains: + const: qcom,sm8250-jpeg-enc + then: + properties: + power-domains: + items: + - description: Titan top GDSC + - description: MX power domain + - description: MMCX power domain + power-domain-names: + items: + - const: titan_top + - const: mx + - const: mmcx + +additionalProperties: false + +examples: + - | + #include <dt-bindings/clock/qcom,camcc-sm8250.h> + #include <dt-bindings/clock/qcom,gcc-sm8250.h> + #include <dt-bindings/interconnect/qcom,sm8250.h> + #include <dt-bindings/interrupt-controller/arm-gic.h> + #include <dt-bindings/power/qcom,rpmhpd.h> + + jpeg-encoder@ac53000 { + compatible = "qcom,sm8250-jpeg-enc"; + reg = <0x0ac53000 0x1000>; + + interrupts = <GIC_SPI 474 IRQ_TYPE_EDGE_RISING>; + + power-domains = <&camcc TITAN_TOP_GDSC>, + <&rpmhpd RPMHPD_MX>, + <&rpmhpd RPMHPD_MMCX>; + power-domain-names = "titan_top", "mx", "mmcx"; + + clocks = <&camcc CAM_CC_JPEG_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>; + clock-names = "core", + "bus", + "config", + "cpas", + "camnoc_axi"; + + interconnects = <&mmss_noc MASTER_CAMNOC_SF 0 &mc_virt SLAVE_EBI_CH0 0>; + interconnect-names = "camnoc"; + + iommus = <&apps_smmu 0x2040 0x400>; + + operating-points-v2 = <&jpeg_opp_table>; + + jpeg_opp_table: opp-table { + compatible = "operating-points-v2"; + + opp-100000000 { + opp-hz = /bits/ 64 <100000000>; + opp-peak-kBps = <262560>; + required-opps = <&rpmhpd_opp_svs_l1>, + <&rpmhpd_opp_low_svs>; + }; + + opp-200000000 { + opp-hz = /bits/ 64 <200000000>; + opp-peak-kBps = <524760>; + required-opps = <&rpmhpd_opp_svs_l1>, + <&rpmhpd_opp_svs>; + }; + + opp-400000000 { + opp-hz = /bits/ 64 <400000000>; + opp-peak-kBps = <978600>; + required-opps = <&rpmhpd_opp_svs_l1>, + <&rpmhpd_opp_svs_l1>; + }; + + opp-480000000 { + opp-hz = /bits/ 64 <480000000>; + opp-peak-kBps = <1095600>; + required-opps = <&rpmhpd_opp_svs_l1>, + <&rpmhpd_opp_nom>; + }; + + opp-600000000 { + opp-hz = /bits/ 64 <600000000>; + opp-peak-kBps = <1095600>; + required-opps = <&rpmhpd_opp_svs_l1>, + <&rpmhpd_opp_turbo>; + }; + }; + };
Signature · 1 line
2.34.1
PATCH v8 2/8 media: jpeg: Add JPEG baseline and JFIF APP0 constants
In reply to Atanas FilipovAdd the standard field values of a baseline (ITU-T T.81) JFIF header to the shared JPEG marker header: sample precision, component counts, sampling factors, quantization table identifiers, SOS table selectors, spectral selection and successive approximation and the JFIF APP0 payload values. Describe the marker segment header and the SOF0 and SOS headers and component specifications as packed structs, so their sizes and field offsets can be taken with sizeof() and offsetof().
--- include/media/jpeg.h | 79 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 79 insertions(+)
include/media/jpeg.h +79 -0
@@ -3,6 +3,8 @@#ifndef _MEDIA_JPEG_H_#define _MEDIA_JPEG_H_ +#include <linux/types.h> +/* JPEG markers */ #define JPEG_MARKER_TEM 0x01#define JPEG_MARKER_SOF0 0xc0
@@ -17,4 +19,81 @@#define JPEG_MARKER_APP0 0xe0#define JPEG_MARKER_COM 0xfe +/* JPEG baseline sample precision (bits per sample) */ +#define JPEG_SAMPLE_PRECISION_BITS 8 + +/* Number of components: greyscale (1) and colour YCbCr (3) */ +#define JPEG_COMP_MONO 1 +#define JPEG_COMP_COLOR 3 + +/* Chroma subsampling factors encoded in SOF0 sampling byte */ +#define JPEG_SAMPLING_H1V1 0x11 +#define JPEG_SAMPLING_H2V2 0x22 + +/* Quantization table destination identifiers */ +#define JPEG_QTABLE_LUMA 0 +#define JPEG_QTABLE_CHROMA 1 + +/* SOS spectral selection and approximation fields (baseline JPEG) */ +#define JPEG_SPECTRAL_START 0x00 +#define JPEG_SPECTRAL_END 0x3f +#define JPEG_APPROX_HIGH_LOW 0x00 + +/* SOS table selector bytes (luma: DC=0/AC=0, chroma: DC=1/AC=1) */ +#define JPEG_TABLE_SEL_LUMA 0x00 +#define JPEG_TABLE_SEL_CHROMA 0x11 + +/* +* JFIF APP0 payload fields, as specified by the JFIF spec referenced from +* ITU-T T.81 Annex B. See: https://www.w3.org/Graphics/JPEG/itu-t81.pdf +*/ +#define JFIF_IDENT_TERM 0x00 +#define JFIF_VERSION_MAJOR 0x01 +#define JFIF_VERSION_MINOR 0x01 +#define JFIF_UNITS_NONE 0x00 +#define JFIF_DENSITY_HI 0x00 +#define JFIF_DENSITY_LO 0x01 +#define JFIF_THUMBNAIL_SIZE 0x00 + +/* Marker segment header: marker and length (ITU-T T.81 B.1.1.4) */ +struct jpeg_seg_hdr { +__be16 marker; +__be16 length;/* bytes from the length field to the end of the segment */ +} __packed; + +/* SOF0 frame header up to the component specifications (ITU-T T.81 B.2.2) */ +struct jpeg_sof_hdr { +struct jpeg_seg_hdr seg; +u8 precision; +__be16 height; +__be16 width; +u8 num_components; +} __packed; + +/* SOF0 frame component specification, one per component */ +struct jpeg_sof_comp { +u8 id; +u8 sampling; +u8 qtable; +} __packed; + +/* SOS scan header up to the component specifications (ITU-T T.81 B.2.3) */ +struct jpeg_sos_hdr { +struct jpeg_seg_hdr seg; +u8 num_components; +} __packed; + +/* SOS scan component specification, one per component */ +struct jpeg_sos_comp { +u8 id; +u8 tables;/* DC and AC entropy table selectors */ +} __packed; + +/* SOS fields after the component specifications */ +struct jpeg_sos_tail { +u8 spectral_start; +u8 spectral_end; +u8 approx; +} __packed; +#endif /* _MEDIA_JPEG_H_ */
Signature · 1 line
2.34.1
PATCH v8 3/8 media: v4l2-jpeg: Add a baseline JPEG header writer
In reply to Atanas FilipovSeveral V4L2 JPEG encoder drivers build the JPEG header in the driver from a fixed template and patch the image size and quantization tables for each frame. Add v4l2_jpeg_write_header() for the baseline case: it writes SOI, an optional JFIF APP0, one DQT segment per table, SOF0, the ITU-T T.81 Annex K reference Huffman tables in one DHT segment and SOS, and returns the offsets of the fields set per frame. Add v4l2_jpeg_hdr_set_size() to set the image size in such a header.
The field values come from media/jpeg.h, so the driver keeps only the hardware specifics.
--- drivers/media/v4l2-core/v4l2-jpeg.c | 165 ++++++++++++++++++++++++++++ include/media/v4l2-jpeg.h | 31 ++++++ 2 files changed, 196 insertions(+)
drivers/media/v4l2-core/v4l2-jpeg.c +165 -0
@@ -13,7 +13,10 @@#include <linux/errno.h> #include <linux/kernel.h> #include <linux/module.h> +#include <linux/stddef.h> +#include <linux/string.h> #include <linux/types.h> +#include <media/jpeg.h> #include <media/v4l2-jpeg.h> MODULE_DESCRIPTION ("V4L2 JPEG header parser helpers" );
@@ -711,3 +714,165 @@ int v4l2_jpeg_parse_header(void *buf, size_t len, struct v4l2_jpeg_header *out)return marker; }EXPORT_SYMBOL_GPL (v4l2_jpeg_parse_header); + +/* baseline JPEG header writer */ + +/* Segment length of a header struct: the marker is not counted */ +#define JPEG_SEG_LEN (hdr) (sizeof(struct hdr) - offsetof(struct jpeg_seg_hdr, length)) + +struct jpeg_hdr_buf { +u8 *buf; +size_t len; +size_t pos; +}; + +/* Writes past the end only advance pos; v4l2_jpeg_write_header() checks it */ +static void jpeg_put_bytes (struct jpeg_hdr_buf *b,const void *src,size_t n) +{ +if (b->pos + n <= b->len) { +if (src) +memcpy (b->buf + b->pos, src, n); +else +memset (b->buf + b->pos,0 , n); + } + b->pos += n; +} + +static void jpeg_put_u8 (struct jpeg_hdr_buf *b,u8 val) +{ +jpeg_put_bytes (b, &val,1 ); +} + +static void jpeg_put_be16 (struct jpeg_hdr_buf *b,u16 val) +{ +u8 data[2 ] = { val >>8 , val &0xff }; + +jpeg_put_bytes (b, data,sizeof (data)); +} + +static void jpeg_put_dht (struct jpeg_hdr_buf *b,u8 class_id,const u8 *table,size_t len) +{ +jpeg_put_u8 (b, class_id); +jpeg_put_bytes (b, table, len); +} + +/** +* v4l2_jpeg_write_header - write a baseline JPEG header +* @buf: destination buffer +* @len: length of the destination buffer +* @params: header parameters +* @layout: returns the header size and the offsets of the fields set per frame +* +* Writes SOI, an optional JFIF APP0, one DQT segment per quantization table, +* SOF0, one DHT segment with the reference Huffman tables of ITU-T.81 Annex K +* and SOS. Width, height and the quantization table values are written as +* zero; set them with v4l2_jpeg_hdr_set_size() and through the +* @layout->dqt_offset offsets. +* +* Returns 0 on success, -EINVAL for an unsupported number of components or +* -ENOSPC if @buf is too small. +*/ +int v4l2_jpeg_write_header (void *buf,size_t len,const struct v4l2_jpeg_hdr_params *params, +struct v4l2_jpeg_hdr_layout *layout) +{ +static const u8 jfif[] = { +'J' ,'F' ,'I' ,'F' ,JFIF_IDENT_TERM , +JFIF_VERSION_MAJOR ,JFIF_VERSION_MINOR , +JFIF_UNITS_NONE , +JFIF_DENSITY_HI ,JFIF_DENSITY_LO ,/* X density */ +JFIF_DENSITY_HI ,JFIF_DENSITY_LO ,/* Y density */ +JFIF_THUMBNAIL_SIZE ,JFIF_THUMBNAIL_SIZE , + }; +struct jpeg_hdr_buf b = { .buf = buf, .len = len }; +unsigned int nc = params->num_components; +unsigned int ntables = nc ==JPEG_COMP_MONO ?1 :2 ; +unsigned int i; + +if (nc !=JPEG_COMP_MONO && nc !=JPEG_COMP_COLOR ) +return -EINVAL ; + +memset (layout,0 ,sizeof (*layout)); + +jpeg_put_be16 (&b,SOI ); + +if (params->jfif) { +jpeg_put_be16 (&b,APP0 ); +jpeg_put_be16 (&b,sizeof (__be16) +sizeof (jfif)); +jpeg_put_bytes (&b, jfif,sizeof (jfif)); + } + +/* one 8-bit table per segment, luma Tq 0, chroma Tq 1 */ +for (i =0 ; i < ntables; i++) { +jpeg_put_be16 (&b,DQT ); +/* length field, Pq/Tq byte, table */ +jpeg_put_be16 (&b,sizeof (__be16) +sizeof (u8) +V4L2_JPEG_PIXELS_IN_BLOCK ); +jpeg_put_u8 (&b, i ?JPEG_QTABLE_CHROMA :JPEG_QTABLE_LUMA ); + layout->dqt_offset[i] = b.pos; +jpeg_put_bytes (&b,NULL ,V4L2_JPEG_PIXELS_IN_BLOCK ); + } + + layout->sof_offset = b.pos; +jpeg_put_be16 (&b,SOF0 ); +jpeg_put_be16 (&b,JPEG_SEG_LEN (jpeg_sof_hdr) + nc *sizeof (struct jpeg_sof_comp )); +jpeg_put_u8 (&b,JPEG_SAMPLE_PRECISION_BITS ); +jpeg_put_be16 (&b,0 );/* height */ +jpeg_put_be16 (&b,0 );/* width */ +jpeg_put_u8 (&b, nc); +for (i =0 ; i < nc; i++) { +jpeg_put_u8 (&b, i +1 ); +jpeg_put_u8 (&b, i ?JPEG_SAMPLING_H1V1 : params->luma_sampling); +jpeg_put_u8 (&b, i ?JPEG_QTABLE_CHROMA :JPEG_QTABLE_LUMA ); + } + +jpeg_put_be16 (&b,DHT ); +/* length field, then per table class a Tc/Th byte and the DC and AC tables */ +jpeg_put_be16 (&b,sizeof (__be16) + ntables * (2 *sizeof (u8) +V4L2_JPEG_REF_HT_DC_LEN + +V4L2_JPEG_REF_HT_AC_LEN )); +jpeg_put_dht (&b,V4L2_JPEG_LUM_HT |V4L2_JPEG_DC_HT , v4l2_jpeg_ref_table_luma_dc_ht, +V4L2_JPEG_REF_HT_DC_LEN ); +jpeg_put_dht (&b,V4L2_JPEG_LUM_HT |V4L2_JPEG_AC_HT , v4l2_jpeg_ref_table_luma_ac_ht, +V4L2_JPEG_REF_HT_AC_LEN ); +if (nc ==JPEG_COMP_COLOR ) { +jpeg_put_dht (&b,V4L2_JPEG_CHR_HT |V4L2_JPEG_DC_HT , + v4l2_jpeg_ref_table_chroma_dc_ht,V4L2_JPEG_REF_HT_DC_LEN ); +jpeg_put_dht (&b,V4L2_JPEG_CHR_HT |V4L2_JPEG_AC_HT , + v4l2_jpeg_ref_table_chroma_ac_ht,V4L2_JPEG_REF_HT_AC_LEN ); + } + +jpeg_put_be16 (&b,SOS ); +jpeg_put_be16 (&b,JPEG_SEG_LEN (jpeg_sos_hdr) + nc *sizeof (struct jpeg_sos_comp ) + +sizeof (struct jpeg_sos_tail )); +jpeg_put_u8 (&b, nc); +for (i =0 ; i < nc; i++) { +jpeg_put_u8 (&b, i +1 ); +jpeg_put_u8 (&b, i ?JPEG_TABLE_SEL_CHROMA :JPEG_TABLE_SEL_LUMA ); + } +jpeg_put_u8 (&b,JPEG_SPECTRAL_START ); +jpeg_put_u8 (&b,JPEG_SPECTRAL_END ); +jpeg_put_u8 (&b,JPEG_APPROX_HIGH_LOW ); + +if (b.pos > len) +return -ENOSPC ; + + layout->size = b.pos; + +return 0 ; +} +EXPORT_SYMBOL_GPL (v4l2_jpeg_write_header); + +/** +* v4l2_jpeg_hdr_set_size - set the image size in a header from v4l2_jpeg_write_header() +* @buf: header buffer +* @layout: layout returned by v4l2_jpeg_write_header() +* @width: image width +* @height: image height +*/ +void v4l2_jpeg_hdr_set_size (void *buf,const struct v4l2_jpeg_hdr_layout *layout,u16 width, +u16 height) +{ +u8 *sof = (u8 *)buf + layout->sof_offset; + +put_unaligned_be16 (height, sof + offsetof(struct jpeg_sof_hdr , height)); +put_unaligned_be16 (width, sof + offsetof(struct jpeg_sof_hdr , width)); +} +EXPORT_SYMBOL_GPL (v4l2_jpeg_hdr_set_size);
include/media/v4l2-jpeg.h +31 -0
@@ -167,8 +167,39 @@ struct v4l2_jpeg_header {enum v4l2_jpeg_app14_tf app14_tf; }; +/** +* struct v4l2_jpeg_hdr_params - baseline JPEG header parameters +* @num_components: number of color components, 1 (grey) or 3 (YCbCr) +* @luma_sampling: luma horizontal and vertical sampling factors, as in the +* SOF0 component specification (0x11, 0x21 or 0x22); chroma uses 0x11 +* @jfif: emit a JFIF APP0 segment after SOI +*/ +struct v4l2_jpeg_hdr_params { +u8 num_components; +u8 luma_sampling; +bool jfif; +}; + +/** +* struct v4l2_jpeg_hdr_layout - offsets of the fields set per frame +* @size: header size in bytes +* @sof_offset: offset of the SOF0 marker +* @dqt_offset: offset of the luma and chroma quantization table values +* (V4L2_JPEG_PIXELS_IN_BLOCK bytes in zigzag order), 0 if not present +*/ +struct v4l2_jpeg_hdr_layout { +u32 size; +u32 sof_offset; +u32 dqt_offset[2 ]; +}; +int v4l2_jpeg_parse_header (void *buf,size_t len,struct v4l2_jpeg_header *out); +int v4l2_jpeg_write_header (void *buf,size_t len,const struct v4l2_jpeg_hdr_params *params, +struct v4l2_jpeg_hdr_layout *layout); +void v4l2_jpeg_hdr_set_size (void *buf,const struct v4l2_jpeg_hdr_layout *layout,u16 width, +u16 height); +extern const u8 v4l2_jpeg_zigzag_scan_index[V4L2_JPEG_PIXELS_IN_BLOCK ];extern const u8 v4l2_jpeg_ref_table_luma_qt[V4L2_JPEG_PIXELS_IN_BLOCK ];extern const u8 v4l2_jpeg_ref_table_chroma_qt[V4L2_JPEG_PIXELS_IN_BLOCK ];
Signature · 1 line
2.34.1
PATCH v8 4/8 media: qcom: jpeg: Add Qualcomm JPEG V4L2 encoder
In reply to Atanas FilipovAdd a Qualcomm JPEG encoder driver implemented on top of the V4L2 mem2mem framework.
The driver wires vb2 queue handling, format negotiation, JPEG header handling, interrupt-driven job completion, and runtime PM/clock/ICC integration for the standalone JPEG encode hardware block.
This series targets SM8250 (Kona) and SC7280 (Kodiak) platforms.
--- drivers/media/platform/qcom/Kconfig | 1 + drivers/media/platform/qcom/Makefile | 1 + drivers/media/platform/qcom/jpeg/Kconfig | 15 + drivers/media/platform/qcom/jpeg/Makefile | 7 + .../media/platform/qcom/jpeg/qcom_jenc_dev.c | 379 ++++ .../media/platform/qcom/jpeg/qcom_jenc_dev.h | 122 ++ .../media/platform/qcom/jpeg/qcom_jenc_v420.c | 1541 +++++++++++++++++ .../media/platform/qcom/jpeg/qcom_jenc_v420.h | 45 + .../qcom/jpeg/qcom_jenc_v420_hw_info.h | 215 +++ .../media/platform/qcom/jpeg/qcom_jenc_v4l2.c | 1175 +++++++++++++ .../media/platform/qcom/jpeg/qcom_jenc_v4l2.h | 13 + 11 files changed, 3514 insertions(+) create mode 100644 drivers/media/platform/qcom/jpeg/Kconfig create mode 100644 drivers/media/platform/qcom/jpeg/Makefile create mode 100644 drivers/media/platform/qcom/jpeg/qcom_jenc_dev.c create mode 100644 drivers/media/platform/qcom/jpeg/qcom_jenc_dev.h create mode 100644 drivers/media/platform/qcom/jpeg/qcom_jenc_v420.c create mode 100644 drivers/media/platform/qcom/jpeg/qcom_jenc_v420.h create mode 100644 drivers/media/platform/qcom/jpeg/qcom_jenc_v420_hw_info.h create mode 100644 drivers/media/platform/qcom/jpeg/qcom_jenc_v4l2.c create mode 100644 drivers/media/platform/qcom/jpeg/qcom_jenc_v4l2.h
drivers/media/platform/qcom/Kconfig +1 -0
@@ -4,4 +4,5 @@ comment "Qualcomm media platform drivers" source "drivers/media/platform/qcom/camss/Kconfig" source "drivers/media/platform/qcom/iris/Kconfig" +source "drivers/media/platform/qcom/jpeg/Kconfig" source "drivers/media/platform/qcom/venus/Kconfig"
drivers/media/platform/qcom/Makefile +1 -0
@@ -1,4 +1,5 @@ # SPDX-License-Identifier: GPL-2.0-only obj-y += camss/ obj-y += iris/ +obj-y += jpeg/ obj-y += venus/
drivers/media/platform/qcom/jpeg/Kconfig new file +15 -0
@@ -0,0 +1,15 @@ +# 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 VIDEOBUF2_DMA_SG + select V4L2_JPEG_HELPER + select V4L2_MEM2MEM_DEV + help + V4L2 mem2mem driver for the Qualcomm JPEG encoder hardware + found in Snapdragon SoCs. + + To compile this driver as a module, choose M here: the + module will be called qcom-jenc.
drivers/media/platform/qcom/jpeg/Makefile new file +7 -0
@@ -0,0 +1,7 @@ +# 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_v420.o
drivers/media/platform/qcom/jpeg/qcom_jenc_dev.c new file +379 -0
379 lines not on this page · raw message
drivers/media/platform/qcom/jpeg/qcom_jenc_dev.h new file +122 -0
122 lines not on this page · raw message
drivers/media/platform/qcom/jpeg/qcom_jenc_v420.c new file +1541 -0
1,541 lines not on this page · raw message
drivers/media/platform/qcom/jpeg/qcom_jenc_v420.h new file +45 -0
45 lines not on this page · raw message
drivers/media/platform/qcom/jpeg/qcom_jenc_v420_hw_info.h new file +215 -0
215 lines not on this page · raw message
drivers/media/platform/qcom/jpeg/qcom_jenc_v4l2.c new file +1175 -0
666 lines not on this page · raw message
drivers/media/platform/qcom/jpeg/qcom_jenc_v4l2.h new file +13 -0
Lines of this file are not shown. View the raw message.
The rest of this diff is not shown. View the raw message.
Signature · 1 line
2.34.1
Part of the diff is not shown here. View the raw message.
[email protected]
AI reviewRe: [PATCH v8 4/8] media: qcom: jpeg: Add Qualcomm JPEG V4L2 encoder
Thank you for your contribution! Sashiko AI review found 10 potential issues to consider: - [High] media: qcom: jpeg: unverified contiguous DMA length in jpeg_store_fe/we_next() - [High] media…
Thank you for your contribution! Sashiko AI review found 10 potential issues to consider:
- [High] media: qcom: jpeg: unverified contiguous DMA length in jpeg_store_fe/we_next()
- [High] media: qcom: jpeg: use-after-free of m2m_ctx in jpeg_finish_work()
- [Medium] media: qcom: jpeg: unadjusted WE_BSIZE_0 limit in jpeg_setup_we_size()
- [Medium] media: qcom: jpeg: unhandled IRQs unmasked in jpeg_init() risk lost IRQ
- [Medium] media: qcom: jpeg: non-exclusive IRQ handling in qcom_jenc_v420_irq_bot()
- [Medium] media: qcom: jpeg: disjoint vdev->lock and vq->lock leave ioctls unserialized
- [Medium] media: qcom: jpeg: missing job_abort in qcom_jpeg_v4l2_m2m_ops blocks streamoff
- [Medium] media: qcom: jpeg: use-after-free on unbind due to devm_kzalloc() of jenc
- [Medium] media: qcom: jpeg: broken V4L2_ENC_CMD_START resume and drain error handling
- [Low] media: qcom: jpeg: mismatched CAPTURE alignment in jpeg_v4l2_set_format()
--
commit 5296b93869b724f0ca5368bbad66d4fa21dc5933
Author: Atanas Filipov <[email protected]>
media: qcom: jpeg: Add Qualcomm JPEG V4L2 encoder
This commit adds a V4L2 mem2mem JPEG encoder driver for Qualcomm SoCs targeting the SM8250 and SC7280 platforms.
Quoted 5 lines
drivers/media/platform/qcom/jpeg/qcom_jenc_dev.c new file +0
-0
[ ... ]
Quoted 8 lines
drivers/media/platform/qcom/jpeg/qcom_jenc_dev.c new file +8
-0+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 ;
drivers/media/platform/qcom/jpeg/qcom_jenc_dev.c line 275
Quoted 10 lines
drivers/media/platform/qcom/jpeg/qcom_jenc_dev.c new file +10
-0+ + jenc->dev = &pdev->dev; +platform_set_drvdata (pdev, jenc); + + rc =devm_mutex_init (&pdev->dev, &jenc->dev_mutex); +if (rc) + goto err_free_jenc; + rc =devm_mutex_init (&pdev->dev, &jenc->hw_ref_lock); +if (rc) + goto err_free_jenc;
[Severity: Medium]
Can unbinding the device while a /dev/videoX file descriptor is open cause a use-after-free of jenc when that file descriptor is later closed?
Because jenc and its mutexes are managed by devres, unbinding the platform driver destroys jenc->dev_mutex and jenc->hw_ref_lock, unmaps jenc->jpeg_base, and frees jenc immediately. When userspace subsequently closes the open file descriptor, fop_jpeg_file_release() (and bop_jpeg_vb2_stop_streaming() if the context was streaming) dereferences ectx->jenc, locks the destroyed mutexes, and v4l2_release() -> video_put() accesses &jenc->v4l2_dev inside the freed struct.
Quoted 5 lines
drivers/media/platform/qcom/jpeg/qcom_jenc_v420.c new file +0
-0
[ ... ]
Quoted 2 lines
drivers/media/platform/qcom/jpeg/qcom_jenc_v420.c new file +2
-0+static int jpeg_init (struct qcom_jenc_dev *jenc) +{
[ ... ]
drivers/media/platform/qcom/jpeg/qcom_jenc_v420.c line 509
Quoted 7 lines
drivers/media/platform/qcom/jpeg/qcom_jenc_v420.c new file +7
-0+jpeg_clear_planes_queues (jenc); + +jpeg_io_write (jenc,JPEG_V420_REG_INT_CLR ,JPEG_V420_IRQ_STATUS_ALL_BITS ); +jpeg_io_write (jenc,JPEG_V420_REG_INT_MASK ,JPEG_V420_IRQ_STATUS_ALL_BITS ); + +return 0 ; +}
[Severity: Medium]
Does unmasking JPEG_V420_IRQ_STATUS_ALL_BITS here risk losing the JPEG_V420_IRQ_STATUS_SESSION_DONE interrupt or overwriting jenc->pending_irq_status?
JPEG_V420_IRQ_STATUS_ALL_BITS enables RD_BUF_PLNS_DONE_MSK, WR_BUF_PLN0_DONE, RD_BUF_PLNS_REQ_ATTN_MSK, and WR_BUF_PLNS_REQ_ATTN_MSK, even though qcom_jenc_v420_irq_bot() only handles SESSION_DONE and SESION_ERROR_MSK. In qcom_jenc_v420_irq_top():
drivers/media/platform/qcom/jpeg/qcom_jenc_v420.c:qcom_jenc_v420_irq_top() {
irq_status = jpeg_io_read(jenc, JPEG_V420_REG_INT_STATUS);
jpeg_io_write(jenc, JPEG_V420_REG_INT_CLR, irq_status & JPEG_V420_IRQ_STATUS_ALL_BITS);
...
irq_status &= ~(JPEG_V420_IRQ_STATUS_RESET_ACK | JPEG_V420_IRQ_STATUS_STOP_ACK);
if (!irq_status) {
spin_unlock_irqrestore(&jenc->hw_lock, flags);
return IRQ_HANDLED;
}
WRITE_ONCE(jenc->pending_irq_status, irq_status);
}If a plane-done interrupt fires at the end of a frame and SESSION_DONE asserts between reading JPEG_V420_REG_INT_STATUS and writing JPEG_V420_REG_INT_CLR, only the plane-done bit is cleared while SESSION_DONE stays asserted without generating a new rising edge, wedging the active m2m job. Even if two interrupts are delivered, a second unhandled interrupt can overwrite jenc->pending_irq_status via WRITE_ONCE() before the threaded handler runs. Only unmasking the interrupt bits the driver actually handles (and accumulating pending_irq_status with atomic or spinlock-protected OR-and-swap) would avoid this.
[ ... ]
Quoted 12 lines
drivers/media/platform/qcom/jpeg/qcom_jenc_v420.c new file +12
-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; + +for (pln =0 ; pln < q->vf.num_planes; pln++) { + buff->plns[pln].sgt =vb2_dma_sg_plane_desc (vb2, pln); +if (!buff->plns[pln].sgt || !buff->plns[pln].sgt->sgl) +return -EINVAL ; + + buff->plns[pln].dma =sg_dma_address (buff->plns[pln].sgt->sgl);
drivers/media/platform/qcom/jpeg/qcom_jenc_v420.c line 594
Quoted 10 lines
drivers/media/platform/qcom/jpeg/qcom_jenc_v420.c new file +10
-0+if (!buff->plns[pln].dma) +return -EINVAL ; + + buff->plns[pln].size =vb2_plane_size (vb2, pln); +if (!buff->plns[pln].size) +return -EINVAL ; + } + +return 0 ; +}
[Severity: High]
Can jpeg_store_fe_next() and jpeg_store_we_next() cause out-of-bounds DMA when a buffer's scatterlist is mapped into multiple segments?
Both functions take only sg_dma_address(sgt->sgl) and program the hardware to DMA the entire plane linearly from that address, without checking that sg_dma_len(sgt->sgl) covers vb2_plane_size(vb2, pln). Because the queues use vb2_dma_sg_memops with VB2_USERPTR and VB2_DMABUF enabled, an unaligned USERPTR (which falls back to per-entry swiotlb bounce mappings on arm64) or a multi-segment DMABUF produces sg_dma_len(sgt->sgl) < vb2_plane_size(vb2, pln), so the hardware reads or writes past the end of the first IOVA segment. Should the driver use vb2_dma_contig_memops instead, or verify that sg_dma_len(sgt->sgl) >= buff->plns[pln].size?
[ ... ]
Quoted 3 lines
drivers/media/platform/qcom/jpeg/qcom_jenc_v420.c new file +3
-0+static int jpeg_apply_we_addr (struct jenc_context *ectx,struct qcom_jenc_queue *q, +struct vb2_buffer *vb) +{
[ ... ]
Quoted 16 lines
drivers/media/platform/qcom/jpeg/qcom_jenc_v420.c new file +16
-0+ header_size = ectx->hdr_cache.layout.size; +if (vb->planes[0 ].length < header_size) +return -EINVAL ; + +memcpy (mptr, ectx->hdr_cache.data, header_size); +v4l2_jpeg_hdr_set_size (mptr, &ectx->hdr_cache.layout, q->vf.width, q->vf.height); + + dma += header_size; + +/* +* Flush CPU writes to the header before handing the buffer to the +* hardware DMA engine. +*/ +jpeg_sync_sg (jenc->dev, frame,DMA_BIDIRECTIONAL , true); + +jpeg_io_write (jenc, jpeg_v420_we_pntr[pln], dma);
[ ... ]
drivers/media/platform/qcom/jpeg/qcom_jenc_v420.c line 902
Quoted 13 lines
drivers/media/platform/qcom/jpeg/qcom_jenc_v420.c new file +13
-0+static void jpeg_setup_we_size (struct jenc_context *ectx,struct qcom_jenc_queue *q) +{ +struct v4l2_pix_format_mplane *dfmt = &q->vf; +struct qcom_jenc_dev *jenc = ectx->jenc; +u8 pln; + +for (pln =0 ; pln <QCOM_JPEG_MAX_PLANES ; pln++) +jpeg_rw_bits (jenc, jpeg_v420_we_stride[pln],JPEG_V420_PLN_WR_STRIDE_MSK ,0 ); + +jpeg_io_write (jenc,JPEG_V420_REG_WE_BSIZE_0 , dfmt->plane_fmt[0 ].sizeimage); + +dev_dbg (ectx->dev,"WE size=%u\n" , dfmt->plane_fmt[0 ].sizeimage); +}
[Severity: Medium]
Should JPEG_V420_REG_WE_BSIZE_0 be reduced by header_size?
jpeg_apply_we_addr() advances the Write Engine base pointer JPEG_V420_REG_WE_PNTR_0 by header_size bytes into the capture buffer, but jpeg_setup_we_size() programs JPEG_V420_REG_WE_BSIZE_0 with the full dfmt->plane_fmt[0].sizeimage. If an encoded frame exceeds sizeimage - header_size, the hardware can DMA up to header_size bytes past the end of a sizeimage-sized buffer, and qcom_jenc_v420_irq_bot() will pass out_size + ctx->hdr_cache.layout.size > vb2_plane_size() to vb2_set_plane_payload().
[ ... ]
Quoted 45 lines
drivers/media/platform/qcom/jpeg/qcom_jenc_v420.c new file +45
-0+irqreturn_t qcom_jenc_v420_irq_bot (int irq,void *data) +{ +struct qcom_jenc_dev *jenc = data; +unsigned long flags; +u32 irq_status; + + irq_status =READ_ONCE (jenc->pending_irq_status); + +if (FIELD_GET (JPEG_V420_IRQ_STATUS_SESSION_DONE , irq_status)) { +struct jenc_context *ctx; + +spin_lock_irqsave (&jenc->hw_lock, flags); + ctx = jenc->actx; + jenc->actx =NULL ; +spin_unlock_irqrestore (&jenc->hw_lock, flags); + +if (ctx && ctx->bufq[JENC_DST_QUEUE ].buff_id >=0 ) { +struct qcom_jenc_queue *dq = &ctx->bufq[JENC_DST_QUEUE ]; +struct qcom_jpeg_buff *frame = &dq->buff[dq->buff_id]; +size_t out_size =jpeg_rd_bits (jenc,JPEG_V420_REG_ENC_OUT_SIZE , +JPEG_V420_STATUS_OUT_SIZE_BYTES_MSK ); + +dev_dbg (jenc->dev,"complete idx:%d addr=%pad size=%zu\n" , + dq->buff_id, &frame->plns[0 ].dma, out_size); + +/* +* Stop the hardware before enc_hw_irq_cb(): it leads to +* v4l2_m2m_job_finish(), which can start the next job's device_run(). +*/ +jpeg_stop (jenc); + jenc->enc_hw_irq_cb (ctx,VB2_BUF_STATE_DONE , + out_size + ctx->hdr_cache.layout.size); + }else { +jpeg_stop (jenc); + } + } + +if (FIELD_GET (JPEG_V420_IRQ_STATUS_SESION_ERROR_MSK , irq_status)) { +struct jenc_context *ctx; + +spin_lock_irqsave (&jenc->hw_lock, flags); + ctx = jenc->actx; + jenc->actx =NULL ; +spin_unlock_irqrestore (&jenc->hw_lock, flags); +
drivers/media/platform/qcom/jpeg/qcom_jenc_v420.c line 1193
Quoted 10 lines
drivers/media/platform/qcom/jpeg/qcom_jenc_v420.c new file +10
-0+dev_err (jenc->dev,"encoder hardware failure=0x%lx\n" , +FIELD_GET (JPEG_V420_IRQ_STATUS_SESION_ERROR_MSK , irq_status)); + +jpeg_stop (jenc); +if (ctx) + jenc->enc_hw_irq_cb (ctx,VB2_BUF_STATE_ERROR ,0 ); + } + +return IRQ_HANDLED ; +}
[Severity: Medium]
What happens if both JPEG_V420_IRQ_STATUS_SESSION_DONE and JPEG_V420_IRQ_STATUS_SESION_ERROR_MSK are set in irq_status?
CPU0 (irq_bot) CPU1 (system_wq)
if (SESSION_DONE)
ctx = jenc->actx;
jenc->actx = NULL;
jpeg_stop(jenc);
enc_hw_irq_cb(..., DONE)
schedule_work(&finish_work)
jpeg_finish_work()
v4l2_m2m_job_finish()
mop_jpeg_m2m_job_run()
jenc->actx = next_ctx;
jpeg_exec(jenc);if (SESION_ERROR_MSK)
ctx = jenc->actx;
jenc->actx = NULL;
jpeg_stop(jenc); <-- stops newly started job
enc_hw_irq_cb(ctx, ERROR)
Because the two checks are non-exclusive and run outside jenc->dev_mutex, the first block completes the failed frame with VB2_BUF_STATE_DONE and schedules finish_work, allowing the next job to start on another CPU before the second block pops the new jenc->actx, stops the hardware, and aborts the new job. Checking SESION_ERROR_MSK first and using else if for SESSION_DONE avoids both reporting a failed job as done and clobbering the next job.
Quoted 5 lines
drivers/media/platform/qcom/jpeg/qcom_jenc_v4l2.c new file +0
-0
[ ... ]
Quoted 19 lines
drivers/media/platform/qcom/jpeg/qcom_jenc_v4l2.c new file +19
-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; +u32 nbx, nby; +u64 size; + + 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); + + f->width =clamp_t (u32, f->width,QCOM_JPEG_HW_MIN_WIDTH ,QCOM_JPEG_HW_MAX_WIDTH ); + f->width =ALIGN_DOWN (f->width,QCOM_JPEG_HW_DEF_HSTEP ); + + f->height =clamp_t (u32, f->height,QCOM_JPEG_HW_MIN_HEIGHT ,QCOM_JPEG_HW_MAX_HEIGHT );
[ ... ]
Quoted 2 lines
drivers/media/platform/qcom/jpeg/qcom_jenc_v4l2.c new file +2
-0+static int jpeg_v4l2_set_format (struct jenc_context *ectx,struct v4l2_format *f) +{
[ ... ]
Quoted 16 lines
drivers/media/platform/qcom/jpeg/qcom_jenc_v4l2.c new file +16
-0+if (V4L2_TYPE_IS_CAPTURE (f->type)) { +/* 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; +
drivers/media/platform/qcom/jpeg/qcom_jenc_v4l2.c line 396
Quoted 10 lines
drivers/media/platform/qcom/jpeg/qcom_jenc_v4l2.c new file +10
-0+/* +* OUTPUT TRY_FMT may crop the width to the block size; keep the +* CAPTURE size equal to the negotiated OUTPUT size. +*/ +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; + } + }
[Severity: Low]
Does VIDIOC_S_FMT on the CAPTURE queue leave pm->plane_fmt[0].sizeimage stale and disagree with VIDIOC_TRY_FMT when the active OUTPUT format is NV12M or NV21M?
jpeg_update_dst_plane() aligns CAPTURE dimensions to 8x1, whereas jpeg_update_src_planes() aligns NV12M/NV21M width down to 16 and rounds height up to 2. When jpeg_v4l2_set_format() is called on CAPTURE with dimensions like 1928x1089, the initial jpeg_v4l2_try_format(ectx, f) computes sizeimage for 1928x1089, and then pm->width and pm->height are overwritten with the OUTPUT-aligned 1920x1090 without recalculating pm->plane_fmt[0].sizeimage (and VIDIOC_TRY_FMT on CAPTURE returns 1928x1089 instead of 1920x1090).
[ ... ]
Quoted 18 lines
drivers/media/platform/qcom/jpeg/qcom_jenc_v4l2.c new file +18
-0+static void jpeg_v4l2_return_bufs (struct jenc_context *ctx,enum vb2_buffer_state buff_state) +{ +bool draining = ctx->fh.m2m_ctx->is_draining; +struct vb2_v4l2_buffer *vb; + +/* Drain CAPTURE queue; signal EOS on last buffer if V4L2_ENC_CMD_STOP. */ +while ((vb =v4l2_m2m_dst_buf_remove (ctx->fh.m2m_ctx))) { +if (draining && !v4l2_m2m_last_dst_buf (ctx->fh.m2m_ctx)) { +vb2_set_plane_payload (&vb->vb2_buf,0 ,0 ); +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); +}
[ ... ]
Quoted 22 lines
drivers/media/platform/qcom/jpeg/qcom_jenc_v4l2.c new file +22
-0+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; +bool do_release; + +mutex_lock (&jenc->dev_mutex); + + do_release = ectx->hw_acquired; + ectx->hw_acquired = false; + +mutex_unlock (&jenc->dev_mutex); + +/* +* qcom_jenc_v420_release() calls jpeg_deinit() which issues HW_STOP and +* waits for the STOP_ACK interrupt completion. It runs before any buffer +* is returned below and outside dev_mutex: the threaded IRQ handler takes +* dev_mutex, and with IRQF_ONESHOT the STOP_ACK interrupt stays masked +* until that handler returns. +*/ +if (do_release) +qcom_jenc_v420_release (ectx);
[ ... ]
drivers/media/platform/qcom/jpeg/qcom_jenc_v4l2.c line 769
Quoted 3 lines
drivers/media/platform/qcom/jpeg/qcom_jenc_v4l2.c new file +3
-0+static const struct v4l2_m2m_ops qcom_jpeg_v4l2_m2m_ops = { + .device_run = mop_jpeg_m2m_job_run, +};
[Severity: Medium]
Without a .job_abort callback in qcom_jpeg_v4l2_m2m_ops, can VIDIOC_STREAMOFF or close() ever reach bop_jpeg_vb2_stop_streaming() while a job is running?
Both v4l2_m2m_streamoff() and v4l2_m2m_ctx_release() call v4l2_m2m_cancel_job() before invoking vb2_streamoff() or vb2_queue_release(). v4l2_m2m_cancel_job() calls m2m_ops->job_abort() if present and then waits uninterruptibly for TRANS_RUNNING to clear, which only happens when v4l2_m2m_job_finish() is called. Because .job_abort is not implemented, the HW_STOP abort path in bop_jpeg_vb2_stop_streaming() -> qcom_jenc_v420_release() is unreachable while a job is active, and any stalled encode job (such as on an unhandled attention interrupt) will hang the calling task indefinitely in v4l2_m2m_cancel_job().
[ ... ]
Quoted 7 lines
drivers/media/platform/qcom/jpeg/qcom_jenc_v4l2.c new file +7
-0+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);
drivers/media/platform/qcom/jpeg/qcom_jenc_v4l2.c line 912
Quoted 10 lines
drivers/media/platform/qcom/jpeg/qcom_jenc_v4l2.c new file +10
-0+if (!vb2_is_streaming (vq)) +return 0 ; + + vq =v4l2_m2m_get_dst_vq (ectx->fh.m2m_ctx); +if (!vb2_is_streaming (vq)) +return 0 ; + } + +return v4l2_m2m_ioctl_encoder_cmd (file, priv, ec); +}
[Severity: Medium]
Does V4L2_ENC_CMD_START after draining leave the CAPTURE queue stuck returning -EPIPE on VIDIOC_DQBUF?
When draining finishes and userspace dequeues the V4L2_BUF_FLAG_LAST buffer, vb2_dqbuf() sets dst_vq->last_buffer_dequeued = true. On V4L2_ENC_CMD_START, v4l2_m2m_ioctl_encoder_cmd() clears m2m_ctx->has_stopped, but nothing calls vb2_clear_last_buffer_dequeued(dst_vq) or v4l2_m2m_try_schedule(). iop_jpeg_encoder_command() also skips v4l2_m2m_ioctl_try_encoder_cmd(), leaving ec->flags unvalidated and unzeroed. In addition, jpeg_v4l2_return_bufs() is only called on job error (VB2_BUF_STATE_ERROR), yet it drains all queued buffers instead of only the failed job's pair and calls v4l2_m2m_last_buffer_done() when draining, which marks the last CAPTURE buffer VB2_BUF_STATE_DONE instead of VB2_BUF_STATE_ERROR.
[ ... ]
Quoted 15 lines
drivers/media/platform/qcom/jpeg/qcom_jenc_v4l2.c new file +15
-0+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 ;
[ ... ]
drivers/media/platform/qcom/jpeg/qcom_jenc_v4l2.c line 974
Quoted 1 line
drivers/media/platform/qcom/jpeg/qcom_jenc_v4l2.c new file +1
-0+ dq->lock = &ectx->ctx_lock;
[Severity: Medium]
Aren't queue ioctls and format/encoder_cmd ioctls serialized by two different mutexes?
jpeg_v4l2_init_queue() sets sq->lock and dq->lock (and thus m2m_ctx->q_lock) to &ectx->ctx_lock, whereas qcom_jpeg_v4l2_register() sets jenc->vdev->lock to &jenc->dev_mutex, and nothing in the driver ever takes ectx->ctx_lock explicitly. In v4l2_ioctl_get_lock(), ioctls with INFO_FL_QUEUE (REQBUFS, CREATE_BUFS, PREPARE_BUF, QBUF, DQBUF, STREAMON, STREAMOFF) lock m2m_ctx->q_lock (&ectx->ctx_lock), while VIDIOC_S_FMT, VIDIOC_G_FMT, and VIDIOC_ENCODER_CMD fall back to vdev->lock (&jenc->dev_mutex). As a result, jpeg_v4l2_set_format() can mutate sq->vf, dq->vf, and ectx->hdr_cache while bop_jpeg_vb2_queue_setup() or bop_jpeg_vb2_buf_prepare() is running, and iop_jpeg_encoder_command() -> v4l2_m2m_ioctl_encoder_cmd() can race with VIDIOC_QBUF and VIDIOC_STREAMON/OFF on m2m_ctx draining state and rdy_queue.
[ ... ]
Quoted 15 lines
drivers/media/platform/qcom/jpeg/qcom_jenc_v4l2.c new file +15
-0+static int fop_jpeg_file_release (struct file *file) +{ +struct jenc_context *ectx =jpeg_file2ctx (file); +struct v4l2_m2m_dev *m2m_dev = ectx->fh.m2m_ctx->m2m_dev; +struct qcom_jenc_dev *jenc = ectx->jenc; +unsigned long flags; + +/* +* Waits until a running job of this context completes: its +* SESSION_DONE interrupt needs jenc->actx, and finish_work must not +* be cancelled before, as it calls v4l2_m2m_job_finish(). +*/ +v4l2_m2m_ctx_release (ectx->fh.m2m_ctx); + +/*
drivers/media/platform/qcom/jpeg/qcom_jenc_v4l2.c line 1081
Quoted 10 lines
drivers/media/platform/qcom/jpeg/qcom_jenc_v4l2.c new file +10
-0+* Ensure the threaded IRQ handler cannot dereference this context +* after it is freed. Clear jenc->actx under hw_lock before +* cancelling work. +*/ +spin_lock_irqsave (&jenc->hw_lock, flags); +if (jenc->actx == ectx) + jenc->actx =NULL ; +spin_unlock_irqrestore (&jenc->hw_lock, flags); + +cancel_work_sync (&ectx->finish_work);
[Severity: High]
Can jpeg_finish_work() dereference ectx->fh.m2m_ctx after v4l2_m2m_ctx_release() frees it?
CPU0 CPU1 (system_wq)fop_jpeg_file_release() jpeg_finish_work()
v4l2_m2m_ctx_release(m2m_ctx) v4l2_m2m_job_finish(..., m2m_ctx)
v4l2_m2m_cancel_job() _v4l2_m2m_job_finish()
wait_event(!(TRANS_RUNNING)) job_flags &= ~TRANS_RUNNING;
wake_up(&m2m_ctx->finished);
kfree(m2m_ctx);
v4l2_m2m_schedule_next_job()
__v4l2_m2m_try_queue(m2m_ctx)
<-- use-after-free cancel_work_sync(&finish_work);
v4l2_m2m_cancel_job() only waits for TRANS_RUNNING to be cleared (or returns immediately if a prior VIDIOC_STREAMOFF already cleared job_flags while finish_work was still queued on system_wq), so v4l2_m2m_ctx_release() frees m2m_ctx before cancel_work_sync(&ectx->finish_work) runs. Calling flush_work(&ectx->finish_work) (or invoking v4l2_m2m_job_finish() directly from the threaded IRQ callback instead of deferring to a workqueue) before v4l2_m2m_ctx_release() would prevent this.
Signature · 1 line
Sashiko AI review · https://sashiko.dev/#/patchset/[email protected]?part=4
kernel test robot
build botRe: [PATCH v8 4/8] media: qcom: jpeg: Add Qualcomm JPEG V4L2 encoder
In reply to Atanas Filipovkernel test robot noticed the following build errors:
Hi Atanas,
kernel test robot noticed the following build errors:
[auto build test ERROR on 630059a5a632377b9b7b487baccde92b7ae1dd47]
url: https://github.com/intel-lab-lkp/linux/commits/Atanas-Filipov/dt-bindings-media-qcom-Add-JPEG-encoder-binding/20261110-183902 base: 630059a5a632377b9b7b487baccde92b7ae1dd47 patch link: https://lore.kernel.org/r/20261110163909.78085-5-atanas.filipov%40oss.qualcomm.com patch subject: [PATCH v8 4/8] media: qcom: jpeg: Add Qualcomm JPEG V4L2 encoder config: sh-allyesconfig (https://download.01.org/0day-ci/archive/20261111/[email protected]/config) compiler: sh4-linux-gcc (GCC) 16.2.0 reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20261111/[email protected]/reproduce)
If you fix the issue in a separate patch/commit (i.e. not just a new version of the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <[email protected]>
| Closes: https://lore.kernel.org/oe-kbuild-all/[email protected]/
All errors (new ones prefixed by >>):
sh4-linux-ld: drivers/media/i2c/tc358746.o: in function `tc358746_probe':
tc358746.c:(.text+0x1d24): undefined reference to `devm_clk_hw_register'
sh4-linux-ld: tc358746.c:(.text+0x1d30): undefined reference to `devm_of_clk_add_hw_provider'
sh4-linux-ld: tc358746.c:(.text+0x1d34): undefined reference to `of_clk_hw_simple_get'
sh4-linux-ld: drivers/media/platform/qcom/jpeg/qcom_jenc_dev.o: in function `qcom_jpeg_pm_suspend':
>> qcom_jenc_dev.c:(.text+0x74): undefined reference to `clk_set_rate_range'
sh4-linux-ld: drivers/media/platform/qcom/jpeg/qcom_jenc_dev.o: in function `qcom_jpeg_pm_resume':
qcom_jenc_dev.c:(.text+0x2e4): undefined reference to `clk_set_rate_range'
--
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki
kernel test robot
build botRe: [PATCH v8 4/8] media: qcom: jpeg: Add Qualcomm JPEG V4L2 encoder
In reply to Atanas Filipovkernel test robot noticed the following build errors:
Hi Atanas,
kernel test robot noticed the following build errors:
[auto build test ERROR on 630059a5a632377b9b7b487baccde92b7ae1dd47]
url: https://github.com/intel-lab-lkp/linux/commits/Atanas-Filipov/dt-bindings-media-qcom-Add-JPEG-encoder-binding/20261110-183902 base: 630059a5a632377b9b7b487baccde92b7ae1dd47 patch link: https://lore.kernel.org/r/20261110163909.78085-5-atanas.filipov%40oss.qualcomm.com patch subject: [PATCH v8 4/8] media: qcom: jpeg: Add Qualcomm JPEG V4L2 encoder config: sh-allmodconfig (https://download.01.org/0day-ci/archive/20261111/[email protected]/config) compiler: sh4-linux-gcc (GCC) 16.2.0 reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20261111/[email protected]/reproduce)
If you fix the issue in a separate patch/commit (i.e. not just a new version of the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <[email protected]>
| Closes: https://lore.kernel.org/oe-kbuild-all/[email protected]/
All errors (new ones prefixed by >>, old ones prefixed by <<):
ERROR: modpost: drivers/net/mdio/mdio-cavium.ko: symbol '__delay' undefined!
ERROR: modpost: drivers/media/i2c/tc358746.ko: symbol 'devm_of_clk_add_hw_provider' undefined!
ERROR: modpost: drivers/media/i2c/tc358746.ko: symbol 'devm_clk_hw_register' undefined!
ERROR: modpost: drivers/media/i2c/tc358746.ko: symbol 'of_clk_hw_simple_get' undefined!
>> ERROR: modpost: drivers/media/platform/qcom/jpeg/qcom-jenc.ko: symbol 'clk_set_rate_range' undefined!
--
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki
PATCH v8 5/8 arm64: dts: qcom: sm8250: Add JPEG encoder node
In reply to Atanas FilipovAdd the JPEG encoder hardware node to the SM8250 device tree so the qcom-jpeg V4L2 encoder driver can bind and operate on this platform.
--- arch/arm64/boot/dts/qcom/sm8250.dtsi | 72 ++++++++++++++++++++++++++++ 1 file changed, 72 insertions(+)
arch/arm64/boot/dts/qcom/sm8250.dtsi +72 -0
@@ -4480,6 +4480,78 @@ cci1_i2c1: i2c-bus@1 { }; }; + jpeg_enc: jpeg-encoder@ac53000 { + compatible = "qcom,sm8250-jpeg-enc"; + status = "disabled"; + + reg = <0x0 0x0ac53000 0x0 0x1000>; + + interrupts = <GIC_SPI 474 IRQ_TYPE_EDGE_RISING>; + + power-domains = <&camcc TITAN_TOP_GDSC>, + <&rpmhpd RPMHPD_MX>, + <&rpmhpd RPMHPD_MMCX>; + power-domain-names = "titan_top", "mx", "mmcx"; + + clocks = <&camcc CAM_CC_JPEG_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>; + + clock-names = "core", + "bus", + "config", + "cpas", + "camnoc_axi"; + + interconnects = <&mmss_noc MASTER_CAMNOC_SF 0 &mc_virt SLAVE_EBI_CH0 0>; + interconnect-names = "camnoc"; + + iommus = <&apps_smmu 0x2040 0x400>; + + operating-points-v2 = <&jpeg_opp_table>; + + jpeg_opp_table: opp-table { + compatible = "operating-points-v2"; + + opp-100000000 { + opp-hz = /bits/ 64 <100000000>; + opp-peak-kBps = <262560>; + required-opps = <&rpmhpd_opp_svs_l1>, + <&rpmhpd_opp_low_svs>; + }; + + opp-200000000 { + opp-hz = /bits/ 64 <200000000>; + opp-peak-kBps = <524760>; + required-opps = <&rpmhpd_opp_svs_l1>, + <&rpmhpd_opp_svs>; + }; + + opp-400000000 { + opp-hz = /bits/ 64 <400000000>; + opp-peak-kBps = <978600>; + required-opps = <&rpmhpd_opp_svs_l1>, + <&rpmhpd_opp_svs_l1>; + }; + + opp-480000000 { + opp-hz = /bits/ 64 <480000000>; + opp-peak-kBps = <1095600>; + required-opps = <&rpmhpd_opp_svs_l1>, + <&rpmhpd_opp_nom>; + }; + + opp-600000000 { + opp-hz = /bits/ 64 <600000000>; + opp-peak-kBps = <1095600>; + required-opps = <&rpmhpd_opp_svs_l1>, + <&rpmhpd_opp_turbo>; + }; + }; + }; + camss: camss@ac6a000 { compatible = "qcom,sm8250-camss"; status = "disabled";
Signature · 1 line
2.34.1
PATCH v8 6/8 arm64: dts: qcom: qrb5165-rb5: Enable JPEG encoder
In reply to Atanas FilipovEnable the JPEG encoder on the RB5 board.
--- arch/arm64/boot/dts/qcom/qrb5165-rb5.dts | 4 ++++ 1 file changed, 4 insertions(+)
arch/arm64/boot/dts/qcom/qrb5165-rb5.dts +4 -0
@@ -668,6 +668,10 @@ redriver_usb_con_sbu: endpoint { }; }; +&jpeg_enc { + status = "okay"; +}; + &mdss { status = "okay"; };
Signature · 1 line
2.34.1
PATCH v8 7/8 arm64: dts: qcom: kodiak: Add JPEG encoder node
In reply to Atanas FilipovAdd the JPEG encoder hardware node to the SC7280 (Kodiak) device tree so the qcom-jpeg V4L2 encoder driver can bind and operate on this platform. The node is disabled by default.
--- arch/arm64/boot/dts/qcom/kodiak.dtsi | 67 ++++++++++++++++++++++++++++ 1 file changed, 67 insertions(+)
arch/arm64/boot/dts/qcom/kodiak.dtsi +67 -0
@@ -5164,6 +5164,73 @@ cci1_i2c1: i2c-bus@1 { }; }; + jpeg_enc: jpeg-encoder@ac4e000 { + compatible = "qcom,sc7280-jpeg-enc"; + status = "disabled"; + + reg = <0x0 0x0ac4e000 0x0 0x1000>; + + interrupts = <GIC_SPI 474 IRQ_TYPE_EDGE_RISING>; + + power-domains = <&camcc CAM_CC_TITAN_TOP_GDSC>, + <&rpmhpd SC7280_CX>; + power-domain-names = "titan_top", "cx"; + + clocks = <&camcc CAM_CC_JPEG_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>; + + clock-names = "core", + "bus", + "config", + "cpas", + "camnoc_axi"; + + interconnects = <&mmss_noc MASTER_CAMNOC_SF QCOM_ICC_TAG_ALWAYS + &mc_virt SLAVE_EBI1 QCOM_ICC_TAG_ALWAYS>; + interconnect-names = "camnoc"; + + iommus = <&apps_smmu 0x20c0 0x20>; + + operating-points-v2 = <&jpeg_opp_table>; + + jpeg_opp_table: opp-table { + compatible = "operating-points-v2"; + + opp-100000000 { + opp-hz = /bits/ 64 <100000000>; + opp-peak-kBps = <258480>; + required-opps = <&rpmhpd_opp_low_svs>; + }; + + opp-200000000 { + opp-hz = /bits/ 64 <200000000>; + opp-peak-kBps = <531480>; + required-opps = <&rpmhpd_opp_low_svs>; + }; + + opp-400000000 { + opp-hz = /bits/ 64 <400000000>; + opp-peak-kBps = <1006560>; + required-opps = <&rpmhpd_opp_svs>; + }; + + opp-480000000 { + opp-hz = /bits/ 64 <480000000>; + opp-peak-kBps = <1084440>; + required-opps = <&rpmhpd_opp_svs_l1>; + }; + + opp-600000000 { + opp-hz = /bits/ 64 <600000000>; + opp-peak-kBps = <1084440>; + required-opps = <&rpmhpd_opp_nom>; + }; + }; + }; + camss: isp@acb3000 { compatible = "qcom,sc7280-camss";
Signature · 1 line
2.34.1
PATCH v8 8/8 arm64: dts: qcom: qcs6490-rb3gen2: Enable JPEG encoder
In reply to Atanas FilipovEnable the JPEG encoder on the RB3 Gen2 board.
--- arch/arm64/boot/dts/qcom/qcs6490-rb3gen2.dts | 4 ++++ 1 file changed, 4 insertions(+)
arch/arm64/boot/dts/qcom/qcs6490-rb3gen2.dts +4 -0
@@ -789,6 +789,10 @@ redriver_usb_con_sbu: endpoint { }; }; +&jpeg_enc { + status = "okay"; +}; + &lpass_va_macro { status = "okay"; };
Signature · 1 line
2.34.1