1*a0e79083SPurna Chandra Mandal /* 2*a0e79083SPurna Chandra Mandal * Copyright (C) 2015 Purna Chandra Mandal <purna.mandal@microchip.com> 3*a0e79083SPurna Chandra Mandal * 4*a0e79083SPurna Chandra Mandal * SPDX-License-Identifier: GPL-2.0+ 5*a0e79083SPurna Chandra Mandal * 6*a0e79083SPurna Chandra Mandal */ 7*a0e79083SPurna Chandra Mandal 8*a0e79083SPurna Chandra Mandal #include <common.h> 9*a0e79083SPurna Chandra Mandal #include <clk.h> 10*a0e79083SPurna Chandra Mandal #include <dm.h> 11*a0e79083SPurna Chandra Mandal #include <div64.h> 12*a0e79083SPurna Chandra Mandal #include <wait_bit.h> 13*a0e79083SPurna Chandra Mandal #include <dm/lists.h> 14*a0e79083SPurna Chandra Mandal #include <asm/io.h> 15*a0e79083SPurna Chandra Mandal #include <mach/pic32.h> 16*a0e79083SPurna Chandra Mandal #include <dt-bindings/clock/microchip,clock.h> 17*a0e79083SPurna Chandra Mandal 18*a0e79083SPurna Chandra Mandal DECLARE_GLOBAL_DATA_PTR; 19*a0e79083SPurna Chandra Mandal 20*a0e79083SPurna Chandra Mandal /* Primary oscillator */ 21*a0e79083SPurna Chandra Mandal #define SYS_POSC_CLK_HZ 24000000 22*a0e79083SPurna Chandra Mandal 23*a0e79083SPurna Chandra Mandal /* FRC clk rate */ 24*a0e79083SPurna Chandra Mandal #define SYS_FRC_CLK_HZ 8000000 25*a0e79083SPurna Chandra Mandal 26*a0e79083SPurna Chandra Mandal /* Clock Registers */ 27*a0e79083SPurna Chandra Mandal #define OSCCON 0x0000 28*a0e79083SPurna Chandra Mandal #define OSCTUNE 0x0010 29*a0e79083SPurna Chandra Mandal #define SPLLCON 0x0020 30*a0e79083SPurna Chandra Mandal #define REFO1CON 0x0080 31*a0e79083SPurna Chandra Mandal #define REFO1TRIM 0x0090 32*a0e79083SPurna Chandra Mandal #define PB1DIV 0x0140 33*a0e79083SPurna Chandra Mandal 34*a0e79083SPurna Chandra Mandal /* SPLL */ 35*a0e79083SPurna Chandra Mandal #define ICLK_MASK 0x00000080 36*a0e79083SPurna Chandra Mandal #define PLLIDIV_MASK 0x00000007 37*a0e79083SPurna Chandra Mandal #define PLLODIV_MASK 0x00000007 38*a0e79083SPurna Chandra Mandal #define CUROSC_MASK 0x00000007 39*a0e79083SPurna Chandra Mandal #define PLLMUL_MASK 0x0000007F 40*a0e79083SPurna Chandra Mandal #define FRCDIV_MASK 0x00000007 41*a0e79083SPurna Chandra Mandal 42*a0e79083SPurna Chandra Mandal /* PBCLK */ 43*a0e79083SPurna Chandra Mandal #define PBDIV_MASK 0x00000007 44*a0e79083SPurna Chandra Mandal 45*a0e79083SPurna Chandra Mandal /* SYSCLK MUX */ 46*a0e79083SPurna Chandra Mandal #define SCLK_SRC_FRC1 0 47*a0e79083SPurna Chandra Mandal #define SCLK_SRC_SPLL 1 48*a0e79083SPurna Chandra Mandal #define SCLK_SRC_POSC 2 49*a0e79083SPurna Chandra Mandal #define SCLK_SRC_FRC2 7 50*a0e79083SPurna Chandra Mandal 51*a0e79083SPurna Chandra Mandal /* Reference Oscillator Control Reg fields */ 52*a0e79083SPurna Chandra Mandal #define REFO_SEL_MASK 0x0f 53*a0e79083SPurna Chandra Mandal #define REFO_SEL_SHIFT 0 54*a0e79083SPurna Chandra Mandal #define REFO_ACTIVE BIT(8) 55*a0e79083SPurna Chandra Mandal #define REFO_DIVSW_EN BIT(9) 56*a0e79083SPurna Chandra Mandal #define REFO_OE BIT(12) 57*a0e79083SPurna Chandra Mandal #define REFO_ON BIT(15) 58*a0e79083SPurna Chandra Mandal #define REFO_DIV_SHIFT 16 59*a0e79083SPurna Chandra Mandal #define REFO_DIV_MASK 0x7fff 60*a0e79083SPurna Chandra Mandal 61*a0e79083SPurna Chandra Mandal /* Reference Oscillator Trim Register Fields */ 62*a0e79083SPurna Chandra Mandal #define REFO_TRIM_REG 0x10 63*a0e79083SPurna Chandra Mandal #define REFO_TRIM_MASK 0x1ff 64*a0e79083SPurna Chandra Mandal #define REFO_TRIM_SHIFT 23 65*a0e79083SPurna Chandra Mandal #define REFO_TRIM_MAX 511 66*a0e79083SPurna Chandra Mandal 67*a0e79083SPurna Chandra Mandal #define ROCLK_SRC_SCLK 0x0 68*a0e79083SPurna Chandra Mandal #define ROCLK_SRC_SPLL 0x7 69*a0e79083SPurna Chandra Mandal #define ROCLK_SRC_ROCLKI 0x8 70*a0e79083SPurna Chandra Mandal 71*a0e79083SPurna Chandra Mandal /* Memory PLL */ 72*a0e79083SPurna Chandra Mandal #define MPLL_IDIV 0x3f 73*a0e79083SPurna Chandra Mandal #define MPLL_MULT 0xff 74*a0e79083SPurna Chandra Mandal #define MPLL_ODIV1 0x7 75*a0e79083SPurna Chandra Mandal #define MPLL_ODIV2 0x7 76*a0e79083SPurna Chandra Mandal #define MPLL_VREG_RDY BIT(23) 77*a0e79083SPurna Chandra Mandal #define MPLL_RDY BIT(31) 78*a0e79083SPurna Chandra Mandal #define MPLL_IDIV_SHIFT 0 79*a0e79083SPurna Chandra Mandal #define MPLL_MULT_SHIFT 8 80*a0e79083SPurna Chandra Mandal #define MPLL_ODIV1_SHIFT 24 81*a0e79083SPurna Chandra Mandal #define MPLL_ODIV2_SHIFT 27 82*a0e79083SPurna Chandra Mandal #define MPLL_IDIV_INIT 0x03 83*a0e79083SPurna Chandra Mandal #define MPLL_MULT_INIT 0x32 84*a0e79083SPurna Chandra Mandal #define MPLL_ODIV1_INIT 0x02 85*a0e79083SPurna Chandra Mandal #define MPLL_ODIV2_INIT 0x01 86*a0e79083SPurna Chandra Mandal 87*a0e79083SPurna Chandra Mandal struct pic32_clk_priv { 88*a0e79083SPurna Chandra Mandal void __iomem *iobase; 89*a0e79083SPurna Chandra Mandal void __iomem *syscfg_base; 90*a0e79083SPurna Chandra Mandal }; 91*a0e79083SPurna Chandra Mandal 92*a0e79083SPurna Chandra Mandal static ulong pic32_get_pll_rate(struct pic32_clk_priv *priv) 93*a0e79083SPurna Chandra Mandal { 94*a0e79083SPurna Chandra Mandal u32 iclk, idiv, odiv, mult; 95*a0e79083SPurna Chandra Mandal ulong plliclk, v; 96*a0e79083SPurna Chandra Mandal 97*a0e79083SPurna Chandra Mandal v = readl(priv->iobase + SPLLCON); 98*a0e79083SPurna Chandra Mandal iclk = (v & ICLK_MASK); 99*a0e79083SPurna Chandra Mandal idiv = ((v >> 8) & PLLIDIV_MASK) + 1; 100*a0e79083SPurna Chandra Mandal odiv = ((v >> 24) & PLLODIV_MASK); 101*a0e79083SPurna Chandra Mandal mult = ((v >> 16) & PLLMUL_MASK) + 1; 102*a0e79083SPurna Chandra Mandal 103*a0e79083SPurna Chandra Mandal plliclk = iclk ? SYS_FRC_CLK_HZ : SYS_POSC_CLK_HZ; 104*a0e79083SPurna Chandra Mandal 105*a0e79083SPurna Chandra Mandal if (odiv < 2) 106*a0e79083SPurna Chandra Mandal odiv = 2; 107*a0e79083SPurna Chandra Mandal else if (odiv < 5) 108*a0e79083SPurna Chandra Mandal odiv = (1 << odiv); 109*a0e79083SPurna Chandra Mandal else 110*a0e79083SPurna Chandra Mandal odiv = 32; 111*a0e79083SPurna Chandra Mandal 112*a0e79083SPurna Chandra Mandal return ((plliclk / idiv) * mult) / odiv; 113*a0e79083SPurna Chandra Mandal } 114*a0e79083SPurna Chandra Mandal 115*a0e79083SPurna Chandra Mandal static ulong pic32_get_sysclk(struct pic32_clk_priv *priv) 116*a0e79083SPurna Chandra Mandal { 117*a0e79083SPurna Chandra Mandal ulong v; 118*a0e79083SPurna Chandra Mandal ulong hz; 119*a0e79083SPurna Chandra Mandal ulong div, frcdiv; 120*a0e79083SPurna Chandra Mandal ulong curr_osc; 121*a0e79083SPurna Chandra Mandal 122*a0e79083SPurna Chandra Mandal /* get clk source */ 123*a0e79083SPurna Chandra Mandal v = readl(priv->iobase + OSCCON); 124*a0e79083SPurna Chandra Mandal curr_osc = (v >> 12) & CUROSC_MASK; 125*a0e79083SPurna Chandra Mandal switch (curr_osc) { 126*a0e79083SPurna Chandra Mandal case SCLK_SRC_FRC1: 127*a0e79083SPurna Chandra Mandal case SCLK_SRC_FRC2: 128*a0e79083SPurna Chandra Mandal frcdiv = ((v >> 24) & FRCDIV_MASK); 129*a0e79083SPurna Chandra Mandal div = ((1 << frcdiv) + 1) + (128 * (frcdiv == 7)); 130*a0e79083SPurna Chandra Mandal hz = SYS_FRC_CLK_HZ / div; 131*a0e79083SPurna Chandra Mandal break; 132*a0e79083SPurna Chandra Mandal 133*a0e79083SPurna Chandra Mandal case SCLK_SRC_SPLL: 134*a0e79083SPurna Chandra Mandal hz = pic32_get_pll_rate(priv); 135*a0e79083SPurna Chandra Mandal break; 136*a0e79083SPurna Chandra Mandal 137*a0e79083SPurna Chandra Mandal case SCLK_SRC_POSC: 138*a0e79083SPurna Chandra Mandal hz = SYS_POSC_CLK_HZ; 139*a0e79083SPurna Chandra Mandal break; 140*a0e79083SPurna Chandra Mandal 141*a0e79083SPurna Chandra Mandal default: 142*a0e79083SPurna Chandra Mandal hz = 0; 143*a0e79083SPurna Chandra Mandal printf("clk: unknown sclk_src.\n"); 144*a0e79083SPurna Chandra Mandal break; 145*a0e79083SPurna Chandra Mandal } 146*a0e79083SPurna Chandra Mandal 147*a0e79083SPurna Chandra Mandal return hz; 148*a0e79083SPurna Chandra Mandal } 149*a0e79083SPurna Chandra Mandal 150*a0e79083SPurna Chandra Mandal static ulong pic32_get_pbclk(struct pic32_clk_priv *priv, int periph) 151*a0e79083SPurna Chandra Mandal { 152*a0e79083SPurna Chandra Mandal void __iomem *reg; 153*a0e79083SPurna Chandra Mandal ulong div, clk_freq; 154*a0e79083SPurna Chandra Mandal 155*a0e79083SPurna Chandra Mandal WARN_ON((periph < PB1CLK) || (periph > PB7CLK)); 156*a0e79083SPurna Chandra Mandal 157*a0e79083SPurna Chandra Mandal clk_freq = pic32_get_sysclk(priv); 158*a0e79083SPurna Chandra Mandal 159*a0e79083SPurna Chandra Mandal reg = priv->iobase + PB1DIV + (periph - PB1CLK) * 0x10; 160*a0e79083SPurna Chandra Mandal div = (readl(reg) & PBDIV_MASK) + 1; 161*a0e79083SPurna Chandra Mandal 162*a0e79083SPurna Chandra Mandal return clk_freq / div; 163*a0e79083SPurna Chandra Mandal } 164*a0e79083SPurna Chandra Mandal 165*a0e79083SPurna Chandra Mandal static ulong pic32_get_cpuclk(struct pic32_clk_priv *priv) 166*a0e79083SPurna Chandra Mandal { 167*a0e79083SPurna Chandra Mandal return pic32_get_pbclk(priv, PB7CLK); 168*a0e79083SPurna Chandra Mandal } 169*a0e79083SPurna Chandra Mandal 170*a0e79083SPurna Chandra Mandal static ulong pic32_set_refclk(struct pic32_clk_priv *priv, int periph, 171*a0e79083SPurna Chandra Mandal int parent_rate, int rate, int parent_id) 172*a0e79083SPurna Chandra Mandal { 173*a0e79083SPurna Chandra Mandal void __iomem *reg; 174*a0e79083SPurna Chandra Mandal u32 div, trim, v; 175*a0e79083SPurna Chandra Mandal u64 frac; 176*a0e79083SPurna Chandra Mandal 177*a0e79083SPurna Chandra Mandal WARN_ON((periph < REF1CLK) || (periph > REF5CLK)); 178*a0e79083SPurna Chandra Mandal 179*a0e79083SPurna Chandra Mandal /* calculate dividers, 180*a0e79083SPurna Chandra Mandal * rate = parent_rate / [2 * (div + (trim / 512))] 181*a0e79083SPurna Chandra Mandal */ 182*a0e79083SPurna Chandra Mandal if (parent_rate <= rate) { 183*a0e79083SPurna Chandra Mandal div = 0; 184*a0e79083SPurna Chandra Mandal trim = 0; 185*a0e79083SPurna Chandra Mandal } else { 186*a0e79083SPurna Chandra Mandal div = parent_rate / (rate << 1); 187*a0e79083SPurna Chandra Mandal frac = parent_rate; 188*a0e79083SPurna Chandra Mandal frac <<= 8; 189*a0e79083SPurna Chandra Mandal do_div(frac, rate); 190*a0e79083SPurna Chandra Mandal frac -= (u64)(div << 9); 191*a0e79083SPurna Chandra Mandal trim = (frac >= REFO_TRIM_MAX) ? REFO_TRIM_MAX : (u32)frac; 192*a0e79083SPurna Chandra Mandal } 193*a0e79083SPurna Chandra Mandal 194*a0e79083SPurna Chandra Mandal reg = priv->iobase + REFO1CON + (periph - REF1CLK) * 0x20; 195*a0e79083SPurna Chandra Mandal 196*a0e79083SPurna Chandra Mandal /* disable clk */ 197*a0e79083SPurna Chandra Mandal writel(REFO_ON | REFO_OE, reg + _CLR_OFFSET); 198*a0e79083SPurna Chandra Mandal 199*a0e79083SPurna Chandra Mandal /* wait till previous src change is active */ 200*a0e79083SPurna Chandra Mandal wait_for_bit(__func__, reg, REFO_DIVSW_EN | REFO_ACTIVE, 201*a0e79083SPurna Chandra Mandal false, CONFIG_SYS_HZ, false); 202*a0e79083SPurna Chandra Mandal 203*a0e79083SPurna Chandra Mandal /* parent_id */ 204*a0e79083SPurna Chandra Mandal v = readl(reg); 205*a0e79083SPurna Chandra Mandal v &= ~(REFO_SEL_MASK << REFO_SEL_SHIFT); 206*a0e79083SPurna Chandra Mandal v |= (parent_id << REFO_SEL_SHIFT); 207*a0e79083SPurna Chandra Mandal 208*a0e79083SPurna Chandra Mandal /* apply rodiv */ 209*a0e79083SPurna Chandra Mandal v &= ~(REFO_DIV_MASK << REFO_DIV_SHIFT); 210*a0e79083SPurna Chandra Mandal v |= (div << REFO_DIV_SHIFT); 211*a0e79083SPurna Chandra Mandal writel(v, reg); 212*a0e79083SPurna Chandra Mandal 213*a0e79083SPurna Chandra Mandal /* apply trim */ 214*a0e79083SPurna Chandra Mandal v = readl(reg + REFO_TRIM_REG); 215*a0e79083SPurna Chandra Mandal v &= ~(REFO_TRIM_MASK << REFO_TRIM_SHIFT); 216*a0e79083SPurna Chandra Mandal v |= (trim << REFO_TRIM_SHIFT); 217*a0e79083SPurna Chandra Mandal writel(v, reg + REFO_TRIM_REG); 218*a0e79083SPurna Chandra Mandal 219*a0e79083SPurna Chandra Mandal /* enable clk */ 220*a0e79083SPurna Chandra Mandal writel(REFO_ON | REFO_OE, reg + _SET_OFFSET); 221*a0e79083SPurna Chandra Mandal 222*a0e79083SPurna Chandra Mandal /* switch divider */ 223*a0e79083SPurna Chandra Mandal writel(REFO_DIVSW_EN, reg + _SET_OFFSET); 224*a0e79083SPurna Chandra Mandal 225*a0e79083SPurna Chandra Mandal /* wait for divider switching to complete */ 226*a0e79083SPurna Chandra Mandal return wait_for_bit(__func__, reg, REFO_DIVSW_EN, false, 227*a0e79083SPurna Chandra Mandal CONFIG_SYS_HZ, false); 228*a0e79083SPurna Chandra Mandal } 229*a0e79083SPurna Chandra Mandal 230*a0e79083SPurna Chandra Mandal static ulong pic32_get_refclk(struct pic32_clk_priv *priv, int periph) 231*a0e79083SPurna Chandra Mandal { 232*a0e79083SPurna Chandra Mandal u32 rodiv, rotrim, rosel, v, parent_rate; 233*a0e79083SPurna Chandra Mandal void __iomem *reg; 234*a0e79083SPurna Chandra Mandal u64 rate64; 235*a0e79083SPurna Chandra Mandal 236*a0e79083SPurna Chandra Mandal WARN_ON((periph < REF1CLK) || (periph > REF5CLK)); 237*a0e79083SPurna Chandra Mandal 238*a0e79083SPurna Chandra Mandal reg = priv->iobase + REFO1CON + (periph - REF1CLK) * 0x20; 239*a0e79083SPurna Chandra Mandal v = readl(reg); 240*a0e79083SPurna Chandra Mandal /* get rosel */ 241*a0e79083SPurna Chandra Mandal rosel = (v >> REFO_SEL_SHIFT) & REFO_SEL_MASK; 242*a0e79083SPurna Chandra Mandal /* get div */ 243*a0e79083SPurna Chandra Mandal rodiv = (v >> REFO_DIV_SHIFT) & REFO_DIV_MASK; 244*a0e79083SPurna Chandra Mandal 245*a0e79083SPurna Chandra Mandal /* get trim */ 246*a0e79083SPurna Chandra Mandal v = readl(reg + REFO_TRIM_REG); 247*a0e79083SPurna Chandra Mandal rotrim = (v >> REFO_TRIM_SHIFT) & REFO_TRIM_MASK; 248*a0e79083SPurna Chandra Mandal 249*a0e79083SPurna Chandra Mandal if (!rodiv) 250*a0e79083SPurna Chandra Mandal return 0; 251*a0e79083SPurna Chandra Mandal 252*a0e79083SPurna Chandra Mandal /* get parent rate */ 253*a0e79083SPurna Chandra Mandal switch (rosel) { 254*a0e79083SPurna Chandra Mandal case ROCLK_SRC_SCLK: 255*a0e79083SPurna Chandra Mandal parent_rate = pic32_get_cpuclk(priv); 256*a0e79083SPurna Chandra Mandal break; 257*a0e79083SPurna Chandra Mandal case ROCLK_SRC_SPLL: 258*a0e79083SPurna Chandra Mandal parent_rate = pic32_get_pll_rate(priv); 259*a0e79083SPurna Chandra Mandal break; 260*a0e79083SPurna Chandra Mandal default: 261*a0e79083SPurna Chandra Mandal parent_rate = 0; 262*a0e79083SPurna Chandra Mandal break; 263*a0e79083SPurna Chandra Mandal } 264*a0e79083SPurna Chandra Mandal 265*a0e79083SPurna Chandra Mandal /* Calculation 266*a0e79083SPurna Chandra Mandal * rate = parent_rate / [2 * (div + (trim / 512))] 267*a0e79083SPurna Chandra Mandal */ 268*a0e79083SPurna Chandra Mandal if (rotrim) { 269*a0e79083SPurna Chandra Mandal rodiv <<= 9; 270*a0e79083SPurna Chandra Mandal rodiv += rotrim; 271*a0e79083SPurna Chandra Mandal rate64 = parent_rate; 272*a0e79083SPurna Chandra Mandal rate64 <<= 8; 273*a0e79083SPurna Chandra Mandal do_div(rate64, rodiv); 274*a0e79083SPurna Chandra Mandal v = (u32)rate64; 275*a0e79083SPurna Chandra Mandal } else { 276*a0e79083SPurna Chandra Mandal v = parent_rate / (rodiv << 1); 277*a0e79083SPurna Chandra Mandal } 278*a0e79083SPurna Chandra Mandal return v; 279*a0e79083SPurna Chandra Mandal } 280*a0e79083SPurna Chandra Mandal 281*a0e79083SPurna Chandra Mandal static ulong pic32_get_mpll_rate(struct pic32_clk_priv *priv) 282*a0e79083SPurna Chandra Mandal { 283*a0e79083SPurna Chandra Mandal u32 v, idiv, mul; 284*a0e79083SPurna Chandra Mandal u32 odiv1, odiv2; 285*a0e79083SPurna Chandra Mandal u64 rate; 286*a0e79083SPurna Chandra Mandal 287*a0e79083SPurna Chandra Mandal v = readl(priv->syscfg_base + CFGMPLL); 288*a0e79083SPurna Chandra Mandal idiv = v & MPLL_IDIV; 289*a0e79083SPurna Chandra Mandal mul = (v >> MPLL_MULT_SHIFT) & MPLL_MULT; 290*a0e79083SPurna Chandra Mandal odiv1 = (v >> MPLL_ODIV1_SHIFT) & MPLL_ODIV1; 291*a0e79083SPurna Chandra Mandal odiv2 = (v >> MPLL_ODIV2_SHIFT) & MPLL_ODIV2; 292*a0e79083SPurna Chandra Mandal 293*a0e79083SPurna Chandra Mandal rate = (SYS_POSC_CLK_HZ / idiv) * mul; 294*a0e79083SPurna Chandra Mandal do_div(rate, odiv1); 295*a0e79083SPurna Chandra Mandal do_div(rate, odiv2); 296*a0e79083SPurna Chandra Mandal 297*a0e79083SPurna Chandra Mandal return (ulong)rate; 298*a0e79083SPurna Chandra Mandal } 299*a0e79083SPurna Chandra Mandal 300*a0e79083SPurna Chandra Mandal static int pic32_mpll_init(struct pic32_clk_priv *priv) 301*a0e79083SPurna Chandra Mandal { 302*a0e79083SPurna Chandra Mandal u32 v, mask; 303*a0e79083SPurna Chandra Mandal 304*a0e79083SPurna Chandra Mandal /* initialize */ 305*a0e79083SPurna Chandra Mandal v = (MPLL_IDIV_INIT << MPLL_IDIV_SHIFT) | 306*a0e79083SPurna Chandra Mandal (MPLL_MULT_INIT << MPLL_MULT_SHIFT) | 307*a0e79083SPurna Chandra Mandal (MPLL_ODIV1_INIT << MPLL_ODIV1_SHIFT) | 308*a0e79083SPurna Chandra Mandal (MPLL_ODIV2_INIT << MPLL_ODIV2_SHIFT); 309*a0e79083SPurna Chandra Mandal 310*a0e79083SPurna Chandra Mandal writel(v, priv->syscfg_base + CFGMPLL); 311*a0e79083SPurna Chandra Mandal 312*a0e79083SPurna Chandra Mandal /* Wait for ready */ 313*a0e79083SPurna Chandra Mandal mask = MPLL_RDY | MPLL_VREG_RDY; 314*a0e79083SPurna Chandra Mandal return wait_for_bit(__func__, priv->syscfg_base + CFGMPLL, mask, 315*a0e79083SPurna Chandra Mandal true, get_tbclk(), false); 316*a0e79083SPurna Chandra Mandal } 317*a0e79083SPurna Chandra Mandal 318*a0e79083SPurna Chandra Mandal static void pic32_clk_init(struct udevice *dev) 319*a0e79083SPurna Chandra Mandal { 320*a0e79083SPurna Chandra Mandal const void *blob = gd->fdt_blob; 321*a0e79083SPurna Chandra Mandal struct pic32_clk_priv *priv; 322*a0e79083SPurna Chandra Mandal ulong rate, pll_hz; 323*a0e79083SPurna Chandra Mandal char propname[50]; 324*a0e79083SPurna Chandra Mandal int i; 325*a0e79083SPurna Chandra Mandal 326*a0e79083SPurna Chandra Mandal priv = dev_get_priv(dev); 327*a0e79083SPurna Chandra Mandal pll_hz = pic32_get_pll_rate(priv); 328*a0e79083SPurna Chandra Mandal 329*a0e79083SPurna Chandra Mandal /* Initialize REFOs as not initialized and enabled on reset. */ 330*a0e79083SPurna Chandra Mandal for (i = REF1CLK; i <= REF5CLK; i++) { 331*a0e79083SPurna Chandra Mandal snprintf(propname, sizeof(propname), 332*a0e79083SPurna Chandra Mandal "microchip,refo%d-frequency", i - REF1CLK + 1); 333*a0e79083SPurna Chandra Mandal rate = fdtdec_get_int(blob, dev->of_offset, propname, 0); 334*a0e79083SPurna Chandra Mandal if (rate) 335*a0e79083SPurna Chandra Mandal pic32_set_refclk(priv, i, pll_hz, rate, ROCLK_SRC_SPLL); 336*a0e79083SPurna Chandra Mandal } 337*a0e79083SPurna Chandra Mandal 338*a0e79083SPurna Chandra Mandal /* Memory PLL */ 339*a0e79083SPurna Chandra Mandal pic32_mpll_init(priv); 340*a0e79083SPurna Chandra Mandal } 341*a0e79083SPurna Chandra Mandal 342*a0e79083SPurna Chandra Mandal static ulong pic32_clk_get_rate(struct udevice *dev) 343*a0e79083SPurna Chandra Mandal { 344*a0e79083SPurna Chandra Mandal struct pic32_clk_priv *priv = dev_get_priv(dev); 345*a0e79083SPurna Chandra Mandal 346*a0e79083SPurna Chandra Mandal return pic32_get_cpuclk(priv); 347*a0e79083SPurna Chandra Mandal } 348*a0e79083SPurna Chandra Mandal 349*a0e79083SPurna Chandra Mandal static ulong pic32_get_periph_rate(struct udevice *dev, int periph) 350*a0e79083SPurna Chandra Mandal { 351*a0e79083SPurna Chandra Mandal struct pic32_clk_priv *priv = dev_get_priv(dev); 352*a0e79083SPurna Chandra Mandal ulong rate; 353*a0e79083SPurna Chandra Mandal 354*a0e79083SPurna Chandra Mandal switch (periph) { 355*a0e79083SPurna Chandra Mandal case PB1CLK ... PB7CLK: 356*a0e79083SPurna Chandra Mandal rate = pic32_get_pbclk(priv, periph); 357*a0e79083SPurna Chandra Mandal break; 358*a0e79083SPurna Chandra Mandal case REF1CLK ... REF5CLK: 359*a0e79083SPurna Chandra Mandal rate = pic32_get_refclk(priv, periph); 360*a0e79083SPurna Chandra Mandal break; 361*a0e79083SPurna Chandra Mandal case PLLCLK: 362*a0e79083SPurna Chandra Mandal rate = pic32_get_pll_rate(priv); 363*a0e79083SPurna Chandra Mandal break; 364*a0e79083SPurna Chandra Mandal case MPLL: 365*a0e79083SPurna Chandra Mandal rate = pic32_get_mpll_rate(priv); 366*a0e79083SPurna Chandra Mandal break; 367*a0e79083SPurna Chandra Mandal default: 368*a0e79083SPurna Chandra Mandal rate = 0; 369*a0e79083SPurna Chandra Mandal break; 370*a0e79083SPurna Chandra Mandal } 371*a0e79083SPurna Chandra Mandal 372*a0e79083SPurna Chandra Mandal return rate; 373*a0e79083SPurna Chandra Mandal } 374*a0e79083SPurna Chandra Mandal 375*a0e79083SPurna Chandra Mandal static ulong pic32_set_periph_rate(struct udevice *dev, int periph, ulong rate) 376*a0e79083SPurna Chandra Mandal { 377*a0e79083SPurna Chandra Mandal struct pic32_clk_priv *priv = dev_get_priv(dev); 378*a0e79083SPurna Chandra Mandal ulong pll_hz; 379*a0e79083SPurna Chandra Mandal 380*a0e79083SPurna Chandra Mandal switch (periph) { 381*a0e79083SPurna Chandra Mandal case REF1CLK ... REF5CLK: 382*a0e79083SPurna Chandra Mandal pll_hz = pic32_get_pll_rate(priv); 383*a0e79083SPurna Chandra Mandal pic32_set_refclk(priv, periph, pll_hz, rate, ROCLK_SRC_SPLL); 384*a0e79083SPurna Chandra Mandal break; 385*a0e79083SPurna Chandra Mandal default: 386*a0e79083SPurna Chandra Mandal break; 387*a0e79083SPurna Chandra Mandal } 388*a0e79083SPurna Chandra Mandal 389*a0e79083SPurna Chandra Mandal return rate; 390*a0e79083SPurna Chandra Mandal } 391*a0e79083SPurna Chandra Mandal 392*a0e79083SPurna Chandra Mandal static struct clk_ops pic32_pic32_clk_ops = { 393*a0e79083SPurna Chandra Mandal .get_rate = pic32_clk_get_rate, 394*a0e79083SPurna Chandra Mandal .set_periph_rate = pic32_set_periph_rate, 395*a0e79083SPurna Chandra Mandal .get_periph_rate = pic32_get_periph_rate, 396*a0e79083SPurna Chandra Mandal }; 397*a0e79083SPurna Chandra Mandal 398*a0e79083SPurna Chandra Mandal static int pic32_clk_probe(struct udevice *dev) 399*a0e79083SPurna Chandra Mandal { 400*a0e79083SPurna Chandra Mandal struct pic32_clk_priv *priv = dev_get_priv(dev); 401*a0e79083SPurna Chandra Mandal fdt_addr_t addr; 402*a0e79083SPurna Chandra Mandal fdt_size_t size; 403*a0e79083SPurna Chandra Mandal 404*a0e79083SPurna Chandra Mandal addr = fdtdec_get_addr_size(gd->fdt_blob, dev->of_offset, "reg", &size); 405*a0e79083SPurna Chandra Mandal if (addr == FDT_ADDR_T_NONE) 406*a0e79083SPurna Chandra Mandal return -EINVAL; 407*a0e79083SPurna Chandra Mandal 408*a0e79083SPurna Chandra Mandal priv->iobase = ioremap(addr, size); 409*a0e79083SPurna Chandra Mandal if (!priv->iobase) 410*a0e79083SPurna Chandra Mandal return -EINVAL; 411*a0e79083SPurna Chandra Mandal 412*a0e79083SPurna Chandra Mandal priv->syscfg_base = pic32_get_syscfg_base(); 413*a0e79083SPurna Chandra Mandal 414*a0e79083SPurna Chandra Mandal /* initialize clocks */ 415*a0e79083SPurna Chandra Mandal pic32_clk_init(dev); 416*a0e79083SPurna Chandra Mandal 417*a0e79083SPurna Chandra Mandal return 0; 418*a0e79083SPurna Chandra Mandal } 419*a0e79083SPurna Chandra Mandal 420*a0e79083SPurna Chandra Mandal static const struct udevice_id pic32_clk_ids[] = { 421*a0e79083SPurna Chandra Mandal { .compatible = "microchip,pic32mzda-clk"}, 422*a0e79083SPurna Chandra Mandal {} 423*a0e79083SPurna Chandra Mandal }; 424*a0e79083SPurna Chandra Mandal 425*a0e79083SPurna Chandra Mandal U_BOOT_DRIVER(pic32_clk) = { 426*a0e79083SPurna Chandra Mandal .name = "pic32_clk", 427*a0e79083SPurna Chandra Mandal .id = UCLASS_CLK, 428*a0e79083SPurna Chandra Mandal .of_match = pic32_clk_ids, 429*a0e79083SPurna Chandra Mandal .flags = DM_FLAG_PRE_RELOC, 430*a0e79083SPurna Chandra Mandal .ops = &pic32_pic32_clk_ops, 431*a0e79083SPurna Chandra Mandal .probe = pic32_clk_probe, 432*a0e79083SPurna Chandra Mandal .priv_auto_alloc_size = sizeof(struct pic32_clk_priv), 433*a0e79083SPurna Chandra Mandal }; 434