static int rkclk_set_pll(struct rk3036_cru *cru, enum rk_clk_id clk_id, const struct pll_div *div) { int pll_id = rk_pll_id(clk_id); struct rk3036_pll *pll = &cru->pll[pll_id]; /* All PLLs have same VCO and output frequency range restrictions. */ uint vco_hz = OSC_HZ / 1000 * div->fbdiv / div->refdiv * 1000; uint output_hz = vco_hz / div->postdiv1 / div->postdiv2; debug("PLL at %p: fbdiv=%d, refdiv=%d, postdiv1=%d, postdiv2=%d,\ vco=%u Hz, output=%u Hz\n", pll, div->fbdiv, div->refdiv, div->postdiv1, div->postdiv2, 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); /* use integer mode */ rk_setreg(&pll->con1, 1 << PLL_DSMPD_SHIFT); rk_clrsetreg(&pll->con0, PLL_POSTDIV1_MASK | PLL_FBDIV_MASK, (div->postdiv1 << PLL_POSTDIV1_SHIFT) | div->fbdiv); rk_clrsetreg(&pll->con1, PLL_POSTDIV2_MASK | PLL_REFDIV_MASK, (div->postdiv2 << PLL_POSTDIV2_SHIFT | div->refdiv << PLL_REFDIV_SHIFT)); /* waiting for pll lock */ while (readl(&pll->con1) & (1 << PLL_LOCK_STATUS_SHIFT)) udelay(1); return 0; }
static int rkclk_set_pll(struct rk3288_cru *cru, enum rk_clk_id clk_id, const struct pll_div *div) { int pll_id = rk_pll_id(clk_id); struct rk3288_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); 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; }
/* Get pll rate by id */ static uint32_t rkclk_pll_get_rate(struct rk3036_cru *cru, enum rk_clk_id clk_id) { uint32_t refdiv, fbdiv, postdiv1, postdiv2; uint32_t con; int pll_id = rk_pll_id(clk_id); struct rk3036_pll *pll = &cru->pll[pll_id]; static u8 clk_shift[CLK_COUNT] = { 0xff, APLL_MODE_SHIFT, DPLL_MODE_SHIFT, 0xff, GPLL_MODE_SHIFT, 0xff }; static u32 clk_mask[CLK_COUNT] = { 0xffffffff, APLL_MODE_MASK, DPLL_MODE_MASK, 0xffffffff, GPLL_MODE_MASK, 0xffffffff }; uint shift; uint mask; con = readl(&cru->cru_mode_con); shift = clk_shift[clk_id]; mask = clk_mask[clk_id]; switch ((con & mask) >> shift) { case GPLL_MODE_SLOW: return OSC_HZ; case GPLL_MODE_NORM: /* normal mode */ con = readl(&pll->con0); postdiv1 = (con & PLL_POSTDIV1_MASK) >> PLL_POSTDIV1_SHIFT; fbdiv = (con & PLL_FBDIV_MASK) >> PLL_FBDIV_SHIFT; con = readl(&pll->con1); postdiv2 = (con & PLL_POSTDIV2_MASK) >> PLL_POSTDIV2_SHIFT; refdiv = (con & PLL_REFDIV_MASK) >> PLL_REFDIV_SHIFT; return (24 * fbdiv / (refdiv * postdiv1 * postdiv2)) * 1000000; case GPLL_MODE_DEEP: default: return 32768; } }