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) {\
return 0;
}
+static int rkclk_configure_cpu(struct rk3188_cru *cru, struct rk3188_grf *grf,
+ unsigned int hz, bool has_bwadj)
+{
+ static const struct pll_div apll_cfg[] = {
+ {.nf = 50, .nr = 1, .no = 2},
+ {.nf = 67, .nr = 1, .no = 1},
+ };
+ int div_core_peri, div_aclk_core, cfg;
+
+ /*
+ * We support two possible frequencies, the safe 600MHz
+ * which will work with default pmic settings and will
+ * be set in SPL to get away from the 24MHz default and
+ * the maximum of 1.6Ghz, which boards can set if they
+ * were able to get pmic support for it.
+ */
+ switch (hz) {
+ case APLL_SAFE_HZ:
+ cfg = 0;
+ div_core_peri = 1;
+ div_aclk_core = 3;
+ break;
+ case APLL_HZ:
+ cfg = 1;
+ div_core_peri = 2;
+ div_aclk_core = 3;
+ break;
+ default:
+ debug("Unsupported ARMCLK frequency");
+ return -EINVAL;
+ }
+
+ /* pll enter slow-mode */
+ rk_clrsetreg(&cru->cru_mode_con, APLL_MODE_MASK << APLL_MODE_SHIFT,
+ APLL_MODE_SLOW << APLL_MODE_SHIFT);
+
+ rkclk_set_pll(cru, CLK_ARM, &apll_cfg[cfg], has_bwadj);
+
+ /* waiting for pll lock */
+ while (!(readl(&grf->soc_status0) & SOCSTS_APLL_LOCK))
+ udelay(1);
+
+ /* Set divider for peripherals attached to the cpu core. */
+ rk_clrsetreg(&cru->cru_clksel_con[0],
+ CORE_PERI_DIV_MASK << CORE_PERI_DIV_SHIFT,
+ div_core_peri << CORE_PERI_DIV_SHIFT);
+
+ /* set up dependent divisor for aclk_core */
+ rk_clrsetreg(&cru->cru_clksel_con[1],
+ CORE_ACLK_DIV_MASK << CORE_ACLK_DIV_SHIFT,
+ div_aclk_core << CORE_ACLK_DIV_SHIFT);
+
+ /* PLL enter normal-mode */
+ rk_clrsetreg(&cru->cru_mode_con, APLL_MODE_MASK << APLL_MODE_SHIFT,
+ APLL_MODE_NORMAL << APLL_MODE_SHIFT);
+
+ return hz;
+}
+
/* Get pll rate by id */
static uint32_t rkclk_pll_get_rate(struct rk3188_cru *cru,
enum rk_clk_id clk_id)
switch (periph) {
case HCLK_EMMC:
+ case SCLK_EMMC:
con = readl(&cru->cru_clksel_con[12]);
div = (con >> EMMC_DIV_SHIFT) & EMMC_DIV_MASK;
break;
case HCLK_SDMMC:
+ case SCLK_SDMMC:
con = readl(&cru->cru_clksel_con[11]);
div = (con >> MMC0_DIV_SHIFT) & MMC0_DIV_MASK;
break;
case HCLK_SDIO:
+ case SCLK_SDIO:
con = readl(&cru->cru_clksel_con[12]);
div = (con >> SDIO_DIV_SHIFT) & SDIO_DIV_MASK;
break;
return -EINVAL;
}
- return DIV_TO_RATE(gclk_rate, div);
+ return DIV_TO_RATE(gclk_rate, div) / 2;
}
static ulong rockchip_mmc_set_clk(struct rk3188_cru *cru, uint gclk_rate,
int src_clk_div;
debug("%s: gclk_rate=%u\n", __func__, gclk_rate);
- src_clk_div = RATE_TO_DIV(gclk_rate, freq);
+ /* mmc clock defaulg div 2 internal, need provide double in cru */
+ src_clk_div = DIV_ROUND_UP(gclk_rate / 2, freq) - 1;
assert(src_clk_div <= 0x3f);
switch (periph) {
case HCLK_EMMC:
+ case SCLK_EMMC:
rk_clrsetreg(&cru->cru_clksel_con[12],
EMMC_DIV_MASK << EMMC_DIV_SHIFT,
src_clk_div << EMMC_DIV_SHIFT);
break;
case HCLK_SDMMC:
+ case SCLK_SDMMC:
rk_clrsetreg(&cru->cru_clksel_con[11],
MMC0_DIV_MASK << MMC0_DIV_SHIFT,
src_clk_div << MMC0_DIV_SHIFT);
break;
case HCLK_SDIO:
+ case SCLK_SDIO:
rk_clrsetreg(&cru->cru_clksel_con[12],
SDIO_DIV_MASK << SDIO_DIV_SHIFT,
src_clk_div << SDIO_DIV_SHIFT);
static ulong rockchip_spi_set_clk(struct rk3188_cru *cru, uint gclk_rate,
int periph, uint freq)
{
- int src_clk_div = RATE_TO_DIV(gclk_rate, freq);
+ int src_clk_div = DIV_ROUND_UP(gclk_rate, freq) - 1;
+ assert(src_clk_div < 128);
switch (periph) {
case SCLK_SPI0:
assert(src_clk_div <= SPI0_DIV_MASK);
* reparent aclk_cpu_pre from apll to gpll
* set up dependent divisors for PCLK/HCLK and ACLK clocks.
*/
- aclk_div = RATE_TO_DIV(GPLL_HZ, CPU_ACLK_HZ);
- assert((aclk_div + 1) * CPU_ACLK_HZ == GPLL_HZ && aclk_div < 0x1f);
+ aclk_div = DIV_ROUND_UP(GPLL_HZ, CPU_ACLK_HZ) - 1;
+ assert((aclk_div + 1) * CPU_ACLK_HZ == GPLL_HZ && aclk_div <= 0x1f);
rk_clrsetreg(&cru->cru_clksel_con[0],
CPU_ACLK_PLL_MASK << CPU_ACLK_PLL_SHIFT |
case HCLK_EMMC:
case HCLK_SDMMC:
case HCLK_SDIO:
+ case SCLK_EMMC:
+ case SCLK_SDMMC:
+ case SCLK_SDIO:
new_rate = rockchip_mmc_get_clk(priv->cru, PERI_HCLK_HZ,
clk->id);
break;
ulong new_rate;
switch (clk->id) {
+ case PLL_APLL:
+ new_rate = rkclk_configure_cpu(priv->cru, priv->grf, rate,
+ priv->has_bwadj);
+ break;
case CLK_DDR:
new_rate = rkclk_configure_ddr(priv->cru, priv->grf, rate,
priv->has_bwadj);
case HCLK_EMMC:
case HCLK_SDMMC:
case HCLK_SDIO:
+ case SCLK_EMMC:
+ case SCLK_SDMMC:
+ case SCLK_SDIO:
new_rate = rockchip_mmc_set_clk(cru, PERI_HCLK_HZ,
clk->id, rate);
break;
#if !CONFIG_IS_ENABLED(OF_PLATDATA)
struct rk3188_clk_priv *priv = dev_get_priv(dev);
- priv->cru = (struct rk3188_cru *)dev_get_addr(dev);
+ priv->cru = (struct rk3188_cru *)devfdt_get_addr(dev);
#endif
return 0;