lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <0353c460-dc47-4171-a434-d52b58b50859@oss.qualcomm.com>
Date: Mon, 19 Jan 2026 11:29:34 +0800
From: Wenmeng Liu <wenmeng.liu@....qualcomm.com>
To: Vijay Kumar Tumati <vijay.tumati@....qualcomm.com>,
        Robert Foss <rfoss@...nel.org>, Todor Tomov <todor.too@...il.com>,
        Bryan O'Donoghue <bryan.odonoghue@...aro.org>,
        Vladimir Zapolskiy <vladimir.zapolskiy@...aro.org>,
        Mauro Carvalho Chehab <mchehab@...nel.org>
Cc: linux-kernel@...r.kernel.org, linux-media@...r.kernel.org,
        linux-arm-msm@...r.kernel.org
Subject: Re: [PATCH v8 3/3] media: qcom: camss: tpg: Add TPG support for
 multiple targets


Hi Vijay,

On 1/17/2026 3:32 AM, Vijay Kumar Tumati wrote:
> Hi Wenmeng,
> 
> On 1/13/2026 1:03 AM, Wenmeng Liu wrote:
>> Add support for TPG found on LeMans, Monaco, Hamoa.
>>
>> Signed-off-by: Wenmeng Liu<wenmeng.liu@....qualcomm.com>
>> ---
>>   drivers/media/platform/qcom/camss/Makefile         |   1 +
>>   drivers/media/platform/qcom/camss/camss-csid-680.c |  14 ++
>>   .../media/platform/qcom/camss/camss-csid-gen3.c    |  14 ++
>>   drivers/media/platform/qcom/camss/camss-tpg-gen1.c | 257 +++++++++++ 
>> ++++++++++
>>   drivers/media/platform/qcom/camss/camss.c          | 128 ++++++++++
>>   5 files changed, 414 insertions(+)
>>
>> diff --git a/drivers/media/platform/qcom/camss/Makefile b/drivers/ 
>> media/platform/qcom/camss/Makefile
>> index 
>> d355e67c25700ac061b878543c32ed8defc03ad0..e8996dacf1771d13ec1936c9bebc0e71566898ef 100644
>> --- a/drivers/media/platform/qcom/camss/Makefile
>> +++ b/drivers/media/platform/qcom/camss/Makefile
>> @@ -28,5 +28,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-680.c b/ 
>> drivers/media/platform/qcom/camss/camss-csid-680.c
>> index 
>> 3ad3a174bcfb8c0d319930d0010df92308cb5ae4..a5da35cae2eb9acf642795c0a91db58d845f211c 100644
>> --- a/drivers/media/platform/qcom/camss/camss-csid-680.c
>> +++ b/drivers/media/platform/qcom/camss/camss-csid-680.c
>> @@ -103,6 +103,8 @@
>>   #define        CSI2_RX_CFG0_PHY_NUM_SEL            20
>>   #define        CSI2_RX_CFG0_PHY_SEL_BASE_IDX            1
>>   #define        CSI2_RX_CFG0_PHY_TYPE_SEL            24
>> +#define        CSI2_RX_CFG0_TPG_NUM_EN                BIT(27)
>> +#define        CSI2_RX_CFG0_TPG_NUM_SEL            GENMASK(29, 28)
>>   #define CSID_CSI2_RX_CFG1                    0x204
>>   #define        CSI2_RX_CFG1_PACKET_ECC_CORRECTION_EN        BIT(0)
>> @@ -185,11 +187,23 @@ static void __csid_configure_rx(struct 
>> csid_device *csid,
>>                   struct csid_phy_config *phy, int vc)
>>   {
>>       u32 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;
> "phy_num_sel" and "tpg_num_sel" can be in if-else. They both are not 
> required at once.

ACK

>> +    if (camss->tpg) {
>> +        tpg = &camss->tpg[phy->csiphy_id];
>> +
>> +        if (csid->tpg_linked && tpg->testgen.mode > 0) {
> If the tpg is linked and the mode is not valid, shouldn't you be 
> throwing error?

ACK
>> +            val |= FIELD_PREP(CSI2_RX_CFG0_TPG_NUM_SEL, phy- 
>> >csiphy_id + 1);
>> +            val |= CSI2_RX_CFG0_TPG_NUM_EN;
> Can we rename this to CSI2_RX_CFG0_TPG_MUX_EN?

ACK

>> +        }
>> +    }
>> +
>>       writel(val, csid->base + CSID_CSI2_RX_CFG0);
>>       val = CSI2_RX_CFG1_PACKET_ECC_CORRECTION_EN;
>> diff --git a/drivers/media/platform/qcom/camss/camss-csid-gen3.c b/ 
>> drivers/media/platform/qcom/camss/camss-csid-gen3.c
>> index 
>> 664245cf6eb0cac662b02f8b920cd1c72db0aeb2..5f9eb533723f2864df64fd6c63e2682fed4a12ae 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        BIT(27)
>> +#define        CSI2_RX_CFG0_TPG_NUM_SEL    GENMASK(29, 28)
>>   #define CSID_CSI2_RX_CFG1        0x204
>>   #define        CSI2_RX_CFG1_ECC_CORRECTION_EN    BIT(0)
>> @@ -109,11 +111,23 @@ static void __csid_configure_rx(struct 
>> csid_device *csid,
>>                   struct csid_phy_config *phy, int vc)
> Same as above.

ACK

>>   {
>>       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 (csid->tpg_linked && tpg->testgen.mode > 0) {
>> +            val |= FIELD_PREP(CSI2_RX_CFG0_TPG_NUM_SEL, phy- 
>> >csiphy_id + 1);
>> +            val |= 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..d7ef7a1709648406dc59c210d355851397980769
>> --- /dev/null
>> +++ b/drivers/media/platform/qcom/camss/camss-tpg-gen1.c
>> @@ -0,0 +1,257 @@
>> +// 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/bitfield.h>
>> +#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_VER(gen, rev, step) \
>> +    (((u32)(gen) << 28) | ((u32)(rev) << 16) | (u32)(step))
>> +
>> +#define TPG_HW_VER_2_0_0                TPG_HW_VER(2, 0, 0)
>> +#define TPG_HW_VER_2_1_0                TPG_HW_VER(2, 1, 0)
>> +
>> +#define TPG_HW_STATUS        0x4
>> +
>> +#define TPG_VC_n_GAIN_CFG(n)        (0x60 + (n) * 0x60)
> I know why this is here but it may be is better to group this with VC 
> based registers. In fact, can you please segregate these macros into sub 
> sections with headings like "TPG global registers", "TPG VC based 
> registers", "TPG DT based registers" etc. Just for better readability.

ACK, registers are arranged according to their addresses, and I will 
mark the global registers.

>> +
>> +#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
> s/NUM_ACTIVE_SLOTS/DT/?, if you really need these macros. Similarly for 
> VCs enabled.

ACK

>> +# 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)
>> +/* v2.0.0: USER[19:4], ENC[23:20] */
>> +# define TPG_V2_VC_m_DT_n_CFG_2_USER_SPECIFIED_PAYLOAD        
>> GENMASK(19, 4)
>> +# define TPG_V2_VC_m_DT_n_CFG_2_ENCODE_FORMAT            GENMASK(23, 20)
> For better readability, can you make these TPG_V2_0_*?
>> +/* v2.1.0: USER[27:4], ENC[31:28] */
>> +# define TPG_V2_1_VC_m_DT_n_CFG_2_USER_SPECIFIED_PAYLOAD    
>> GENMASK(27, 4)
>> +# define TPG_V2_1_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_HBI_PCT_DEFAULT            545    /* 545% */
>> +#define TPG_VBI_PCT_DEFAULT            10    /* 10% */
>> +#define PERCENT_BASE                100
>> +#define BITS_PER_BYTE                8
>> +
>> +/* Default user-specified payload for TPG test generator.
>> + * Keep consistent with CSID TPG default: 0xBE.
>> + */
>> +#define TPG_USER_SPECIFIED_PAYLOAD_DEFAULT    0xBE
>> +#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)
> Add function headers? For this  and a few other below.

I received a comment asking me to remove the comments,
if a function is not called in multiple places or its purpose cannot be 
directly understood, adding extra documentation is useless.

>> +{
>> +    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++) {
> Here as well, can we segregate the code to global, VC based and DT based 
> configs with some comments?

This loop all contains configurations related to VC/DT.
Will add some comments for this.

>> +        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);
>> +        if (IS_ERR(format))
>> +            return -EINVAL;
>> +
>> +        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));
>> +
>> +        if (tpg->hw_version == TPG_HW_VER_2_0_0) {
>> +            val = FIELD_PREP(TPG_VC_m_DT_n_CFG_2_PAYLOAD_MODE, tg- 
>> >mode - 1) |
>> +                
>> FIELD_PREP(TPG_V2_VC_m_DT_n_CFG_2_USER_SPECIFIED_PAYLOAD,
>> +                       TPG_USER_SPECIFIED_PAYLOAD_DEFAULT) |
>> +                FIELD_PREP(TPG_V2_VC_m_DT_n_CFG_2_ENCODE_FORMAT,
>> +                       format->encode_format);
>> +        } else if (tpg->hw_version >= TPG_HW_VER_2_1_0) {
>> +            val = FIELD_PREP(TPG_VC_m_DT_n_CFG_2_PAYLOAD_MODE, tg- 
>> >mode - 1) |
>> +                
>> FIELD_PREP(TPG_V2_1_VC_m_DT_n_CFG_2_USER_SPECIFIED_PAYLOAD,
>> +                       TPG_USER_SPECIFIED_PAYLOAD_DEFAULT) |
>> +                FIELD_PREP(TPG_V2_1_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));
>> +
>> +        val = DIV_ROUND_UP(input_format->width * format->bpp * 
>> TPG_HBI_PCT_DEFAULT,
>> +                   BITS_PER_BYTE * lane_cnt * PERCENT_BASE);
>> +        writel(val, tpg->base + TPG_VC_n_HBI_CFG(i));
>> +        val = input_format->height * TPG_VBI_PCT_DEFAULT / PERCENT_BASE;
>> +        writel(val, 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 */
> Although this driver is not supporting more than one DT in a VC right 
> now, is there a way we can make the API generic enough to receive #DTs 
> in each VS and their dimensions?

ACK

>> +        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) |
> Same here, is there a way to make the API generic to receive CPHY / DPHY 
> mode required?

ACK

>> +          FIELD_PREP(TPG_CTRL_NUM_ACTIVE_LANES, lane_cnt - 1) |
>> +          FIELD_PREP(TPG_CTRL_VC_DT_PATTERN_ID, 0) |
> You are assuming frame interleaved mode always. It may be is a good 
> start but a bunch of functionality is missing here. Just please think of 
> the scalability of the API even though the driver support is limited at 
> this point.

ACK

>> +          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);
> Why not just reuse the reset function?

ACK

>> +}
>> +
>> +static int tpg_configure_stream(struct tpg_device *tpg, u8 enable)
>> +{
>> +    int ret = 0;
>> +
>> +    if (enable)
>> +        ret = tpg_stream_on(tpg);
>> +    else
>> +        tpg_stream_off(tpg);
>> +
>> +    return ret;
>> +}
>> +
>> +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);
>> +
>> +    tpg->hw_version = 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
> Doesn't seem like there is any wait here, right?

Do you have any suggestions on this? I noticed that there is no delay 
downstream either.

> Also, do you want to 
> clear the IRQs in reset?

Following the maintainer's suggestion, I removed IRQ support, but we do 
need to add IRQ clearing.

>> + * @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 
>> 43fdcb9af101ef34b118035ca9c68757b66118df..5cddf1bc09f97c2c61f907939bb54663d8eab3d4 100644
>> --- a/drivers/media/platform/qcom/camss/camss.c
>> +++ b/drivers/media/platform/qcom/camss/camss.c
>> @@ -3199,6 +3199,65 @@ static const struct camss_subdev_resources 
>> csiphy_res_8775p[] = {
>>       },
>>   };
>> +static const struct camss_subdev_resources tpg_res_8775p[] = {
>> +    /* TPG0 */
>> +    {
>> +        .regulators = {  },
>> +        .clock = { "camnoc_rt_axi", "cpas_ahb", "csiphy_rx" },
> Why should TPG need camnoc_rt_axi clk?

As tested ,TPG can`t streaming without camnoc_rt_axi clk.
For Pixel path, some platform can stream without camnoc_rt_axi clk but 
TPG not.

>> +        .clock_rate = {
>> +            { 400000000 },
>> +            { 0 },
>> +            { 400000000 },
>> +        },
>> +        .reg = { "tpg0" },
>> +        .interrupt = { "tpg0" },
>> +        .tpg = {
>> +            .lane_cnt = 4,
>> +            .vc_cnt = 1,
>> +            .formats = &tpg_formats_gen1,
>> +            .hw_ops = &tpg_ops_gen1
>> +        }
>> +    },
>> +
>> +    /* TPG1 */
>> +    {
>> +        .regulators = {  },
>> +        .clock = { "camnoc_rt_axi", "cpas_ahb", "csiphy_rx" },
>> +        .clock_rate = {
>> +            { 400000000 },
>> +            { 0 },
>> +            { 400000000 },
>> +        },
>> +        .reg = { "tpg1" },
>> +        .interrupt = { "tpg1" },
>> +        .tpg = {
>> +            .lane_cnt = 4,
>> +            .vc_cnt = 1,
>> +            .formats = &tpg_formats_gen1,
>> +            .hw_ops = &tpg_ops_gen1
>> +        }
>> +    },
>> +
>> +    /* TPG2 */
>> +    {
>> +        .regulators = {  },
>> +        .clock = { "camnoc_rt_axi", "cpas_ahb", "csiphy_rx" },
>> +        .clock_rate = {
>> +            { 400000000 },
>> +            { 0 },
>> +            { 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 */ { @@ -3595,6 
>> +3654,62 @@ static const struct camss_subdev_resources 
>> csiphy_res_x1e80100[] = { }, }; +static const struct 
>> camss_subdev_resources tpg_res_x1e80100[] = { + /* TPG0 */ + 
>> { + .regulators = { }, + .clock = { "camnoc_rt_axi", "cpas_ahb", 
>> "csid_csiphy_rx" },
>> +        .clock_rate = {
>> +            { 400000000 },
>> +            { 0 },
>> +            { 400000000 },
>> +        },
>> +        .reg = { "csitpg0" },
>> +        .tpg = {
>> +            .lane_cnt = 4,
>> +            .vc_cnt = 1,
>> +            .formats = &tpg_formats_gen1,
>> +            .hw_ops = &tpg_ops_gen1
>> +        }
>> +    },
>> +
>> +    /* TPG1 */
>> +    {
>> +        .regulators = {  },
>> +        .clock = { "camnoc_rt_axi", "cpas_ahb", "csid_csiphy_rx" },
>> +        .clock_rate = {
>> +            { 400000000 },
>> +            { 0 },
>> +            { 400000000 },
>> +        },
>> +        .reg = { "csitpg1" },
>> +        .tpg = {
>> +            .lane_cnt = 4,
>> +            .vc_cnt = 1,
>> +            .formats = &tpg_formats_gen1,
>> +            .hw_ops = &tpg_ops_gen1
>> +        }
>> +    },
>> +
>> +    /* TPG2 */
>> +    {
>> +        .regulators = {  },
>> +        .clock = { "camnoc_rt_axi", "cpas_ahb", "csid_csiphy_rx" },
>> +        .clock_rate = {
>> +            { 400000000 },
>> +            { 0 },
>> +            { 400000000 },
>> +        },
>> +        .reg = { "csitpg2" },
>> +        .tpg = {
>> +            .lane_cnt = 4,
>> +            .vc_cnt = 1,
>> +            .formats = &tpg_formats_gen1,
>> +            .hw_ops = &tpg_ops_gen1
>> +        }
>> +    },
>> +};
>> +
>>   static const struct camss_subdev_resources csid_res_x1e80100[] = {
>>       /* CSID0 */
>>       {
>> @@ -4674,6 +4789,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)
>> @@ -4863,11 +4985,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), @@ -4877,11 +5001,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), @@ -4992,11 +5118,13 @@ static const 
>> struct camss_resources x1e80100_resources = { .pd_name = "top",
>>       .csiphy_res = csiphy_res_x1e80100,
>>       .csid_res = csid_res_x1e80100,
>> +    .tpg_res = tpg_res_x1e80100,
>>       .vfe_res = vfe_res_x1e80100,
>>       .csid_wrapper_res = &csid_wrapper_res_x1e80100,
>>       .icc_res = icc_res_x1e80100,
>>       .icc_path_num = ARRAY_SIZE(icc_res_x1e80100),
>>       .csiphy_num = ARRAY_SIZE(csiphy_res_x1e80100),
>> +    .tpg_num = ARRAY_SIZE(tpg_res_x1e80100),
>>       .csid_num = ARRAY_SIZE(csid_res_x1e80100),
>>       .vfe_num = ARRAY_SIZE(vfe_res_x1e80100),
>>   };
> 
> Thanks,
> 
> Vijay.
> 

Thanks,
Wenmeng

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ