[PATCH 23/31] clk: mediatek: add support to configure clock driver parent

Weijie Gao weijie.gao at mediatek.com
Tue Aug 23 12:43:06 CEST 2022


On Sat, 2022-08-13 at 00:18 -0400, Sean Anderson wrote:
> On 8/3/22 11:36 PM, Weijie Gao wrote:
> > This patch adds support for a clock node to configure its parent
> > clock
> > where possible.
> > 
> > Signed-off-by: Weijie Gao <weijie.gao at mediatek.com>
> > ---
> >   drivers/clk/mediatek/clk-mtk.c | 79 ++++++++++++++++++++---------
> > -----
> >   drivers/clk/mediatek/clk-mtk.h |  2 +
> >   2 files changed, 48 insertions(+), 33 deletions(-)
> > 
> > diff --git a/drivers/clk/mediatek/clk-mtk.c
> > b/drivers/clk/mediatek/clk-mtk.c
> > index d99ea55df0..908ed2b4ba 100644
> > --- a/drivers/clk/mediatek/clk-mtk.c
> > +++ b/drivers/clk/mediatek/clk-mtk.c
> > @@ -42,20 +42,14 @@
> >    * the accurate frequency.
> >    */
> >   static ulong mtk_clk_find_parent_rate(struct clk *clk, int id,
> > -				      const struct driver *drv)
> > +				      struct udevice *pdev)
> >   {
> >   	struct clk parent = { .id = id, };
> >   
> > -	if (drv) {
> > -		struct udevice *dev;
> > -
> > -		if (uclass_get_device_by_driver(UCLASS_CLK, drv,
> > &dev))
> > -			return -ENODEV;
> > -
> > -		parent.dev = dev;
> > -	} else {
> > +	if (pdev)
> > +		parent.dev = pdev;
> > +	else
> >   		parent.dev = clk->dev;
> > -	}
> >   
> >   	return clk_get_rate(&parent);
> 
> You must call clk_request(parent) before calling clk_get_rate.

Currently the mtk clock driver doest not really register all the clock
devices. The ops->request is NULL.

The clk->id is only used by the specific soc clock driver (clk-
mtxxxx.c) as a reference to the soc's clock list.

Once clk_get_rate is called, the driver will use clk->id to search the
actual clock internally in the driver.
If a clock has its parent clock,  the driver will fill up the parent
clock's id and then call clk_get_rate again. Again clk_get_rate will go
into the driver and do the same thing until a clock has no parent.

As you can see we only use the clk->id, not the clk udevice, there's no
need to call clk_request. Only a few top-level clk udevices are
registered as the entrace to this driver (topckgen/infrasys/...).

> 
> >   }
> > @@ -296,7 +290,7 @@ static ulong
> > mtk_topckgen_get_factor_rate(struct clk
> >   *clk, u32 off)
> >   	switch (fdiv->flags & CLK_PARENT_MASK) {
> >   	case CLK_PARENT_APMIXED:
> >   		rate = mtk_clk_find_parent_rate(clk, fdiv-
> > >parent,
> > -				DM_DRIVER_GET(mtk_clk_apmixedsys))
> > ;
> > +						priv->parent);
> >   		break;
> >   	case CLK_PARENT_TOPCKGEN:
> >   		rate = mtk_clk_find_parent_rate(clk, fdiv-
> > >parent, NULL);
> > @@ -322,9 +316,18 @@ static ulong mtk_topckgen_get_mux_rate(struct
> > clk *clk,
> >   u32 off)
> >   
> >   	if (mux->parent[index] == CLK_XTAL && priv->tree->flags &
> > CLK_BYPASS_XTAL)
> >   		flag = 1;
> > -	if (mux->parent[index] > 0 || flag == 1)
> > -		return mtk_clk_find_parent_rate(clk, mux-
> > >parent[index],
> > -						NULL);
> > +	if (mux->parent[index] > 0 || flag == 1) {
> > +		switch (mux->flags & CLK_PARENT_MASK) {
> > +		case CLK_PARENT_APMIXED:
> > +			return mtk_clk_find_parent_rate(clk, mux-
> > >parent[index],
> > +							priv-
> > >parent);
> > +			break;
> > +		default:
> > +			return mtk_clk_find_parent_rate(clk, mux-
> > >parent[index],
> > +							NULL);
> > +			break;
> > +		}
> > +	}
> >   
> >   	return priv->tree->xtal_rate;
> >   }
> > @@ -343,7 +346,7 @@ static ulong mtk_topckgen_get_rate(struct clk
> > *clk)
> >   						 priv->tree-
> > >muxes_offs);
> >   }
> >   
> > -static int mtk_topckgen_enable(struct clk *clk)
> > +static int mtk_clk_mux_enable(struct clk *clk)
> >   {
> >   	struct mtk_clk_priv *priv = dev_get_priv(clk->dev);
> >   	const struct mtk_composite *mux;
> > @@ -376,7 +379,7 @@ static int mtk_topckgen_enable(struct clk *clk)
> >   	return 0;
> >   }
> >   
> > -static int mtk_topckgen_disable(struct clk *clk)
> > +static int mtk_clk_mux_disable(struct clk *clk)
> >   {
> >   	struct mtk_clk_priv *priv = dev_get_priv(clk->dev);
> >   	const struct mtk_composite *mux;
> > @@ -402,7 +405,7 @@ static int mtk_topckgen_disable(struct clk
> > *clk)
> >   	return 0;
> >   }
> >   
> > -static int mtk_topckgen_set_parent(struct clk *clk, struct clk
> > *parent)
> > +static int mtk_common_clk_set_parent(struct clk *clk, struct clk
> > *parent)
> >   {
> >   	struct mtk_clk_priv *priv = dev_get_priv(clk->dev);
> >   
> > @@ -474,19 +477,7 @@ static ulong mtk_clk_gate_get_rate(struct clk
> > *clk)
> >   	struct mtk_cg_priv *priv = dev_get_priv(clk->dev);
> >   	const struct mtk_gate *gate = &priv->gates[clk->id];
> >   
> > -	switch (gate->flags & CLK_PARENT_MASK) {
> > -	case CLK_PARENT_APMIXED:
> > -		return mtk_clk_find_parent_rate(clk, gate->parent,
> > -				DM_DRIVER_GET(mtk_clk_apmixedsys))
> > ;
> > -		break;
> > -	case CLK_PARENT_TOPCKGEN:
> > -		return mtk_clk_find_parent_rate(clk, gate->parent,
> > -				DM_DRIVER_GET(mtk_clk_topckgen));
> > -		break;
> > -
> > -	default:
> > -		return priv->tree->xtal_rate;
> > -	}
> > +	return mtk_clk_find_parent_rate(clk, gate->parent, priv-
> > >parent);
> >   }
> >   
> >   const struct clk_ops mtk_clk_apmixedsys_ops = {
> > @@ -497,10 +488,10 @@ const struct clk_ops mtk_clk_apmixedsys_ops =
> > {
> >   };
> >   
> >   const struct clk_ops mtk_clk_topckgen_ops = {
> > -	.enable = mtk_topckgen_enable,
> > -	.disable = mtk_topckgen_disable,
> > +	.enable = mtk_clk_mux_enable,
> > +	.disable = mtk_clk_mux_disable,
> >   	.get_rate = mtk_topckgen_get_rate,
> > -	.set_parent = mtk_topckgen_set_parent,
> > +	.set_parent = mtk_common_clk_set_parent,
> >   };
> >   
> >   const struct clk_ops mtk_clk_gate_ops = {
> > @@ -513,11 +504,22 @@ int mtk_common_clk_init(struct udevice *dev,
> >   			const struct mtk_clk_tree *tree)
> >   {
> >   	struct mtk_clk_priv *priv = dev_get_priv(dev);
> > +	struct udevice *parent;
> > +	int ret;
> >   
> >   	priv->base = dev_read_addr_ptr(dev);
> >   	if (!priv->base)
> >   		return -ENOENT;
> >   
> > +	ret = uclass_get_device_by_phandle(UCLASS_CLK, dev,
> > "clock-parent",
> >   &parent);
> > +	if (ret || !parent) {
> > +		ret = uclass_get_device_by_driver(UCLASS_CLK,
> > +				DM_DRIVER_GET(mtk_clk_apmixedsys),
> > &parent);
> > +		if (ret || !parent)
> > +			return -ENOENT;
> > +	}
> > +
> > +	priv->parent = parent;
> >   	priv->tree = tree;
> >   
> >   	return 0;
> > @@ -528,11 +530,22 @@ int mtk_common_clk_gate_init(struct udevice
> > *dev,
> >   			     const struct mtk_gate *gates)
> >   {
> >   	struct mtk_cg_priv *priv = dev_get_priv(dev);
> > +	struct udevice *parent;
> > +	int ret;
> >   
> >   	priv->base = dev_read_addr_ptr(dev);
> >   	if (!priv->base)
> >   		return -ENOENT;
> >   
> > +	ret = uclass_get_device_by_phandle(UCLASS_CLK, dev,
> > "clock-parent",
> >   &parent);
> 
> Why not just use clk_get?

As I mentioned before, this driver does not register clk udevices, the
clk_get_* won't work, and there's no real parent clocks. We have to
parse the fdt to get the actual top-level clk udevice specified as the
parent clock.

> 
> > +	if (ret || !parent) {
> > +		ret = uclass_get_device_by_driver(UCLASS_CLK,
> > +				DM_DRIVER_GET(mtk_clk_topckgen),
> > &parent);
> > +		if (ret || !parent)
> > +			return -ENOENT;
> > +	}
> > +
> > +	priv->parent = parent;
> >   	priv->tree = tree;
> >   	priv->gates = gates;
> >   
> > diff --git a/drivers/clk/mediatek/clk-mtk.h
> > b/drivers/clk/mediatek/clk-mtk.h
> > index 0ab6912bf0..7955d469db 100644
> > --- a/drivers/clk/mediatek/clk-mtk.h
> > +++ b/drivers/clk/mediatek/clk-mtk.h
> > @@ -203,11 +203,13 @@ struct mtk_clk_tree {
> >   };
> >   
> >   struct mtk_clk_priv {
> > +	struct udevice *parent;
> >   	void __iomem *base;
> >   	const struct mtk_clk_tree *tree;
> >   };
> >   
> >   struct mtk_cg_priv {
> > +	struct udevice *parent;
> >   	void __iomem *base;
> >   	const struct mtk_clk_tree *tree;
> >   	const struct mtk_gate *gates;
> > 
> 
> --Sean


More information about the U-Boot mailing list