From mboxrd@z Thu Jan 1 00:00:00 1970 From: Heiko =?ISO-8859-1?Q?St=FCbner?= Date: Sun, 17 Jul 2016 17:33:41 +0200 Subject: [U-Boot] [PATCH 9/9] rockchip: rk3188: Add clock driver In-Reply-To: References: <1468621041-11487-1-git-send-email-heiko@sntech.de> <1468621041-11487-10-git-send-email-heiko@sntech.de> Message-ID: <3005812.9fWFW3yNq8@diego> List-Id: MIME-Version: 1.0 Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7bit To: u-boot@lists.denx.de Am Sonntag, 17. Juli 2016, 08:13:58 schrieb Simon Glass: > Hi Heiko, > > On 15 July 2016 at 16:17, Heiko Stuebner wrote: > > Add a driver for setting up and modifying the various PLLs and peripheral > > clocks on the RK3188. > > > > Signed-off-by: Heiko Stuebner > > --- > > > > arch/arm/include/asm/arch-rockchip/cru_rk3188.h | 186 ++++++++++ > > drivers/clk/Makefile | 1 + > > drivers/clk/clk_rk3188.c | 464 > > ++++++++++++++++++++++++ 3 files changed, 651 insertions(+) > > create mode 100644 arch/arm/include/asm/arch-rockchip/cru_rk3188.h > > create mode 100644 drivers/clk/clk_rk3188.c > > Could you add a patch to move these files into a drivers/clk/rockchip > directory? ok > > new file mode 100644 > > index 0000000..4c28393 > > --- /dev/null > > +++ b/drivers/clk/clk_rk3188.c > > @@ -0,0 +1,465 @@ > > +/* > > + * (C) Copyright 2015 Google, Inc > > + * (C) Copyright 2016 Heiko Stuebner > > + * > > + * SPDX-License-Identifier: GPL-2.0 > > + */ > > + > > +#include > > +#include > > +#include > > +#include > > +#include > > +#include > > +#include > > +#include > > +#include > > +#include > > +#include > > +#include > > +#include > > +#include > > + > > +DECLARE_GLOBAL_DATA_PTR; > > + > > +struct rk3188_clk_priv { > > + struct rk3188_grf *grf; > > + struct rk3188_cru *cru; > > + ulong rate; > > + bool has_bwadj; > > +}; > > + > > +struct pll_div { > > + u32 nr; > > + u32 nf; > > + u32 no; > > +}; > > + > > +enum { > > + VCO_MAX_HZ = 2200U * 1000000, > > + VCO_MIN_HZ = 440 * 1000000, > > + OUTPUT_MAX_HZ = 2200U * 1000000, > > + OUTPUT_MIN_HZ = 30 * 1000000, > > + FREF_MAX_HZ = 2200U * 1000000, > > + FREF_MIN_HZ = 30 * 1000, > > +}; > > + > > +enum { > > + /* PLL CON0 */ > > + PLL_OD_MASK = 0x0f, > > + > > + /* PLL CON1 */ > > + PLL_NF_MASK = 0x1fff, > > + > > + /* PLL CON2 */ > > + PLL_BWADJ_MASK = 0x0fff, > > + > > + /* PLL CON3 */ > > + PLL_RESET_SHIFT = 5, > > + > > + /* GRF_SOC_STATUS0 */ > > + SOCSTS_DPLL_LOCK = 1 << 5, > > + SOCSTS_APLL_LOCK = 1 << 6, > > + SOCSTS_CPLL_LOCK = 1 << 7, > > + SOCSTS_GPLL_LOCK = 1 << 8, > > +}; > > + > > +#define RATE_TO_DIV(input_rate, output_rate) \ > > + ((input_rate) / (output_rate) - 1); > > + > > +#define DIV_TO_RATE(input_rate, div) ((input_rate) / ((div) + 1)) > > + > > +#define PLL_DIVISORS(hz, _nr, _no) {\ > > + .nr = _nr, .nf = (u32)((u64)hz * _nr * _no / OSC_HZ), .no = _no};\ > > + _Static_assert(((u64)hz * _nr * _no / OSC_HZ) * OSC_HZ /\ > > + (_nr * _no) == hz, #hz "Hz cannot be hit with PLL > > "\ > > + "divisors on line " __stringify(__LINE__)); > > + > > +/* Keep divisors as low as possible to reduce jitter and power usage */ > > +static const struct pll_div apll_init_cfg = PLL_DIVISORS(APLL_HZ, 1, 1); > > +static const struct pll_div gpll_init_cfg = PLL_DIVISORS(GPLL_HZ, 2, 2); > > +static const struct pll_div cpll_init_cfg = PLL_DIVISORS(CPLL_HZ, 1, 2); > > + > > +void *rockchip_get_cru(void) > > +{ > > + struct rk3188_clk_priv *priv; > > + struct udevice *dev; > > + int ret; > > + > > + ret = uclass_get_device_by_name(UCLASS_CLK, > > + "clock-controller at 20000000", > > &dev); > > This seems odd. Could you use uclass_get_device(UCLASS_CLK, 0, .&dev) ? Index 0 actually gets me the 24MHz oscillator fixed clock :-), which is why I switched to the by-name variant to not depend on some dts or uclass ordering. I'm wondering how that works on the other socs. > > > + if (ret) > > + return ERR_PTR(ret); > > + > > + priv = dev_get_priv(dev); > > + > > + return priv->cru; > > +} > > + > > +static int rkclk_set_pll(struct rk3188_cru *cru, enum rk_clk_id clk_id, > > + const struct pll_div *div, bool has_bwadj) > > +{ > > + int pll_id = rk_pll_id(clk_id); > > + struct rk3188_pll *pll = &cru->pll[pll_id]; > > + /* All PLLs have same VCO and output frequency range restrictions. > > */ + uint vco_hz = OSC_HZ / 1000 * div->nf / div->nr * 1000; > > + uint output_hz = vco_hz / div->no; > > + > > + debug("PLL at %x: nf=%d, nr=%d, no=%d, vco=%u Hz, output=%u Hz\n", > > + (uint)pll, div->nf, div->nr, div->no, vco_hz, output_hz); > > + assert(vco_hz >= VCO_MIN_HZ && vco_hz <= VCO_MAX_HZ && > > + output_hz >= OUTPUT_MIN_HZ && output_hz <= OUTPUT_MAX_HZ && > > + (div->no == 1 || !(div->no % 2))); > > + > > + /* enter reset */ > > + rk_setreg(&pll->con3, 1 << PLL_RESET_SHIFT); > > + > > + rk_clrsetreg(&pll->con0, > > + CLKR_MASK << CLKR_SHIFT | PLL_OD_MASK, > > + ((div->nr - 1) << CLKR_SHIFT) | (div->no - 1)); > > + rk_clrsetreg(&pll->con1, CLKF_MASK, div->nf - 1); > > + > > + if (has_bwadj) > > + rk_clrsetreg(&pll->con2, PLL_BWADJ_MASK, (div->nf >> 1) - > > 1); + > > + udelay(10); > > + > > + /* return from reset */ > > + rk_clrreg(&pll->con3, 1 << PLL_RESET_SHIFT); > > + > > + return 0; > > +} > > + > > +static inline unsigned int log2(unsigned int value) > > Hmm this should go in a common file. Perhaps bitfield.h or common.h? it looks like uboot is already carrying ilog2() in include/linux/log2.h ? [...] > > +static int rk3188_clk_probe(struct udevice *dev) > > +{ > > + struct rk3188_clk_priv *priv = dev_get_priv(dev); > > + > > + priv->cru = (struct rk3188_cru *)dev_get_addr(dev); > > + priv->grf = syscon_get_first_range(ROCKCHIP_SYSCON_GRF); > > + priv->has_bwadj = of_device_is_compatible(dev, > > "rockchip,rk3188a-cru") + ? 1 : 0; > > You should add a .data member to your udevice_id array below using a > two-member enum, and check dev_get_driver_data() here. ah, nice to know. I was wondering if and how uboot was handling .data stuff but my short skimming through the sources didn't reveal that. Will change. Heiko