diff mbox series

[v6,2/5] clk: qcom: regmap: add PHY clock source implementation

Message ID 20220513175339.2981959-3-dmitry.baryshkov@linaro.org
State New
Headers show
Series PCI: qcom: Rework pipe_clk/pipe_clk_src handling | expand

Commit Message

Dmitry Baryshkov May 13, 2022, 5:53 p.m. UTC
On recent Qualcomm platforms the QMP PIPE clocks feed into a set of
muxes which must be parked to the "safe" source (bi_tcxo) when
corresponding GDSC is turned off and on again. Currently this is
handcoded in the PCIe driver by reparenting the gcc_pipe_N_clk_src
clock. However the same code sequence should be applied in the
pcie-qcom endpoint, USB3 and UFS drivers.

Rather than copying this sequence over and over again, follow the
example of clk_rcg2_shared_ops and implement this parking in the
enable() and disable() clock operations. Supplement the regmap-mux with
the new clk_regmap_phy_mux type, which implements such multiplexers
as a simple gate clocks.

This is possible since each of these multiplexers has just two clock
sources: one coming from the PHY and a reference (XO) one.  If the clock
is running off the from-PHY source, report it as enabled. Report it as
disabled otherwise (if it uses reference source).

This way the PHY will disable the pipe clock before turning off the
GDSC, which in turn would lead to disabling corresponding pipe_clk_src
(and thus it being parked to a safe, reference clock source). And vice
versa, after enabling the GDSC the PHY will enable the pipe clock, which
would cause pipe_clk_src to be switched from a safe source to the
working one.

Signed-off-by: Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
---
 drivers/clk/qcom/Makefile             |  1 +
 drivers/clk/qcom/clk-regmap-phy-mux.c | 62 +++++++++++++++++++++++++++
 drivers/clk/qcom/clk-regmap-phy-mux.h | 37 ++++++++++++++++
 3 files changed, 100 insertions(+)
 create mode 100644 drivers/clk/qcom/clk-regmap-phy-mux.c
 create mode 100644 drivers/clk/qcom/clk-regmap-phy-mux.h

Comments

Johan Hovold May 18, 2022, 7:34 a.m. UTC | #1
On Fri, May 13, 2022 at 08:53:36PM +0300, Dmitry Baryshkov wrote:
> On recent Qualcomm platforms the QMP PIPE clocks feed into a set of
> muxes which must be parked to the "safe" source (bi_tcxo) when
> corresponding GDSC is turned off and on again. Currently this is
> handcoded in the PCIe driver by reparenting the gcc_pipe_N_clk_src
> clock. However the same code sequence should be applied in the
> pcie-qcom endpoint, USB3 and UFS drivers.
> 
> Rather than copying this sequence over and over again, follow the
> example of clk_rcg2_shared_ops and implement this parking in the
> enable() and disable() clock operations. Supplement the regmap-mux with
> the new clk_regmap_phy_mux type, which implements such multiplexers
> as a simple gate clocks.
> 
> This is possible since each of these multiplexers has just two clock
> sources: one coming from the PHY and a reference (XO) one.  If the clock
> is running off the from-PHY source, report it as enabled. Report it as
> disabled otherwise (if it uses reference source).
> 
> This way the PHY will disable the pipe clock before turning off the
> GDSC, which in turn would lead to disabling corresponding pipe_clk_src
> (and thus it being parked to a safe, reference clock source). And vice
> versa, after enabling the GDSC the PHY will enable the pipe clock, which
> would cause pipe_clk_src to be switched from a safe source to the
> working one.
> 
> Signed-off-by: Dmitry Baryshkov <dmitry.baryshkov@linaro.org>

This looks really good now. Thanks for sticking with it.

Just one nit below.

> diff --git a/drivers/clk/qcom/clk-regmap-phy-mux.h b/drivers/clk/qcom/clk-regmap-phy-mux.h
> new file mode 100644
> index 000000000000..6260912191c5
> --- /dev/null
> +++ b/drivers/clk/qcom/clk-regmap-phy-mux.h
> @@ -0,0 +1,37 @@
> +/* SPDX-License-Identifier: GPL-2.0-only */
> +/*
> + * Copyright (c) 2022, Linaro Ltd.
> + * Author: Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
> + */
> +
> +#ifndef __QCOM_CLK_REGMAP_PHY_MUX_H__
> +#define __QCOM_CLK_REGMAP_PHY_MUX_H__
> +
> +#include <linux/clk-provider.h>
> +#include "clk-regmap.h"
> +
> +/*
> + * A special clock implementation for PHY pipe and symbols clock sources.

s/sources/muxes/

> + *
> + * If the clock is running off the from-PHY source, report it as enabled.
> + * Report it as disabled otherwise (if it uses reference source).
> + *
> + * This way the PHY will disable the pipe clock before turning off the GDSC,

s|pipe|pipe/symbol|

> + * which in turn would lead to disabling corresponding pipe_clk_src (and thus
> + * it being parked to a safe, reference clock source). And vice versa, after
> + * enabling the GDSC the PHY will enable the pipe clock, which would cause

s|pipe|pipe/symbol|

> + * pipe_clk_src to be switched from a safe source to the working one.
> + */

You're still referring to the old pipe_clk_src name in two places in
this comment.

Should this be reflected in Subject as well (e.g. "PHY mux
implementation")?

> +
> +struct clk_regmap_phy_mux {
> +	u32			reg;
> +	u32			shift;
> +	u32			width;
> +	u32			phy_src_val;
> +	u32			ref_src_val;
> +	struct clk_regmap	clkr;
> +};
> +
> +extern const struct clk_ops clk_regmap_phy_mux_ops;
> +
> +#endif

With the above fixed:

Reviewed-by: Johan Hovold <johan+linaro@kernel.org>

I've also tested the series on sc8280xp-crd and sa8295p-adp:

Tested-by: Johan Hovold <johan+linaro@kernel.org>

Johan
Johan Hovold May 18, 2022, 7:48 a.m. UTC | #2
On Wed, May 18, 2022 at 09:34:19AM +0200, Johan Hovold wrote:
> On Fri, May 13, 2022 at 08:53:36PM +0300, Dmitry Baryshkov wrote:

> > +/*
> > + * A special clock implementation for PHY pipe and symbols clock sources.
> 
> s/sources/muxes/
> 
> > + *
> > + * If the clock is running off the from-PHY source, report it as enabled.
> > + * Report it as disabled otherwise (if it uses reference source).
> > + *
> > + * This way the PHY will disable the pipe clock before turning off the GDSC,
> 
> s|pipe|pipe/symbol|
> 
> > + * which in turn would lead to disabling corresponding pipe_clk_src (and thus
> > + * it being parked to a safe, reference clock source). And vice versa, after
> > + * enabling the GDSC the PHY will enable the pipe clock, which would cause
> 
> s|pipe|pipe/symbol|
> 
> > + * pipe_clk_src to be switched from a safe source to the working one.
> > + */
> 
> You're still referring to the old pipe_clk_src name in two places in
> this comment.

Just remembered that the PCIe/USB mux is also referred to as
pipe_clk_src and that your not referring to the clock implementation.

I guess the comment works as-is even if the example refers to just
USB/PCIe.

> Should this be reflected in Subject as well (e.g. "PHY mux
> implementation")?

Johan
Stephen Boyd May 18, 2022, 5:58 p.m. UTC | #3
Quoting Dmitry Baryshkov (2022-05-13 10:53:36)
> diff --git a/drivers/clk/qcom/clk-regmap-phy-mux.c b/drivers/clk/qcom/clk-regmap-phy-mux.c
> new file mode 100644
> index 000000000000..d7a45f7fa1aa
> --- /dev/null
> +++ b/drivers/clk/qcom/clk-regmap-phy-mux.c
> @@ -0,0 +1,62 @@
> +// SPDX-License-Identifier: GPL-2.0-only
> +/*
> + * Copyright (c) 2022, Linaro Ltd.
> + */
> +
> +#include <linux/kernel.h>
> +#include <linux/bitops.h>
> +#include <linux/regmap.h>
> +#include <linux/export.h>

clk-provider.h for clk_hw/clk_ops usage. It helps with grep to identify
clk providers.

> +
> +#include "clk-regmap-phy-mux.h"

Same for clk-regmap.h, avoid include hell.

> +
> +static inline struct clk_regmap_phy_mux *to_clk_regmap_phy_mux(struct clk_hw *hw)
> +{
> +       return container_of(to_clk_regmap(hw), struct clk_regmap_phy_mux, clkr);
> +}
> +
> +static int phy_mux_is_enabled(struct clk_hw *hw)
> +{
> +       struct clk_regmap_phy_mux *phy_mux = to_clk_regmap_phy_mux(hw);
> +       struct clk_regmap *clkr = to_clk_regmap(hw);
> +       unsigned int mask = GENMASK(phy_mux->width + phy_mux->shift - 1, phy_mux->shift);
> +       unsigned int val;
> +
> +       regmap_read(clkr->regmap, phy_mux->reg, &val);
> +       val = (val & mask) >> phy_mux->shift;

Can this use FIELD_GET?

> +
> +       WARN_ON(val != phy_mux->phy_src_val && val != phy_mux->ref_src_val);
> +
> +       return val == phy_mux->phy_src_val;
> +}
> +
> +static int phy_mux_enable(struct clk_hw *hw)
> +{
> +       struct clk_regmap_phy_mux *phy_mux = to_clk_regmap_phy_mux(hw);
> +       struct clk_regmap *clkr = to_clk_regmap(hw);
> +       unsigned int mask = GENMASK(phy_mux->width + phy_mux->shift - 1, phy_mux->shift);
> +       unsigned int val;
> +
> +       val = phy_mux->phy_src_val << phy_mux->shift;

Can this use FIELD_PREP?

> +
> +       return regmap_update_bits(clkr->regmap, phy_mux->reg, mask, val);
> +}
> +
> +static void phy_mux_disable(struct clk_hw *hw)
> +{
> +       struct clk_regmap_phy_mux *phy_mux = to_clk_regmap_phy_mux(hw);
> +       struct clk_regmap *clkr = to_clk_regmap(hw);
> +       unsigned int mask = GENMASK(phy_mux->width + phy_mux->shift - 1, phy_mux->shift);
> +       unsigned int val;
> +
> +       val = phy_mux->ref_src_val << phy_mux->shift;
> +
> +       regmap_update_bits(clkr->regmap, phy_mux->reg, mask, val);
> +}
> +
> +const struct clk_ops clk_regmap_phy_mux_ops = {
> +       .enable = phy_mux_enable,
> +       .disable = phy_mux_disable,
> +       .is_enabled = phy_mux_is_enabled,
> +};
> +EXPORT_SYMBOL_GPL(clk_regmap_phy_mux_ops);
> diff --git a/drivers/clk/qcom/clk-regmap-phy-mux.h b/drivers/clk/qcom/clk-regmap-phy-mux.h
> new file mode 100644
> index 000000000000..6260912191c5
> --- /dev/null
> +++ b/drivers/clk/qcom/clk-regmap-phy-mux.h
> @@ -0,0 +1,37 @@
> +/* SPDX-License-Identifier: GPL-2.0-only */
> +/*
> + * Copyright (c) 2022, Linaro Ltd.
> + * Author: Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
> + */
> +
> +#ifndef __QCOM_CLK_REGMAP_PHY_MUX_H__
> +#define __QCOM_CLK_REGMAP_PHY_MUX_H__
> +
> +#include <linux/clk-provider.h>
> +#include "clk-regmap.h"
> +
> +/*
> + * A special clock implementation for PHY pipe and symbols clock sources.

Remove "special" please. Everything is special :)

> + *
> + * If the clock is running off the from-PHY source, report it as enabled.

from-PHY is @phy_src_val? Maybe add that information like "from-PHY
source (@phy_src_val)"

> + * Report it as disabled otherwise (if it uses reference source).

Same for @ref_src_val

> + *
> + * This way the PHY will disable the pipe clock before turning off the GDSC,
> + * which in turn would lead to disabling corresponding pipe_clk_src (and thus
> + * it being parked to a safe, reference clock source). And vice versa, after
> + * enabling the GDSC the PHY will enable the pipe clock, which would cause
> + * pipe_clk_src to be switched from a safe source to the working one.

Might as well make it into real kernel-doc at the same time.

> + */
> +
> +struct clk_regmap_phy_mux {
> +       u32                     reg;
> +       u32                     shift;
> +       u32                     width;

Technically neither of these need to be u32 and could be u8 to save a
byte or two. The other thing is that possibly the width and shift never
changes? The RCG layout is pretty well fixed. Does hardcoding it work?

> +       u32                     phy_src_val;
> +       u32                     ref_src_val;

I feel like "_val" is redundant. Just "ref_src" and "phy_src"? Shorter
is nice.

> +       struct clk_regmap       clkr;
> +};
> +
> +extern const struct clk_ops clk_regmap_phy_mux_ops;
Dmitry Baryshkov May 18, 2022, 7:19 p.m. UTC | #4
On 18/05/2022 20:58, Stephen Boyd wrote:
> Quoting Dmitry Baryshkov (2022-05-13 10:53:36)
>> diff --git a/drivers/clk/qcom/clk-regmap-phy-mux.c b/drivers/clk/qcom/clk-regmap-phy-mux.c
>> new file mode 100644
>> index 000000000000..d7a45f7fa1aa
>> --- /dev/null
>> +++ b/drivers/clk/qcom/clk-regmap-phy-mux.c
>> @@ -0,0 +1,62 @@
>> +// SPDX-License-Identifier: GPL-2.0-only
>> +/*
>> + * Copyright (c) 2022, Linaro Ltd.
>> + */
>> +
>> +#include <linux/kernel.h>
>> +#include <linux/bitops.h>
>> +#include <linux/regmap.h>
>> +#include <linux/export.h>
> 
> clk-provider.h for clk_hw/clk_ops usage. It helps with grep to identify
> clk providers.
> 
>> +
>> +#include "clk-regmap-phy-mux.h"
> 
> Same for clk-regmap.h, avoid include hell.
> 
>> +
>> +static inline struct clk_regmap_phy_mux *to_clk_regmap_phy_mux(struct clk_hw *hw)
>> +{
>> +       return container_of(to_clk_regmap(hw), struct clk_regmap_phy_mux, clkr);
>> +}
>> +
>> +static int phy_mux_is_enabled(struct clk_hw *hw)
>> +{
>> +       struct clk_regmap_phy_mux *phy_mux = to_clk_regmap_phy_mux(hw);
>> +       struct clk_regmap *clkr = to_clk_regmap(hw);
>> +       unsigned int mask = GENMASK(phy_mux->width + phy_mux->shift - 1, phy_mux->shift);
>> +       unsigned int val;
>> +
>> +       regmap_read(clkr->regmap, phy_mux->reg, &val);
>> +       val = (val & mask) >> phy_mux->shift;
> 
> Can this use FIELD_GET?
> 
>> +
>> +       WARN_ON(val != phy_mux->phy_src_val && val != phy_mux->ref_src_val);
>> +
>> +       return val == phy_mux->phy_src_val;
>> +}
>> +
>> +static int phy_mux_enable(struct clk_hw *hw)
>> +{
>> +       struct clk_regmap_phy_mux *phy_mux = to_clk_regmap_phy_mux(hw);
>> +       struct clk_regmap *clkr = to_clk_regmap(hw);
>> +       unsigned int mask = GENMASK(phy_mux->width + phy_mux->shift - 1, phy_mux->shift);
>> +       unsigned int val;
>> +
>> +       val = phy_mux->phy_src_val << phy_mux->shift;
> 
> Can this use FIELD_PREP?
> 
>> +
>> +       return regmap_update_bits(clkr->regmap, phy_mux->reg, mask, val);
>> +}
>> +
>> +static void phy_mux_disable(struct clk_hw *hw)
>> +{
>> +       struct clk_regmap_phy_mux *phy_mux = to_clk_regmap_phy_mux(hw);
>> +       struct clk_regmap *clkr = to_clk_regmap(hw);
>> +       unsigned int mask = GENMASK(phy_mux->width + phy_mux->shift - 1, phy_mux->shift);
>> +       unsigned int val;
>> +
>> +       val = phy_mux->ref_src_val << phy_mux->shift;
>> +
>> +       regmap_update_bits(clkr->regmap, phy_mux->reg, mask, val);
>> +}
>> +
>> +const struct clk_ops clk_regmap_phy_mux_ops = {
>> +       .enable = phy_mux_enable,
>> +       .disable = phy_mux_disable,
>> +       .is_enabled = phy_mux_is_enabled,
>> +};
>> +EXPORT_SYMBOL_GPL(clk_regmap_phy_mux_ops);
>> diff --git a/drivers/clk/qcom/clk-regmap-phy-mux.h b/drivers/clk/qcom/clk-regmap-phy-mux.h
>> new file mode 100644
>> index 000000000000..6260912191c5
>> --- /dev/null
>> +++ b/drivers/clk/qcom/clk-regmap-phy-mux.h
>> @@ -0,0 +1,37 @@
>> +/* SPDX-License-Identifier: GPL-2.0-only */
>> +/*
>> + * Copyright (c) 2022, Linaro Ltd.
>> + * Author: Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
>> + */
>> +
>> +#ifndef __QCOM_CLK_REGMAP_PHY_MUX_H__
>> +#define __QCOM_CLK_REGMAP_PHY_MUX_H__
>> +
>> +#include <linux/clk-provider.h>
>> +#include "clk-regmap.h"
>> +
>> +/*
>> + * A special clock implementation for PHY pipe and symbols clock sources.
> 
> Remove "special" please. Everything is special :)

ack for the docs changes, will send shortly.

> 
>> + *
>> + * If the clock is running off the from-PHY source, report it as enabled.
> 
> from-PHY is @phy_src_val? Maybe add that information like "from-PHY
> source (@phy_src_val)"
> 
>> + * Report it as disabled otherwise (if it uses reference source).
> 
> Same for @ref_src_val
> 
>> + *
>> + * This way the PHY will disable the pipe clock before turning off the GDSC,
>> + * which in turn would lead to disabling corresponding pipe_clk_src (and thus
>> + * it being parked to a safe, reference clock source). And vice versa, after
>> + * enabling the GDSC the PHY will enable the pipe clock, which would cause
>> + * pipe_clk_src to be switched from a safe source to the working one.
> 
> Might as well make it into real kernel-doc at the same time.
> 
>> + */
>> +
>> +struct clk_regmap_phy_mux {
>> +       u32                     reg;
>> +       u32                     shift;
>> +       u32                     width;
> 
> Technically neither of these need to be u32 and could be u8 to save a
> byte or two. The other thing is that possibly the width and shift never
> changes? The RCG layout is pretty well fixed. Does hardcoding it work?

It seems, I can hardcode shift=0 and width=2.

> 
>> +       u32                     phy_src_val;
>> +       u32                     ref_src_val;
> 
> I feel like "_val" is redundant. Just "ref_src" and "phy_src"? Shorter
> is nice.

I had this since I wanted to point that these are 'values', not the 
enum-ed sources. But I can drop this now.

> 
>> +       struct clk_regmap       clkr;
>> +};
>> +
>> +extern const struct clk_ops clk_regmap_phy_mux_ops;
Dmitry Baryshkov May 19, 2022, 11:16 a.m. UTC | #5
On 18/05/2022 20:58, Stephen Boyd wrote:
> Quoting Dmitry Baryshkov (2022-05-13 10:53:36)
>> diff --git a/drivers/clk/qcom/clk-regmap-phy-mux.c b/drivers/clk/qcom/clk-regmap-phy-mux.c
>> new file mode 100644
>> index 000000000000..d7a45f7fa1aa
>> --- /dev/null
>> +++ b/drivers/clk/qcom/clk-regmap-phy-mux.c
>> @@ -0,0 +1,62 @@
>> +// SPDX-License-Identifier: GPL-2.0-only
>> +/*
>> + * Copyright (c) 2022, Linaro Ltd.
>> + */
>> +
>> +#include <linux/kernel.h>
>> +#include <linux/bitops.h>
>> +#include <linux/regmap.h>
>> +#include <linux/export.h>
> 
> clk-provider.h for clk_hw/clk_ops usage. It helps with grep to identify
> clk providers.
> 
>> +
>> +#include "clk-regmap-phy-mux.h"
> 
> Same for clk-regmap.h, avoid include hell.

I couldn't catch this comment. I think we need clk-regmap.h in 
clk-regmap-phy-mux.h as clk_regmap is a part of defined structure.

>> +
>> +static inline struct clk_regmap_phy_mux *to_clk_regmap_phy_mux(struct clk_hw *hw)
>> +{
>> +       return container_of(to_clk_regmap(hw), struct clk_regmap_phy_mux, clkr);
>> +}
>> +
>> +static int phy_mux_is_enabled(struct clk_hw *hw)
>> +{
>> +       struct clk_regmap_phy_mux *phy_mux = to_clk_regmap_phy_mux(hw);
>> +       struct clk_regmap *clkr = to_clk_regmap(hw);
>> +       unsigned int mask = GENMASK(phy_mux->width + phy_mux->shift - 1, phy_mux->shift);
>> +       unsigned int val;
>> +
>> +       regmap_read(clkr->regmap, phy_mux->reg, &val);
>> +       val = (val & mask) >> phy_mux->shift;
> 
> Can this use FIELD_GET?
> 
>> +
>> +       WARN_ON(val != phy_mux->phy_src_val && val != phy_mux->ref_src_val);
>> +
>> +       return val == phy_mux->phy_src_val;
>> +}
>> +
>> +static int phy_mux_enable(struct clk_hw *hw)
>> +{
>> +       struct clk_regmap_phy_mux *phy_mux = to_clk_regmap_phy_mux(hw);
>> +       struct clk_regmap *clkr = to_clk_regmap(hw);
>> +       unsigned int mask = GENMASK(phy_mux->width + phy_mux->shift - 1, phy_mux->shift);
>> +       unsigned int val;
>> +
>> +       val = phy_mux->phy_src_val << phy_mux->shift;
> 
> Can this use FIELD_PREP?
> 
>> +
>> +       return regmap_update_bits(clkr->regmap, phy_mux->reg, mask, val);
>> +}
>> +
>> +static void phy_mux_disable(struct clk_hw *hw)
>> +{
>> +       struct clk_regmap_phy_mux *phy_mux = to_clk_regmap_phy_mux(hw);
>> +       struct clk_regmap *clkr = to_clk_regmap(hw);
>> +       unsigned int mask = GENMASK(phy_mux->width + phy_mux->shift - 1, phy_mux->shift);
>> +       unsigned int val;
>> +
>> +       val = phy_mux->ref_src_val << phy_mux->shift;
>> +
>> +       regmap_update_bits(clkr->regmap, phy_mux->reg, mask, val);
>> +}
>> +
>> +const struct clk_ops clk_regmap_phy_mux_ops = {
>> +       .enable = phy_mux_enable,
>> +       .disable = phy_mux_disable,
>> +       .is_enabled = phy_mux_is_enabled,
>> +};
>> +EXPORT_SYMBOL_GPL(clk_regmap_phy_mux_ops);
>> diff --git a/drivers/clk/qcom/clk-regmap-phy-mux.h b/drivers/clk/qcom/clk-regmap-phy-mux.h
>> new file mode 100644
>> index 000000000000..6260912191c5
>> --- /dev/null
>> +++ b/drivers/clk/qcom/clk-regmap-phy-mux.h
>> @@ -0,0 +1,37 @@
>> +/* SPDX-License-Identifier: GPL-2.0-only */
>> +/*
>> + * Copyright (c) 2022, Linaro Ltd.
>> + * Author: Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
>> + */
>> +
>> +#ifndef __QCOM_CLK_REGMAP_PHY_MUX_H__
>> +#define __QCOM_CLK_REGMAP_PHY_MUX_H__
>> +
>> +#include <linux/clk-provider.h>
>> +#include "clk-regmap.h"
>> +
>> +/*
>> + * A special clock implementation for PHY pipe and symbols clock sources.
> 
> Remove "special" please. Everything is special :)
> 
>> + *
>> + * If the clock is running off the from-PHY source, report it as enabled.
> 
> from-PHY is @phy_src_val? Maybe add that information like "from-PHY
> source (@phy_src_val)"
> 
>> + * Report it as disabled otherwise (if it uses reference source).
> 
> Same for @ref_src_val
> 
>> + *
>> + * This way the PHY will disable the pipe clock before turning off the GDSC,
>> + * which in turn would lead to disabling corresponding pipe_clk_src (and thus
>> + * it being parked to a safe, reference clock source). And vice versa, after
>> + * enabling the GDSC the PHY will enable the pipe clock, which would cause
>> + * pipe_clk_src to be switched from a safe source to the working one.
> 
> Might as well make it into real kernel-doc at the same time.
> 
>> + */
>> +
>> +struct clk_regmap_phy_mux {
>> +       u32                     reg;
>> +       u32                     shift;
>> +       u32                     width;
> 
> Technically neither of these need to be u32 and could be u8 to save a
> byte or two. The other thing is that possibly the width and shift never
> changes? The RCG layout is pretty well fixed. Does hardcoding it work?
> 
>> +       u32                     phy_src_val;
>> +       u32                     ref_src_val;
> 
> I feel like "_val" is redundant. Just "ref_src" and "phy_src"? Shorter
> is nice.
> 
>> +       struct clk_regmap       clkr;
>> +};
>> +
>> +extern const struct clk_ops clk_regmap_phy_mux_ops;
Dmitry Baryshkov May 19, 2022, 11:44 a.m. UTC | #6
On 18/05/2022 10:48, Johan Hovold wrote:
> On Wed, May 18, 2022 at 09:34:19AM +0200, Johan Hovold wrote:
>> On Fri, May 13, 2022 at 08:53:36PM +0300, Dmitry Baryshkov wrote:
> 
>>> +/*
>>> + * A special clock implementation for PHY pipe and symbols clock sources.
>>
>> s/sources/muxes/
>>
>>> + *
>>> + * If the clock is running off the from-PHY source, report it as enabled.
>>> + * Report it as disabled otherwise (if it uses reference source).
>>> + *
>>> + * This way the PHY will disable the pipe clock before turning off the GDSC,
>>
>> s|pipe|pipe/symbol|
>>
>>> + * which in turn would lead to disabling corresponding pipe_clk_src (and thus
>>> + * it being parked to a safe, reference clock source). And vice versa, after
>>> + * enabling the GDSC the PHY will enable the pipe clock, which would cause
>>
>> s|pipe|pipe/symbol|
>>
>>> + * pipe_clk_src to be switched from a safe source to the working one.
>>> + */
>>
>> You're still referring to the old pipe_clk_src name in two places in
>> this comment.
> 
> Just remembered that the PCIe/USB mux is also referred to as
> pipe_clk_src and that your not referring to the clock implementation.
> 
> I guess the comment works as-is even if the example refers to just
> USB/PCIe.

I will add a phrase mentioning UFS symbol clocks.

> 
>> Should this be reflected in Subject as well (e.g. "PHY mux
>> implementation")?
> 
> Johan
Stephen Boyd May 20, 2022, 10:49 p.m. UTC | #7
Quoting Dmitry Baryshkov (2022-05-19 04:16:19)
> On 18/05/2022 20:58, Stephen Boyd wrote:
> > Quoting Dmitry Baryshkov (2022-05-13 10:53:36)
> >> diff --git a/drivers/clk/qcom/clk-regmap-phy-mux.c b/drivers/clk/qcom/clk-regmap-phy-mux.c
> >> new file mode 100644
> >> index 000000000000..d7a45f7fa1aa
> >> --- /dev/null
> >> +++ b/drivers/clk/qcom/clk-regmap-phy-mux.c
[...]
> >> +
> >> +#include "clk-regmap-phy-mux.h"
> > 
> > Same for clk-regmap.h, avoid include hell.
> 
> I couldn't catch this comment. I think we need clk-regmap.h in 
> clk-regmap-phy-mux.h as clk_regmap is a part of defined structure.
> 

Don't rely on implicit includes. It makes changing header files error
prone. Also, please trim replies.
Dmitry Baryshkov May 21, 2022, 12:38 a.m. UTC | #8
On 21/05/2022 01:49, Stephen Boyd wrote:
> Quoting Dmitry Baryshkov (2022-05-19 04:16:19)
>> On 18/05/2022 20:58, Stephen Boyd wrote:
>>> Quoting Dmitry Baryshkov (2022-05-13 10:53:36)
>>>> diff --git a/drivers/clk/qcom/clk-regmap-phy-mux.c b/drivers/clk/qcom/clk-regmap-phy-mux.c
>>>> new file mode 100644
>>>> index 000000000000..d7a45f7fa1aa
>>>> --- /dev/null
>>>> +++ b/drivers/clk/qcom/clk-regmap-phy-mux.c
> [...]
>>>> +
>>>> +#include "clk-regmap-phy-mux.h"
>>>
>>> Same for clk-regmap.h, avoid include hell.
>>
>> I couldn't catch this comment. I think we need clk-regmap.h in
>> clk-regmap-phy-mux.h as clk_regmap is a part of defined structure.
>>
> 
> Don't rely on implicit includes. It makes changing header files error
> prone. Also, please trim replies.

Ack. Will change this in v8.
diff mbox series

Patch

diff --git a/drivers/clk/qcom/Makefile b/drivers/clk/qcom/Makefile
index 671cf5821af1..e4ceb5819ae6 100644
--- a/drivers/clk/qcom/Makefile
+++ b/drivers/clk/qcom/Makefile
@@ -11,6 +11,7 @@  clk-qcom-y += clk-branch.o
 clk-qcom-y += clk-regmap-divider.o
 clk-qcom-y += clk-regmap-mux.o
 clk-qcom-y += clk-regmap-mux-div.o
+clk-qcom-y += clk-regmap-phy-mux.o
 clk-qcom-$(CONFIG_KRAIT_CLOCKS) += clk-krait.o
 clk-qcom-y += clk-hfpll.o
 clk-qcom-y += reset.o
diff --git a/drivers/clk/qcom/clk-regmap-phy-mux.c b/drivers/clk/qcom/clk-regmap-phy-mux.c
new file mode 100644
index 000000000000..d7a45f7fa1aa
--- /dev/null
+++ b/drivers/clk/qcom/clk-regmap-phy-mux.c
@@ -0,0 +1,62 @@ 
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (c) 2022, Linaro Ltd.
+ */
+
+#include <linux/kernel.h>
+#include <linux/bitops.h>
+#include <linux/regmap.h>
+#include <linux/export.h>
+
+#include "clk-regmap-phy-mux.h"
+
+static inline struct clk_regmap_phy_mux *to_clk_regmap_phy_mux(struct clk_hw *hw)
+{
+	return container_of(to_clk_regmap(hw), struct clk_regmap_phy_mux, clkr);
+}
+
+static int phy_mux_is_enabled(struct clk_hw *hw)
+{
+	struct clk_regmap_phy_mux *phy_mux = to_clk_regmap_phy_mux(hw);
+	struct clk_regmap *clkr = to_clk_regmap(hw);
+	unsigned int mask = GENMASK(phy_mux->width + phy_mux->shift - 1, phy_mux->shift);
+	unsigned int val;
+
+	regmap_read(clkr->regmap, phy_mux->reg, &val);
+	val = (val & mask) >> phy_mux->shift;
+
+	WARN_ON(val != phy_mux->phy_src_val && val != phy_mux->ref_src_val);
+
+	return val == phy_mux->phy_src_val;
+}
+
+static int phy_mux_enable(struct clk_hw *hw)
+{
+	struct clk_regmap_phy_mux *phy_mux = to_clk_regmap_phy_mux(hw);
+	struct clk_regmap *clkr = to_clk_regmap(hw);
+	unsigned int mask = GENMASK(phy_mux->width + phy_mux->shift - 1, phy_mux->shift);
+	unsigned int val;
+
+	val = phy_mux->phy_src_val << phy_mux->shift;
+
+	return regmap_update_bits(clkr->regmap, phy_mux->reg, mask, val);
+}
+
+static void phy_mux_disable(struct clk_hw *hw)
+{
+	struct clk_regmap_phy_mux *phy_mux = to_clk_regmap_phy_mux(hw);
+	struct clk_regmap *clkr = to_clk_regmap(hw);
+	unsigned int mask = GENMASK(phy_mux->width + phy_mux->shift - 1, phy_mux->shift);
+	unsigned int val;
+
+	val = phy_mux->ref_src_val << phy_mux->shift;
+
+	regmap_update_bits(clkr->regmap, phy_mux->reg, mask, val);
+}
+
+const struct clk_ops clk_regmap_phy_mux_ops = {
+	.enable = phy_mux_enable,
+	.disable = phy_mux_disable,
+	.is_enabled = phy_mux_is_enabled,
+};
+EXPORT_SYMBOL_GPL(clk_regmap_phy_mux_ops);
diff --git a/drivers/clk/qcom/clk-regmap-phy-mux.h b/drivers/clk/qcom/clk-regmap-phy-mux.h
new file mode 100644
index 000000000000..6260912191c5
--- /dev/null
+++ b/drivers/clk/qcom/clk-regmap-phy-mux.h
@@ -0,0 +1,37 @@ 
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Copyright (c) 2022, Linaro Ltd.
+ * Author: Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
+ */
+
+#ifndef __QCOM_CLK_REGMAP_PHY_MUX_H__
+#define __QCOM_CLK_REGMAP_PHY_MUX_H__
+
+#include <linux/clk-provider.h>
+#include "clk-regmap.h"
+
+/*
+ * A special clock implementation for PHY pipe and symbols clock sources.
+ *
+ * If the clock is running off the from-PHY source, report it as enabled.
+ * Report it as disabled otherwise (if it uses reference source).
+ *
+ * This way the PHY will disable the pipe clock before turning off the GDSC,
+ * which in turn would lead to disabling corresponding pipe_clk_src (and thus
+ * it being parked to a safe, reference clock source). And vice versa, after
+ * enabling the GDSC the PHY will enable the pipe clock, which would cause
+ * pipe_clk_src to be switched from a safe source to the working one.
+ */
+
+struct clk_regmap_phy_mux {
+	u32			reg;
+	u32			shift;
+	u32			width;
+	u32			phy_src_val;
+	u32			ref_src_val;
+	struct clk_regmap	clkr;
+};
+
+extern const struct clk_ops clk_regmap_phy_mux_ops;
+
+#endif