* [PATCH v4 0/3] media: qcom: camss: Add sa8775p/qcs8300 camss TPG support
@ 2025-09-25 0:31 Wenmeng Liu
2025-09-25 0:31 ` [PATCH v4 1/3] media: qcom: camss: Add support for TPG common Wenmeng Liu
` (2 more replies)
0 siblings, 3 replies; 9+ messages in thread
From: Wenmeng Liu @ 2025-09-25 0:31 UTC (permalink / raw)
To: Robert Foss, Todor Tomov, Bryan O'Donoghue,
Vladimir Zapolskiy, Mauro Carvalho Chehab
Cc: linux-kernel, linux-media, linux-arm-msm, Wenmeng Liu
This series adds driver changes to bring up the TPG interfaces
in SA8775P and QCS8300.
We have tested this on qcs9100-ride board and qcs8300-ride board with
'Test Pattern Generator'. Unlike CSID TPG, this TPG can be seen as
a combination of CSIPHY and sensor.
Tested with following commands:
- media-ctl --reset
- media-ctl -V '"msm_tpg0":0[fmt:SRGGB10/4608x2592 field:none]'
- media-ctl -V '"msm_csid0":0[fmt:SRGGB10/4608x2592 field:none]'
- media-ctl -V '"msm_vfe0_rdi0":0[fmt:SRGGB10/4608x2592 field:none]'
- media-ctl -l '"msm_tpg0":1->"msm_csid0":0[1]'
- media-ctl -l '"msm_csid0":1->"msm_vfe0_rdi0":0[1]'
- v4l2-ctl -d /dev/v4l-subdev4 -c test_pattern=9
- yavta -B capture-mplane -n 5 -f SRGGB10P -s 4608x2592 /dev/video0
--capture=7
Changes in V4:
- Rebase changes
- Use GENMASK to define bit fields and avoid using tabs. Use FIELD_PREP and FIELD_GET uniformly to access bit fields.
- Link to V3:https://lore.kernel.org/all/20250822-camss_tpg-v3-0-c7833a5f10d0@quicinc.com/
Changes in V3:
- Change the payload mode string
- Change the method for setting the TPG clock rate
- Remove the TPG IRQ
- Format correction
- Remove unused variables
- Merge functions and eliminate redundancy
- Modify the register write method
- Change TPG matching method to use grp_id
- Encapsulate magic numbers as macros
- Link to V2: https://lore.kernel.org/all/20250717-lemans_tpg-v2-0-a2538659349c@quicinc.com/
Changes in V2:
- rebase tpg changes based on new versions of sa8775p and qcs8300 camss patches
- Link to V1: https://lore.kernel.org/all/20250211-sa8775p_tpg-v1-0-3f76c5f8431f@quicinc.com/
---
Wenmeng Liu (3):
media: qcom: camss: Add support for TPG common
media: qcom: camss: Add link support for TPG common
media: qcom: camss: tpg: Add TPG support for SA8775P and QCS8300
drivers/media/platform/qcom/camss/Makefile | 2 +
.../media/platform/qcom/camss/camss-csid-gen3.c | 17 +
drivers/media/platform/qcom/camss/camss-csid.c | 43 +-
drivers/media/platform/qcom/camss/camss-csiphy.c | 1 +
drivers/media/platform/qcom/camss/camss-csiphy.h | 2 +
drivers/media/platform/qcom/camss/camss-tpg-gen1.c | 219 +++++++
drivers/media/platform/qcom/camss/camss-tpg.c | 696 +++++++++++++++++++++
drivers/media/platform/qcom/camss/camss-tpg.h | 125 ++++
drivers/media/platform/qcom/camss/camss.c | 131 ++++
drivers/media/platform/qcom/camss/camss.h | 5 +
10 files changed, 1227 insertions(+), 14 deletions(-)
---
base-commit: ce7f1a983b074f6cf8609068088ca3182c569ee4
change-id: 20250924-camss_tpg-0cab6ce6372a
Best regards,
--
Wenmeng <wenmeng.liu@oss.qualcomm.com>
^ permalink raw reply [flat|nested] 9+ messages in thread
* [PATCH v4 1/3] media: qcom: camss: Add support for TPG common
2025-09-25 0:31 [PATCH v4 0/3] media: qcom: camss: Add sa8775p/qcs8300 camss TPG support Wenmeng Liu
@ 2025-09-25 0:31 ` Wenmeng Liu
2025-10-07 10:44 ` Konrad Dybcio
2025-09-25 0:32 ` [PATCH v4 2/3] media: qcom: camss: Add link " Wenmeng Liu
2025-09-25 0:32 ` [PATCH v4 3/3] media: qcom: camss: tpg: Add TPG support for SA8775P and QCS8300 Wenmeng Liu
2 siblings, 1 reply; 9+ messages in thread
From: Wenmeng Liu @ 2025-09-25 0:31 UTC (permalink / raw)
To: Robert Foss, Todor Tomov, Bryan O'Donoghue,
Vladimir Zapolskiy, Mauro Carvalho Chehab
Cc: linux-kernel, linux-media, linux-arm-msm, Wenmeng Liu
Add support for TPG common, unlike CSID TPG, this TPG can
be seen as a combination of CSIPHY and sensor.
Signed-off-by: Wenmeng Liu <wenmeng.liu@oss.qualcomm.com>
---
drivers/media/platform/qcom/camss/Makefile | 1 +
drivers/media/platform/qcom/camss/camss-tpg.c | 696 ++++++++++++++++++++++++++
drivers/media/platform/qcom/camss/camss-tpg.h | 125 +++++
drivers/media/platform/qcom/camss/camss.h | 5 +
4 files changed, 827 insertions(+)
diff --git a/drivers/media/platform/qcom/camss/Makefile b/drivers/media/platform/qcom/camss/Makefile
index 23960d02877de132b63ebfe88affe55576256829..0eda4b18ad0e93f5e63135fabd5a02ae67bcd5ad 100644
--- a/drivers/media/platform/qcom/camss/Makefile
+++ b/drivers/media/platform/qcom/camss/Makefile
@@ -26,5 +26,6 @@ qcom-camss-objs += \
camss-vfe.o \
camss-video.o \
camss-format.o \
+ camss-tpg.o \
obj-$(CONFIG_VIDEO_QCOM_CAMSS) += qcom-camss.o
diff --git a/drivers/media/platform/qcom/camss/camss-tpg.c b/drivers/media/platform/qcom/camss/camss-tpg.c
new file mode 100644
index 0000000000000000000000000000000000000000..c436cdb7041b555ce9458270eb46996e78f1d5eb
--- /dev/null
+++ b/drivers/media/platform/qcom/camss/camss-tpg.c
@@ -0,0 +1,696 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ *
+ * Qualcomm MSM Camera Subsystem - TPG Module
+ *
+ * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
+ */
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/io.h>
+#include <linux/kernel.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+#include <media/media-entity.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-subdev.h>
+
+#include "camss-tpg.h"
+#include "camss.h"
+
+const char * const testgen_payload_modes[] = {
+ "Disabled",
+ "Incrementing",
+ "Alternating 0x55/0xAA",
+ "Reserved",
+ "Reserved",
+ "Pseudo-random Data",
+ "User Specified",
+ "Reserved",
+ "Reserved",
+ "Color bars",
+ "Reserved"
+};
+
+static const struct tpg_format_info formats_gen1[] = {
+ {
+ MEDIA_BUS_FMT_SBGGR8_1X8,
+ DATA_TYPE_RAW_8BIT,
+ ENCODE_FORMAT_UNCOMPRESSED_8_BIT,
+ },
+ {
+ MEDIA_BUS_FMT_SGBRG8_1X8,
+ DATA_TYPE_RAW_8BIT,
+ ENCODE_FORMAT_UNCOMPRESSED_8_BIT,
+ },
+ {
+ MEDIA_BUS_FMT_SGRBG8_1X8,
+ DATA_TYPE_RAW_8BIT,
+ ENCODE_FORMAT_UNCOMPRESSED_8_BIT,
+ },
+ {
+ MEDIA_BUS_FMT_SRGGB8_1X8,
+ DATA_TYPE_RAW_8BIT,
+ ENCODE_FORMAT_UNCOMPRESSED_8_BIT,
+ },
+ {
+ MEDIA_BUS_FMT_SBGGR10_1X10,
+ DATA_TYPE_RAW_10BIT,
+ ENCODE_FORMAT_UNCOMPRESSED_10_BIT,
+ },
+ {
+ MEDIA_BUS_FMT_SGBRG10_1X10,
+ DATA_TYPE_RAW_10BIT,
+ ENCODE_FORMAT_UNCOMPRESSED_10_BIT,
+ },
+ {
+ MEDIA_BUS_FMT_SGRBG10_1X10,
+ DATA_TYPE_RAW_10BIT,
+ ENCODE_FORMAT_UNCOMPRESSED_10_BIT,
+ },
+ {
+ MEDIA_BUS_FMT_SRGGB10_1X10,
+ DATA_TYPE_RAW_10BIT,
+ ENCODE_FORMAT_UNCOMPRESSED_10_BIT,
+ },
+ {
+ MEDIA_BUS_FMT_SBGGR12_1X12,
+ DATA_TYPE_RAW_12BIT,
+ ENCODE_FORMAT_UNCOMPRESSED_12_BIT,
+ },
+ {
+ MEDIA_BUS_FMT_SGBRG12_1X12,
+ DATA_TYPE_RAW_12BIT,
+ ENCODE_FORMAT_UNCOMPRESSED_12_BIT,
+ },
+ {
+ MEDIA_BUS_FMT_SGRBG12_1X12,
+ DATA_TYPE_RAW_12BIT,
+ ENCODE_FORMAT_UNCOMPRESSED_12_BIT,
+ },
+ {
+ MEDIA_BUS_FMT_SRGGB12_1X12,
+ DATA_TYPE_RAW_12BIT,
+ ENCODE_FORMAT_UNCOMPRESSED_12_BIT,
+ },
+ {
+ MEDIA_BUS_FMT_Y8_1X8,
+ DATA_TYPE_RAW_8BIT,
+ ENCODE_FORMAT_UNCOMPRESSED_8_BIT,
+ },
+ {
+ MEDIA_BUS_FMT_Y10_1X10,
+ DATA_TYPE_RAW_10BIT,
+ ENCODE_FORMAT_UNCOMPRESSED_10_BIT,
+ },
+};
+
+const struct tpg_formats tpg_formats_gen1 = {
+ .nformats = ARRAY_SIZE(formats_gen1),
+ .formats = formats_gen1
+};
+
+const struct tpg_format_info *tpg_get_fmt_entry(struct tpg_device *tpg,
+ const struct tpg_format_info *formats,
+ unsigned int nformats,
+ u32 code)
+{
+ struct device *dev = tpg->camss->dev;
+ size_t i;
+
+ for (i = 0; i < nformats; i++)
+ if (code == formats[i].code)
+ return &formats[i];
+
+ dev_warn_once(dev, "Unknown format\n");
+
+ return ERR_PTR(-EINVAL);
+}
+
+/*
+ * tpg_set_clock_rates - set clock rates on tpg module
+ * @tpg: tpg device
+ */
+static int tpg_set_clock_rates(struct tpg_device *tpg)
+{
+ struct device *dev = tpg->camss->dev;
+ int ret;
+ int i;
+
+ for (i = 0; i < tpg->nclocks; i++) {
+ struct camss_clock *clock = &tpg->clock[i];
+ long round_rate;
+
+ if (clock->freq[0] > 0) {
+ round_rate = clk_round_rate(clock->clk, clock->freq[0]);
+ if (round_rate < 0) {
+ dev_err(dev, "clk round rate failed: %ld\n",
+ round_rate);
+ return -EINVAL;
+ }
+
+ ret = clk_set_rate(clock->clk, round_rate);
+ if (ret < 0) {
+ dev_err(dev, "clk set rate failed: %d\n", ret);
+ return ret;
+ }
+ }
+ }
+
+ return 0;
+}
+
+/*
+ * tpg_set_power - Power on/off tpg module
+ * @sd: tpg V4L2 subdevice
+ * @on: Requested power state
+ *
+ * Return 0 on success or a negative error code otherwise
+ */
+static int tpg_set_power(struct v4l2_subdev *sd, int on)
+{
+ struct tpg_device *tpg = v4l2_get_subdevdata(sd);
+ struct device *dev = tpg->camss->dev;
+
+ if (on) {
+ int ret;
+
+ ret = pm_runtime_resume_and_get(dev);
+ if (ret < 0)
+ return ret;
+
+ ret = tpg_set_clock_rates(tpg);
+ if (ret < 0) {
+ pm_runtime_put_sync(dev);
+ return ret;
+ }
+
+ ret = camss_enable_clocks(tpg->nclocks, tpg->clock, dev);
+ if (ret < 0) {
+ pm_runtime_put_sync(dev);
+ return ret;
+ }
+
+ tpg->res->hw_ops->reset(tpg);
+
+ tpg->res->hw_ops->hw_version(tpg);
+ } else {
+ camss_disable_clocks(tpg->nclocks, tpg->clock);
+
+ pm_runtime_put_sync(dev);
+ }
+
+ return 0;
+}
+
+/*
+ * tpg_set_stream - Enable/disable streaming on tpg module
+ * @sd: tpg V4L2 subdevice
+ * @enable: Requested streaming state
+ *
+ * Return 0 on success or a negative error code otherwise
+ */
+static int tpg_set_stream(struct v4l2_subdev *sd, int enable)
+{
+ struct tpg_device *tpg = v4l2_get_subdevdata(sd);
+ int ret = 0;
+
+ if (enable) {
+ ret = v4l2_ctrl_handler_setup(&tpg->ctrls);
+ if (ret < 0) {
+ dev_err(tpg->camss->dev,
+ "could not sync v4l2 controls: %d\n", ret);
+ return ret;
+ }
+ }
+
+ tpg->res->hw_ops->configure_stream(tpg, enable);
+
+ return 0;
+}
+
+/*
+ * __tpg_get_format - Get pointer to format structure
+ * @tpg: tpg device
+ * @cfg: V4L2 subdev pad configuration
+ * @pad: pad from which format is requested
+ * @which: TRY or ACTIVE format
+ *
+ * Return pointer to TRY or ACTIVE format structure
+ */
+static struct v4l2_mbus_framefmt *
+__tpg_get_format(struct tpg_device *tpg,
+ struct v4l2_subdev_state *sd_state,
+ unsigned int pad,
+ enum v4l2_subdev_format_whence which)
+{
+ if (which == V4L2_SUBDEV_FORMAT_TRY)
+ return v4l2_subdev_state_get_format(sd_state,
+ pad);
+
+ return &tpg->fmt[pad];
+}
+
+/*
+ * tpg_try_format - Handle try format by pad subdev method
+ * @tpg: tpg device
+ * @cfg: V4L2 subdev pad configuration
+ * @pad: pad on which format is requested
+ * @fmt: pointer to v4l2 format structure
+ * @which: wanted subdev format
+ */
+static void tpg_try_format(struct tpg_device *tpg,
+ struct v4l2_subdev_state *sd_state,
+ unsigned int pad,
+ struct v4l2_mbus_framefmt *fmt,
+ enum v4l2_subdev_format_whence which)
+{
+ unsigned int i;
+
+ switch (pad) {
+ case MSM_TPG_PAD_SINK:
+ for (i = 0; i < tpg->res->formats->nformats; i++)
+ if (tpg->res->formats->formats[i].code == fmt->code)
+ break;
+
+ /* If not found, use SBGGR8 as default */
+ if (i >= tpg->res->formats->nformats)
+ fmt->code = MEDIA_BUS_FMT_SBGGR8_1X8;
+
+ fmt->width = clamp_t(u32, fmt->width, 1, 8191);
+ fmt->height = clamp_t(u32, fmt->height, 1, 8191);
+
+ fmt->field = V4L2_FIELD_NONE;
+ fmt->colorspace = V4L2_COLORSPACE_SRGB;
+
+ break;
+ case MSM_TPG_PAD_SRC:
+ *fmt = *__tpg_get_format(tpg, sd_state,
+ MSM_TPG_PAD_SINK,
+ which);
+
+ break;
+ }
+}
+
+/*
+ * tpg_enum_mbus_code - Handle format enumeration
+ * @sd: tpg V4L2 subdevice
+ * @cfg: V4L2 subdev pad configuration
+ * @code: pointer to v4l2_subdev_mbus_code_enum structure
+ * return -EINVAL or zero on success
+ */
+static int tpg_enum_mbus_code(struct v4l2_subdev *sd,
+ struct v4l2_subdev_state *sd_state,
+ struct v4l2_subdev_mbus_code_enum *code)
+{
+ struct tpg_device *tpg = v4l2_get_subdevdata(sd);
+ struct v4l2_mbus_framefmt *format;
+
+ if (code->pad == MSM_TPG_PAD_SINK) {
+ if (code->index >= tpg->res->formats->nformats)
+ return -EINVAL;
+
+ code->code = tpg->res->formats->formats[code->index].code;
+ } else {
+ if (code->index > 0)
+ return -EINVAL;
+
+ format = __tpg_get_format(tpg, sd_state,
+ MSM_TPG_PAD_SINK,
+ code->which);
+
+ code->code = format->code;
+ }
+
+ return 0;
+}
+
+/*
+ * tpg_enum_frame_size - Handle frame size enumeration
+ * @sd: tpg V4L2 subdevice
+ * @cfg: V4L2 subdev pad configuration
+ * @fse: pointer to v4l2_subdev_frame_size_enum structure
+ * return -EINVAL or zero on success
+ */
+static int tpg_enum_frame_size(struct v4l2_subdev *sd,
+ struct v4l2_subdev_state *sd_state,
+ struct v4l2_subdev_frame_size_enum *fse)
+{
+ struct tpg_device *tpg = v4l2_get_subdevdata(sd);
+ struct v4l2_mbus_framefmt format;
+
+ if (fse->index != 0)
+ return -EINVAL;
+
+ format.code = fse->code;
+ format.width = 1;
+ format.height = 1;
+ tpg_try_format(tpg, sd_state, fse->pad, &format, fse->which);
+ fse->min_width = format.width;
+ fse->min_height = format.height;
+
+ if (format.code != fse->code)
+ return -EINVAL;
+
+ format.code = fse->code;
+ format.width = -1;
+ format.height = -1;
+ tpg_try_format(tpg, sd_state, fse->pad, &format, fse->which);
+ fse->max_width = format.width;
+ fse->max_height = format.height;
+
+ return 0;
+}
+
+/*
+ * tpg_get_format - Handle get format by pads subdev method
+ * @sd: tpg V4L2 subdevice
+ * @cfg: V4L2 subdev pad configuration
+ * @fmt: pointer to v4l2 subdev format structure
+ *
+ * Return -EINVAL or zero on success
+ */
+static int tpg_get_format(struct v4l2_subdev *sd,
+ struct v4l2_subdev_state *sd_state,
+ struct v4l2_subdev_format *fmt)
+{
+ struct tpg_device *tpg = v4l2_get_subdevdata(sd);
+ struct v4l2_mbus_framefmt *format;
+
+ format = __tpg_get_format(tpg, sd_state, fmt->pad, fmt->which);
+ if (!format)
+ return -EINVAL;
+
+ fmt->format = *format;
+
+ return 0;
+}
+
+/*
+ * tpg_set_format - Handle set format by pads subdev method
+ * @sd: tpg V4L2 subdevice
+ * @cfg: V4L2 subdev pad configuration
+ * @fmt: pointer to v4l2 subdev format structure
+ *
+ * Return -EINVAL or zero on success
+ */
+static int tpg_set_format(struct v4l2_subdev *sd,
+ struct v4l2_subdev_state *sd_state,
+ struct v4l2_subdev_format *fmt)
+{
+ struct tpg_device *tpg = v4l2_get_subdevdata(sd);
+ struct v4l2_mbus_framefmt *format;
+
+ format = __tpg_get_format(tpg, sd_state, fmt->pad, fmt->which);
+ if (!format)
+ return -EINVAL;
+
+ tpg_try_format(tpg, sd_state, fmt->pad, &fmt->format,
+ fmt->which);
+ *format = fmt->format;
+
+ if (fmt->pad == MSM_TPG_PAD_SINK) {
+ format = __tpg_get_format(tpg, sd_state,
+ MSM_TPG_PAD_SRC,
+ fmt->which);
+
+ *format = fmt->format;
+ tpg_try_format(tpg, sd_state, MSM_TPG_PAD_SRC,
+ format,
+ fmt->which);
+ }
+ return 0;
+}
+
+/*
+ * tpg_init_formats - Initialize formats on all pads
+ * @sd: tpg V4L2 subdevice
+ * @fh: V4L2 subdev file handle
+ *
+ * Initialize all pad formats with default values.
+ *
+ * Return 0 on success or a negative error code otherwise
+ */
+static int tpg_init_formats(struct v4l2_subdev *sd,
+ struct v4l2_subdev_fh *fh)
+{
+ struct v4l2_subdev_format format = {
+ .pad = MSM_TPG_PAD_SINK,
+ .which = fh ? V4L2_SUBDEV_FORMAT_TRY :
+ V4L2_SUBDEV_FORMAT_ACTIVE,
+ .format = {
+ .code = MEDIA_BUS_FMT_SBGGR8_1X8,
+ .width = 1920,
+ .height = 1080
+ }
+ };
+
+ return tpg_set_format(sd, fh ? fh->state : NULL, &format);
+}
+
+/*
+ * tpg_set_test_pattern - Set test generator's pattern mode
+ * @tpg: TPG device
+ * @value: desired test pattern mode
+ *
+ * Return 0 on success or a negative error code otherwise
+ */
+static int tpg_set_test_pattern(struct tpg_device *tpg, s32 value)
+{
+ return tpg->res->hw_ops->configure_testgen_pattern(tpg, value);
+}
+
+/*
+ * tpg_s_ctrl - Handle set control subdev method
+ * @ctrl: pointer to v4l2 control structure
+ *
+ * Return 0 on success or a negative error code otherwise
+ */
+static int tpg_s_ctrl(struct v4l2_ctrl *ctrl)
+{
+ struct tpg_device *tpg = container_of(ctrl->handler,
+ struct tpg_device, ctrls);
+ int ret = -EINVAL;
+
+ switch (ctrl->id) {
+ case V4L2_CID_TEST_PATTERN:
+ ret = tpg_set_test_pattern(tpg, ctrl->val);
+ break;
+ }
+
+ return ret;
+}
+
+static const struct v4l2_ctrl_ops tpg_ctrl_ops = {
+ .s_ctrl = tpg_s_ctrl,
+};
+
+/*
+ * msm_tpg_subdev_init - Initialize tpg device structure and resources
+ * @tpg: tpg device
+ * @res: tpg module resources table
+ * @id: tpg module id
+ *
+ * Return 0 on success or a negative error code otherwise
+ */
+int msm_tpg_subdev_init(struct camss *camss,
+ struct tpg_device *tpg,
+ const struct camss_subdev_resources *res, u8 id)
+{
+ struct platform_device *pdev;
+ struct device *dev;
+ int i, j;
+
+ dev = camss->dev;
+ pdev = to_platform_device(dev);
+
+ tpg->camss = camss;
+ tpg->id = id;
+ tpg->res = &res->tpg;
+ tpg->res->hw_ops->subdev_init(tpg);
+
+ tpg->base = devm_platform_ioremap_resource_byname(pdev, res->reg[0]);
+ if (IS_ERR(tpg->base))
+ return PTR_ERR(tpg->base);
+
+ tpg->nclocks = 0;
+ while (res->clock[tpg->nclocks])
+ tpg->nclocks++;
+
+ if (tpg->nclocks) {
+ tpg->clock = devm_kcalloc(dev,
+ tpg->nclocks, sizeof(*tpg->clock),
+ GFP_KERNEL);
+ if (!tpg->clock)
+ return -ENOMEM;
+
+ for (i = 0; i < tpg->nclocks; i++) {
+ struct camss_clock *clock = &tpg->clock[i];
+
+ clock->clk = devm_clk_get(dev, res->clock[i]);
+ if (IS_ERR(clock->clk))
+ return PTR_ERR(clock->clk);
+
+ clock->name = res->clock[i];
+
+ clock->nfreqs = 0;
+ while (res->clock_rate[i][clock->nfreqs])
+ clock->nfreqs++;
+
+ if (!clock->nfreqs) {
+ clock->freq = NULL;
+ continue;
+ }
+
+ clock->freq = devm_kcalloc(dev,
+ clock->nfreqs,
+ sizeof(*clock->freq),
+ GFP_KERNEL);
+ if (!clock->freq)
+ return -ENOMEM;
+
+ for (j = 0; j < clock->nfreqs; j++)
+ clock->freq[j] = res->clock_rate[i][j];
+ }
+ }
+
+ return 0;
+}
+
+/*
+ * tpg_link_setup - Setup tpg connections
+ * @entity: Pointer to media entity structure
+ * @local: Pointer to local pad
+ * @remote: Pointer to remote pad
+ * @flags: Link flags
+ *
+ * Rreturn 0 on success
+ */
+static int tpg_link_setup(struct media_entity *entity,
+ const struct media_pad *local,
+ const struct media_pad *remote, u32 flags)
+{
+ if (flags & MEDIA_LNK_FL_ENABLED)
+ if (media_pad_remote_pad_first(local))
+ return -EBUSY;
+
+ return 0;
+}
+
+static const struct v4l2_subdev_core_ops tpg_core_ops = {
+ .s_power = tpg_set_power,
+};
+
+static const struct v4l2_subdev_video_ops tpg_video_ops = {
+ .s_stream = tpg_set_stream,
+};
+
+static const struct v4l2_subdev_pad_ops tpg_pad_ops = {
+ .enum_mbus_code = tpg_enum_mbus_code,
+ .enum_frame_size = tpg_enum_frame_size,
+ .get_fmt = tpg_get_format,
+ .set_fmt = tpg_set_format,
+};
+
+static const struct v4l2_subdev_ops tpg_v4l2_ops = {
+ .core = &tpg_core_ops,
+ .video = &tpg_video_ops,
+ .pad = &tpg_pad_ops,
+};
+
+static const struct v4l2_subdev_internal_ops tpg_v4l2_internal_ops = {
+ .open = tpg_init_formats,
+};
+
+static const struct media_entity_operations tpg_media_ops = {
+ .link_setup = tpg_link_setup,
+ .link_validate = v4l2_subdev_link_validate,
+};
+
+/*
+ * msm_tpg_register_entity - Register subdev node for tpg module
+ * @tpg: tpg device
+ * @v4l2_dev: V4L2 device
+ *
+ * Return 0 on success or a negative error code otherwise
+ */
+int msm_tpg_register_entity(struct tpg_device *tpg,
+ struct v4l2_device *v4l2_dev)
+{
+ struct v4l2_subdev *sd = &tpg->subdev;
+ struct media_pad *pads = tpg->pads;
+ struct device *dev = tpg->camss->dev;
+ int ret;
+
+ v4l2_subdev_init(sd, &tpg_v4l2_ops);
+ sd->internal_ops = &tpg_v4l2_internal_ops;
+ sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE |
+ V4L2_SUBDEV_FL_HAS_EVENTS;
+ snprintf(sd->name, ARRAY_SIZE(sd->name), "%s%d",
+ MSM_TPG_NAME, tpg->id);
+ sd->grp_id = TPG_GUP_ID;
+ v4l2_set_subdevdata(sd, tpg);
+
+ ret = v4l2_ctrl_handler_init(&tpg->ctrls, 1);
+ if (ret < 0) {
+ dev_err(dev, "Failed to init ctrl handler: %d\n", ret);
+ return ret;
+ }
+
+ tpg->testgen_mode = v4l2_ctrl_new_std_menu_items(&tpg->ctrls,
+ &tpg_ctrl_ops, V4L2_CID_TEST_PATTERN,
+ tpg->testgen.nmodes, 0, 0,
+ tpg->testgen.modes);
+
+ if (tpg->ctrls.error) {
+ dev_err(dev, "Failed to init ctrl: %d\n", tpg->ctrls.error);
+ ret = tpg->ctrls.error;
+ goto free_ctrl;
+ }
+
+ tpg->subdev.ctrl_handler = &tpg->ctrls;
+
+ ret = tpg_init_formats(sd, NULL);
+ if (ret < 0) {
+ dev_err(dev, "Failed to init format: %d\n", ret);
+ goto free_ctrl;
+ }
+
+ pads[MSM_TPG_PAD_SINK].flags = MEDIA_PAD_FL_SINK;
+ pads[MSM_TPG_PAD_SRC].flags = MEDIA_PAD_FL_SOURCE;
+
+ sd->entity.function = MEDIA_ENT_F_PROC_VIDEO_PIXEL_FORMATTER;
+ sd->entity.ops = &tpg_media_ops;
+ ret = media_entity_pads_init(&sd->entity, MSM_TPG_PADS_NUM, pads);
+ if (ret < 0) {
+ dev_err(dev, "Failed to init media entity: %d\n", ret);
+ goto free_ctrl;
+ }
+
+ ret = v4l2_device_register_subdev(v4l2_dev, sd);
+ if (ret < 0) {
+ dev_err(dev, "Failed to register subdev: %d\n", ret);
+ media_entity_cleanup(&sd->entity);
+ goto free_ctrl;
+ }
+
+ return 0;
+
+free_ctrl:
+ v4l2_ctrl_handler_free(&tpg->ctrls);
+
+ return ret;
+}
+
+/*
+ * msm_tpg_unregister_entity - Unregister tpg module subdev node
+ * @tpg: tpg device
+ */
+void msm_tpg_unregister_entity(struct tpg_device *tpg)
+{
+ v4l2_device_unregister_subdev(&tpg->subdev);
+ media_entity_cleanup(&tpg->subdev.entity);
+ v4l2_ctrl_handler_free(&tpg->ctrls);
+}
diff --git a/drivers/media/platform/qcom/camss/camss-tpg.h b/drivers/media/platform/qcom/camss/camss-tpg.h
new file mode 100644
index 0000000000000000000000000000000000000000..c40c10cc4ad1d7967c5d9dd878a8d69177b2281f
--- /dev/null
+++ b/drivers/media/platform/qcom/camss/camss-tpg.h
@@ -0,0 +1,125 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * camss-tpg.h
+ *
+ * Qualcomm MSM Camera Subsystem - TPG Module
+ *
+ * Copyright (c) 2024 Qualcomm Innovation Center, Inc. All rights reserved.
+ */
+#ifndef QC_MSM_CAMSS_TPG_H
+#define QC_MSM_CAMSS_TPG_H
+
+#include <linux/clk.h>
+#include <media/media-entity.h>
+#include <media/v4l2-ctrls.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-mediabus.h>
+#include <media/v4l2-subdev.h>
+
+#define MSM_TPG_PAD_SINK 0
+#define MSM_TPG_PAD_SRC 1
+#define MSM_TPG_PADS_NUM 2
+
+#define DATA_TYPE_RAW_8BIT 0x2a
+#define DATA_TYPE_RAW_10BIT 0x2b
+#define DATA_TYPE_RAW_12BIT 0x2c
+
+#define ENCODE_FORMAT_UNCOMPRESSED_8_BIT 0x1
+#define ENCODE_FORMAT_UNCOMPRESSED_10_BIT 0x2
+#define ENCODE_FORMAT_UNCOMPRESSED_12_BIT 0x3
+#define ENCODE_FORMAT_UNCOMPRESSED_14_BIT 0x4
+#define ENCODE_FORMAT_UNCOMPRESSED_16_BIT 0x5
+#define ENCODE_FORMAT_UNCOMPRESSED_20_BIT 0x6
+#define ENCODE_FORMAT_UNCOMPRESSED_24_BIT 0x7
+
+#define TPG_GUP_ID 0
+#define MSM_TPG_NAME "msm_tpg"
+
+enum tpg_testgen_mode {
+ TPG_PAYLOAD_MODE_DISABLED = 0,
+ TPG_PAYLOAD_MODE_INCREMENTING = 1,
+ TPG_PAYLOAD_MODE_ALTERNATING_55_AA = 2,
+ TPG_PAYLOAD_MODE_RANDOM = 5,
+ TPG_PAYLOAD_MODE_USER_SPECIFIED = 6,
+ TPG_PAYLOAD_MODE_COLOR_BARS = 9,
+ TPG_PAYLOAD_MODE_NUM_SUPPORTED_GEN1 = 9,
+};
+
+struct tpg_testgen_config {
+ enum tpg_testgen_mode mode;
+ const char * const*modes;
+ u8 nmodes;
+};
+
+struct tpg_format_info {
+ u32 code;
+ u8 data_type;
+ u8 encode_format;
+};
+
+struct tpg_formats {
+ unsigned int nformats;
+ const struct tpg_format_info *formats;
+};
+
+struct tpg_device;
+
+struct tpg_hw_ops {
+ void (*configure_stream)(struct tpg_device *tpg, u8 enable);
+
+ int (*configure_testgen_pattern)(struct tpg_device *tpg, s32 val);
+
+ u32 (*hw_version)(struct tpg_device *tpg);
+
+ int (*reset)(struct tpg_device *tpg);
+
+ void (*subdev_init)(struct tpg_device *tpg);
+};
+
+struct tpg_subdev_resources {
+ u8 lane_cnt;
+ u8 vc_cnt;
+ const struct tpg_formats *formats;
+ const struct tpg_hw_ops *hw_ops;
+};
+
+struct tpg_device {
+ struct camss *camss;
+ u8 id;
+ struct v4l2_subdev subdev;
+ struct media_pad pads[MSM_TPG_PADS_NUM];
+ void __iomem *base;
+ struct camss_clock *clock;
+ int nclocks;
+ struct tpg_testgen_config testgen;
+ struct v4l2_mbus_framefmt fmt[MSM_TPG_PADS_NUM];
+ struct v4l2_ctrl_handler ctrls;
+ struct v4l2_ctrl *testgen_mode;
+ const struct tpg_subdev_resources *res;
+ const struct tpg_format *formats;
+ unsigned int nformats;
+};
+
+struct camss_subdev_resources;
+
+const struct tpg_format_info *tpg_get_fmt_entry(struct tpg_device *tpg,
+ const struct tpg_format_info *formats,
+ unsigned int nformats,
+ u32 code);
+
+int msm_tpg_subdev_init(struct camss *camss,
+ struct tpg_device *tpg,
+ const struct camss_subdev_resources *res, u8 id);
+
+int msm_tpg_register_entity(struct tpg_device *tpg,
+ struct v4l2_device *v4l2_dev);
+
+void msm_tpg_unregister_entity(struct tpg_device *tpg);
+
+extern const char * const testgen_payload_modes[];
+
+extern const struct tpg_formats tpg_formats_gen1;
+
+extern const struct tpg_hw_ops tpg_ops_gen1;
+
+#endif /* QC_MSM_CAMSS_TPG_H */
diff --git a/drivers/media/platform/qcom/camss/camss.h b/drivers/media/platform/qcom/camss/camss.h
index a70fbc78ccc307c0abc2f3c834fb1e2dafd83c6b..9a66f3a90c02b4cc475c4d3033205feb7e98f5d3 100644
--- a/drivers/media/platform/qcom/camss/camss.h
+++ b/drivers/media/platform/qcom/camss/camss.h
@@ -21,6 +21,7 @@
#include "camss-csid.h"
#include "camss-csiphy.h"
#include "camss-ispif.h"
+#include "camss-tpg.h"
#include "camss-vfe.h"
#include "camss-format.h"
@@ -51,6 +52,7 @@ struct camss_subdev_resources {
char *interrupt[CAMSS_RES_MAX];
union {
struct csiphy_subdev_resources csiphy;
+ struct tpg_subdev_resources tpg;
struct csid_subdev_resources csid;
struct vfe_subdev_resources vfe;
};
@@ -101,6 +103,7 @@ struct camss_resources {
enum camss_version version;
const char *pd_name;
const struct camss_subdev_resources *csiphy_res;
+ const struct camss_subdev_resources *tpg_res;
const struct camss_subdev_resources *csid_res;
const struct camss_subdev_resources *ispif_res;
const struct camss_subdev_resources *vfe_res;
@@ -108,6 +111,7 @@ struct camss_resources {
const struct resources_icc *icc_res;
const unsigned int icc_path_num;
const unsigned int csiphy_num;
+ const unsigned int tpg_num;
const unsigned int csid_num;
const unsigned int vfe_num;
};
@@ -118,6 +122,7 @@ struct camss {
struct media_device media_dev;
struct device *dev;
struct csiphy_device *csiphy;
+ struct tpg_device *tpg;
struct csid_device *csid;
struct ispif_device *ispif;
struct vfe_device *vfe;
--
2.34.1
^ permalink raw reply related [flat|nested] 9+ messages in thread
* [PATCH v4 2/3] media: qcom: camss: Add link support for TPG common
2025-09-25 0:31 [PATCH v4 0/3] media: qcom: camss: Add sa8775p/qcs8300 camss TPG support Wenmeng Liu
2025-09-25 0:31 ` [PATCH v4 1/3] media: qcom: camss: Add support for TPG common Wenmeng Liu
@ 2025-09-25 0:32 ` Wenmeng Liu
2025-09-25 0:32 ` [PATCH v4 3/3] media: qcom: camss: tpg: Add TPG support for SA8775P and QCS8300 Wenmeng Liu
2 siblings, 0 replies; 9+ messages in thread
From: Wenmeng Liu @ 2025-09-25 0:32 UTC (permalink / raw)
To: Robert Foss, Todor Tomov, Bryan O'Donoghue,
Vladimir Zapolskiy, Mauro Carvalho Chehab
Cc: linux-kernel, linux-media, linux-arm-msm, Wenmeng Liu
TPG is connected to the csid as an entity, the link
needs to be adapted.
Signed-off-by: Wenmeng Liu <wenmeng.liu@oss.qualcomm.com>
---
drivers/media/platform/qcom/camss/camss-csid.c | 43 +++++++++++++-------
drivers/media/platform/qcom/camss/camss-csiphy.c | 1 +
drivers/media/platform/qcom/camss/camss-csiphy.h | 2 +
drivers/media/platform/qcom/camss/camss.c | 52 ++++++++++++++++++++++++
4 files changed, 84 insertions(+), 14 deletions(-)
diff --git a/drivers/media/platform/qcom/camss/camss-csid.c b/drivers/media/platform/qcom/camss/camss-csid.c
index 5284b5857368c37c202cd89dad6ae8042b637537..196cbc0b60e9bf95a06b053c69c967e345ffcd4b 100644
--- a/drivers/media/platform/qcom/camss/camss-csid.c
+++ b/drivers/media/platform/qcom/camss/camss-csid.c
@@ -35,6 +35,8 @@
#define HW_VERSION_REVISION 16
#define HW_VERSION_GENERATION 28
+#define LANE_CFG_BITWIDTH 4
+
#define MSM_CSID_NAME "msm_csid"
const char * const csid_testgen_modes[] = {
@@ -1227,18 +1229,22 @@ void msm_csid_get_csid_id(struct media_entity *entity, u8 *id)
}
/*
- * csid_get_lane_assign - Calculate CSI2 lane assign configuration parameter
- * @lane_cfg - CSI2 lane configuration
+ * csid_get_lane_assign - Calculate lane assign by csiphy/tpg lane num
+ * @num: lane num
+ * @pos_array: Array of lane positions
*
* Return lane assign
*/
-static u32 csid_get_lane_assign(struct csiphy_lanes_cfg *lane_cfg)
+static u32 csid_get_lane_assign(int num, struct csiphy_lanes_cfg *lane_cfg)
{
u32 lane_assign = 0;
+ int pos;
int i;
- for (i = 0; i < lane_cfg->num_data; i++)
- lane_assign |= lane_cfg->data[i].pos << (i * 4);
+ for (i = 0; i < num; i++) {
+ pos = lane_cfg ? lane_cfg->data[i].pos : i;
+ lane_assign |= pos << (i * LANE_CFG_BITWIDTH);
+ }
return lane_assign;
}
@@ -1266,6 +1272,7 @@ static int csid_link_setup(struct media_entity *entity,
struct csid_device *csid;
struct csiphy_device *csiphy;
struct csiphy_lanes_cfg *lane_cfg;
+ struct tpg_device *tpg;
sd = media_entity_to_v4l2_subdev(entity);
csid = v4l2_get_subdevdata(sd);
@@ -1277,18 +1284,26 @@ static int csid_link_setup(struct media_entity *entity,
return -EBUSY;
sd = media_entity_to_v4l2_subdev(remote->entity);
- csiphy = v4l2_get_subdevdata(sd);
+ if (sd->grp_id == TPG_GUP_ID) {
+ tpg = v4l2_get_subdevdata(sd);
- /* If a sensor is not linked to CSIPHY */
- /* do no allow a link from CSIPHY to CSID */
- if (!csiphy->cfg.csi2)
- return -EPERM;
+ csid->phy.lane_cnt = tpg->res->lane_cnt;
+ csid->phy.csiphy_id = tpg->id;
+ csid->phy.lane_assign = csid_get_lane_assign(csid->phy.lane_cnt, NULL);
+ } else {
+ csiphy = v4l2_get_subdevdata(sd);
- csid->phy.csiphy_id = csiphy->id;
+ /* If a sensor is not linked to CSIPHY */
+ /* do no allow a link from CSIPHY to CSID */
+ if (!csiphy->cfg.csi2)
+ return -EPERM;
- lane_cfg = &csiphy->cfg.csi2->lane_cfg;
- csid->phy.lane_cnt = lane_cfg->num_data;
- csid->phy.lane_assign = csid_get_lane_assign(lane_cfg);
+ csid->phy.csiphy_id = csiphy->id;
+
+ lane_cfg = &csiphy->cfg.csi2->lane_cfg;
+ csid->phy.lane_cnt = lane_cfg->num_data;
+ csid->phy.lane_assign = csid_get_lane_assign(lane_cfg->num_data, lane_cfg);
+ }
}
/* Decide which virtual channels to enable based on which source pads are enabled */
if (local->flags & MEDIA_PAD_FL_SOURCE) {
diff --git a/drivers/media/platform/qcom/camss/camss-csiphy.c b/drivers/media/platform/qcom/camss/camss-csiphy.c
index 2de97f58f9ae4f91e8bba39dcadf92bea8cf6f73..680580d7fe46a215777f3fa1b347f4297deea024 100644
--- a/drivers/media/platform/qcom/camss/camss-csiphy.c
+++ b/drivers/media/platform/qcom/camss/camss-csiphy.c
@@ -799,6 +799,7 @@ int msm_csiphy_register_entity(struct csiphy_device *csiphy,
sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
snprintf(sd->name, ARRAY_SIZE(sd->name), "%s%d",
MSM_CSIPHY_NAME, csiphy->id);
+ sd->grp_id = CSIPHY_GUP_ID;
v4l2_set_subdevdata(sd, csiphy);
ret = csiphy_init_formats(sd, NULL);
diff --git a/drivers/media/platform/qcom/camss/camss-csiphy.h b/drivers/media/platform/qcom/camss/camss-csiphy.h
index 895f80003c441dcacf98435f91567f90afa29279..b7bcf2bdd2124f77b5354b15b33aa1e0983143e8 100644
--- a/drivers/media/platform/qcom/camss/camss-csiphy.h
+++ b/drivers/media/platform/qcom/camss/camss-csiphy.h
@@ -21,6 +21,8 @@
#define MSM_CSIPHY_PAD_SRC 1
#define MSM_CSIPHY_PADS_NUM 2
+#define CSIPHY_GUP_ID 1
+
struct csiphy_lane {
u8 pos;
u8 pol;
diff --git a/drivers/media/platform/qcom/camss/camss.c b/drivers/media/platform/qcom/camss/camss.c
index 2fbcd0e343aac9620a5a30719c42e1b887cf34ed..2ede19e1347ae32f2f6919905b535352bcd134be 100644
--- a/drivers/media/platform/qcom/camss/camss.c
+++ b/drivers/media/platform/qcom/camss/camss.c
@@ -3691,6 +3691,19 @@ static int camss_init_subdevices(struct camss *camss)
}
}
+ if (camss->tpg) {
+ for (i = 0; i < camss->res->tpg_num; i++) {
+ ret = msm_tpg_subdev_init(camss, &camss->tpg[i],
+ &res->tpg_res[i], i);
+ if (ret < 0) {
+ dev_err(camss->dev,
+ "Failed to init tpg%d sub-device: %d\n",
+ i, ret);
+ return ret;
+ }
+ }
+ }
+
/* note: SM8250 requires VFE to be initialized before CSID */
for (i = 0; i < camss->res->vfe_num; i++) {
ret = msm_vfe_subdev_init(camss, &camss->vfe[i],
@@ -3779,6 +3792,23 @@ static int camss_link_entities(struct camss *camss)
}
}
+ for (i = 0; i < camss->res->tpg_num; i++) {
+ for (j = 0; j < camss->res->csid_num; j++) {
+ ret = media_create_pad_link(&camss->tpg[i].subdev.entity,
+ MSM_TPG_PAD_SRC,
+ &camss->csid[j].subdev.entity,
+ MSM_CSID_PAD_SINK,
+ 0);
+ if (ret < 0) {
+ camss_link_err(camss,
+ camss->tpg[i].subdev.entity.name,
+ camss->csid[j].subdev.entity.name,
+ ret);
+ return ret;
+ }
+ }
+ }
+
if (camss->ispif) {
for (i = 0; i < camss->res->csid_num; i++) {
for (j = 0; j < camss->ispif->line_num; j++) {
@@ -3883,6 +3913,19 @@ static int camss_register_entities(struct camss *camss)
}
}
+ if (camss->tpg) {
+ for (i = 0; i < camss->res->tpg_num; i++) {
+ ret = msm_tpg_register_entity(&camss->tpg[i],
+ &camss->v4l2_dev);
+ if (ret < 0) {
+ dev_err(camss->dev,
+ "Failed to register tpg%d entity: %d\n",
+ i, ret);
+ goto err_reg_tpg;
+ }
+ }
+ }
+
for (i = 0; i < camss->res->csid_num; i++) {
ret = msm_csid_register_entity(&camss->csid[i],
&camss->v4l2_dev);
@@ -3926,6 +3969,10 @@ static int camss_register_entities(struct camss *camss)
for (i--; i >= 0; i--)
msm_csid_unregister_entity(&camss->csid[i]);
+ i = camss->res->tpg_num;
+err_reg_tpg:
+ for (i--; i >= 0; i--)
+ msm_tpg_unregister_entity(&camss->tpg[i]);
i = camss->res->csiphy_num;
err_reg_csiphy:
for (i--; i >= 0; i--)
@@ -3947,6 +3994,11 @@ static void camss_unregister_entities(struct camss *camss)
for (i = 0; i < camss->res->csiphy_num; i++)
msm_csiphy_unregister_entity(&camss->csiphy[i]);
+ if (camss->tpg) {
+ for (i = 0; i < camss->res->tpg_num; i++)
+ msm_tpg_unregister_entity(&camss->tpg[i]);
+ }
+
for (i = 0; i < camss->res->csid_num; i++)
msm_csid_unregister_entity(&camss->csid[i]);
--
2.34.1
^ permalink raw reply related [flat|nested] 9+ messages in thread
* [PATCH v4 3/3] media: qcom: camss: tpg: Add TPG support for SA8775P and QCS8300
2025-09-25 0:31 [PATCH v4 0/3] media: qcom: camss: Add sa8775p/qcs8300 camss TPG support Wenmeng Liu
2025-09-25 0:31 ` [PATCH v4 1/3] media: qcom: camss: Add support for TPG common Wenmeng Liu
2025-09-25 0:32 ` [PATCH v4 2/3] media: qcom: camss: Add link " Wenmeng Liu
@ 2025-09-25 0:32 ` Wenmeng Liu
2025-09-26 6:08 ` kernel test robot
2025-10-08 10:50 ` Konrad Dybcio
2 siblings, 2 replies; 9+ messages in thread
From: Wenmeng Liu @ 2025-09-25 0:32 UTC (permalink / raw)
To: Robert Foss, Todor Tomov, Bryan O'Donoghue,
Vladimir Zapolskiy, Mauro Carvalho Chehab
Cc: linux-kernel, linux-media, linux-arm-msm, Wenmeng Liu
Add support for TPG found on SA8775P and QCS8300.
Signed-off-by: Wenmeng Liu <wenmeng.liu@oss.qualcomm.com>
---
drivers/media/platform/qcom/camss/Makefile | 1 +
.../media/platform/qcom/camss/camss-csid-gen3.c | 17 ++
drivers/media/platform/qcom/camss/camss-tpg-gen1.c | 219 +++++++++++++++++++++
drivers/media/platform/qcom/camss/camss.c | 79 ++++++++
4 files changed, 316 insertions(+)
diff --git a/drivers/media/platform/qcom/camss/Makefile b/drivers/media/platform/qcom/camss/Makefile
index 0eda4b18ad0e93f5e63135fabd5a02ae67bcd5ad..28bc3d9ba16dfa34a8fd35973beed0c3f2b67e00 100644
--- a/drivers/media/platform/qcom/camss/Makefile
+++ b/drivers/media/platform/qcom/camss/Makefile
@@ -27,5 +27,6 @@ qcom-camss-objs += \
camss-video.o \
camss-format.o \
camss-tpg.o \
+ camss-tpg-gen1.o \
obj-$(CONFIG_VIDEO_QCOM_CAMSS) += qcom-camss.o
diff --git a/drivers/media/platform/qcom/camss/camss-csid-gen3.c b/drivers/media/platform/qcom/camss/camss-csid-gen3.c
index 664245cf6eb0cac662b02f8b920cd1c72db0aeb2..8e0b0cbaa0010f4b4a156877ac2fe805e5c4422e 100644
--- a/drivers/media/platform/qcom/camss/camss-csid-gen3.c
+++ b/drivers/media/platform/qcom/camss/camss-csid-gen3.c
@@ -66,6 +66,8 @@
#define CSI2_RX_CFG0_VC_MODE 3
#define CSI2_RX_CFG0_DL0_INPUT_SEL 4
#define CSI2_RX_CFG0_PHY_NUM_SEL 20
+#define CSI2_RX_CFG0_TPG_NUM_EN 27
+#define CSI2_RX_CFG0_TPG_NUM_SEL 28
#define CSID_CSI2_RX_CFG1 0x204
#define CSI2_RX_CFG1_ECC_CORRECTION_EN BIT(0)
@@ -109,11 +111,26 @@ static void __csid_configure_rx(struct csid_device *csid,
struct csid_phy_config *phy, int vc)
{
int val;
+ struct camss *camss;
+ struct tpg_device *tpg;
+ camss = csid->camss;
val = (phy->lane_cnt - 1) << CSI2_RX_CFG0_NUM_ACTIVE_LANES;
val |= phy->lane_assign << CSI2_RX_CFG0_DL0_INPUT_SEL;
val |= (phy->csiphy_id + CSI2_RX_CFG0_PHY_SEL_BASE_IDX) << CSI2_RX_CFG0_PHY_NUM_SEL;
+ if (camss->tpg) {
+ tpg = &camss->tpg[phy->csiphy_id];
+
+ if (tpg->testgen.mode > 0) {
+ val |= (phy->csiphy_id + 1) << CSI2_RX_CFG0_TPG_NUM_SEL;
+ val |= 1 << CSI2_RX_CFG0_TPG_NUM_EN;
+ } else {
+ val |= 0 << CSI2_RX_CFG0_TPG_NUM_SEL;
+ val |= 0 << CSI2_RX_CFG0_TPG_NUM_EN;
+ }
+ }
+
writel(val, csid->base + CSID_CSI2_RX_CFG0);
val = CSI2_RX_CFG1_ECC_CORRECTION_EN;
diff --git a/drivers/media/platform/qcom/camss/camss-tpg-gen1.c b/drivers/media/platform/qcom/camss/camss-tpg-gen1.c
new file mode 100644
index 0000000000000000000000000000000000000000..d0d7ebd710f8cc8ee7005ebc0809d82ece722dff
--- /dev/null
+++ b/drivers/media/platform/qcom/camss/camss-tpg-gen1.c
@@ -0,0 +1,219 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ *
+ * Qualcomm MSM Camera Subsystem - TPG (Test Patter Generator) Module
+ *
+ * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
+ */
+#include <linux/completion.h>
+#include <linux/io.h>
+#include <linux/kernel.h>
+#include <linux/of.h>
+
+#include "camss-tpg.h"
+#include "camss.h"
+
+#define TPG_HW_VERSION 0x0
+# define HW_VERSION_STEPPING GENMASK(15, 0)
+# define HW_VERSION_REVISION GENMASK(27, 16)
+# define HW_VERSION_GENERATION GENMASK(31, 28)
+
+#define TPG_HW_STATUS 0x4
+
+#define TPG_VC_n_GAIN_CFG(n) (0x60 + (n) * 0x60)
+
+#define TPG_CTRL 0x64
+# define TPG_CTRL_TEST_EN BIT(0)
+# define TPG_CTRL_PHY_SEL BIT(3)
+# define TPG_CTRL_NUM_ACTIVE_LANES GENMASK(5, 4)
+# define TPG_CTRL_VC_DT_PATTERN_ID GENMASK(8, 6)
+# define TPG_CTRL_OVERLAP_SHDR_EN BIT(10)
+# define TPG_CTRL_NUM_ACTIVE_VC GENMASK(31, 30)
+# define NUM_ACTIVE_VC_0_ENABLED 0
+# define NUM_ACTIVE_VC_0_1_ENABLED 1
+# define NUM_ACTIVE_VC_0_1_2_ENABLED 2
+# define NUM_ACTIVE_VC_0_1_3_ENABLED 3
+
+#define TPG_VC_n_CFG0(n) (0x68 + (n) * 0x60)
+# define TPG_VC_n_CFG0_VC_NUM GENMASK(4, 0)
+# define TPG_VC_n_CFG0_NUM_ACTIVE_DT GENMASK(9, 8)
+# define NUM_ACTIVE_SLOTS_0_ENABLED 0
+# define NUM_ACTIVE_SLOTS_0_1_ENABLED 1
+# define NUM_ACTIVE_SLOTS_0_1_2_ENABLED 2
+# define NUM_ACTIVE_SLOTS_0_1_3_ENABLED 3
+# define TPG_VC_n_CFG0_NUM_BATCH GENMASK(15, 12)
+# define TPG_VC_n_CFG0_NUM_FRAMES GENMASK(31, 16)
+
+#define TPG_VC_n_LSFR_SEED(n) (0x6C + (n) * 0x60)
+
+#define TPG_VC_n_HBI_CFG(n) (0x70 + (n) * 0x60)
+
+#define TPG_VC_n_VBI_CFG(n) (0x74 + (n) * 0x60)
+
+#define TPG_VC_n_COLOR_BARS_CFG(n) (0x78 + (n) * 0x60)
+# define TPG_VC_n_COLOR_BARS_CFG_PIX_PATTERN GENMASK(2, 0)
+# define TPG_VC_n_COLOR_BARS_CFG_QCFA_EN BIT(3)
+# define TPG_VC_n_COLOR_BARS_CFG_SPLIT_EN BIT(4)
+# define TPG_VC_n_COLOR_BARS_CFG_NOISE_EN BIT(5)
+# define TPG_VC_n_COLOR_BARS_CFG_ROTATE_PERIOD GENMASK(13, 8)
+# define TPG_VC_n_COLOR_BARS_CFG_XCFA_EN BIT(16)
+# define TPG_VC_n_COLOR_BARS_CFG_SIZE_X GENMASK(26, 24)
+# define TPG_VC_n_COLOR_BARS_CFG_SIZE_Y GENMASK(30, 28)
+
+#define TPG_VC_m_DT_n_CFG_0(m, n) (0x7C + (m) * 0x60 + (n) * 0xC)
+# define TPG_VC_m_DT_n_CFG_0_FRAME_HEIGHT GENMASK(15, 0)
+# define TPG_VC_m_DT_n_CFG_0_FRAME_WIDTH GENMASK(31, 16)
+
+#define TPG_VC_m_DT_n_CFG_1(m, n) (0x80 + (m) * 0x60 + (n) * 0xC)
+# define TPG_VC_m_DT_n_CFG_1_DATA_TYPE GENMASK(5, 0)
+# define TPG_VC_m_DT_n_CFG_1_ECC_XOR_MASK GENMASK(13, 8)
+# define TPG_VC_m_DT_n_CFG_1_CRC_XOR_MASK GENMASK(31, 16)
+
+#define TPG_VC_m_DT_n_CFG_2(m, n) (0x84 + (m) * 0x60 + (n) * 0xC)
+# define TPG_VC_m_DT_n_CFG_2_PAYLOAD_MODE GENMASK(3, 0)
+# define TPG_VC_m_DT_n_CFG_2_USER_SPECIFIED_PAYLOAD GENMASK(27, 4)
+# define TPG_VC_m_DT_n_CFG_2_ENCODE_FORMAT GENMASK(31, 28)
+
+#define TPG_VC_n_COLOR_BAR_CFA_COLOR0(n) (0xB0 + (n) * 0x60)
+#define TPG_VC_n_COLOR_BAR_CFA_COLOR1(n) (0xB4 + (n) * 0x60)
+#define TPG_VC_n_COLOR_BAR_CFA_COLOR2(n) (0xB8 + (n) * 0x60)
+#define TPG_VC_n_COLOR_BAR_CFA_COLOR3(n) (0xBC + (n) * 0x60)
+
+/* Line offset between VC(n) and VC(n-1), n form 1 to 3 */
+#define TPG_VC_n_SHDR_CFG (0x84 + (n) * 0x60)
+
+#define TPG_CLEAR 0x1F4
+
+#define TPG_USER_SPECIFIED_PAYLOAD_DEFAULT 0xBE
+#define TPG_HBI_CFG_DEFAULT 0x4701
+#define TPG_VBI_CFG_DEFAULT 0x438
+#define TPG_LFSR_SEED_DEFAULT 0x12345678
+#define TPG_COLOR_BARS_CFG_STANDARD \
+ FIELD_PREP(TPG_VC_n_COLOR_BARS_CFG_ROTATE_PERIOD, 0xA)
+
+static int tpg_stream_on(struct tpg_device *tpg)
+{
+ struct tpg_testgen_config *tg = &tpg->testgen;
+ struct v4l2_mbus_framefmt *input_format;
+ const struct tpg_format_info *format;
+ u8 lane_cnt = tpg->res->lane_cnt;
+ u8 dt_cnt = 0;
+ u8 i;
+ u32 val;
+
+ /* Loop through all enabled VCs and configure stream for each */
+ for (i = 0; i < tpg->res->vc_cnt; i++) {
+ input_format = &tpg->fmt[MSM_TPG_PAD_SRC + i];
+ format = tpg_get_fmt_entry(tpg,
+ tpg->res->formats->formats,
+ tpg->res->formats->nformats,
+ input_format->code);
+
+ val = FIELD_PREP(TPG_VC_m_DT_n_CFG_0_FRAME_HEIGHT, input_format->height & 0xffff) |
+ FIELD_PREP(TPG_VC_m_DT_n_CFG_0_FRAME_WIDTH, input_format->width & 0xffff);
+ writel(val, tpg->base + TPG_VC_m_DT_n_CFG_0(i, dt_cnt));
+
+ val = FIELD_PREP(TPG_VC_m_DT_n_CFG_1_DATA_TYPE, format->data_type);
+ writel(val, tpg->base + TPG_VC_m_DT_n_CFG_1(i, dt_cnt));
+
+ val = FIELD_PREP(TPG_VC_m_DT_n_CFG_2_PAYLOAD_MODE, tg->mode - 1) |
+ FIELD_PREP(TPG_VC_m_DT_n_CFG_2_USER_SPECIFIED_PAYLOAD,
+ TPG_USER_SPECIFIED_PAYLOAD_DEFAULT) |
+ FIELD_PREP(TPG_VC_m_DT_n_CFG_2_ENCODE_FORMAT, format->encode_format);
+ writel(val, tpg->base + TPG_VC_m_DT_n_CFG_2(i, dt_cnt));
+
+ writel(TPG_COLOR_BARS_CFG_STANDARD, tpg->base + TPG_VC_n_COLOR_BARS_CFG(i));
+
+ writel(TPG_HBI_CFG_DEFAULT, tpg->base + TPG_VC_n_HBI_CFG(i));
+ writel(TPG_VBI_CFG_DEFAULT, tpg->base + TPG_VC_n_VBI_CFG(i));
+
+ writel(TPG_LFSR_SEED_DEFAULT, tpg->base + TPG_VC_n_LSFR_SEED(i));
+
+ /* configure one DT, infinite frames */
+ val = FIELD_PREP(TPG_VC_n_CFG0_VC_NUM, i) |
+ FIELD_PREP(TPG_VC_n_CFG0_NUM_FRAMES, 0);
+ writel(val, tpg->base + TPG_VC_n_CFG0(i));
+ }
+
+ val = FIELD_PREP(TPG_CTRL_TEST_EN, 1) |
+ FIELD_PREP(TPG_CTRL_PHY_SEL, 0) |
+ FIELD_PREP(TPG_CTRL_NUM_ACTIVE_LANES, lane_cnt - 1) |
+ FIELD_PREP(TPG_CTRL_VC_DT_PATTERN_ID, 0) |
+ FIELD_PREP(TPG_CTRL_NUM_ACTIVE_VC, tpg->res->vc_cnt - 1);
+ writel(val, tpg->base + TPG_CTRL);
+
+ return 0;
+}
+
+static void tpg_stream_off(struct tpg_device *tpg)
+{
+ writel(0, tpg->base + TPG_CTRL);
+ writel(1, tpg->base + TPG_CLEAR);
+}
+
+static void tpg_configure_stream(struct tpg_device *tpg, u8 enable)
+{
+ if (enable)
+ tpg_stream_on(tpg);
+ else
+ tpg_stream_off(tpg);
+}
+
+static int tpg_configure_testgen_pattern(struct tpg_device *tpg, s32 val)
+{
+ if (val > 0 && val <= TPG_PAYLOAD_MODE_COLOR_BARS)
+ tpg->testgen.mode = val;
+
+ return 0;
+}
+
+/*
+ * tpg_hw_version - tpg hardware version query
+ * @tpg: tpg device
+ *
+ * Return HW version or error
+ */
+static u32 tpg_hw_version(struct tpg_device *tpg)
+{
+ u32 hw_version;
+ u32 hw_gen;
+ u32 hw_rev;
+ u32 hw_step;
+
+ hw_version = readl(tpg->base + TPG_HW_VERSION);
+ hw_gen = FIELD_GET(HW_VERSION_GENERATION, hw_version);
+ hw_rev = FIELD_GET(HW_VERSION_REVISION, hw_version);
+ hw_step = FIELD_GET(HW_VERSION_STEPPING, hw_version);
+ dev_dbg_once(tpg->camss->dev, "tpg HW Version = %u.%u.%u\n",
+ hw_gen, hw_rev, hw_step);
+
+ return hw_version;
+}
+
+/*
+ * tpg_reset - Trigger reset on tpg module and wait to complete
+ * @tpg: tpg device
+ *
+ * Return 0 on success or a negative error code otherwise
+ */
+static int tpg_reset(struct tpg_device *tpg)
+{
+ writel(0, tpg->base + TPG_CTRL);
+ writel(1, tpg->base + TPG_CLEAR);
+
+ return 0;
+}
+
+static void tpg_subdev_init(struct tpg_device *tpg)
+{
+ tpg->testgen.modes = testgen_payload_modes;
+ tpg->testgen.nmodes = TPG_PAYLOAD_MODE_NUM_SUPPORTED_GEN1;
+}
+
+const struct tpg_hw_ops tpg_ops_gen1 = {
+ .configure_stream = tpg_configure_stream,
+ .configure_testgen_pattern = tpg_configure_testgen_pattern,
+ .hw_version = tpg_hw_version,
+ .reset = tpg_reset,
+ .subdev_init = tpg_subdev_init,
+};
diff --git a/drivers/media/platform/qcom/camss/camss.c b/drivers/media/platform/qcom/camss/camss.c
index 2ede19e1347ae32f2f6919905b535352bcd134be..dcb99e4eeb9bd9a777e4bc370fa8eff0dd03301f 100644
--- a/drivers/media/platform/qcom/camss/camss.c
+++ b/drivers/media/platform/qcom/camss/camss.c
@@ -2745,6 +2745,62 @@ static const struct camss_subdev_resources csiphy_res_8775p[] = {
},
};
+static const struct camss_subdev_resources tpg_res_8775p[] = {
+ /* TPG0 */
+ {
+ .regulators = { },
+ .clock = { "csiphy_rx", "camnoc_axi" },
+ .clock_rate = {
+ { 400000000 },
+ { 400000000 },
+ },
+ .reg = { "tpg0" },
+ .interrupt = { "tpg0" },
+ .tpg = {
+ .lane_cnt = 4,
+ .vc_cnt = 1,
+ .formats = &tpg_formats_gen1,
+ .hw_ops = &tpg_ops_gen1
+ }
+ },
+
+ /* TPG1 */
+ {
+ .regulators = { },
+ .clock = { "csiphy_rx", "camnoc_axi" },
+ .clock_rate = {
+ { 400000000 },
+ { 400000000 },
+ },
+ .reg = { "tpg1" },
+ .interrupt = { "tpg1" },
+ .tpg = {
+ .lane_cnt = 4,
+ .vc_cnt = 1,
+ .formats = &tpg_formats_gen1,
+ .hw_ops = &tpg_ops_gen1
+ }
+ },
+
+ /* TPG2 */
+ {
+ .regulators = { },
+ .clock = { "csiphy_rx", "camnoc_axi" },
+ .clock_rate = {
+ { 400000000 },
+ { 400000000 },
+ },
+ .reg = { "tpg2" },
+ .interrupt = { "tpg2" },
+ .tpg = {
+ .lane_cnt = 4,
+ .vc_cnt = 1,
+ .formats = &tpg_formats_gen1,
+ .hw_ops = &tpg_ops_gen1
+ }
+ },
+};
+
static const struct camss_subdev_resources csid_res_8775p[] = {
/* CSID0 */
{
@@ -4217,6 +4273,13 @@ static int camss_probe(struct platform_device *pdev)
if (!camss->csiphy)
return -ENOMEM;
+ if (camss->res->tpg_num > 0) {
+ camss->tpg = devm_kcalloc(dev, camss->res->tpg_num,
+ sizeof(*camss->tpg), GFP_KERNEL);
+ if (!camss->tpg)
+ return -ENOMEM;
+ }
+
camss->csid = devm_kcalloc(dev, camss->res->csid_num, sizeof(*camss->csid),
GFP_KERNEL);
if (!camss->csid)
@@ -4350,6 +4413,7 @@ static const struct camss_resources msm8916_resources = {
.ispif_res = &ispif_res_8x16,
.vfe_res = vfe_res_8x16,
.csiphy_num = ARRAY_SIZE(csiphy_res_8x16),
+ .tpg_num = 0,
.csid_num = ARRAY_SIZE(csid_res_8x16),
.vfe_num = ARRAY_SIZE(vfe_res_8x16),
};
@@ -4363,6 +4427,7 @@ static const struct camss_resources msm8953_resources = {
.ispif_res = &ispif_res_8x53,
.vfe_res = vfe_res_8x53,
.csiphy_num = ARRAY_SIZE(csiphy_res_8x96),
+ .tpg_num = 0,
.csid_num = ARRAY_SIZE(csid_res_8x53),
.vfe_num = ARRAY_SIZE(vfe_res_8x53),
};
@@ -4374,6 +4439,7 @@ static const struct camss_resources msm8996_resources = {
.ispif_res = &ispif_res_8x96,
.vfe_res = vfe_res_8x96,
.csiphy_num = ARRAY_SIZE(csiphy_res_8x96),
+ .tpg_num = 0,
.csid_num = ARRAY_SIZE(csid_res_8x96),
.vfe_num = ARRAY_SIZE(vfe_res_8x96),
};
@@ -4386,6 +4452,7 @@ static const struct camss_resources qcm2290_resources = {
.icc_res = icc_res_2290,
.icc_path_num = ARRAY_SIZE(icc_res_2290),
.csiphy_num = ARRAY_SIZE(csiphy_res_2290),
+ .tpg_num = 0,
.csid_num = ARRAY_SIZE(csid_res_2290),
.vfe_num = ARRAY_SIZE(vfe_res_2290),
};
@@ -4394,11 +4461,13 @@ static const struct camss_resources qcs8300_resources = {
.version = CAMSS_8300,
.pd_name = "top",
.csiphy_res = csiphy_res_8300,
+ .tpg_res = tpg_res_8775p,
.csid_res = csid_res_8775p,
.csid_wrapper_res = &csid_wrapper_res_sm8550,
.vfe_res = vfe_res_8775p,
.icc_res = icc_res_qcs8300,
.csiphy_num = ARRAY_SIZE(csiphy_res_8300),
+ .tpg_num = ARRAY_SIZE(tpg_res_8775p),
.csid_num = ARRAY_SIZE(csid_res_8775p),
.vfe_num = ARRAY_SIZE(vfe_res_8775p),
.icc_path_num = ARRAY_SIZE(icc_res_qcs8300),
@@ -4408,11 +4477,13 @@ static const struct camss_resources sa8775p_resources = {
.version = CAMSS_8775P,
.pd_name = "top",
.csiphy_res = csiphy_res_8775p,
+ .tpg_res = tpg_res_8775p,
.csid_res = csid_res_8775p,
.csid_wrapper_res = &csid_wrapper_res_sm8550,
.vfe_res = vfe_res_8775p,
.icc_res = icc_res_sa8775p,
.csiphy_num = ARRAY_SIZE(csiphy_res_8775p),
+ .tpg_num = ARRAY_SIZE(tpg_res_8775p),
.csid_num = ARRAY_SIZE(csid_res_8775p),
.vfe_num = ARRAY_SIZE(vfe_res_8775p),
.icc_path_num = ARRAY_SIZE(icc_res_sa8775p),
@@ -4425,6 +4496,7 @@ static const struct camss_resources sdm660_resources = {
.ispif_res = &ispif_res_660,
.vfe_res = vfe_res_660,
.csiphy_num = ARRAY_SIZE(csiphy_res_660),
+ .tpg_num = 0,
.csid_num = ARRAY_SIZE(csid_res_660),
.vfe_num = ARRAY_SIZE(vfe_res_660),
};
@@ -4435,6 +4507,7 @@ static const struct camss_resources sdm670_resources = {
.csid_res = csid_res_670,
.vfe_res = vfe_res_670,
.csiphy_num = ARRAY_SIZE(csiphy_res_670),
+ .tpg_num = 0,
.csid_num = ARRAY_SIZE(csid_res_670),
.vfe_num = ARRAY_SIZE(vfe_res_670),
};
@@ -4446,6 +4519,7 @@ static const struct camss_resources sdm845_resources = {
.csid_res = csid_res_845,
.vfe_res = vfe_res_845,
.csiphy_num = ARRAY_SIZE(csiphy_res_845),
+ .tpg_num = 0,
.csid_num = ARRAY_SIZE(csid_res_845),
.vfe_num = ARRAY_SIZE(vfe_res_845),
};
@@ -4459,6 +4533,7 @@ static const struct camss_resources sm8250_resources = {
.icc_res = icc_res_sm8250,
.icc_path_num = ARRAY_SIZE(icc_res_sm8250),
.csiphy_num = ARRAY_SIZE(csiphy_res_8250),
+ .tpg_num = 0,
.csid_num = ARRAY_SIZE(csid_res_8250),
.vfe_num = ARRAY_SIZE(vfe_res_8250),
};
@@ -4473,6 +4548,7 @@ static const struct camss_resources sc8280xp_resources = {
.icc_res = icc_res_sc8280xp,
.icc_path_num = ARRAY_SIZE(icc_res_sc8280xp),
.csiphy_num = ARRAY_SIZE(csiphy_res_sc8280xp),
+ .tpg_num = 0,
.csid_num = ARRAY_SIZE(csid_res_sc8280xp),
.vfe_num = ARRAY_SIZE(vfe_res_sc8280xp),
};
@@ -4486,6 +4562,7 @@ static const struct camss_resources sc7280_resources = {
.icc_res = icc_res_sc7280,
.icc_path_num = ARRAY_SIZE(icc_res_sc7280),
.csiphy_num = ARRAY_SIZE(csiphy_res_7280),
+ .tpg_num = 0,
.csid_num = ARRAY_SIZE(csid_res_7280),
.vfe_num = ARRAY_SIZE(vfe_res_7280),
};
@@ -4500,6 +4577,7 @@ static const struct camss_resources sm8550_resources = {
.icc_res = icc_res_sm8550,
.icc_path_num = ARRAY_SIZE(icc_res_sm8550),
.csiphy_num = ARRAY_SIZE(csiphy_res_8550),
+ .tpg_num = 0,
.csid_num = ARRAY_SIZE(csid_res_8550),
.vfe_num = ARRAY_SIZE(vfe_res_8550),
};
@@ -4514,6 +4592,7 @@ static const struct camss_resources x1e80100_resources = {
.icc_res = icc_res_x1e80100,
.icc_path_num = ARRAY_SIZE(icc_res_x1e80100),
.csiphy_num = ARRAY_SIZE(csiphy_res_x1e80100),
+ .tpg_num = 0,
.csid_num = ARRAY_SIZE(csid_res_x1e80100),
.vfe_num = ARRAY_SIZE(vfe_res_x1e80100),
};
--
2.34.1
^ permalink raw reply related [flat|nested] 9+ messages in thread
* Re: [PATCH v4 3/3] media: qcom: camss: tpg: Add TPG support for SA8775P and QCS8300
2025-09-25 0:32 ` [PATCH v4 3/3] media: qcom: camss: tpg: Add TPG support for SA8775P and QCS8300 Wenmeng Liu
@ 2025-09-26 6:08 ` kernel test robot
2025-10-08 10:50 ` Konrad Dybcio
1 sibling, 0 replies; 9+ messages in thread
From: kernel test robot @ 2025-09-26 6:08 UTC (permalink / raw)
To: Wenmeng Liu, Robert Foss, Todor Tomov, Bryan O'Donoghue,
Vladimir Zapolskiy, Mauro Carvalho Chehab
Cc: llvm, oe-kbuild-all, linux-media, linux-kernel, linux-arm-msm,
Wenmeng Liu
Hi Wenmeng,
kernel test robot noticed the following build errors:
[auto build test ERROR on ce7f1a983b074f6cf8609068088ca3182c569ee4]
url: https://github.com/intel-lab-lkp/linux/commits/Wenmeng-Liu/media-qcom-camss-Add-support-for-TPG-common/20250925-083535
base: ce7f1a983b074f6cf8609068088ca3182c569ee4
patch link: https://lore.kernel.org/r/20250925-camss_tpg-v4-3-d2eb099902c8%40oss.qualcomm.com
patch subject: [PATCH v4 3/3] media: qcom: camss: tpg: Add TPG support for SA8775P and QCS8300
config: i386-buildonly-randconfig-005-20250926 (https://download.01.org/0day-ci/archive/20250926/202509261315.Ut2kQNiR-lkp@intel.com/config)
compiler: clang version 20.1.8 (https://github.com/llvm/llvm-project 87f0227cb60147a26a1eeb4fb06e3b505e9c7261)
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20250926/202509261315.Ut2kQNiR-lkp@intel.com/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 <lkp@intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202509261315.Ut2kQNiR-lkp@intel.com/
All errors (new ones prefixed by >>):
>> drivers/media/platform/qcom/camss/camss-tpg-gen1.c:112:9: error: call to undeclared function 'FIELD_PREP'; ISO C99 and later do not support implicit function declarations [-Wimplicit-function-declaration]
112 | val = FIELD_PREP(TPG_VC_m_DT_n_CFG_0_FRAME_HEIGHT, input_format->height & 0xffff) |
| ^
drivers/media/platform/qcom/camss/camss-tpg-gen1.c:138:8: error: call to undeclared function 'FIELD_PREP'; ISO C99 and later do not support implicit function declarations [-Wimplicit-function-declaration]
138 | val = FIELD_PREP(TPG_CTRL_TEST_EN, 1) |
| ^
>> drivers/media/platform/qcom/camss/camss-tpg-gen1.c:184:11: error: call to undeclared function 'FIELD_GET'; ISO C99 and later do not support implicit function declarations [-Wimplicit-function-declaration]
184 | hw_gen = FIELD_GET(HW_VERSION_GENERATION, hw_version);
| ^
3 errors generated.
vim +/FIELD_PREP +112 drivers/media/platform/qcom/camss/camss-tpg-gen1.c
86
87 #define TPG_USER_SPECIFIED_PAYLOAD_DEFAULT 0xBE
88 #define TPG_HBI_CFG_DEFAULT 0x4701
89 #define TPG_VBI_CFG_DEFAULT 0x438
90 #define TPG_LFSR_SEED_DEFAULT 0x12345678
91 #define TPG_COLOR_BARS_CFG_STANDARD \
92 FIELD_PREP(TPG_VC_n_COLOR_BARS_CFG_ROTATE_PERIOD, 0xA)
93
94 static int tpg_stream_on(struct tpg_device *tpg)
95 {
96 struct tpg_testgen_config *tg = &tpg->testgen;
97 struct v4l2_mbus_framefmt *input_format;
98 const struct tpg_format_info *format;
99 u8 lane_cnt = tpg->res->lane_cnt;
100 u8 dt_cnt = 0;
101 u8 i;
102 u32 val;
103
104 /* Loop through all enabled VCs and configure stream for each */
105 for (i = 0; i < tpg->res->vc_cnt; i++) {
106 input_format = &tpg->fmt[MSM_TPG_PAD_SRC + i];
107 format = tpg_get_fmt_entry(tpg,
108 tpg->res->formats->formats,
109 tpg->res->formats->nformats,
110 input_format->code);
111
> 112 val = FIELD_PREP(TPG_VC_m_DT_n_CFG_0_FRAME_HEIGHT, input_format->height & 0xffff) |
113 FIELD_PREP(TPG_VC_m_DT_n_CFG_0_FRAME_WIDTH, input_format->width & 0xffff);
114 writel(val, tpg->base + TPG_VC_m_DT_n_CFG_0(i, dt_cnt));
115
116 val = FIELD_PREP(TPG_VC_m_DT_n_CFG_1_DATA_TYPE, format->data_type);
117 writel(val, tpg->base + TPG_VC_m_DT_n_CFG_1(i, dt_cnt));
118
119 val = FIELD_PREP(TPG_VC_m_DT_n_CFG_2_PAYLOAD_MODE, tg->mode - 1) |
120 FIELD_PREP(TPG_VC_m_DT_n_CFG_2_USER_SPECIFIED_PAYLOAD,
121 TPG_USER_SPECIFIED_PAYLOAD_DEFAULT) |
122 FIELD_PREP(TPG_VC_m_DT_n_CFG_2_ENCODE_FORMAT, format->encode_format);
123 writel(val, tpg->base + TPG_VC_m_DT_n_CFG_2(i, dt_cnt));
124
125 writel(TPG_COLOR_BARS_CFG_STANDARD, tpg->base + TPG_VC_n_COLOR_BARS_CFG(i));
126
127 writel(TPG_HBI_CFG_DEFAULT, tpg->base + TPG_VC_n_HBI_CFG(i));
128 writel(TPG_VBI_CFG_DEFAULT, tpg->base + TPG_VC_n_VBI_CFG(i));
129
130 writel(TPG_LFSR_SEED_DEFAULT, tpg->base + TPG_VC_n_LSFR_SEED(i));
131
132 /* configure one DT, infinite frames */
133 val = FIELD_PREP(TPG_VC_n_CFG0_VC_NUM, i) |
134 FIELD_PREP(TPG_VC_n_CFG0_NUM_FRAMES, 0);
135 writel(val, tpg->base + TPG_VC_n_CFG0(i));
136 }
137
138 val = FIELD_PREP(TPG_CTRL_TEST_EN, 1) |
139 FIELD_PREP(TPG_CTRL_PHY_SEL, 0) |
140 FIELD_PREP(TPG_CTRL_NUM_ACTIVE_LANES, lane_cnt - 1) |
141 FIELD_PREP(TPG_CTRL_VC_DT_PATTERN_ID, 0) |
142 FIELD_PREP(TPG_CTRL_NUM_ACTIVE_VC, tpg->res->vc_cnt - 1);
143 writel(val, tpg->base + TPG_CTRL);
144
145 return 0;
146 }
147
148 static void tpg_stream_off(struct tpg_device *tpg)
149 {
150 writel(0, tpg->base + TPG_CTRL);
151 writel(1, tpg->base + TPG_CLEAR);
152 }
153
154 static void tpg_configure_stream(struct tpg_device *tpg, u8 enable)
155 {
156 if (enable)
157 tpg_stream_on(tpg);
158 else
159 tpg_stream_off(tpg);
160 }
161
162 static int tpg_configure_testgen_pattern(struct tpg_device *tpg, s32 val)
163 {
164 if (val > 0 && val <= TPG_PAYLOAD_MODE_COLOR_BARS)
165 tpg->testgen.mode = val;
166
167 return 0;
168 }
169
170 /*
171 * tpg_hw_version - tpg hardware version query
172 * @tpg: tpg device
173 *
174 * Return HW version or error
175 */
176 static u32 tpg_hw_version(struct tpg_device *tpg)
177 {
178 u32 hw_version;
179 u32 hw_gen;
180 u32 hw_rev;
181 u32 hw_step;
182
183 hw_version = readl(tpg->base + TPG_HW_VERSION);
> 184 hw_gen = FIELD_GET(HW_VERSION_GENERATION, hw_version);
185 hw_rev = FIELD_GET(HW_VERSION_REVISION, hw_version);
186 hw_step = FIELD_GET(HW_VERSION_STEPPING, hw_version);
187 dev_dbg_once(tpg->camss->dev, "tpg HW Version = %u.%u.%u\n",
188 hw_gen, hw_rev, hw_step);
189
190 return hw_version;
191 }
192
--
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki
^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: [PATCH v4 1/3] media: qcom: camss: Add support for TPG common
2025-09-25 0:31 ` [PATCH v4 1/3] media: qcom: camss: Add support for TPG common Wenmeng Liu
@ 2025-10-07 10:44 ` Konrad Dybcio
2025-10-16 12:55 ` Wenmeng Liu
0 siblings, 1 reply; 9+ messages in thread
From: Konrad Dybcio @ 2025-10-07 10:44 UTC (permalink / raw)
To: Wenmeng Liu, Robert Foss, Todor Tomov, Bryan O'Donoghue,
Vladimir Zapolskiy, Mauro Carvalho Chehab
Cc: linux-kernel, linux-media, linux-arm-msm
On 9/25/25 2:31 AM, Wenmeng Liu wrote:
> Add support for TPG common, unlike CSID TPG, this TPG can
Is "TPG common" the actual name of the IP?
Konrad
^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: [PATCH v4 3/3] media: qcom: camss: tpg: Add TPG support for SA8775P and QCS8300
2025-09-25 0:32 ` [PATCH v4 3/3] media: qcom: camss: tpg: Add TPG support for SA8775P and QCS8300 Wenmeng Liu
2025-09-26 6:08 ` kernel test robot
@ 2025-10-08 10:50 ` Konrad Dybcio
2025-10-16 12:56 ` Wenmeng Liu
1 sibling, 1 reply; 9+ messages in thread
From: Konrad Dybcio @ 2025-10-08 10:50 UTC (permalink / raw)
To: Wenmeng Liu, Robert Foss, Todor Tomov, Bryan O'Donoghue,
Vladimir Zapolskiy, Mauro Carvalho Chehab
Cc: linux-kernel, linux-media, linux-arm-msm
On 9/25/25 2:32 AM, Wenmeng Liu wrote:
> Add support for TPG found on SA8775P and QCS8300.
>
> Signed-off-by: Wenmeng Liu <wenmeng.liu@oss.qualcomm.com>
> ---
[...]
> @@ -4350,6 +4413,7 @@ static const struct camss_resources msm8916_resources = {
> .ispif_res = &ispif_res_8x16,
> .vfe_res = vfe_res_8x16,
> .csiphy_num = ARRAY_SIZE(csiphy_res_8x16),
> + .tpg_num = 0,
Uninitialized fields of partially-initialized structs default to zero,
i.e. drop all lines like this
Konrad
^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: [PATCH v4 1/3] media: qcom: camss: Add support for TPG common
2025-10-07 10:44 ` Konrad Dybcio
@ 2025-10-16 12:55 ` Wenmeng Liu
0 siblings, 0 replies; 9+ messages in thread
From: Wenmeng Liu @ 2025-10-16 12:55 UTC (permalink / raw)
To: Konrad Dybcio, Robert Foss, Todor Tomov, Bryan O'Donoghue,
Vladimir Zapolskiy, Mauro Carvalho Chehab
Cc: linux-kernel, linux-media, linux-arm-msm
On 10/7/2025 6:44 PM, Konrad Dybcio wrote:
> On 9/25/25 2:31 AM, Wenmeng Liu wrote:
>> Add support for TPG common, unlike CSID TPG, this TPG can
>
> Is "TPG common" the actual name of the IP?
>
> Konrad
No, it's just a description of the TPG universal code. The updated
description will be included in the next version.
Thanks,
Wenmeng
^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: [PATCH v4 3/3] media: qcom: camss: tpg: Add TPG support for SA8775P and QCS8300
2025-10-08 10:50 ` Konrad Dybcio
@ 2025-10-16 12:56 ` Wenmeng Liu
0 siblings, 0 replies; 9+ messages in thread
From: Wenmeng Liu @ 2025-10-16 12:56 UTC (permalink / raw)
To: Konrad Dybcio, Robert Foss, Todor Tomov, Bryan O'Donoghue,
Vladimir Zapolskiy, Mauro Carvalho Chehab
Cc: linux-kernel, linux-media, linux-arm-msm
On 10/8/2025 6:50 PM, Konrad Dybcio wrote:
> On 9/25/25 2:32 AM, Wenmeng Liu wrote:
>> Add support for TPG found on SA8775P and QCS8300.
>>
>> Signed-off-by: Wenmeng Liu <wenmeng.liu@oss.qualcomm.com>
>> ---
>
> [...]
>
>> @@ -4350,6 +4413,7 @@ static const struct camss_resources msm8916_resources = {
>> .ispif_res = &ispif_res_8x16,
>> .vfe_res = vfe_res_8x16,
>> .csiphy_num = ARRAY_SIZE(csiphy_res_8x16),
>> + .tpg_num = 0,
>
> Uninitialized fields of partially-initialized structs default to zero,
> i.e. drop all lines like this
>
> Konrad
sure, will update in next version.
Thanks,
Wenmeng
^ permalink raw reply [flat|nested] 9+ messages in thread
end of thread, other threads:[~2025-10-16 12:56 UTC | newest]
Thread overview: 9+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2025-09-25 0:31 [PATCH v4 0/3] media: qcom: camss: Add sa8775p/qcs8300 camss TPG support Wenmeng Liu
2025-09-25 0:31 ` [PATCH v4 1/3] media: qcom: camss: Add support for TPG common Wenmeng Liu
2025-10-07 10:44 ` Konrad Dybcio
2025-10-16 12:55 ` Wenmeng Liu
2025-09-25 0:32 ` [PATCH v4 2/3] media: qcom: camss: Add link " Wenmeng Liu
2025-09-25 0:32 ` [PATCH v4 3/3] media: qcom: camss: tpg: Add TPG support for SA8775P and QCS8300 Wenmeng Liu
2025-09-26 6:08 ` kernel test robot
2025-10-08 10:50 ` Konrad Dybcio
2025-10-16 12:56 ` Wenmeng Liu
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox