On Tue, 19 Mar 2024 at 17:15, <neil.armstrong@xxxxxxxxxx> wrote: > > On 19/03/2024 15:46, Dmitry Baryshkov wrote: > > On Tue, 19 Mar 2024 at 16:35, Neil Armstrong <neil.armstrong@xxxxxxxxxx> 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@xxxxxxxxxx> 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@xxxxxxxxxx> > >>>>> --- > >>>>> 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