The PCIe Gen4x2 PHY found in the SM8[456]50 SoCs have a second clock,
add the code to register it for PHYs configs that sets a aux_clock_rate.
In order to get the right clock, add qmp_pcie_clk_hw_get() which uses
the newly introduced QMP_PCIE_PIPE_CLK & QMP_PCIE_PHY_AUX_CLK clock
IDs and also supports the legacy bindings by returning the PIPE clock.
Signed-off-by: Neil Armstrong <neil.armstrong@linaro.org>
---
drivers/phy/qualcomm/phy-qcom-qmp-pcie.c | 70 ++++++++++++++++++++++++++++++++
1 file changed, 70 insertions(+)
diff --git a/drivers/phy/qualcomm/phy-qcom-qmp-pcie.c b/drivers/phy/qualcomm/phy-qcom-qmp-pcie.c
index 079b3e306489..2d05226ae200 100644
--- a/drivers/phy/qualcomm/phy-qcom-qmp-pcie.c
+++ b/drivers/phy/qualcomm/phy-qcom-qmp-pcie.c
@@ -22,6 +22,8 @@
#include <linux/reset.h>
#include <linux/slab.h>
+#include <dt-bindings/phy/phy-qcom-qmp.h>
+
#include "phy-qcom-qmp-common.h"
#include "phy-qcom-qmp.h"
@@ -2389,6 +2391,9 @@ struct qmp_phy_cfg {
/* QMP PHY pipe clock interface rate */
unsigned long pipe_clock_rate;
+
+ /* QMP PHY AUX clock interface rate */
+ unsigned long aux_clock_rate;
};
struct qmp_pcie {
@@ -2420,6 +2425,7 @@ struct qmp_pcie {
int mode;
struct clk_fixed_rate pipe_clk_fixed;
+ struct clk_fixed_rate aux_clk_fixed;
};
static inline void qphy_setbits(void __iomem *base, u32 offset, u32 val)
@@ -3681,6 +3687,62 @@ static int phy_pipe_clk_register(struct qmp_pcie *qmp, struct device_node *np)
return devm_clk_hw_register(qmp->dev, &fixed->hw);
}
+/*
+ * Register a fixed rate PHY aux clock.
+ *
+ * The <s>_phy_aux_clksrc generated by PHY goes to the GCC that gate
+ * controls it. The <s>_phy_aux_clk coming out of the GCC is requested
+ * by the PHY driver for its operations.
+ * We register the <s>_phy_aux_clksrc here. The gcc driver takes care
+ * of assigning this <s>_phy_aux_clksrc as parent to <s>_phy_aux_clk.
+ * Below picture shows this relationship.
+ *
+ * +---------------+
+ * | PHY block |<<---------------------------------------------+
+ * | | |
+ * | +-------+ | +-----+ |
+ * I/P---^-->| PLL |---^--->phy_aux_clksrc--->| GCC |--->phy_aux_clk---+
+ * clk | +-------+ | +-----+
+ * +---------------+
+ */
+static int phy_aux_clk_register(struct qmp_pcie *qmp, struct device_node *np)
+{
+ struct clk_fixed_rate *fixed = &qmp->aux_clk_fixed;
+ struct clk_init_data init = { };
+ int ret;
+
+ ret = of_property_read_string_index(np, "clock-output-names", 1, &init.name);
+ if (ret) {
+ dev_err(qmp->dev, "%pOFn: No clock-output-names index 1\n", np);
+ return ret;
+ }
+
+ init.ops = &clk_fixed_rate_ops;
+
+ fixed->fixed_rate = qmp->cfg->aux_clock_rate;
+ fixed->hw.init = &init;
+
+ return devm_clk_hw_register(qmp->dev, &fixed->hw);
+}
+
+static struct clk_hw *qmp_pcie_clk_hw_get(struct of_phandle_args *clkspec, void *data)
+{
+ struct qmp_pcie *qmp = data;
+
+ /* Support legacy bindings */
+ if (!clkspec->args_count)
+ return &qmp->pipe_clk_fixed.hw;
+
+ switch (clkspec->args[0]) {
+ case QMP_PCIE_PIPE_CLK:
+ return &qmp->pipe_clk_fixed.hw;
+ case QMP_PCIE_PHY_AUX_CLK:
+ return &qmp->aux_clk_fixed.hw;
+ }
+
+ return ERR_PTR(-EINVAL);
+}
+
static int qmp_pcie_register_clocks(struct qmp_pcie *qmp, struct device_node *np)
{
int ret;
@@ -3689,6 +3751,14 @@ static int qmp_pcie_register_clocks(struct qmp_pcie *qmp, struct device_node *np
if (ret)
return ret;
+ if (qmp->cfg->aux_clock_rate) {
+ ret = phy_aux_clk_register(qmp, np);
+ if (ret)
+ return ret;
+
+ return devm_of_clk_add_hw_provider(qmp->dev, qmp_pcie_clk_hw_get, qmp);
+ }
+
return devm_of_clk_add_hw_provider(qmp->dev, of_clk_hw_simple_get,
&qmp->pipe_clk_fixed.hw);
}
--
2.34.1
On Tue, 19 Mar 2024 at 12:45, Neil Armstrong <neil.armstrong@linaro.org> wrote:
>
> The PCIe Gen4x2 PHY found in the SM8[456]50 SoCs have a second clock,
> add the code to register it for PHYs configs that sets a aux_clock_rate.
>
> In order to get the right clock, add qmp_pcie_clk_hw_get() which uses
> the newly introduced QMP_PCIE_PIPE_CLK & QMP_PCIE_PHY_AUX_CLK clock
> IDs and also supports the legacy bindings by returning the PIPE clock.
>
> Signed-off-by: Neil Armstrong <neil.armstrong@linaro.org>
> ---
> drivers/phy/qualcomm/phy-qcom-qmp-pcie.c | 70 ++++++++++++++++++++++++++++++++
> 1 file changed, 70 insertions(+)
>
> diff --git a/drivers/phy/qualcomm/phy-qcom-qmp-pcie.c b/drivers/phy/qualcomm/phy-qcom-qmp-pcie.c
> index 079b3e306489..2d05226ae200 100644
> --- a/drivers/phy/qualcomm/phy-qcom-qmp-pcie.c
> +++ b/drivers/phy/qualcomm/phy-qcom-qmp-pcie.c
> @@ -22,6 +22,8 @@
> #include <linux/reset.h>
> #include <linux/slab.h>
>
> +#include <dt-bindings/phy/phy-qcom-qmp.h>
> +
> #include "phy-qcom-qmp-common.h"
>
> #include "phy-qcom-qmp.h"
> @@ -2389,6 +2391,9 @@ struct qmp_phy_cfg {
>
> /* QMP PHY pipe clock interface rate */
> unsigned long pipe_clock_rate;
> +
> + /* QMP PHY AUX clock interface rate */
> + unsigned long aux_clock_rate;
> };
>
> struct qmp_pcie {
> @@ -2420,6 +2425,7 @@ struct qmp_pcie {
> int mode;
>
> struct clk_fixed_rate pipe_clk_fixed;
> + struct clk_fixed_rate aux_clk_fixed;
> };
>
> static inline void qphy_setbits(void __iomem *base, u32 offset, u32 val)
> @@ -3681,6 +3687,62 @@ static int phy_pipe_clk_register(struct qmp_pcie *qmp, struct device_node *np)
> return devm_clk_hw_register(qmp->dev, &fixed->hw);
> }
>
> +/*
> + * Register a fixed rate PHY aux clock.
> + *
> + * The <s>_phy_aux_clksrc generated by PHY goes to the GCC that gate
> + * controls it. The <s>_phy_aux_clk coming out of the GCC is requested
> + * by the PHY driver for its operations.
> + * We register the <s>_phy_aux_clksrc here. The gcc driver takes care
> + * of assigning this <s>_phy_aux_clksrc as parent to <s>_phy_aux_clk.
> + * Below picture shows this relationship.
> + *
> + * +---------------+
> + * | PHY block |<<---------------------------------------------+
> + * | | |
> + * | +-------+ | +-----+ |
> + * I/P---^-->| PLL |---^--->phy_aux_clksrc--->| GCC |--->phy_aux_clk---+
> + * clk | +-------+ | +-----+
> + * +---------------+
> + */
> +static int phy_aux_clk_register(struct qmp_pcie *qmp, struct device_node *np)
> +{
> + struct clk_fixed_rate *fixed = &qmp->aux_clk_fixed;
> + struct clk_init_data init = { };
> + int ret;
> +
> + ret = of_property_read_string_index(np, "clock-output-names", 1, &init.name);
> + if (ret) {
> + dev_err(qmp->dev, "%pOFn: No clock-output-names index 1\n", np);
> + return ret;
> + }
> +
> + init.ops = &clk_fixed_rate_ops;
> +
> + fixed->fixed_rate = qmp->cfg->aux_clock_rate;
> + fixed->hw.init = &init;
> +
> + return devm_clk_hw_register(qmp->dev, &fixed->hw);
> +}
> +
> +static struct clk_hw *qmp_pcie_clk_hw_get(struct of_phandle_args *clkspec, void *data)
> +{
> + struct qmp_pcie *qmp = data;
> +
> + /* Support legacy bindings */
> + if (!clkspec->args_count)
> + return &qmp->pipe_clk_fixed.hw;
> +
> + switch (clkspec->args[0]) {
> + case QMP_PCIE_PIPE_CLK:
> + return &qmp->pipe_clk_fixed.hw;
> + case QMP_PCIE_PHY_AUX_CLK:
> + return &qmp->aux_clk_fixed.hw;
> + }
> +
> + return ERR_PTR(-EINVAL);
> +}
Can we use of_clk_hw_onecell_get() instead? I think it even should be
possible to use onecell for both cases, it will look at the first arg,
which will be 0 in case of #clock-cells equal to 0.
> +
> static int qmp_pcie_register_clocks(struct qmp_pcie *qmp, struct device_node *np)
> {
> int ret;
> @@ -3689,6 +3751,14 @@ static int qmp_pcie_register_clocks(struct qmp_pcie *qmp, struct device_node *np
> if (ret)
> return ret;
>
> + if (qmp->cfg->aux_clock_rate) {
> + ret = phy_aux_clk_register(qmp, np);
> + if (ret)
> + return ret;
> +
> + return devm_of_clk_add_hw_provider(qmp->dev, qmp_pcie_clk_hw_get, qmp);
> + }
> +
> return devm_of_clk_add_hw_provider(qmp->dev, of_clk_hw_simple_get,
> &qmp->pipe_clk_fixed.hw);
> }
>
> --
> 2.34.1
>
>
--
With best wishes
Dmitry
On 19/03/2024 11:55, Dmitry Baryshkov wrote:
> On Tue, 19 Mar 2024 at 12:45, Neil Armstrong <neil.armstrong@linaro.org> wrote:
>>
>> The PCIe Gen4x2 PHY found in the SM8[456]50 SoCs have a second clock,
>> add the code to register it for PHYs configs that sets a aux_clock_rate.
>>
>> In order to get the right clock, add qmp_pcie_clk_hw_get() which uses
>> the newly introduced QMP_PCIE_PIPE_CLK & QMP_PCIE_PHY_AUX_CLK clock
>> IDs and also supports the legacy bindings by returning the PIPE clock.
>>
>> Signed-off-by: Neil Armstrong <neil.armstrong@linaro.org>
>> ---
>> drivers/phy/qualcomm/phy-qcom-qmp-pcie.c | 70 ++++++++++++++++++++++++++++++++
>> 1 file changed, 70 insertions(+)
>>
>> diff --git a/drivers/phy/qualcomm/phy-qcom-qmp-pcie.c b/drivers/phy/qualcomm/phy-qcom-qmp-pcie.c
>> index 079b3e306489..2d05226ae200 100644
>> --- a/drivers/phy/qualcomm/phy-qcom-qmp-pcie.c
>> +++ b/drivers/phy/qualcomm/phy-qcom-qmp-pcie.c
>> @@ -22,6 +22,8 @@
>> #include <linux/reset.h>
>> #include <linux/slab.h>
>>
>> +#include <dt-bindings/phy/phy-qcom-qmp.h>
>> +
>> #include "phy-qcom-qmp-common.h"
>>
>> #include "phy-qcom-qmp.h"
>> @@ -2389,6 +2391,9 @@ struct qmp_phy_cfg {
>>
>> /* QMP PHY pipe clock interface rate */
>> unsigned long pipe_clock_rate;
>> +
>> + /* QMP PHY AUX clock interface rate */
>> + unsigned long aux_clock_rate;
>> };
>>
>> struct qmp_pcie {
>> @@ -2420,6 +2425,7 @@ struct qmp_pcie {
>> int mode;
>>
>> struct clk_fixed_rate pipe_clk_fixed;
>> + struct clk_fixed_rate aux_clk_fixed;
>> };
>>
>> static inline void qphy_setbits(void __iomem *base, u32 offset, u32 val)
>> @@ -3681,6 +3687,62 @@ static int phy_pipe_clk_register(struct qmp_pcie *qmp, struct device_node *np)
>> return devm_clk_hw_register(qmp->dev, &fixed->hw);
>> }
>>
>> +/*
>> + * Register a fixed rate PHY aux clock.
>> + *
>> + * The <s>_phy_aux_clksrc generated by PHY goes to the GCC that gate
>> + * controls it. The <s>_phy_aux_clk coming out of the GCC is requested
>> + * by the PHY driver for its operations.
>> + * We register the <s>_phy_aux_clksrc here. The gcc driver takes care
>> + * of assigning this <s>_phy_aux_clksrc as parent to <s>_phy_aux_clk.
>> + * Below picture shows this relationship.
>> + *
>> + * +---------------+
>> + * | PHY block |<<---------------------------------------------+
>> + * | | |
>> + * | +-------+ | +-----+ |
>> + * I/P---^-->| PLL |---^--->phy_aux_clksrc--->| GCC |--->phy_aux_clk---+
>> + * clk | +-------+ | +-----+
>> + * +---------------+
>> + */
>> +static int phy_aux_clk_register(struct qmp_pcie *qmp, struct device_node *np)
>> +{
>> + struct clk_fixed_rate *fixed = &qmp->aux_clk_fixed;
>> + struct clk_init_data init = { };
>> + int ret;
>> +
>> + ret = of_property_read_string_index(np, "clock-output-names", 1, &init.name);
>> + if (ret) {
>> + dev_err(qmp->dev, "%pOFn: No clock-output-names index 1\n", np);
>> + return ret;
>> + }
>> +
>> + init.ops = &clk_fixed_rate_ops;
>> +
>> + fixed->fixed_rate = qmp->cfg->aux_clock_rate;
>> + fixed->hw.init = &init;
>> +
>> + return devm_clk_hw_register(qmp->dev, &fixed->hw);
>> +}
>> +
>> +static struct clk_hw *qmp_pcie_clk_hw_get(struct of_phandle_args *clkspec, void *data)
>> +{
>> + struct qmp_pcie *qmp = data;
>> +
>> + /* Support legacy bindings */
>> + if (!clkspec->args_count)
>> + return &qmp->pipe_clk_fixed.hw;
>> +
>> + switch (clkspec->args[0]) {
>> + case QMP_PCIE_PIPE_CLK:
>> + return &qmp->pipe_clk_fixed.hw;
>> + case QMP_PCIE_PHY_AUX_CLK:
>> + return &qmp->aux_clk_fixed.hw;
>> + }
>> +
>> + return ERR_PTR(-EINVAL);
>> +}
>
> Can we use of_clk_hw_onecell_get() instead? I think it even should be
> possible to use onecell for both cases, it will look at the first arg,
> which will be 0 in case of #clock-cells equal to 0.
Let me investigate if it's possible
>
>> +
>> static int qmp_pcie_register_clocks(struct qmp_pcie *qmp, struct device_node *np)
>> {
>> int ret;
>> @@ -3689,6 +3751,14 @@ static int qmp_pcie_register_clocks(struct qmp_pcie *qmp, struct device_node *np
>> if (ret)
>> return ret;
>>
>> + if (qmp->cfg->aux_clock_rate) {
>> + ret = phy_aux_clk_register(qmp, np);
>> + if (ret)
>> + return ret;
>> +
>> + return devm_of_clk_add_hw_provider(qmp->dev, qmp_pcie_clk_hw_get, qmp);
>> + }
>> +
>> return devm_of_clk_add_hw_provider(qmp->dev, of_clk_hw_simple_get,
>> &qmp->pipe_clk_fixed.hw);
>> }
>>
>> --
>> 2.34.1
>>
>>
>
>
On 19/03/2024 11:59, Neil Armstrong wrote:
> On 19/03/2024 11:55, Dmitry Baryshkov wrote:
>> On Tue, 19 Mar 2024 at 12:45, Neil Armstrong <neil.armstrong@linaro.org> wrote:
>>>
>>> The PCIe Gen4x2 PHY found in the SM8[456]50 SoCs have a second clock,
>>> add the code to register it for PHYs configs that sets a aux_clock_rate.
>>>
>>> In order to get the right clock, add qmp_pcie_clk_hw_get() which uses
>>> the newly introduced QMP_PCIE_PIPE_CLK & QMP_PCIE_PHY_AUX_CLK clock
>>> IDs and also supports the legacy bindings by returning the PIPE clock.
>>>
>>> Signed-off-by: Neil Armstrong <neil.armstrong@linaro.org>
>>> ---
>>> drivers/phy/qualcomm/phy-qcom-qmp-pcie.c | 70 ++++++++++++++++++++++++++++++++
>>> 1 file changed, 70 insertions(+)
>>>
>>> diff --git a/drivers/phy/qualcomm/phy-qcom-qmp-pcie.c b/drivers/phy/qualcomm/phy-qcom-qmp-pcie.c
>>> index 079b3e306489..2d05226ae200 100644
>>> --- a/drivers/phy/qualcomm/phy-qcom-qmp-pcie.c
>>> +++ b/drivers/phy/qualcomm/phy-qcom-qmp-pcie.c
>>> @@ -22,6 +22,8 @@
>>> #include <linux/reset.h>
>>> #include <linux/slab.h>
>>>
>>> +#include <dt-bindings/phy/phy-qcom-qmp.h>
>>> +
>>> #include "phy-qcom-qmp-common.h"
>>>
>>> #include "phy-qcom-qmp.h"
>>> @@ -2389,6 +2391,9 @@ struct qmp_phy_cfg {
>>>
>>> /* QMP PHY pipe clock interface rate */
>>> unsigned long pipe_clock_rate;
>>> +
>>> + /* QMP PHY AUX clock interface rate */
>>> + unsigned long aux_clock_rate;
>>> };
>>>
>>> struct qmp_pcie {
>>> @@ -2420,6 +2425,7 @@ struct qmp_pcie {
>>> int mode;
>>>
>>> struct clk_fixed_rate pipe_clk_fixed;
>>> + struct clk_fixed_rate aux_clk_fixed;
>>> };
>>>
>>> static inline void qphy_setbits(void __iomem *base, u32 offset, u32 val)
>>> @@ -3681,6 +3687,62 @@ static int phy_pipe_clk_register(struct qmp_pcie *qmp, struct device_node *np)
>>> return devm_clk_hw_register(qmp->dev, &fixed->hw);
>>> }
>>>
>>> +/*
>>> + * Register a fixed rate PHY aux clock.
>>> + *
>>> + * The <s>_phy_aux_clksrc generated by PHY goes to the GCC that gate
>>> + * controls it. The <s>_phy_aux_clk coming out of the GCC is requested
>>> + * by the PHY driver for its operations.
>>> + * We register the <s>_phy_aux_clksrc here. The gcc driver takes care
>>> + * of assigning this <s>_phy_aux_clksrc as parent to <s>_phy_aux_clk.
>>> + * Below picture shows this relationship.
>>> + *
>>> + * +---------------+
>>> + * | PHY block |<<---------------------------------------------+
>>> + * | | |
>>> + * | +-------+ | +-----+ |
>>> + * I/P---^-->| PLL |---^--->phy_aux_clksrc--->| GCC |--->phy_aux_clk---+
>>> + * clk | +-------+ | +-----+
>>> + * +---------------+
>>> + */
>>> +static int phy_aux_clk_register(struct qmp_pcie *qmp, struct device_node *np)
>>> +{
>>> + struct clk_fixed_rate *fixed = &qmp->aux_clk_fixed;
>>> + struct clk_init_data init = { };
>>> + int ret;
>>> +
>>> + ret = of_property_read_string_index(np, "clock-output-names", 1, &init.name);
>>> + if (ret) {
>>> + dev_err(qmp->dev, "%pOFn: No clock-output-names index 1\n", np);
>>> + return ret;
>>> + }
>>> +
>>> + init.ops = &clk_fixed_rate_ops;
>>> +
>>> + fixed->fixed_rate = qmp->cfg->aux_clock_rate;
>>> + fixed->hw.init = &init;
>>> +
>>> + return devm_clk_hw_register(qmp->dev, &fixed->hw);
>>> +}
>>> +
>>> +static struct clk_hw *qmp_pcie_clk_hw_get(struct of_phandle_args *clkspec, void *data)
>>> +{
>>> + struct qmp_pcie *qmp = data;
>>> +
>>> + /* Support legacy bindings */
>>> + if (!clkspec->args_count)
>>> + return &qmp->pipe_clk_fixed.hw;
>>> +
>>> + switch (clkspec->args[0]) {
>>> + case QMP_PCIE_PIPE_CLK:
>>> + return &qmp->pipe_clk_fixed.hw;
>>> + case QMP_PCIE_PHY_AUX_CLK:
>>> + return &qmp->aux_clk_fixed.hw;
>>> + }
>>> +
>>> + return ERR_PTR(-EINVAL);
>>> +}
>>
>> Can we use of_clk_hw_onecell_get() instead? I think it even should be
>> possible to use onecell for both cases, it will look at the first arg,
>> which will be 0 in case of #clock-cells equal to 0.
>
> Let me investigate if it's possible
Ok, it would work but it would require building a clk_hw_onecell_data a runtime,
while we could simply provide this qmp_pcie_clk_hw_get() and avoid runtime 2 allocations.
I'm not sure it's worth it.
Neil
>
>>
>>> +
>>> static int qmp_pcie_register_clocks(struct qmp_pcie *qmp, struct device_node *np)
>>> {
>>> int ret;
>>> @@ -3689,6 +3751,14 @@ static int qmp_pcie_register_clocks(struct qmp_pcie *qmp, struct device_node *np
>>> if (ret)
>>> return ret;
>>>
>>> + if (qmp->cfg->aux_clock_rate) {
>>> + ret = phy_aux_clk_register(qmp, np);
>>> + if (ret)
>>> + return ret;
>>> +
>>> + return devm_of_clk_add_hw_provider(qmp->dev, qmp_pcie_clk_hw_get, qmp);
>>> + }
>>> +
>>> return devm_of_clk_add_hw_provider(qmp->dev, of_clk_hw_simple_get,
>>> &qmp->pipe_clk_fixed.hw);
>>> }
>>>
>>> --
>>> 2.34.1
>>>
>>>
>>
>>
>
On Tue, 19 Mar 2024 at 16:35, Neil Armstrong <neil.armstrong@linaro.org> wrote:
>
> On 19/03/2024 11:59, Neil Armstrong wrote:
> > On 19/03/2024 11:55, Dmitry Baryshkov wrote:
> >> On Tue, 19 Mar 2024 at 12:45, Neil Armstrong <neil.armstrong@linaro.org> wrote:
> >>>
> >>> The PCIe Gen4x2 PHY found in the SM8[456]50 SoCs have a second clock,
> >>> add the code to register it for PHYs configs that sets a aux_clock_rate.
> >>>
> >>> In order to get the right clock, add qmp_pcie_clk_hw_get() which uses
> >>> the newly introduced QMP_PCIE_PIPE_CLK & QMP_PCIE_PHY_AUX_CLK clock
> >>> IDs and also supports the legacy bindings by returning the PIPE clock.
> >>>
> >>> Signed-off-by: Neil Armstrong <neil.armstrong@linaro.org>
> >>> ---
> >>> drivers/phy/qualcomm/phy-qcom-qmp-pcie.c | 70 ++++++++++++++++++++++++++++++++
> >>> 1 file changed, 70 insertions(+)
> >>>
> >>> diff --git a/drivers/phy/qualcomm/phy-qcom-qmp-pcie.c b/drivers/phy/qualcomm/phy-qcom-qmp-pcie.c
> >>> index 079b3e306489..2d05226ae200 100644
> >>> --- a/drivers/phy/qualcomm/phy-qcom-qmp-pcie.c
> >>> +++ b/drivers/phy/qualcomm/phy-qcom-qmp-pcie.c
> >>> @@ -22,6 +22,8 @@
> >>> #include <linux/reset.h>
> >>> #include <linux/slab.h>
> >>>
> >>> +#include <dt-bindings/phy/phy-qcom-qmp.h>
> >>> +
> >>> #include "phy-qcom-qmp-common.h"
> >>>
> >>> #include "phy-qcom-qmp.h"
> >>> @@ -2389,6 +2391,9 @@ struct qmp_phy_cfg {
> >>>
> >>> /* QMP PHY pipe clock interface rate */
> >>> unsigned long pipe_clock_rate;
> >>> +
> >>> + /* QMP PHY AUX clock interface rate */
> >>> + unsigned long aux_clock_rate;
> >>> };
> >>>
> >>> struct qmp_pcie {
> >>> @@ -2420,6 +2425,7 @@ struct qmp_pcie {
> >>> int mode;
> >>>
> >>> struct clk_fixed_rate pipe_clk_fixed;
> >>> + struct clk_fixed_rate aux_clk_fixed;
> >>> };
> >>>
> >>> static inline void qphy_setbits(void __iomem *base, u32 offset, u32 val)
> >>> @@ -3681,6 +3687,62 @@ static int phy_pipe_clk_register(struct qmp_pcie *qmp, struct device_node *np)
> >>> return devm_clk_hw_register(qmp->dev, &fixed->hw);
> >>> }
> >>>
> >>> +/*
> >>> + * Register a fixed rate PHY aux clock.
> >>> + *
> >>> + * The <s>_phy_aux_clksrc generated by PHY goes to the GCC that gate
> >>> + * controls it. The <s>_phy_aux_clk coming out of the GCC is requested
> >>> + * by the PHY driver for its operations.
> >>> + * We register the <s>_phy_aux_clksrc here. The gcc driver takes care
> >>> + * of assigning this <s>_phy_aux_clksrc as parent to <s>_phy_aux_clk.
> >>> + * Below picture shows this relationship.
> >>> + *
> >>> + * +---------------+
> >>> + * | PHY block |<<---------------------------------------------+
> >>> + * | | |
> >>> + * | +-------+ | +-----+ |
> >>> + * I/P---^-->| PLL |---^--->phy_aux_clksrc--->| GCC |--->phy_aux_clk---+
> >>> + * clk | +-------+ | +-----+
> >>> + * +---------------+
> >>> + */
> >>> +static int phy_aux_clk_register(struct qmp_pcie *qmp, struct device_node *np)
> >>> +{
> >>> + struct clk_fixed_rate *fixed = &qmp->aux_clk_fixed;
> >>> + struct clk_init_data init = { };
> >>> + int ret;
> >>> +
> >>> + ret = of_property_read_string_index(np, "clock-output-names", 1, &init.name);
> >>> + if (ret) {
> >>> + dev_err(qmp->dev, "%pOFn: No clock-output-names index 1\n", np);
> >>> + return ret;
> >>> + }
> >>> +
> >>> + init.ops = &clk_fixed_rate_ops;
> >>> +
> >>> + fixed->fixed_rate = qmp->cfg->aux_clock_rate;
> >>> + fixed->hw.init = &init;
> >>> +
> >>> + return devm_clk_hw_register(qmp->dev, &fixed->hw);
> >>> +}
> >>> +
> >>> +static struct clk_hw *qmp_pcie_clk_hw_get(struct of_phandle_args *clkspec, void *data)
> >>> +{
> >>> + struct qmp_pcie *qmp = data;
> >>> +
> >>> + /* Support legacy bindings */
> >>> + if (!clkspec->args_count)
> >>> + return &qmp->pipe_clk_fixed.hw;
> >>> +
> >>> + switch (clkspec->args[0]) {
> >>> + case QMP_PCIE_PIPE_CLK:
> >>> + return &qmp->pipe_clk_fixed.hw;
> >>> + case QMP_PCIE_PHY_AUX_CLK:
> >>> + return &qmp->aux_clk_fixed.hw;
> >>> + }
> >>> +
> >>> + return ERR_PTR(-EINVAL);
> >>> +}
> >>
> >> Can we use of_clk_hw_onecell_get() instead? I think it even should be
> >> possible to use onecell for both cases, it will look at the first arg,
> >> which will be 0 in case of #clock-cells equal to 0.
> >
> > Let me investigate if it's possible
>
> Ok, it would work but it would require building a clk_hw_onecell_data a runtime,
> while we could simply provide this qmp_pcie_clk_hw_get() and avoid runtime 2 allocations.
>
> I'm not sure it's worth it.
Single allocation (or even 0 allocations if you embed it into struct
qmp_pcie) for the sake of using standard helpers.
--
With best wishes
Dmitry
On 19/03/2024 15:46, Dmitry Baryshkov wrote:
> On Tue, 19 Mar 2024 at 16:35, Neil Armstrong <neil.armstrong@linaro.org> wrote:
>>
>> On 19/03/2024 11:59, Neil Armstrong wrote:
>>> On 19/03/2024 11:55, Dmitry Baryshkov wrote:
>>>> On Tue, 19 Mar 2024 at 12:45, Neil Armstrong <neil.armstrong@linaro.org> wrote:
>>>>>
>>>>> The PCIe Gen4x2 PHY found in the SM8[456]50 SoCs have a second clock,
>>>>> add the code to register it for PHYs configs that sets a aux_clock_rate.
>>>>>
>>>>> In order to get the right clock, add qmp_pcie_clk_hw_get() which uses
>>>>> the newly introduced QMP_PCIE_PIPE_CLK & QMP_PCIE_PHY_AUX_CLK clock
>>>>> IDs and also supports the legacy bindings by returning the PIPE clock.
>>>>>
>>>>> Signed-off-by: Neil Armstrong <neil.armstrong@linaro.org>
>>>>> ---
>>>>> drivers/phy/qualcomm/phy-qcom-qmp-pcie.c | 70 ++++++++++++++++++++++++++++++++
>>>>> 1 file changed, 70 insertions(+)
>>>>>
>>>>> diff --git a/drivers/phy/qualcomm/phy-qcom-qmp-pcie.c b/drivers/phy/qualcomm/phy-qcom-qmp-pcie.c
>>>>> index 079b3e306489..2d05226ae200 100644
>>>>> --- a/drivers/phy/qualcomm/phy-qcom-qmp-pcie.c
>>>>> +++ b/drivers/phy/qualcomm/phy-qcom-qmp-pcie.c
>>>>> @@ -22,6 +22,8 @@
>>>>> #include <linux/reset.h>
>>>>> #include <linux/slab.h>
>>>>>
>>>>> +#include <dt-bindings/phy/phy-qcom-qmp.h>
>>>>> +
>>>>> #include "phy-qcom-qmp-common.h"
>>>>>
>>>>> #include "phy-qcom-qmp.h"
>>>>> @@ -2389,6 +2391,9 @@ struct qmp_phy_cfg {
>>>>>
>>>>> /* QMP PHY pipe clock interface rate */
>>>>> unsigned long pipe_clock_rate;
>>>>> +
>>>>> + /* QMP PHY AUX clock interface rate */
>>>>> + unsigned long aux_clock_rate;
>>>>> };
>>>>>
>>>>> struct qmp_pcie {
>>>>> @@ -2420,6 +2425,7 @@ struct qmp_pcie {
>>>>> int mode;
>>>>>
>>>>> struct clk_fixed_rate pipe_clk_fixed;
>>>>> + struct clk_fixed_rate aux_clk_fixed;
>>>>> };
>>>>>
>>>>> static inline void qphy_setbits(void __iomem *base, u32 offset, u32 val)
>>>>> @@ -3681,6 +3687,62 @@ static int phy_pipe_clk_register(struct qmp_pcie *qmp, struct device_node *np)
>>>>> return devm_clk_hw_register(qmp->dev, &fixed->hw);
>>>>> }
>>>>>
>>>>> +/*
>>>>> + * Register a fixed rate PHY aux clock.
>>>>> + *
>>>>> + * The <s>_phy_aux_clksrc generated by PHY goes to the GCC that gate
>>>>> + * controls it. The <s>_phy_aux_clk coming out of the GCC is requested
>>>>> + * by the PHY driver for its operations.
>>>>> + * We register the <s>_phy_aux_clksrc here. The gcc driver takes care
>>>>> + * of assigning this <s>_phy_aux_clksrc as parent to <s>_phy_aux_clk.
>>>>> + * Below picture shows this relationship.
>>>>> + *
>>>>> + * +---------------+
>>>>> + * | PHY block |<<---------------------------------------------+
>>>>> + * | | |
>>>>> + * | +-------+ | +-----+ |
>>>>> + * I/P---^-->| PLL |---^--->phy_aux_clksrc--->| GCC |--->phy_aux_clk---+
>>>>> + * clk | +-------+ | +-----+
>>>>> + * +---------------+
>>>>> + */
>>>>> +static int phy_aux_clk_register(struct qmp_pcie *qmp, struct device_node *np)
>>>>> +{
>>>>> + struct clk_fixed_rate *fixed = &qmp->aux_clk_fixed;
>>>>> + struct clk_init_data init = { };
>>>>> + int ret;
>>>>> +
>>>>> + ret = of_property_read_string_index(np, "clock-output-names", 1, &init.name);
>>>>> + if (ret) {
>>>>> + dev_err(qmp->dev, "%pOFn: No clock-output-names index 1\n", np);
>>>>> + return ret;
>>>>> + }
>>>>> +
>>>>> + init.ops = &clk_fixed_rate_ops;
>>>>> +
>>>>> + fixed->fixed_rate = qmp->cfg->aux_clock_rate;
>>>>> + fixed->hw.init = &init;
>>>>> +
>>>>> + return devm_clk_hw_register(qmp->dev, &fixed->hw);
>>>>> +}
>>>>> +
>>>>> +static struct clk_hw *qmp_pcie_clk_hw_get(struct of_phandle_args *clkspec, void *data)
>>>>> +{
>>>>> + struct qmp_pcie *qmp = data;
>>>>> +
>>>>> + /* Support legacy bindings */
>>>>> + if (!clkspec->args_count)
>>>>> + return &qmp->pipe_clk_fixed.hw;
>>>>> +
>>>>> + switch (clkspec->args[0]) {
>>>>> + case QMP_PCIE_PIPE_CLK:
>>>>> + return &qmp->pipe_clk_fixed.hw;
>>>>> + case QMP_PCIE_PHY_AUX_CLK:
>>>>> + return &qmp->aux_clk_fixed.hw;
>>>>> + }
>>>>> +
>>>>> + return ERR_PTR(-EINVAL);
>>>>> +}
>>>>
>>>> Can we use of_clk_hw_onecell_get() instead? I think it even should be
>>>> possible to use onecell for both cases, it will look at the first arg,
>>>> which will be 0 in case of #clock-cells equal to 0.
>>>
>>> Let me investigate if it's possible
>>
>> Ok, it would work but it would require building a clk_hw_onecell_data a runtime,
>> while we could simply provide this qmp_pcie_clk_hw_get() and avoid runtime 2 allocations.
>>
>> I'm not sure it's worth it.
>
> Single allocation (or even 0 allocations if you embed it into struct
> qmp_pcie) for the sake of using standard helpers.
And I just recall I tried the same for Amlogic clocks, but the clk_hw_onecell_data hws
field is a flexible array member you can't set at runtime, if you try you'll get:
drivers/phy/qualcomm/phy-qcom-qmp-pcie.c:3753:38: error: invalid use of flexible array member
3753 | qmp->clk_hw_data.hws = qmp->clk_hws;
Neil
>
>
>
On Tue, 19 Mar 2024 at 17:15, <neil.armstrong@linaro.org> wrote:
>
> On 19/03/2024 15:46, Dmitry Baryshkov wrote:
> > On Tue, 19 Mar 2024 at 16:35, Neil Armstrong <neil.armstrong@linaro.org> wrote:
> >>
> >> On 19/03/2024 11:59, Neil Armstrong wrote:
> >>> On 19/03/2024 11:55, Dmitry Baryshkov wrote:
> >>>> On Tue, 19 Mar 2024 at 12:45, Neil Armstrong <neil.armstrong@linaro.org> wrote:
> >>>>>
> >>>>> The PCIe Gen4x2 PHY found in the SM8[456]50 SoCs have a second clock,
> >>>>> add the code to register it for PHYs configs that sets a aux_clock_rate.
> >>>>>
> >>>>> In order to get the right clock, add qmp_pcie_clk_hw_get() which uses
> >>>>> the newly introduced QMP_PCIE_PIPE_CLK & QMP_PCIE_PHY_AUX_CLK clock
> >>>>> IDs and also supports the legacy bindings by returning the PIPE clock.
> >>>>>
> >>>>> Signed-off-by: Neil Armstrong <neil.armstrong@linaro.org>
> >>>>> ---
> >>>>> drivers/phy/qualcomm/phy-qcom-qmp-pcie.c | 70 ++++++++++++++++++++++++++++++++
> >>>>> 1 file changed, 70 insertions(+)
> >>>>>
> >>>>> diff --git a/drivers/phy/qualcomm/phy-qcom-qmp-pcie.c b/drivers/phy/qualcomm/phy-qcom-qmp-pcie.c
> >>>>> index 079b3e306489..2d05226ae200 100644
> >>>>> --- a/drivers/phy/qualcomm/phy-qcom-qmp-pcie.c
> >>>>> +++ b/drivers/phy/qualcomm/phy-qcom-qmp-pcie.c
> >>>>> @@ -22,6 +22,8 @@
> >>>>> #include <linux/reset.h>
> >>>>> #include <linux/slab.h>
> >>>>>
> >>>>> +#include <dt-bindings/phy/phy-qcom-qmp.h>
> >>>>> +
> >>>>> #include "phy-qcom-qmp-common.h"
> >>>>>
> >>>>> #include "phy-qcom-qmp.h"
> >>>>> @@ -2389,6 +2391,9 @@ struct qmp_phy_cfg {
> >>>>>
> >>>>> /* QMP PHY pipe clock interface rate */
> >>>>> unsigned long pipe_clock_rate;
> >>>>> +
> >>>>> + /* QMP PHY AUX clock interface rate */
> >>>>> + unsigned long aux_clock_rate;
> >>>>> };
> >>>>>
> >>>>> struct qmp_pcie {
> >>>>> @@ -2420,6 +2425,7 @@ struct qmp_pcie {
> >>>>> int mode;
> >>>>>
> >>>>> struct clk_fixed_rate pipe_clk_fixed;
> >>>>> + struct clk_fixed_rate aux_clk_fixed;
> >>>>> };
> >>>>>
> >>>>> static inline void qphy_setbits(void __iomem *base, u32 offset, u32 val)
> >>>>> @@ -3681,6 +3687,62 @@ static int phy_pipe_clk_register(struct qmp_pcie *qmp, struct device_node *np)
> >>>>> return devm_clk_hw_register(qmp->dev, &fixed->hw);
> >>>>> }
> >>>>>
> >>>>> +/*
> >>>>> + * Register a fixed rate PHY aux clock.
> >>>>> + *
> >>>>> + * The <s>_phy_aux_clksrc generated by PHY goes to the GCC that gate
> >>>>> + * controls it. The <s>_phy_aux_clk coming out of the GCC is requested
> >>>>> + * by the PHY driver for its operations.
> >>>>> + * We register the <s>_phy_aux_clksrc here. The gcc driver takes care
> >>>>> + * of assigning this <s>_phy_aux_clksrc as parent to <s>_phy_aux_clk.
> >>>>> + * Below picture shows this relationship.
> >>>>> + *
> >>>>> + * +---------------+
> >>>>> + * | PHY block |<<---------------------------------------------+
> >>>>> + * | | |
> >>>>> + * | +-------+ | +-----+ |
> >>>>> + * I/P---^-->| PLL |---^--->phy_aux_clksrc--->| GCC |--->phy_aux_clk---+
> >>>>> + * clk | +-------+ | +-----+
> >>>>> + * +---------------+
> >>>>> + */
> >>>>> +static int phy_aux_clk_register(struct qmp_pcie *qmp, struct device_node *np)
> >>>>> +{
> >>>>> + struct clk_fixed_rate *fixed = &qmp->aux_clk_fixed;
> >>>>> + struct clk_init_data init = { };
> >>>>> + int ret;
> >>>>> +
> >>>>> + ret = of_property_read_string_index(np, "clock-output-names", 1, &init.name);
> >>>>> + if (ret) {
> >>>>> + dev_err(qmp->dev, "%pOFn: No clock-output-names index 1\n", np);
> >>>>> + return ret;
> >>>>> + }
> >>>>> +
> >>>>> + init.ops = &clk_fixed_rate_ops;
> >>>>> +
> >>>>> + fixed->fixed_rate = qmp->cfg->aux_clock_rate;
> >>>>> + fixed->hw.init = &init;
> >>>>> +
> >>>>> + return devm_clk_hw_register(qmp->dev, &fixed->hw);
> >>>>> +}
> >>>>> +
> >>>>> +static struct clk_hw *qmp_pcie_clk_hw_get(struct of_phandle_args *clkspec, void *data)
> >>>>> +{
> >>>>> + struct qmp_pcie *qmp = data;
> >>>>> +
> >>>>> + /* Support legacy bindings */
> >>>>> + if (!clkspec->args_count)
> >>>>> + return &qmp->pipe_clk_fixed.hw;
> >>>>> +
> >>>>> + switch (clkspec->args[0]) {
> >>>>> + case QMP_PCIE_PIPE_CLK:
> >>>>> + return &qmp->pipe_clk_fixed.hw;
> >>>>> + case QMP_PCIE_PHY_AUX_CLK:
> >>>>> + return &qmp->aux_clk_fixed.hw;
> >>>>> + }
> >>>>> +
> >>>>> + return ERR_PTR(-EINVAL);
> >>>>> +}
> >>>>
> >>>> Can we use of_clk_hw_onecell_get() instead? I think it even should be
> >>>> possible to use onecell for both cases, it will look at the first arg,
> >>>> which will be 0 in case of #clock-cells equal to 0.
> >>>
> >>> Let me investigate if it's possible
> >>
> >> Ok, it would work but it would require building a clk_hw_onecell_data a runtime,
> >> while we could simply provide this qmp_pcie_clk_hw_get() and avoid runtime 2 allocations.
> >>
> >> I'm not sure it's worth it.
> >
> > Single allocation (or even 0 allocations if you embed it into struct
> > qmp_pcie) for the sake of using standard helpers.
>
> And I just recall I tried the same for Amlogic clocks, but the clk_hw_onecell_data hws
> field is a flexible array member you can't set at runtime, if you try you'll get:
> drivers/phy/qualcomm/phy-qcom-qmp-pcie.c:3753:38: error: invalid use of flexible array member
> 3753 | qmp->clk_hw_data.hws = qmp->clk_hws;
Yes, so it's either
devm_kzalloc(dev, struct_size(data, hws, 2), GFP_KERNEL);
or
struct qmp_pcie {
...
struct {
struct clk_hw_onecell_data clk_data;
struct clk_hw clocks[2];
};
};
>
> Neil
>
> >
> >
> >
>
--
With best wishes
Dmitry
On 19/03/2024 17:05, Dmitry Baryshkov wrote:
> On Tue, 19 Mar 2024 at 17:15, <neil.armstrong@linaro.org> wrote:
>>
>> On 19/03/2024 15:46, Dmitry Baryshkov wrote:
>>> On Tue, 19 Mar 2024 at 16:35, Neil Armstrong <neil.armstrong@linaro.org> wrote:
>>>>
>>>> On 19/03/2024 11:59, Neil Armstrong wrote:
>>>>> On 19/03/2024 11:55, Dmitry Baryshkov wrote:
>>>>>> On Tue, 19 Mar 2024 at 12:45, Neil Armstrong <neil.armstrong@linaro.org> wrote:
>>>>>>>
>>>>>>> The PCIe Gen4x2 PHY found in the SM8[456]50 SoCs have a second clock,
>>>>>>> add the code to register it for PHYs configs that sets a aux_clock_rate.
>>>>>>>
>>>>>>> In order to get the right clock, add qmp_pcie_clk_hw_get() which uses
>>>>>>> the newly introduced QMP_PCIE_PIPE_CLK & QMP_PCIE_PHY_AUX_CLK clock
>>>>>>> IDs and also supports the legacy bindings by returning the PIPE clock.
>>>>>>>
>>>>>>> Signed-off-by: Neil Armstrong <neil.armstrong@linaro.org>
>>>>>>> ---
>>>>>>> drivers/phy/qualcomm/phy-qcom-qmp-pcie.c | 70 ++++++++++++++++++++++++++++++++
>>>>>>> 1 file changed, 70 insertions(+)
>>>>>>>
>>>>>>> diff --git a/drivers/phy/qualcomm/phy-qcom-qmp-pcie.c b/drivers/phy/qualcomm/phy-qcom-qmp-pcie.c
>>>>>>> index 079b3e306489..2d05226ae200 100644
>>>>>>> --- a/drivers/phy/qualcomm/phy-qcom-qmp-pcie.c
>>>>>>> +++ b/drivers/phy/qualcomm/phy-qcom-qmp-pcie.c
>>>>>>> @@ -22,6 +22,8 @@
>>>>>>> #include <linux/reset.h>
>>>>>>> #include <linux/slab.h>
>>>>>>>
>>>>>>> +#include <dt-bindings/phy/phy-qcom-qmp.h>
>>>>>>> +
>>>>>>> #include "phy-qcom-qmp-common.h"
>>>>>>>
>>>>>>> #include "phy-qcom-qmp.h"
>>>>>>> @@ -2389,6 +2391,9 @@ struct qmp_phy_cfg {
>>>>>>>
>>>>>>> /* QMP PHY pipe clock interface rate */
>>>>>>> unsigned long pipe_clock_rate;
>>>>>>> +
>>>>>>> + /* QMP PHY AUX clock interface rate */
>>>>>>> + unsigned long aux_clock_rate;
>>>>>>> };
>>>>>>>
>>>>>>> struct qmp_pcie {
>>>>>>> @@ -2420,6 +2425,7 @@ struct qmp_pcie {
>>>>>>> int mode;
>>>>>>>
>>>>>>> struct clk_fixed_rate pipe_clk_fixed;
>>>>>>> + struct clk_fixed_rate aux_clk_fixed;
>>>>>>> };
>>>>>>>
>>>>>>> static inline void qphy_setbits(void __iomem *base, u32 offset, u32 val)
>>>>>>> @@ -3681,6 +3687,62 @@ static int phy_pipe_clk_register(struct qmp_pcie *qmp, struct device_node *np)
>>>>>>> return devm_clk_hw_register(qmp->dev, &fixed->hw);
>>>>>>> }
>>>>>>>
>>>>>>> +/*
>>>>>>> + * Register a fixed rate PHY aux clock.
>>>>>>> + *
>>>>>>> + * The <s>_phy_aux_clksrc generated by PHY goes to the GCC that gate
>>>>>>> + * controls it. The <s>_phy_aux_clk coming out of the GCC is requested
>>>>>>> + * by the PHY driver for its operations.
>>>>>>> + * We register the <s>_phy_aux_clksrc here. The gcc driver takes care
>>>>>>> + * of assigning this <s>_phy_aux_clksrc as parent to <s>_phy_aux_clk.
>>>>>>> + * Below picture shows this relationship.
>>>>>>> + *
>>>>>>> + * +---------------+
>>>>>>> + * | PHY block |<<---------------------------------------------+
>>>>>>> + * | | |
>>>>>>> + * | +-------+ | +-----+ |
>>>>>>> + * I/P---^-->| PLL |---^--->phy_aux_clksrc--->| GCC |--->phy_aux_clk---+
>>>>>>> + * clk | +-------+ | +-----+
>>>>>>> + * +---------------+
>>>>>>> + */
>>>>>>> +static int phy_aux_clk_register(struct qmp_pcie *qmp, struct device_node *np)
>>>>>>> +{
>>>>>>> + struct clk_fixed_rate *fixed = &qmp->aux_clk_fixed;
>>>>>>> + struct clk_init_data init = { };
>>>>>>> + int ret;
>>>>>>> +
>>>>>>> + ret = of_property_read_string_index(np, "clock-output-names", 1, &init.name);
>>>>>>> + if (ret) {
>>>>>>> + dev_err(qmp->dev, "%pOFn: No clock-output-names index 1\n", np);
>>>>>>> + return ret;
>>>>>>> + }
>>>>>>> +
>>>>>>> + init.ops = &clk_fixed_rate_ops;
>>>>>>> +
>>>>>>> + fixed->fixed_rate = qmp->cfg->aux_clock_rate;
>>>>>>> + fixed->hw.init = &init;
>>>>>>> +
>>>>>>> + return devm_clk_hw_register(qmp->dev, &fixed->hw);
>>>>>>> +}
>>>>>>> +
>>>>>>> +static struct clk_hw *qmp_pcie_clk_hw_get(struct of_phandle_args *clkspec, void *data)
>>>>>>> +{
>>>>>>> + struct qmp_pcie *qmp = data;
>>>>>>> +
>>>>>>> + /* Support legacy bindings */
>>>>>>> + if (!clkspec->args_count)
>>>>>>> + return &qmp->pipe_clk_fixed.hw;
>>>>>>> +
>>>>>>> + switch (clkspec->args[0]) {
>>>>>>> + case QMP_PCIE_PIPE_CLK:
>>>>>>> + return &qmp->pipe_clk_fixed.hw;
>>>>>>> + case QMP_PCIE_PHY_AUX_CLK:
>>>>>>> + return &qmp->aux_clk_fixed.hw;
>>>>>>> + }
>>>>>>> +
>>>>>>> + return ERR_PTR(-EINVAL);
>>>>>>> +}
>>>>>>
>>>>>> Can we use of_clk_hw_onecell_get() instead? I think it even should be
>>>>>> possible to use onecell for both cases, it will look at the first arg,
>>>>>> which will be 0 in case of #clock-cells equal to 0.
>>>>>
>>>>> Let me investigate if it's possible
>>>>
>>>> Ok, it would work but it would require building a clk_hw_onecell_data a runtime,
>>>> while we could simply provide this qmp_pcie_clk_hw_get() and avoid runtime 2 allocations.
>>>>
>>>> I'm not sure it's worth it.
>>>
>>> Single allocation (or even 0 allocations if you embed it into struct
>>> qmp_pcie) for the sake of using standard helpers.
>>
>> And I just recall I tried the same for Amlogic clocks, but the clk_hw_onecell_data hws
>> field is a flexible array member you can't set at runtime, if you try you'll get:
>> drivers/phy/qualcomm/phy-qcom-qmp-pcie.c:3753:38: error: invalid use of flexible array member
>> 3753 | qmp->clk_hw_data.hws = qmp->clk_hws;
>
> Yes, so it's either
> devm_kzalloc(dev, struct_size(data, hws, 2), GFP_KERNEL);
> or
> struct qmp_pcie {
> ...
> struct {
> struct clk_hw_onecell_data clk_data;
> struct clk_hw clocks[2];
> };
> };
I won't go down this path because of that mess and using of_clk_hw_onecell_get() would need
to still add a custom getter before calling of_clk_hw_onecell_get() to handle the
#clock-cells=0 legacy case.
Neil
>
>>
>> Neil
>>
>>>
>>>
>>>
>>
>
>
On Tue, 19 Mar 2024 at 18:46, <neil.armstrong@linaro.org> wrote:
>
> On 19/03/2024 17:05, Dmitry Baryshkov wrote:
> > On Tue, 19 Mar 2024 at 17:15, <neil.armstrong@linaro.org> wrote:
> >>
> >> On 19/03/2024 15:46, Dmitry Baryshkov wrote:
> >>> On Tue, 19 Mar 2024 at 16:35, Neil Armstrong <neil.armstrong@linaro.org> wrote:
> >>>>
> >>>> On 19/03/2024 11:59, Neil Armstrong wrote:
> >>>>> On 19/03/2024 11:55, Dmitry Baryshkov wrote:
> >>>>>> On Tue, 19 Mar 2024 at 12:45, Neil Armstrong <neil.armstrong@linaro.org> wrote:
> >>>>>>>
> >>>>>>> The PCIe Gen4x2 PHY found in the SM8[456]50 SoCs have a second clock,
> >>>>>>> add the code to register it for PHYs configs that sets a aux_clock_rate.
> >>>>>>>
> >>>>>>> In order to get the right clock, add qmp_pcie_clk_hw_get() which uses
> >>>>>>> the newly introduced QMP_PCIE_PIPE_CLK & QMP_PCIE_PHY_AUX_CLK clock
> >>>>>>> IDs and also supports the legacy bindings by returning the PIPE clock.
> >>>>>>>
> >>>>>>> Signed-off-by: Neil Armstrong <neil.armstrong@linaro.org>
> >>>>>>> ---
> >>>>>>> drivers/phy/qualcomm/phy-qcom-qmp-pcie.c | 70 ++++++++++++++++++++++++++++++++
> >>>>>>> 1 file changed, 70 insertions(+)
> >>>>>>>
> >>>>>>> diff --git a/drivers/phy/qualcomm/phy-qcom-qmp-pcie.c b/drivers/phy/qualcomm/phy-qcom-qmp-pcie.c
> >>>>>>> index 079b3e306489..2d05226ae200 100644
> >>>>>>> --- a/drivers/phy/qualcomm/phy-qcom-qmp-pcie.c
> >>>>>>> +++ b/drivers/phy/qualcomm/phy-qcom-qmp-pcie.c
> >>>>>>> @@ -22,6 +22,8 @@
> >>>>>>> #include <linux/reset.h>
> >>>>>>> #include <linux/slab.h>
> >>>>>>>
> >>>>>>> +#include <dt-bindings/phy/phy-qcom-qmp.h>
> >>>>>>> +
> >>>>>>> #include "phy-qcom-qmp-common.h"
> >>>>>>>
> >>>>>>> #include "phy-qcom-qmp.h"
> >>>>>>> @@ -2389,6 +2391,9 @@ struct qmp_phy_cfg {
> >>>>>>>
> >>>>>>> /* QMP PHY pipe clock interface rate */
> >>>>>>> unsigned long pipe_clock_rate;
> >>>>>>> +
> >>>>>>> + /* QMP PHY AUX clock interface rate */
> >>>>>>> + unsigned long aux_clock_rate;
> >>>>>>> };
> >>>>>>>
> >>>>>>> struct qmp_pcie {
> >>>>>>> @@ -2420,6 +2425,7 @@ struct qmp_pcie {
> >>>>>>> int mode;
> >>>>>>>
> >>>>>>> struct clk_fixed_rate pipe_clk_fixed;
> >>>>>>> + struct clk_fixed_rate aux_clk_fixed;
> >>>>>>> };
> >>>>>>>
> >>>>>>> static inline void qphy_setbits(void __iomem *base, u32 offset, u32 val)
> >>>>>>> @@ -3681,6 +3687,62 @@ static int phy_pipe_clk_register(struct qmp_pcie *qmp, struct device_node *np)
> >>>>>>> return devm_clk_hw_register(qmp->dev, &fixed->hw);
> >>>>>>> }
> >>>>>>>
> >>>>>>> +/*
> >>>>>>> + * Register a fixed rate PHY aux clock.
> >>>>>>> + *
> >>>>>>> + * The <s>_phy_aux_clksrc generated by PHY goes to the GCC that gate
> >>>>>>> + * controls it. The <s>_phy_aux_clk coming out of the GCC is requested
> >>>>>>> + * by the PHY driver for its operations.
> >>>>>>> + * We register the <s>_phy_aux_clksrc here. The gcc driver takes care
> >>>>>>> + * of assigning this <s>_phy_aux_clksrc as parent to <s>_phy_aux_clk.
> >>>>>>> + * Below picture shows this relationship.
> >>>>>>> + *
> >>>>>>> + * +---------------+
> >>>>>>> + * | PHY block |<<---------------------------------------------+
> >>>>>>> + * | | |
> >>>>>>> + * | +-------+ | +-----+ |
> >>>>>>> + * I/P---^-->| PLL |---^--->phy_aux_clksrc--->| GCC |--->phy_aux_clk---+
> >>>>>>> + * clk | +-------+ | +-----+
> >>>>>>> + * +---------------+
> >>>>>>> + */
> >>>>>>> +static int phy_aux_clk_register(struct qmp_pcie *qmp, struct device_node *np)
> >>>>>>> +{
> >>>>>>> + struct clk_fixed_rate *fixed = &qmp->aux_clk_fixed;
> >>>>>>> + struct clk_init_data init = { };
> >>>>>>> + int ret;
> >>>>>>> +
> >>>>>>> + ret = of_property_read_string_index(np, "clock-output-names", 1, &init.name);
> >>>>>>> + if (ret) {
> >>>>>>> + dev_err(qmp->dev, "%pOFn: No clock-output-names index 1\n", np);
> >>>>>>> + return ret;
> >>>>>>> + }
> >>>>>>> +
> >>>>>>> + init.ops = &clk_fixed_rate_ops;
> >>>>>>> +
> >>>>>>> + fixed->fixed_rate = qmp->cfg->aux_clock_rate;
> >>>>>>> + fixed->hw.init = &init;
> >>>>>>> +
> >>>>>>> + return devm_clk_hw_register(qmp->dev, &fixed->hw);
> >>>>>>> +}
> >>>>>>> +
> >>>>>>> +static struct clk_hw *qmp_pcie_clk_hw_get(struct of_phandle_args *clkspec, void *data)
> >>>>>>> +{
> >>>>>>> + struct qmp_pcie *qmp = data;
> >>>>>>> +
> >>>>>>> + /* Support legacy bindings */
> >>>>>>> + if (!clkspec->args_count)
> >>>>>>> + return &qmp->pipe_clk_fixed.hw;
> >>>>>>> +
> >>>>>>> + switch (clkspec->args[0]) {
> >>>>>>> + case QMP_PCIE_PIPE_CLK:
> >>>>>>> + return &qmp->pipe_clk_fixed.hw;
> >>>>>>> + case QMP_PCIE_PHY_AUX_CLK:
> >>>>>>> + return &qmp->aux_clk_fixed.hw;
> >>>>>>> + }
> >>>>>>> +
> >>>>>>> + return ERR_PTR(-EINVAL);
> >>>>>>> +}
> >>>>>>
> >>>>>> Can we use of_clk_hw_onecell_get() instead? I think it even should be
> >>>>>> possible to use onecell for both cases, it will look at the first arg,
> >>>>>> which will be 0 in case of #clock-cells equal to 0.
> >>>>>
> >>>>> Let me investigate if it's possible
> >>>>
> >>>> Ok, it would work but it would require building a clk_hw_onecell_data a runtime,
> >>>> while we could simply provide this qmp_pcie_clk_hw_get() and avoid runtime 2 allocations.
> >>>>
> >>>> I'm not sure it's worth it.
> >>>
> >>> Single allocation (or even 0 allocations if you embed it into struct
> >>> qmp_pcie) for the sake of using standard helpers.
> >>
> >> And I just recall I tried the same for Amlogic clocks, but the clk_hw_onecell_data hws
> >> field is a flexible array member you can't set at runtime, if you try you'll get:
> >> drivers/phy/qualcomm/phy-qcom-qmp-pcie.c:3753:38: error: invalid use of flexible array member
> >> 3753 | qmp->clk_hw_data.hws = qmp->clk_hws;
> >
> > Yes, so it's either
> > devm_kzalloc(dev, struct_size(data, hws, 2), GFP_KERNEL);
> > or
> > struct qmp_pcie {
> > ...
> > struct {
> > struct clk_hw_onecell_data clk_data;
> > struct clk_hw clocks[2];
> > };
> > };
>
> I won't go down this path because of that mess and using of_clk_hw_onecell_get() would need
> to still add a custom getter before calling of_clk_hw_onecell_get() to handle the
> #clock-cells=0 legacy case.
No need for custom getters, if you select the getter during DT probe.
But yes, choose whatever seems better.
>
> Neil
>
> >
> >>
> >> Neil
> >>
> >>>
> >>>
> >>>
> >>
> >
> >
>
--
With best wishes
Dmitry
On 19/03/2024 15:46, Dmitry Baryshkov wrote:
> On Tue, 19 Mar 2024 at 16:35, Neil Armstrong <neil.armstrong@linaro.org> wrote:
>>
>> On 19/03/2024 11:59, Neil Armstrong wrote:
>>> On 19/03/2024 11:55, Dmitry Baryshkov wrote:
>>>> On Tue, 19 Mar 2024 at 12:45, Neil Armstrong <neil.armstrong@linaro.org> wrote:
>>>>>
>>>>> The PCIe Gen4x2 PHY found in the SM8[456]50 SoCs have a second clock,
>>>>> add the code to register it for PHYs configs that sets a aux_clock_rate.
>>>>>
>>>>> In order to get the right clock, add qmp_pcie_clk_hw_get() which uses
>>>>> the newly introduced QMP_PCIE_PIPE_CLK & QMP_PCIE_PHY_AUX_CLK clock
>>>>> IDs and also supports the legacy bindings by returning the PIPE clock.
>>>>>
>>>>> Signed-off-by: Neil Armstrong <neil.armstrong@linaro.org>
>>>>> ---
>>>>> drivers/phy/qualcomm/phy-qcom-qmp-pcie.c | 70 ++++++++++++++++++++++++++++++++
>>>>> 1 file changed, 70 insertions(+)
>>>>>
>>>>> diff --git a/drivers/phy/qualcomm/phy-qcom-qmp-pcie.c b/drivers/phy/qualcomm/phy-qcom-qmp-pcie.c
>>>>> index 079b3e306489..2d05226ae200 100644
>>>>> --- a/drivers/phy/qualcomm/phy-qcom-qmp-pcie.c
>>>>> +++ b/drivers/phy/qualcomm/phy-qcom-qmp-pcie.c
>>>>> @@ -22,6 +22,8 @@
>>>>> #include <linux/reset.h>
>>>>> #include <linux/slab.h>
>>>>>
>>>>> +#include <dt-bindings/phy/phy-qcom-qmp.h>
>>>>> +
>>>>> #include "phy-qcom-qmp-common.h"
>>>>>
>>>>> #include "phy-qcom-qmp.h"
>>>>> @@ -2389,6 +2391,9 @@ struct qmp_phy_cfg {
>>>>>
>>>>> /* QMP PHY pipe clock interface rate */
>>>>> unsigned long pipe_clock_rate;
>>>>> +
>>>>> + /* QMP PHY AUX clock interface rate */
>>>>> + unsigned long aux_clock_rate;
>>>>> };
>>>>>
>>>>> struct qmp_pcie {
>>>>> @@ -2420,6 +2425,7 @@ struct qmp_pcie {
>>>>> int mode;
>>>>>
>>>>> struct clk_fixed_rate pipe_clk_fixed;
>>>>> + struct clk_fixed_rate aux_clk_fixed;
>>>>> };
>>>>>
>>>>> static inline void qphy_setbits(void __iomem *base, u32 offset, u32 val)
>>>>> @@ -3681,6 +3687,62 @@ static int phy_pipe_clk_register(struct qmp_pcie *qmp, struct device_node *np)
>>>>> return devm_clk_hw_register(qmp->dev, &fixed->hw);
>>>>> }
>>>>>
>>>>> +/*
>>>>> + * Register a fixed rate PHY aux clock.
>>>>> + *
>>>>> + * The <s>_phy_aux_clksrc generated by PHY goes to the GCC that gate
>>>>> + * controls it. The <s>_phy_aux_clk coming out of the GCC is requested
>>>>> + * by the PHY driver for its operations.
>>>>> + * We register the <s>_phy_aux_clksrc here. The gcc driver takes care
>>>>> + * of assigning this <s>_phy_aux_clksrc as parent to <s>_phy_aux_clk.
>>>>> + * Below picture shows this relationship.
>>>>> + *
>>>>> + * +---------------+
>>>>> + * | PHY block |<<---------------------------------------------+
>>>>> + * | | |
>>>>> + * | +-------+ | +-----+ |
>>>>> + * I/P---^-->| PLL |---^--->phy_aux_clksrc--->| GCC |--->phy_aux_clk---+
>>>>> + * clk | +-------+ | +-----+
>>>>> + * +---------------+
>>>>> + */
>>>>> +static int phy_aux_clk_register(struct qmp_pcie *qmp, struct device_node *np)
>>>>> +{
>>>>> + struct clk_fixed_rate *fixed = &qmp->aux_clk_fixed;
>>>>> + struct clk_init_data init = { };
>>>>> + int ret;
>>>>> +
>>>>> + ret = of_property_read_string_index(np, "clock-output-names", 1, &init.name);
>>>>> + if (ret) {
>>>>> + dev_err(qmp->dev, "%pOFn: No clock-output-names index 1\n", np);
>>>>> + return ret;
>>>>> + }
>>>>> +
>>>>> + init.ops = &clk_fixed_rate_ops;
>>>>> +
>>>>> + fixed->fixed_rate = qmp->cfg->aux_clock_rate;
>>>>> + fixed->hw.init = &init;
>>>>> +
>>>>> + return devm_clk_hw_register(qmp->dev, &fixed->hw);
>>>>> +}
>>>>> +
>>>>> +static struct clk_hw *qmp_pcie_clk_hw_get(struct of_phandle_args *clkspec, void *data)
>>>>> +{
>>>>> + struct qmp_pcie *qmp = data;
>>>>> +
>>>>> + /* Support legacy bindings */
>>>>> + if (!clkspec->args_count)
>>>>> + return &qmp->pipe_clk_fixed.hw;
>>>>> +
>>>>> + switch (clkspec->args[0]) {
>>>>> + case QMP_PCIE_PIPE_CLK:
>>>>> + return &qmp->pipe_clk_fixed.hw;
>>>>> + case QMP_PCIE_PHY_AUX_CLK:
>>>>> + return &qmp->aux_clk_fixed.hw;
>>>>> + }
>>>>> +
>>>>> + return ERR_PTR(-EINVAL);
>>>>> +}
>>>>
>>>> Can we use of_clk_hw_onecell_get() instead? I think it even should be
>>>> possible to use onecell for both cases, it will look at the first arg,
>>>> which will be 0 in case of #clock-cells equal to 0.
I didn't find evidence this is the case, while following of_parse_clkspec() called
from of_clk_get_hw() or clk_core_get(), where clkspec is not initialized, the
__of_parse_phandle_with_args() and of_phandle_iterator_args() don't touch
clkspec->args if it->cur_count is 0. So clkspec->args[0] may be left initialized
and it would be abusingthe API to use it with #clocks-cells = 0.
>>>
>>> Let me investigate if it's possible
>>
>> Ok, it would work but it would require building a clk_hw_onecell_data a runtime,
>> while we could simply provide this qmp_pcie_clk_hw_get() and avoid runtime 2 allocations.
>>
>> I'm not sure it's worth it.
>
> Single allocation (or even 0 allocations if you embed it into struct
> qmp_pcie) for the sake of using standard helpers.
>
Well, sure
Thanks,
Neil
On Tue, 19 Mar 2024 at 17:10, <neil.armstrong@linaro.org> wrote:
>
> On 19/03/2024 15:46, Dmitry Baryshkov wrote:
> > On Tue, 19 Mar 2024 at 16:35, Neil Armstrong <neil.armstrong@linaro.org> wrote:
> >>
> >> On 19/03/2024 11:59, Neil Armstrong wrote:
> >>> On 19/03/2024 11:55, Dmitry Baryshkov wrote:
> >>>> On Tue, 19 Mar 2024 at 12:45, Neil Armstrong <neil.armstrong@linaro.org> wrote:
> >>>>>
> >>>>> The PCIe Gen4x2 PHY found in the SM8[456]50 SoCs have a second clock,
> >>>>> add the code to register it for PHYs configs that sets a aux_clock_rate.
> >>>>>
> >>>>> In order to get the right clock, add qmp_pcie_clk_hw_get() which uses
> >>>>> the newly introduced QMP_PCIE_PIPE_CLK & QMP_PCIE_PHY_AUX_CLK clock
> >>>>> IDs and also supports the legacy bindings by returning the PIPE clock.
> >>>>>
> >>>>> Signed-off-by: Neil Armstrong <neil.armstrong@linaro.org>
> >>>>> ---
> >>>>> drivers/phy/qualcomm/phy-qcom-qmp-pcie.c | 70 ++++++++++++++++++++++++++++++++
> >>>>> 1 file changed, 70 insertions(+)
> >>>>>
> >>>>> diff --git a/drivers/phy/qualcomm/phy-qcom-qmp-pcie.c b/drivers/phy/qualcomm/phy-qcom-qmp-pcie.c
> >>>>> index 079b3e306489..2d05226ae200 100644
> >>>>> --- a/drivers/phy/qualcomm/phy-qcom-qmp-pcie.c
> >>>>> +++ b/drivers/phy/qualcomm/phy-qcom-qmp-pcie.c
> >>>>> @@ -22,6 +22,8 @@
> >>>>> #include <linux/reset.h>
> >>>>> #include <linux/slab.h>
> >>>>>
> >>>>> +#include <dt-bindings/phy/phy-qcom-qmp.h>
> >>>>> +
> >>>>> #include "phy-qcom-qmp-common.h"
> >>>>>
> >>>>> #include "phy-qcom-qmp.h"
> >>>>> @@ -2389,6 +2391,9 @@ struct qmp_phy_cfg {
> >>>>>
> >>>>> /* QMP PHY pipe clock interface rate */
> >>>>> unsigned long pipe_clock_rate;
> >>>>> +
> >>>>> + /* QMP PHY AUX clock interface rate */
> >>>>> + unsigned long aux_clock_rate;
> >>>>> };
> >>>>>
> >>>>> struct qmp_pcie {
> >>>>> @@ -2420,6 +2425,7 @@ struct qmp_pcie {
> >>>>> int mode;
> >>>>>
> >>>>> struct clk_fixed_rate pipe_clk_fixed;
> >>>>> + struct clk_fixed_rate aux_clk_fixed;
> >>>>> };
> >>>>>
> >>>>> static inline void qphy_setbits(void __iomem *base, u32 offset, u32 val)
> >>>>> @@ -3681,6 +3687,62 @@ static int phy_pipe_clk_register(struct qmp_pcie *qmp, struct device_node *np)
> >>>>> return devm_clk_hw_register(qmp->dev, &fixed->hw);
> >>>>> }
> >>>>>
> >>>>> +/*
> >>>>> + * Register a fixed rate PHY aux clock.
> >>>>> + *
> >>>>> + * The <s>_phy_aux_clksrc generated by PHY goes to the GCC that gate
> >>>>> + * controls it. The <s>_phy_aux_clk coming out of the GCC is requested
> >>>>> + * by the PHY driver for its operations.
> >>>>> + * We register the <s>_phy_aux_clksrc here. The gcc driver takes care
> >>>>> + * of assigning this <s>_phy_aux_clksrc as parent to <s>_phy_aux_clk.
> >>>>> + * Below picture shows this relationship.
> >>>>> + *
> >>>>> + * +---------------+
> >>>>> + * | PHY block |<<---------------------------------------------+
> >>>>> + * | | |
> >>>>> + * | +-------+ | +-----+ |
> >>>>> + * I/P---^-->| PLL |---^--->phy_aux_clksrc--->| GCC |--->phy_aux_clk---+
> >>>>> + * clk | +-------+ | +-----+
> >>>>> + * +---------------+
> >>>>> + */
> >>>>> +static int phy_aux_clk_register(struct qmp_pcie *qmp, struct device_node *np)
> >>>>> +{
> >>>>> + struct clk_fixed_rate *fixed = &qmp->aux_clk_fixed;
> >>>>> + struct clk_init_data init = { };
> >>>>> + int ret;
> >>>>> +
> >>>>> + ret = of_property_read_string_index(np, "clock-output-names", 1, &init.name);
> >>>>> + if (ret) {
> >>>>> + dev_err(qmp->dev, "%pOFn: No clock-output-names index 1\n", np);
> >>>>> + return ret;
> >>>>> + }
> >>>>> +
> >>>>> + init.ops = &clk_fixed_rate_ops;
> >>>>> +
> >>>>> + fixed->fixed_rate = qmp->cfg->aux_clock_rate;
> >>>>> + fixed->hw.init = &init;
> >>>>> +
> >>>>> + return devm_clk_hw_register(qmp->dev, &fixed->hw);
> >>>>> +}
> >>>>> +
> >>>>> +static struct clk_hw *qmp_pcie_clk_hw_get(struct of_phandle_args *clkspec, void *data)
> >>>>> +{
> >>>>> + struct qmp_pcie *qmp = data;
> >>>>> +
> >>>>> + /* Support legacy bindings */
> >>>>> + if (!clkspec->args_count)
> >>>>> + return &qmp->pipe_clk_fixed.hw;
> >>>>> +
> >>>>> + switch (clkspec->args[0]) {
> >>>>> + case QMP_PCIE_PIPE_CLK:
> >>>>> + return &qmp->pipe_clk_fixed.hw;
> >>>>> + case QMP_PCIE_PHY_AUX_CLK:
> >>>>> + return &qmp->aux_clk_fixed.hw;
> >>>>> + }
> >>>>> +
> >>>>> + return ERR_PTR(-EINVAL);
> >>>>> +}
> >>>>
> >>>> Can we use of_clk_hw_onecell_get() instead? I think it even should be
> >>>> possible to use onecell for both cases, it will look at the first arg,
> >>>> which will be 0 in case of #clock-cells equal to 0.
>
> I didn't find evidence this is the case, while following of_parse_clkspec() called
> from of_clk_get_hw() or clk_core_get(), where clkspec is not initialized, the
> __of_parse_phandle_with_args() and of_phandle_iterator_args() don't touch
> clkspec->args if it->cur_count is 0. So clkspec->args[0] may be left initialized
> and it would be abusingthe API to use it with #clocks-cells = 0.
Ack, true.
>
> >>>
> >>> Let me investigate if it's possible
> >>
> >> Ok, it would work but it would require building a clk_hw_onecell_data a runtime,
> >> while we could simply provide this qmp_pcie_clk_hw_get() and avoid runtime 2 allocations.
> >>
> >> I'm not sure it's worth it.
> >
> > Single allocation (or even 0 allocations if you embed it into struct
> > qmp_pcie) for the sake of using standard helpers.
> >
> Well, sure
>
> Thanks,
> Neil
>
--
With best wishes
Dmitry
© 2016 - 2026 Red Hat, Inc.