1*82a248dfSMarek Behún // SPDX-License-Identifier: GPL-2.0+ 2*82a248dfSMarek Behún /* 3*82a248dfSMarek Behún * Marvell Armada 37xx SoC Peripheral clocks 4*82a248dfSMarek Behún * 5*82a248dfSMarek Behún * Marek Behun <marek.behun@nic.cz> 6*82a248dfSMarek Behún * 7*82a248dfSMarek Behún * Based on Linux driver by: 8*82a248dfSMarek Behún * Gregory CLEMENT <gregory.clement@free-electrons.com> 9*82a248dfSMarek Behún */ 10*82a248dfSMarek Behún 11*82a248dfSMarek Behún #include <common.h> 12*82a248dfSMarek Behún #include <malloc.h> 13*82a248dfSMarek Behún #include <clk-uclass.h> 14*82a248dfSMarek Behún #include <clk.h> 15*82a248dfSMarek Behún #include <dm.h> 16*82a248dfSMarek Behún #include <asm/io.h> 17*82a248dfSMarek Behún #include <asm/arch/cpu.h> 18*82a248dfSMarek Behún 19*82a248dfSMarek Behún #define TBG_SEL 0x0 20*82a248dfSMarek Behún #define DIV_SEL0 0x4 21*82a248dfSMarek Behún #define DIV_SEL1 0x8 22*82a248dfSMarek Behún #define DIV_SEL2 0xC 23*82a248dfSMarek Behún #define CLK_SEL 0x10 24*82a248dfSMarek Behún #define CLK_DIS 0x14 25*82a248dfSMarek Behún 26*82a248dfSMarek Behún enum a37xx_periph_parent { 27*82a248dfSMarek Behún TBG_A_P = 0, 28*82a248dfSMarek Behún TBG_B_P = 1, 29*82a248dfSMarek Behún TBG_A_S = 2, 30*82a248dfSMarek Behún TBG_B_S = 3, 31*82a248dfSMarek Behún MAX_TBG_PARENTS = 4, 32*82a248dfSMarek Behún XTAL = 4, 33*82a248dfSMarek Behún MAX_PARENTS = 5, 34*82a248dfSMarek Behún }; 35*82a248dfSMarek Behún 36*82a248dfSMarek Behún static const struct { 37*82a248dfSMarek Behún const char *name; 38*82a248dfSMarek Behún enum a37xx_periph_parent parent; 39*82a248dfSMarek Behún } a37xx_periph_parent_names[] = { 40*82a248dfSMarek Behún { "TBG-A-P", TBG_A_P }, 41*82a248dfSMarek Behún { "TBG-B-P", TBG_B_P }, 42*82a248dfSMarek Behún { "TBG-A-S", TBG_A_S }, 43*82a248dfSMarek Behún { "TBG-B-S", TBG_B_S }, 44*82a248dfSMarek Behún { "xtal", XTAL }, 45*82a248dfSMarek Behún }; 46*82a248dfSMarek Behún 47*82a248dfSMarek Behún struct clk_periph; 48*82a248dfSMarek Behún 49*82a248dfSMarek Behún struct a37xx_periphclk { 50*82a248dfSMarek Behún void __iomem *reg; 51*82a248dfSMarek Behún 52*82a248dfSMarek Behún ulong parents[MAX_PARENTS]; 53*82a248dfSMarek Behún 54*82a248dfSMarek Behún const struct clk_periph *clks; 55*82a248dfSMarek Behún bool clk_has_periph_parent[16]; 56*82a248dfSMarek Behún int clk_parent[16]; 57*82a248dfSMarek Behún 58*82a248dfSMarek Behún int count; 59*82a248dfSMarek Behún }; 60*82a248dfSMarek Behún 61*82a248dfSMarek Behún struct clk_div_table { 62*82a248dfSMarek Behún u32 div; 63*82a248dfSMarek Behún u32 val; 64*82a248dfSMarek Behún }; 65*82a248dfSMarek Behún 66*82a248dfSMarek Behún struct clk_periph { 67*82a248dfSMarek Behún const char *name; 68*82a248dfSMarek Behún 69*82a248dfSMarek Behún const char *parent_name; 70*82a248dfSMarek Behún 71*82a248dfSMarek Behún u32 disable_bit; 72*82a248dfSMarek Behún int mux_shift; 73*82a248dfSMarek Behún 74*82a248dfSMarek Behún const struct clk_div_table *div_table[2]; 75*82a248dfSMarek Behún s32 div_reg_off[2]; 76*82a248dfSMarek Behún u32 div_mask[2]; 77*82a248dfSMarek Behún int div_shift[2]; 78*82a248dfSMarek Behún 79*82a248dfSMarek Behún unsigned can_gate : 1; 80*82a248dfSMarek Behún unsigned can_mux : 1; 81*82a248dfSMarek Behún unsigned dividers : 2; 82*82a248dfSMarek Behún }; 83*82a248dfSMarek Behún 84*82a248dfSMarek Behún static const struct clk_div_table div_table1[] = { 85*82a248dfSMarek Behún { 1, 1 }, 86*82a248dfSMarek Behún { 2, 2 }, 87*82a248dfSMarek Behún { 0, 0 }, 88*82a248dfSMarek Behún }; 89*82a248dfSMarek Behún 90*82a248dfSMarek Behún static const struct clk_div_table div_table2[] = { 91*82a248dfSMarek Behún { 2, 1 }, 92*82a248dfSMarek Behún { 4, 2 }, 93*82a248dfSMarek Behún { 0, 0 }, 94*82a248dfSMarek Behún }; 95*82a248dfSMarek Behún 96*82a248dfSMarek Behún static const struct clk_div_table div_table6[] = { 97*82a248dfSMarek Behún { 1, 1 }, 98*82a248dfSMarek Behún { 2, 2 }, 99*82a248dfSMarek Behún { 3, 3 }, 100*82a248dfSMarek Behún { 4, 4 }, 101*82a248dfSMarek Behún { 5, 5 }, 102*82a248dfSMarek Behún { 6, 6 }, 103*82a248dfSMarek Behún { 0, 0 }, 104*82a248dfSMarek Behún }; 105*82a248dfSMarek Behún 106*82a248dfSMarek Behún #define CLK_FULL_DD(_n, _d, _mux, _r0, _r1, _s0, _s1) \ 107*82a248dfSMarek Behún { \ 108*82a248dfSMarek Behún .name = #_n, \ 109*82a248dfSMarek Behún .disable_bit = BIT(_d), \ 110*82a248dfSMarek Behún .mux_shift = _mux, \ 111*82a248dfSMarek Behún .div_table[0] = div_table6, \ 112*82a248dfSMarek Behún .div_table[1] = div_table6, \ 113*82a248dfSMarek Behún .div_reg_off[0] = _r0, \ 114*82a248dfSMarek Behún .div_reg_off[1] = _r1, \ 115*82a248dfSMarek Behún .div_shift[0] = _s0, \ 116*82a248dfSMarek Behún .div_shift[1] = _s1, \ 117*82a248dfSMarek Behún .div_mask[0] = 7, \ 118*82a248dfSMarek Behún .div_mask[1] = 7, \ 119*82a248dfSMarek Behún .can_gate = 1, \ 120*82a248dfSMarek Behún .can_mux = 1, \ 121*82a248dfSMarek Behún .dividers = 2, \ 122*82a248dfSMarek Behún } 123*82a248dfSMarek Behún 124*82a248dfSMarek Behún #define CLK_FULL(_n, _d, _mux, _r, _s, _m, _t) \ 125*82a248dfSMarek Behún { \ 126*82a248dfSMarek Behún .name = #_n, \ 127*82a248dfSMarek Behún .disable_bit = BIT(_d), \ 128*82a248dfSMarek Behún .mux_shift = _mux, \ 129*82a248dfSMarek Behún .div_table[0] = _t, \ 130*82a248dfSMarek Behún .div_reg_off[0] = _r, \ 131*82a248dfSMarek Behún .div_shift[0] = _s, \ 132*82a248dfSMarek Behún .div_mask[0] = _m, \ 133*82a248dfSMarek Behún .can_gate = 1, \ 134*82a248dfSMarek Behún .can_mux = 1, \ 135*82a248dfSMarek Behún .dividers = 1, \ 136*82a248dfSMarek Behún } 137*82a248dfSMarek Behún 138*82a248dfSMarek Behún #define CLK_GATE_DIV(_n, _d, _r, _s, _m, _t, _p) \ 139*82a248dfSMarek Behún { \ 140*82a248dfSMarek Behún .name = #_n, \ 141*82a248dfSMarek Behún .parent_name = _p, \ 142*82a248dfSMarek Behún .disable_bit = BIT(_d), \ 143*82a248dfSMarek Behún .div_table[0] = _t, \ 144*82a248dfSMarek Behún .div_reg_off[0] = _r, \ 145*82a248dfSMarek Behún .div_shift[0] = _s, \ 146*82a248dfSMarek Behún .div_mask[0] = _m, \ 147*82a248dfSMarek Behún .can_gate = 1, \ 148*82a248dfSMarek Behún .dividers = 1, \ 149*82a248dfSMarek Behún } 150*82a248dfSMarek Behún 151*82a248dfSMarek Behún #define CLK_GATE(_n, _d, _p) \ 152*82a248dfSMarek Behún { \ 153*82a248dfSMarek Behún .name = #_n, \ 154*82a248dfSMarek Behún .parent_name = _p, \ 155*82a248dfSMarek Behún .disable_bit = BIT(_d), \ 156*82a248dfSMarek Behún .can_gate = 1, \ 157*82a248dfSMarek Behún } 158*82a248dfSMarek Behún 159*82a248dfSMarek Behún #define CLK_MUX_DIV(_n, _mux, _r, _s, _m, _t) \ 160*82a248dfSMarek Behún { \ 161*82a248dfSMarek Behún .name = #_n, \ 162*82a248dfSMarek Behún .mux_shift = _mux, \ 163*82a248dfSMarek Behún .div_table[0] = _t, \ 164*82a248dfSMarek Behún .div_reg_off[0] = _r, \ 165*82a248dfSMarek Behún .div_shift[0] = _s, \ 166*82a248dfSMarek Behún .div_mask[0] = _m, \ 167*82a248dfSMarek Behún .can_mux = 1, \ 168*82a248dfSMarek Behún .dividers = 1, \ 169*82a248dfSMarek Behún } 170*82a248dfSMarek Behún 171*82a248dfSMarek Behún #define CLK_MUX_DD(_n, _mux, _r0, _r1, _s0, _s1) \ 172*82a248dfSMarek Behún { \ 173*82a248dfSMarek Behún .name = #_n, \ 174*82a248dfSMarek Behún .mux_shift = _mux, \ 175*82a248dfSMarek Behún .div_table[0] = div_table6, \ 176*82a248dfSMarek Behún .div_table[1] = div_table6, \ 177*82a248dfSMarek Behún .div_reg_off[0] = _r0, \ 178*82a248dfSMarek Behún .div_reg_off[1] = _r1, \ 179*82a248dfSMarek Behún .div_shift[0] = _s0, \ 180*82a248dfSMarek Behún .div_shift[1] = _s1, \ 181*82a248dfSMarek Behún .div_mask[0] = 7, \ 182*82a248dfSMarek Behún .div_mask[1] = 7, \ 183*82a248dfSMarek Behún .can_mux = 1, \ 184*82a248dfSMarek Behún .dividers = 2, \ 185*82a248dfSMarek Behún } 186*82a248dfSMarek Behún 187*82a248dfSMarek Behún /* NB periph clocks */ 188*82a248dfSMarek Behún static const struct clk_periph clks_nb[] = { 189*82a248dfSMarek Behún CLK_FULL_DD(mmc, 2, 0, DIV_SEL2, DIV_SEL2, 16, 13), 190*82a248dfSMarek Behún CLK_FULL_DD(sata_host, 3, 2, DIV_SEL2, DIV_SEL2, 10, 7), 191*82a248dfSMarek Behún CLK_FULL_DD(sec_at, 6, 4, DIV_SEL1, DIV_SEL1, 3, 0), 192*82a248dfSMarek Behún CLK_FULL_DD(sec_dap, 7, 6, DIV_SEL1, DIV_SEL1, 9, 6), 193*82a248dfSMarek Behún CLK_FULL_DD(tscem, 8, 8, DIV_SEL1, DIV_SEL1, 15, 12), 194*82a248dfSMarek Behún CLK_FULL(tscem_tmx, 10, 10, DIV_SEL1, 18, 7, div_table6), 195*82a248dfSMarek Behún CLK_GATE(avs, 11, "xtal"), 196*82a248dfSMarek Behún CLK_FULL_DD(sqf, 12, 12, DIV_SEL1, DIV_SEL1, 27, 24), 197*82a248dfSMarek Behún CLK_FULL_DD(pwm, 13, 14, DIV_SEL0, DIV_SEL0, 3, 0), 198*82a248dfSMarek Behún CLK_GATE(i2c_2, 16, "xtal"), 199*82a248dfSMarek Behún CLK_GATE(i2c_1, 17, "xtal"), 200*82a248dfSMarek Behún CLK_GATE_DIV(ddr_phy, 19, DIV_SEL0, 18, 1, div_table2, "TBG-A-S"), 201*82a248dfSMarek Behún CLK_FULL_DD(ddr_fclk, 21, 16, DIV_SEL0, DIV_SEL0, 15, 12), 202*82a248dfSMarek Behún CLK_FULL(trace, 22, 18, DIV_SEL0, 20, 7, div_table6), 203*82a248dfSMarek Behún CLK_FULL(counter, 23, 20, DIV_SEL0, 23, 7, div_table6), 204*82a248dfSMarek Behún CLK_FULL_DD(eip97, 24, 24, DIV_SEL2, DIV_SEL2, 22, 19), 205*82a248dfSMarek Behún CLK_MUX_DIV(cpu, 22, DIV_SEL0, 28, 7, div_table6), 206*82a248dfSMarek Behún { }, 207*82a248dfSMarek Behún }; 208*82a248dfSMarek Behún 209*82a248dfSMarek Behún /* SB periph clocks */ 210*82a248dfSMarek Behún static const struct clk_periph clks_sb[] = { 211*82a248dfSMarek Behún CLK_MUX_DD(gbe_50, 6, DIV_SEL2, DIV_SEL2, 6, 9), 212*82a248dfSMarek Behún CLK_MUX_DD(gbe_core, 8, DIV_SEL1, DIV_SEL1, 18, 21), 213*82a248dfSMarek Behún CLK_MUX_DD(gbe_125, 10, DIV_SEL1, DIV_SEL1, 6, 9), 214*82a248dfSMarek Behún CLK_GATE(gbe1_50, 0, "gbe_50"), 215*82a248dfSMarek Behún CLK_GATE(gbe0_50, 1, "gbe_50"), 216*82a248dfSMarek Behún CLK_GATE(gbe1_125, 2, "gbe_125"), 217*82a248dfSMarek Behún CLK_GATE(gbe0_125, 3, "gbe_125"), 218*82a248dfSMarek Behún CLK_GATE_DIV(gbe1_core, 4, DIV_SEL1, 13, 1, div_table1, "gbe_core"), 219*82a248dfSMarek Behún CLK_GATE_DIV(gbe0_core, 5, DIV_SEL1, 14, 1, div_table1, "gbe_core"), 220*82a248dfSMarek Behún CLK_GATE_DIV(gbe_bm, 12, DIV_SEL1, 0, 1, div_table1, "gbe_core"), 221*82a248dfSMarek Behún CLK_FULL_DD(sdio, 11, 14, DIV_SEL0, DIV_SEL0, 3, 6), 222*82a248dfSMarek Behún CLK_FULL_DD(usb32_usb2_sys, 16, 16, DIV_SEL0, DIV_SEL0, 9, 12), 223*82a248dfSMarek Behún CLK_FULL_DD(usb32_ss_sys, 17, 18, DIV_SEL0, DIV_SEL0, 15, 18), 224*82a248dfSMarek Behún { }, 225*82a248dfSMarek Behún }; 226*82a248dfSMarek Behún 227*82a248dfSMarek Behún static inline int get_mux(struct a37xx_periphclk *priv, int shift) 228*82a248dfSMarek Behún { 229*82a248dfSMarek Behún return (readl(priv->reg + TBG_SEL) >> shift) & 3; 230*82a248dfSMarek Behún } 231*82a248dfSMarek Behún 232*82a248dfSMarek Behún static ulong periph_clk_get_rate(struct a37xx_periphclk *priv, int id); 233*82a248dfSMarek Behún 234*82a248dfSMarek Behún static ulong get_parent_rate(struct a37xx_periphclk *priv, int id) 235*82a248dfSMarek Behún { 236*82a248dfSMarek Behún const struct clk_periph *clk = &priv->clks[id]; 237*82a248dfSMarek Behún ulong res; 238*82a248dfSMarek Behún 239*82a248dfSMarek Behún if (clk->can_mux) { 240*82a248dfSMarek Behún /* parent is one of TBG clocks */ 241*82a248dfSMarek Behún int tbg = get_mux(priv, clk->mux_shift); 242*82a248dfSMarek Behún 243*82a248dfSMarek Behún res = priv->parents[tbg]; 244*82a248dfSMarek Behún } else if (priv->clk_has_periph_parent[id]) { 245*82a248dfSMarek Behún /* parent is one of other periph clocks */ 246*82a248dfSMarek Behún 247*82a248dfSMarek Behún if (priv->clk_parent[id] >= priv->count) 248*82a248dfSMarek Behún return -EINVAL; 249*82a248dfSMarek Behún 250*82a248dfSMarek Behún res = periph_clk_get_rate(priv, priv->clk_parent[id]); 251*82a248dfSMarek Behún } else { 252*82a248dfSMarek Behún /* otherwise parent is one of TBGs or XTAL */ 253*82a248dfSMarek Behún 254*82a248dfSMarek Behún if (priv->clk_parent[id] >= MAX_PARENTS) 255*82a248dfSMarek Behún return -EINVAL; 256*82a248dfSMarek Behún 257*82a248dfSMarek Behún res = priv->parents[priv->clk_parent[id]]; 258*82a248dfSMarek Behún } 259*82a248dfSMarek Behún 260*82a248dfSMarek Behún return res; 261*82a248dfSMarek Behún } 262*82a248dfSMarek Behún 263*82a248dfSMarek Behún static ulong get_div(struct a37xx_periphclk *priv, 264*82a248dfSMarek Behún const struct clk_periph *clk, int idx) 265*82a248dfSMarek Behún { 266*82a248dfSMarek Behún const struct clk_div_table *i; 267*82a248dfSMarek Behún u32 reg; 268*82a248dfSMarek Behún 269*82a248dfSMarek Behún reg = readl(priv->reg + clk->div_reg_off[idx]); 270*82a248dfSMarek Behún reg = (reg >> clk->div_shift[idx]) & clk->div_mask[idx]; 271*82a248dfSMarek Behún 272*82a248dfSMarek Behún /* find divisor for register value val */ 273*82a248dfSMarek Behún for (i = clk->div_table[idx]; i && i->div != 0; ++i) 274*82a248dfSMarek Behún if (i->val == reg) 275*82a248dfSMarek Behún return i->div; 276*82a248dfSMarek Behún 277*82a248dfSMarek Behún return 0; 278*82a248dfSMarek Behún } 279*82a248dfSMarek Behún 280*82a248dfSMarek Behún static ulong periph_clk_get_rate(struct a37xx_periphclk *priv, int id) 281*82a248dfSMarek Behún { 282*82a248dfSMarek Behún const struct clk_periph *clk = &priv->clks[id]; 283*82a248dfSMarek Behún ulong rate, div; 284*82a248dfSMarek Behún int i; 285*82a248dfSMarek Behún 286*82a248dfSMarek Behún rate = get_parent_rate(priv, id); 287*82a248dfSMarek Behún if (rate == -EINVAL) 288*82a248dfSMarek Behún return -EINVAL; 289*82a248dfSMarek Behún 290*82a248dfSMarek Behún /* divide the parent rate by dividers */ 291*82a248dfSMarek Behún div = 1; 292*82a248dfSMarek Behún for (i = 0; i < clk->dividers; ++i) 293*82a248dfSMarek Behún div *= get_div(priv, clk, i); 294*82a248dfSMarek Behún 295*82a248dfSMarek Behún if (!div) 296*82a248dfSMarek Behún return 0; 297*82a248dfSMarek Behún 298*82a248dfSMarek Behún return DIV_ROUND_UP(rate, div); 299*82a248dfSMarek Behún } 300*82a248dfSMarek Behún 301*82a248dfSMarek Behún static ulong armada_37xx_periph_clk_get_rate(struct clk *clk) 302*82a248dfSMarek Behún { 303*82a248dfSMarek Behún struct a37xx_periphclk *priv = dev_get_priv(clk->dev); 304*82a248dfSMarek Behún 305*82a248dfSMarek Behún if (clk->id >= priv->count) 306*82a248dfSMarek Behún return -EINVAL; 307*82a248dfSMarek Behún 308*82a248dfSMarek Behún return periph_clk_get_rate(priv, clk->id); 309*82a248dfSMarek Behún } 310*82a248dfSMarek Behún 311*82a248dfSMarek Behún static int periph_clk_enable(struct clk *clk, int enable) 312*82a248dfSMarek Behún { 313*82a248dfSMarek Behún struct a37xx_periphclk *priv = dev_get_priv(clk->dev); 314*82a248dfSMarek Behún const struct clk_periph *periph_clk = &priv->clks[clk->id]; 315*82a248dfSMarek Behún 316*82a248dfSMarek Behún if (clk->id >= priv->count) 317*82a248dfSMarek Behún return -EINVAL; 318*82a248dfSMarek Behún 319*82a248dfSMarek Behún if (!periph_clk->can_gate) 320*82a248dfSMarek Behún return -ENOTSUPP; 321*82a248dfSMarek Behún 322*82a248dfSMarek Behún if (enable) 323*82a248dfSMarek Behún clrbits_le32(priv->reg + CLK_DIS, periph_clk->disable_bit); 324*82a248dfSMarek Behún else 325*82a248dfSMarek Behún setbits_le32(priv->reg + CLK_DIS, periph_clk->disable_bit); 326*82a248dfSMarek Behún 327*82a248dfSMarek Behún return 0; 328*82a248dfSMarek Behún } 329*82a248dfSMarek Behún 330*82a248dfSMarek Behún static int armada_37xx_periph_clk_enable(struct clk *clk) 331*82a248dfSMarek Behún { 332*82a248dfSMarek Behún return periph_clk_enable(clk, 1); 333*82a248dfSMarek Behún } 334*82a248dfSMarek Behún 335*82a248dfSMarek Behún static int armada_37xx_periph_clk_disable(struct clk *clk) 336*82a248dfSMarek Behún { 337*82a248dfSMarek Behún return periph_clk_enable(clk, 0); 338*82a248dfSMarek Behún } 339*82a248dfSMarek Behún 340*82a248dfSMarek Behún int armada_37xx_periph_clk_dump(struct udevice *dev) 341*82a248dfSMarek Behún { 342*82a248dfSMarek Behún struct a37xx_periphclk *priv = dev_get_priv(dev); 343*82a248dfSMarek Behún const struct clk_periph *clks; 344*82a248dfSMarek Behún int i; 345*82a248dfSMarek Behún 346*82a248dfSMarek Behún if (!priv) 347*82a248dfSMarek Behún return -ENODEV; 348*82a248dfSMarek Behún 349*82a248dfSMarek Behún clks = priv->clks; 350*82a248dfSMarek Behún 351*82a248dfSMarek Behún for (i = 0; i < priv->count; ++i) 352*82a248dfSMarek Behún printf(" %s at %lu Hz\n", clks[i].name, 353*82a248dfSMarek Behún periph_clk_get_rate(priv, i)); 354*82a248dfSMarek Behún printf("\n"); 355*82a248dfSMarek Behún 356*82a248dfSMarek Behún return 0; 357*82a248dfSMarek Behún } 358*82a248dfSMarek Behún 359*82a248dfSMarek Behún static int armada_37xx_periph_clk_probe(struct udevice *dev) 360*82a248dfSMarek Behún { 361*82a248dfSMarek Behún struct a37xx_periphclk *priv = dev_get_priv(dev); 362*82a248dfSMarek Behún const struct clk_periph *clks; 363*82a248dfSMarek Behún int ret, i; 364*82a248dfSMarek Behún 365*82a248dfSMarek Behún clks = (const struct clk_periph *)dev_get_driver_data(dev); 366*82a248dfSMarek Behún if (!clks) 367*82a248dfSMarek Behún return -ENODEV; 368*82a248dfSMarek Behún 369*82a248dfSMarek Behún priv->reg = dev_read_addr_ptr(dev); 370*82a248dfSMarek Behún if (!priv->reg) { 371*82a248dfSMarek Behún dev_err(dev, "no io address\n"); 372*82a248dfSMarek Behún return -ENODEV; 373*82a248dfSMarek Behún } 374*82a248dfSMarek Behún 375*82a248dfSMarek Behún /* count clk_periph nodes */ 376*82a248dfSMarek Behún priv->count = 0; 377*82a248dfSMarek Behún while (clks[priv->count].name) 378*82a248dfSMarek Behún priv->count++; 379*82a248dfSMarek Behún 380*82a248dfSMarek Behún priv->clks = clks; 381*82a248dfSMarek Behún 382*82a248dfSMarek Behún /* assign parent IDs to nodes which have non-NULL parent_name */ 383*82a248dfSMarek Behún for (i = 0; i < priv->count; ++i) { 384*82a248dfSMarek Behún int j; 385*82a248dfSMarek Behún 386*82a248dfSMarek Behún if (!clks[i].parent_name) 387*82a248dfSMarek Behún continue; 388*82a248dfSMarek Behún 389*82a248dfSMarek Behún /* first try if parent_name is one of TBGs or XTAL */ 390*82a248dfSMarek Behún for (j = 0; j < MAX_PARENTS; ++j) 391*82a248dfSMarek Behún if (!strcmp(clks[i].parent_name, 392*82a248dfSMarek Behún a37xx_periph_parent_names[j].name)) 393*82a248dfSMarek Behún break; 394*82a248dfSMarek Behún 395*82a248dfSMarek Behún if (j < MAX_PARENTS) { 396*82a248dfSMarek Behún priv->clk_has_periph_parent[i] = false; 397*82a248dfSMarek Behún priv->clk_parent[i] = 398*82a248dfSMarek Behún a37xx_periph_parent_names[j].parent; 399*82a248dfSMarek Behún continue; 400*82a248dfSMarek Behún } 401*82a248dfSMarek Behún 402*82a248dfSMarek Behún /* else parent_name should be one of other periph clocks */ 403*82a248dfSMarek Behún for (j = 0; j < priv->count; ++j) { 404*82a248dfSMarek Behún if (!strcmp(clks[i].parent_name, clks[j].name)) 405*82a248dfSMarek Behún break; 406*82a248dfSMarek Behún } 407*82a248dfSMarek Behún 408*82a248dfSMarek Behún if (j < priv->count) { 409*82a248dfSMarek Behún priv->clk_has_periph_parent[i] = true; 410*82a248dfSMarek Behún priv->clk_parent[i] = j; 411*82a248dfSMarek Behún continue; 412*82a248dfSMarek Behún } 413*82a248dfSMarek Behún 414*82a248dfSMarek Behún dev_err(dev, "undefined parent %s\n", clks[i].parent_name); 415*82a248dfSMarek Behún return -EINVAL; 416*82a248dfSMarek Behún } 417*82a248dfSMarek Behún 418*82a248dfSMarek Behún for (i = 0; i < MAX_PARENTS; ++i) { 419*82a248dfSMarek Behún struct clk clk; 420*82a248dfSMarek Behún 421*82a248dfSMarek Behún if (i == XTAL) { 422*82a248dfSMarek Behún priv->parents[i] = get_ref_clk() * 1000000; 423*82a248dfSMarek Behún continue; 424*82a248dfSMarek Behún } 425*82a248dfSMarek Behún 426*82a248dfSMarek Behún ret = clk_get_by_index(dev, i, &clk); 427*82a248dfSMarek Behún if (ret) { 428*82a248dfSMarek Behún dev_err(dev, "one of parent clocks (%i) missing: %i\n", 429*82a248dfSMarek Behún i, ret); 430*82a248dfSMarek Behún return -ENODEV; 431*82a248dfSMarek Behún } 432*82a248dfSMarek Behún 433*82a248dfSMarek Behún priv->parents[i] = clk_get_rate(&clk); 434*82a248dfSMarek Behún clk_free(&clk); 435*82a248dfSMarek Behún } 436*82a248dfSMarek Behún 437*82a248dfSMarek Behún return 0; 438*82a248dfSMarek Behún } 439*82a248dfSMarek Behún 440*82a248dfSMarek Behún static const struct clk_ops armada_37xx_periph_clk_ops = { 441*82a248dfSMarek Behún .get_rate = armada_37xx_periph_clk_get_rate, 442*82a248dfSMarek Behún .enable = armada_37xx_periph_clk_enable, 443*82a248dfSMarek Behún .disable = armada_37xx_periph_clk_disable, 444*82a248dfSMarek Behún }; 445*82a248dfSMarek Behún 446*82a248dfSMarek Behún static const struct udevice_id armada_37xx_periph_clk_ids[] = { 447*82a248dfSMarek Behún { 448*82a248dfSMarek Behún .compatible = "marvell,armada-3700-periph-clock-nb", 449*82a248dfSMarek Behún .data = (ulong)clks_nb, 450*82a248dfSMarek Behún }, 451*82a248dfSMarek Behún { 452*82a248dfSMarek Behún .compatible = "marvell,armada-3700-periph-clock-sb", 453*82a248dfSMarek Behún .data = (ulong)clks_sb, 454*82a248dfSMarek Behún }, 455*82a248dfSMarek Behún {} 456*82a248dfSMarek Behún }; 457*82a248dfSMarek Behún 458*82a248dfSMarek Behún U_BOOT_DRIVER(armada_37xx_periph_clk) = { 459*82a248dfSMarek Behún .name = "armada_37xx_periph_clk", 460*82a248dfSMarek Behún .id = UCLASS_CLK, 461*82a248dfSMarek Behún .of_match = armada_37xx_periph_clk_ids, 462*82a248dfSMarek Behún .ops = &armada_37xx_periph_clk_ops, 463*82a248dfSMarek Behún .priv_auto_alloc_size = sizeof(struct a37xx_periphclk), 464*82a248dfSMarek Behún .probe = armada_37xx_periph_clk_probe, 465*82a248dfSMarek Behún }; 466