This patch extends the cmdq_pkt_write API to support SoCs that do not
have subsys ID mapping by introducing new register write APIs:
- cmdq_pkt_write_pa() and cmdq_pkt_write_subsys() replace
cmdq_pkt_write()
- cmdq_pkt_write_mask_pa() and cmdq_pkt_write_mask_subsys() replace
cmdq_pkt_write_mask()
To ensure consistent function pointer interfaces, both
cmdq_pkt_write_pa() and cmdq_pkt_write_subsys() provide subsys and
pa_base parameters. This unifies how register writes are invoked,
regardless of whether subsys ID is supported by the device.
All GCEs support writing registers by PA (with mask) without subsys,
but this requires extra GCE instructions to convert the PA into a GCE
readable format, reducing performance compared to using subsys directly.
Therefore, subsys is preferred for register writes when available.
API documentation and function pointer declarations in cmdq_client_reg
have been updated. The original write APIs will be removed after all
CMDQ users transition to the new interfaces.
Signed-off-by: Jason-JH Lin <jason-jh.lin@mediatek.com>
---
drivers/soc/mediatek/mtk-cmdq-helper.c | 54 +++++++++++++++++
include/linux/soc/mediatek/mtk-cmdq.h | 83 ++++++++++++++++++++++++++
2 files changed, 137 insertions(+)
diff --git a/drivers/soc/mediatek/mtk-cmdq-helper.c b/drivers/soc/mediatek/mtk-cmdq-helper.c
index 80806fbeba91..a884e481efa6 100644
--- a/drivers/soc/mediatek/mtk-cmdq-helper.c
+++ b/drivers/soc/mediatek/mtk-cmdq-helper.c
@@ -85,6 +85,16 @@ int cmdq_dev_get_client_reg(struct device *dev,
/* make subsys invalid */
client_reg->subsys = CMDQ_SUBSYS_INVALID;
+ /*
+ * All GCEs support writing register PA with mask without subsys,
+ * but this requires extra GCE instructions to convert the PA into
+ * a format that GCE can handle, which is less performance than
+ * directly using subsys. Therefore, when subsys is available,
+ * we prefer to use subsys for writing register PA.
+ */
+ client_reg->reg_write = cmdq_pkt_write_pa;
+ client_reg->reg_write_mask = cmdq_pkt_write_mask_pa;
+
return 0;
}
@@ -93,6 +103,9 @@ int cmdq_dev_get_client_reg(struct device *dev,
client_reg->size = (u16)spec.args[2];
of_node_put(spec.np);
+ client_reg->reg_write = cmdq_pkt_write_subsys;
+ client_reg->reg_write_mask = cmdq_pkt_write_mask_subsys;
+
return 0;
}
EXPORT_SYMBOL(cmdq_dev_get_client_reg);
@@ -214,6 +227,26 @@ int cmdq_pkt_write(struct cmdq_pkt *pkt, u8 subsys, u16 offset, u32 value)
}
EXPORT_SYMBOL(cmdq_pkt_write);
+int cmdq_pkt_write_pa(struct cmdq_pkt *pkt, u8 subsys /*unused*/, u32 pa_base,
+ u16 offset, u32 value)
+{
+ int err;
+
+ err = cmdq_pkt_assign(pkt, CMDQ_THR_SPR_IDX0, CMDQ_ADDR_HIGH(pa_base));
+ if (err < 0)
+ return err;
+
+ return cmdq_pkt_write_s_value(pkt, CMDQ_THR_SPR_IDX0, CMDQ_ADDR_LOW(offset), value);
+}
+EXPORT_SYMBOL(cmdq_pkt_write_pa);
+
+int cmdq_pkt_write_subsys(struct cmdq_pkt *pkt, u8 subsys, u32 pa_base /*unused*/,
+ u16 offset, u32 value)
+{
+ return cmdq_pkt_write(pkt, subsys, offset, value);
+}
+EXPORT_SYMBOL(cmdq_pkt_write_subsys);
+
int cmdq_pkt_write_mask(struct cmdq_pkt *pkt, u8 subsys,
u16 offset, u32 value, u32 mask)
{
@@ -231,6 +264,27 @@ int cmdq_pkt_write_mask(struct cmdq_pkt *pkt, u8 subsys,
}
EXPORT_SYMBOL(cmdq_pkt_write_mask);
+int cmdq_pkt_write_mask_pa(struct cmdq_pkt *pkt, u8 subsys /*unused*/, u32 pa_base,
+ u16 offset, u32 value, u32 mask)
+{
+ int err;
+
+ err = cmdq_pkt_assign(pkt, CMDQ_THR_SPR_IDX0, CMDQ_ADDR_HIGH(pa_base));
+ if (err < 0)
+ return err;
+
+ return cmdq_pkt_write_s_mask_value(pkt, CMDQ_THR_SPR_IDX0,
+ CMDQ_ADDR_LOW(offset), value, mask);
+}
+EXPORT_SYMBOL(cmdq_pkt_write_mask_pa);
+
+int cmdq_pkt_write_mask_subsys(struct cmdq_pkt *pkt, u8 subsys, u32 pa_base /*unused*/,
+ u16 offset, u32 value, u32 mask)
+{
+ return cmdq_pkt_write_mask(pkt, subsys, offset, value, mask);
+}
+EXPORT_SYMBOL(cmdq_pkt_write_mask_subsys);
+
int cmdq_pkt_read_s(struct cmdq_pkt *pkt, u16 high_addr_reg_idx, u16 addr_low,
u16 reg_idx)
{
diff --git a/include/linux/soc/mediatek/mtk-cmdq.h b/include/linux/soc/mediatek/mtk-cmdq.h
index 154d0511a0ad..f6dc43c036bd 100644
--- a/include/linux/soc/mediatek/mtk-cmdq.h
+++ b/include/linux/soc/mediatek/mtk-cmdq.h
@@ -57,6 +57,10 @@ struct cmdq_client_reg {
phys_addr_t pa_base;
u16 offset;
u16 size;
+ int (*reg_write)(struct cmdq_pkt *pkt, u8 subsys, u32 pa_base,
+ u16 offset, u32 value);
+ int (*reg_write_mask)(struct cmdq_pkt *pkt, u8 subsys, u32 pa_base,
+ u16 offset, u32 value, u32 mask);
};
struct cmdq_client {
@@ -124,6 +128,32 @@ void cmdq_pkt_destroy(struct cmdq_client *client, struct cmdq_pkt *pkt);
*/
int cmdq_pkt_write(struct cmdq_pkt *pkt, u8 subsys, u16 offset, u32 value);
+/**
+ * cmdq_pkt_write_pa() - append write command to the CMDQ packet with pa_base
+ * @pkt: the CMDQ packet
+ * @subsys: unused parameter
+ * @pa_base: the physical address base of the hardware register
+ * @offset: register offset from CMDQ sub system
+ * @value: the specified target register value
+ *
+ * Return: 0 for success; else the error code is returned
+ */
+int cmdq_pkt_write_pa(struct cmdq_pkt *pkt, u8 subsys /*unused*/,
+ u32 pa_base, u16 offset, u32 value);
+
+/**
+ * cmdq_pkt_write_subsys() - append write command to the CMDQ packet with subsys
+ * @pkt: the CMDQ packet
+ * @subsys: the CMDQ sub system code
+ * @pa_base: unused parameter
+ * @offset: register offset from CMDQ sub system
+ * @value: the specified target register value
+ *
+ * Return: 0 for success; else the error code is returned
+ */
+int cmdq_pkt_write_subsys(struct cmdq_pkt *pkt, u8 subsys,
+ u32 pa_base /*unused*/, u16 offset, u32 value);
+
/**
* cmdq_pkt_write_mask() - append write command with mask to the CMDQ packet
* @pkt: the CMDQ packet
@@ -137,6 +167,34 @@ int cmdq_pkt_write(struct cmdq_pkt *pkt, u8 subsys, u16 offset, u32 value);
int cmdq_pkt_write_mask(struct cmdq_pkt *pkt, u8 subsys,
u16 offset, u32 value, u32 mask);
+/**
+ * cmdq_pkt_write_mask_pa() - append write command with mask to the CMDQ packet with pa
+ * @pkt: the CMDQ packet
+ * @subsys: unused parameter
+ * @pa_base: the physical address base of the hardware register
+ * @offset: register offset from CMDQ sub system
+ * @value: the specified target register value
+ * @mask: the specified target register mask
+ *
+ * Return: 0 for success; else the error code is returned
+ */
+int cmdq_pkt_write_mask_pa(struct cmdq_pkt *pkt, u8 subsys /*unused*/,
+ u32 pa_base, u16 offset, u32 value, u32 mask);
+
+/**
+ * cmdq_pkt_write_mask_subsys() - append write command with mask to the CMDQ packet with subsys
+ * @pkt: the CMDQ packet
+ * @subsys: the CMDQ sub system code
+ * @pa_base: unused parameter
+ * @offset: register offset from CMDQ sub system
+ * @value: the specified target register value
+ * @mask: the specified target register mask
+ *
+ * Return: 0 for success; else the error code is returned
+ */
+int cmdq_pkt_write_mask_subsys(struct cmdq_pkt *pkt, u8 subsys,
+ u32 pa_base /*unused*/, u16 offset, u32 value, u32 mask);
+
/*
* cmdq_pkt_read_s() - append read_s command to the CMDQ packet
* @pkt: the CMDQ packet
@@ -439,12 +497,37 @@ static inline int cmdq_pkt_write(struct cmdq_pkt *pkt, u8 subsys, u16 offset, u3
return -ENOENT;
}
+static inline int cmdq_pkt_write_pa(struct cmdq_pkt *pkt, u8 subsys /*unused*/,
+ u32 pa_base, u16 offset, u32 value)
+{
+ return -ENOENT;
+}
+
+static inline int cmdq_pkt_write_subsys(struct cmdq_pkt *pkt, u8 subsys,
+ u32 pa_base /*unused*/, u16 offset, u32 value)
+{
+ return -ENOENT;
+}
+
static inline int cmdq_pkt_write_mask(struct cmdq_pkt *pkt, u8 subsys,
u16 offset, u32 value, u32 mask)
{
return -ENOENT;
}
+static inline int cmdq_pkt_write_mask_pa(struct cmdq_pkt *pkt, u8 subsys /*unused*/,
+ u32 pa_base, u16 offset, u32 value, u32 mask)
+{
+ return -ENOENT;
+}
+
+static inline int cmdq_pkt_write_mask_subsys(struct cmdq_pkt *pkt, u8 subsys,
+ u32 pa_base /*unused*/, u16 offset,
+ u32 value, u32 mask)
+{
+ return -ENOENT;
+}
+
static inline int cmdq_pkt_read_s(struct cmdq_pkt *pkt, u16 high_addr_reg_idx,
u16 addr_low, u16 reg_idx)
{
--
2.43.0
Il 17/10/25 08:44, Jason-JH Lin ha scritto:
> This patch extends the cmdq_pkt_write API to support SoCs that do not
> have subsys ID mapping by introducing new register write APIs:
> - cmdq_pkt_write_pa() and cmdq_pkt_write_subsys() replace
> cmdq_pkt_write()
> - cmdq_pkt_write_mask_pa() and cmdq_pkt_write_mask_subsys() replace
> cmdq_pkt_write_mask()
>
> To ensure consistent function pointer interfaces, both
> cmdq_pkt_write_pa() and cmdq_pkt_write_subsys() provide subsys and
> pa_base parameters. This unifies how register writes are invoked,
> regardless of whether subsys ID is supported by the device.
>
> All GCEs support writing registers by PA (with mask) without subsys,
> but this requires extra GCE instructions to convert the PA into a GCE
> readable format, reducing performance compared to using subsys directly.
> Therefore, subsys is preferred for register writes when available.
>
> API documentation and function pointer declarations in cmdq_client_reg
> have been updated. The original write APIs will be removed after all
> CMDQ users transition to the new interfaces.
>
> Signed-off-by: Jason-JH Lin <jason-jh.lin@mediatek.com>
> ---
> drivers/soc/mediatek/mtk-cmdq-helper.c | 54 +++++++++++++++++
> include/linux/soc/mediatek/mtk-cmdq.h | 83 ++++++++++++++++++++++++++
> 2 files changed, 137 insertions(+)
>
> diff --git a/include/linux/soc/mediatek/mtk-cmdq.h b/include/linux/soc/mediatek/mtk-cmdq.h
> index 154d0511a0ad..f6dc43c036bd 100644
> --- a/include/linux/soc/mediatek/mtk-cmdq.h
> +++ b/include/linux/soc/mediatek/mtk-cmdq.h
> @@ -57,6 +57,10 @@ struct cmdq_client_reg {
> phys_addr_t pa_base;
> u16 offset;
> u16 size;
> + int (*reg_write)(struct cmdq_pkt *pkt, u8 subsys, u32 pa_base,
> + u16 offset, u32 value);
(*pkt_write)
> + int (*reg_write_mask)(struct cmdq_pkt *pkt, u8 subsys, u32 pa_base,
> + u16 offset, u32 value, u32 mask);
(*pkt_write_mask)
those names make a lot more sense.
After applying the requested changes,
Reviewed-by: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
> };
On Mon, 2025-10-20 at 12:04 +0200, AngeloGioacchino Del Regno wrote:
>
> External email : Please do not click links or open attachments until
> you have verified the sender or the content.
>
>
> Il 17/10/25 08:44, Jason-JH Lin ha scritto:
> > This patch extends the cmdq_pkt_write API to support SoCs that do
> > not
> > have subsys ID mapping by introducing new register write APIs:
> > - cmdq_pkt_write_pa() and cmdq_pkt_write_subsys() replace
> > cmdq_pkt_write()
> > - cmdq_pkt_write_mask_pa() and cmdq_pkt_write_mask_subsys() replace
> > cmdq_pkt_write_mask()
> >
> > To ensure consistent function pointer interfaces, both
> > cmdq_pkt_write_pa() and cmdq_pkt_write_subsys() provide subsys and
> > pa_base parameters. This unifies how register writes are invoked,
> > regardless of whether subsys ID is supported by the device.
> >
> > All GCEs support writing registers by PA (with mask) without
> > subsys,
> > but this requires extra GCE instructions to convert the PA into a
> > GCE
> > readable format, reducing performance compared to using subsys
> > directly.
> > Therefore, subsys is preferred for register writes when available.
> >
> > API documentation and function pointer declarations in
> > cmdq_client_reg
> > have been updated. The original write APIs will be removed after
> > all
> > CMDQ users transition to the new interfaces.
> >
> > Signed-off-by: Jason-JH Lin <jason-jh.lin@mediatek.com>
> > ---
> > drivers/soc/mediatek/mtk-cmdq-helper.c | 54 +++++++++++++++++
> > include/linux/soc/mediatek/mtk-cmdq.h | 83
> > ++++++++++++++++++++++++++
> > 2 files changed, 137 insertions(+)
> >
>
> > diff --git a/include/linux/soc/mediatek/mtk-cmdq.h
> > b/include/linux/soc/mediatek/mtk-cmdq.h
> > index 154d0511a0ad..f6dc43c036bd 100644
> > --- a/include/linux/soc/mediatek/mtk-cmdq.h
> > +++ b/include/linux/soc/mediatek/mtk-cmdq.h
> > @@ -57,6 +57,10 @@ struct cmdq_client_reg {
> > phys_addr_t pa_base;
> > u16 offset;
> > u16 size;
> > + int (*reg_write)(struct cmdq_pkt *pkt, u8 subsys, u32
> > pa_base,
> > + u16 offset, u32 value);
>
> (*pkt_write)
>
> > + int (*reg_write_mask)(struct cmdq_pkt *pkt, u8 subsys, u32
> > pa_base,
> > + u16 offset, u32 value, u32 mask);
>
> (*pkt_write_mask)
>
> those names make a lot more sense.
>
Hi Angelo,
The reason why I use reg_write/reg_write_mask is to imply these APIs
only provide writing HW register address function, not writing DRAM
address.
So we don't need to care about mminfra_offset in these APIs.
I can add comment for this.
What do you think?
Or should I change its name to pkt_write/pkt_write_amsk?
Regards,
Jason-JH Lin
> After applying the requested changes,
>
> Reviewed-by: AngeloGioacchino Del Regno
> <angelogioacchino.delregno@collabora.com>
>
> > };
Il 23/10/25 06:03, Jason-JH Lin (林睿祥) ha scritto:
> On Mon, 2025-10-20 at 12:04 +0200, AngeloGioacchino Del Regno wrote:
>>
>> External email : Please do not click links or open attachments until
>> you have verified the sender or the content.
>>
>>
>> Il 17/10/25 08:44, Jason-JH Lin ha scritto:
>>> This patch extends the cmdq_pkt_write API to support SoCs that do
>>> not
>>> have subsys ID mapping by introducing new register write APIs:
>>> - cmdq_pkt_write_pa() and cmdq_pkt_write_subsys() replace
>>> cmdq_pkt_write()
>>> - cmdq_pkt_write_mask_pa() and cmdq_pkt_write_mask_subsys() replace
>>> cmdq_pkt_write_mask()
>>>
>>> To ensure consistent function pointer interfaces, both
>>> cmdq_pkt_write_pa() and cmdq_pkt_write_subsys() provide subsys and
>>> pa_base parameters. This unifies how register writes are invoked,
>>> regardless of whether subsys ID is supported by the device.
>>>
>>> All GCEs support writing registers by PA (with mask) without
>>> subsys,
>>> but this requires extra GCE instructions to convert the PA into a
>>> GCE
>>> readable format, reducing performance compared to using subsys
>>> directly.
>>> Therefore, subsys is preferred for register writes when available.
>>>
>>> API documentation and function pointer declarations in
>>> cmdq_client_reg
>>> have been updated. The original write APIs will be removed after
>>> all
>>> CMDQ users transition to the new interfaces.
>>>
>>> Signed-off-by: Jason-JH Lin <jason-jh.lin@mediatek.com>
>>> ---
>>> drivers/soc/mediatek/mtk-cmdq-helper.c | 54 +++++++++++++++++
>>> include/linux/soc/mediatek/mtk-cmdq.h | 83
>>> ++++++++++++++++++++++++++
>>> 2 files changed, 137 insertions(+)
>>>
>>
>>> diff --git a/include/linux/soc/mediatek/mtk-cmdq.h
>>> b/include/linux/soc/mediatek/mtk-cmdq.h
>>> index 154d0511a0ad..f6dc43c036bd 100644
>>> --- a/include/linux/soc/mediatek/mtk-cmdq.h
>>> +++ b/include/linux/soc/mediatek/mtk-cmdq.h
>>> @@ -57,6 +57,10 @@ struct cmdq_client_reg {
>>> phys_addr_t pa_base;
>>> u16 offset;
>>> u16 size;
>>> + int (*reg_write)(struct cmdq_pkt *pkt, u8 subsys, u32
>>> pa_base,
>>> + u16 offset, u32 value);
>>
>> (*pkt_write)
>>
>>> + int (*reg_write_mask)(struct cmdq_pkt *pkt, u8 subsys, u32
>>> pa_base,
>>> + u16 offset, u32 value, u32 mask);
>>
>> (*pkt_write_mask)
>>
>> those names make a lot more sense.
>>
> Hi Angelo,
>
> The reason why I use reg_write/reg_write_mask is to imply these APIs
> only provide writing HW register address function, not writing DRAM
> address.
> So we don't need to care about mminfra_offset in these APIs.
Sure I understand that we don't need to care about mminfra_offset - but those
function pointers are effectively replacing the "(xyz)pkt_write" functions.
Changing the name to reg_write will create a lot of confusion.
>
> I can add comment for this.
>
> What do you think?
> Or should I change its name to pkt_write/pkt_write_amsk?
Please change the name to pkt_write/pkt_write_mask and if you think it's useful
also add a comment saying that those functions are already accounting for the
mminfra_offset internally.
Cheers,
Angelo
>
> Regards,
> Jason-JH Lin
>
>> After applying the requested changes,
>>
>> Reviewed-by: AngeloGioacchino Del Regno
>> <angelogioacchino.delregno@collabora.com>
>>
>>> };
>
© 2016 - 2025 Red Hat, Inc.