*/
#include <common.h>
-#include <clk.h>
+#include <clk-uclass.h>
#include <dm.h>
#include <errno.h>
#include <syscon.h>
DECLARE_GLOBAL_DATA_PTR;
-struct rk3288_clk_plat {
- enum rk_clk_id clk_id;
-};
-
struct rk3288_clk_priv {
struct rk3288_grf *grf;
struct rk3288_cru *cru;
/* PLL CON3 */
PLL_RESET_SHIFT = 5,
+ /* CLKSEL0 */
+ CORE_SEL_PLL_MASK = 1,
+ CORE_SEL_PLL_SHIFT = 15,
+ A17_DIV_MASK = 0x1f,
+ A17_DIV_SHIFT = 8,
+ MP_DIV_MASK = 0xf,
+ MP_DIV_SHIFT = 4,
+ M0_DIV_MASK = 0xf,
+ M0_DIV_SHIFT = 0,
+
/* CLKSEL1: pd bus clk pll sel: codec or general */
PD_BUS_SEL_PLL_MASK = 15,
PD_BUS_SEL_CPLL = 0,
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);
-int rkclk_get_clk(enum rk_clk_id clk_id, struct udevice **devp)
-{
- struct udevice *dev;
-
- for (uclass_find_first_device(UCLASS_CLK, &dev);
- dev;
- uclass_find_next_device(&dev)) {
- struct rk3288_clk_plat *plat = dev_get_platdata(dev);
-
- if (plat->clk_id == clk_id) {
- *devp = dev;
- return device_probe(dev);
- }
- }
-
- return -ENODEV;
-}
-
void *rockchip_get_cru(void)
{
struct rk3288_clk_priv *priv;
struct udevice *dev;
int ret;
- ret = rkclk_get_clk(CLK_GENERAL, &dev);
+ ret = uclass_get_device(UCLASS_CLK, 0, &dev);
if (ret)
return ERR_PTR(ret);
+
priv = dev_get_priv(dev);
+
return priv->cru;
}
return 0;
}
+static int rockchip_mac_set_clk(struct rk3288_cru *cru,
+ int periph, uint freq)
+{
+ /* Assuming mac_clk is fed by an external clock */
+ rk_clrsetreg(&cru->cru_clksel_con[21],
+ RMII_EXTCLK_MASK << RMII_EXTCLK_SHIFT,
+ RMII_EXTCLK_SELECT_EXT_CLK << RMII_EXTCLK_SHIFT);
+
+ return 0;
+}
+
static int rockchip_vop_set_clk(struct rk3288_cru *cru, struct rk3288_grf *grf,
int periph, unsigned int rate_hz)
{
}
#endif
+void rkclk_configure_cpu(struct rk3288_cru *cru, struct rk3288_grf *grf)
+{
+ /* 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_init_cfg);
+
+ /* waiting for pll lock */
+ while (!(readl(&grf->soc_status[1]) & SOCSTS_APLL_LOCK))
+ udelay(1);
+
+ /*
+ * core clock pll source selection and
+ * set up dependent divisors for MPAXI/M0AXI and ARM clocks.
+ * core clock select apll, apll clk = 1800MHz
+ * arm clk = 1800MHz, mpclk = 450MHz, m0clk = 900MHz
+ */
+ rk_clrsetreg(&cru->cru_clksel_con[0],
+ CORE_SEL_PLL_MASK << CORE_SEL_PLL_SHIFT |
+ A17_DIV_MASK << A17_DIV_SHIFT |
+ MP_DIV_MASK << MP_DIV_SHIFT |
+ M0_DIV_MASK << M0_DIV_SHIFT,
+ 0 << A17_DIV_SHIFT |
+ 3 << MP_DIV_SHIFT |
+ 1 << M0_DIV_SHIFT);
+
+ /*
+ * set up dependent divisors for L2RAM/ATCLK and PCLK clocks.
+ * l2ramclk = 900MHz, atclk = 450MHz, pclk_dbg = 450MHz
+ */
+ rk_clrsetreg(&cru->cru_clksel_con[37],
+ CLK_L2RAM_DIV_MASK << CLK_L2RAM_DIV_SHIFT |
+ ATCLK_CORE_DIV_CON_MASK << ATCLK_CORE_DIV_CON_SHIFT |
+ PCLK_CORE_DBG_DIV_MASK >> PCLK_CORE_DBG_DIV_SHIFT,
+ 1 << CLK_L2RAM_DIV_SHIFT |
+ 3 << ATCLK_CORE_DIV_CON_SHIFT |
+ 3 << PCLK_CORE_DBG_DIV_SHIFT);
+
+ /* PLL enter normal-mode */
+ rk_clrsetreg(&cru->cru_mode_con,
+ APLL_MODE_MASK << APLL_MODE_SHIFT,
+ APLL_MODE_NORMAL << APLL_MODE_SHIFT);
+}
+
/* Get pll rate by id */
static uint32_t rkclk_pll_get_rate(struct rk3288_cru *cru,
enum rk_clk_id clk_id)
}
}
-static ulong rk3288_clk_get_rate(struct udevice *dev)
-{
- struct rk3288_clk_plat *plat = dev_get_platdata(dev);
- struct rk3288_clk_priv *priv = dev_get_priv(dev);
-
- debug("%s\n", dev->name);
- return rkclk_pll_get_rate(priv->cru, plat->clk_id);
-}
-
-static ulong rk3288_clk_set_rate(struct udevice *dev, ulong rate)
-{
- struct rk3288_clk_plat *plat = dev_get_platdata(dev);
- struct rk3288_clk_priv *priv = dev_get_priv(dev);
-
- debug("%s\n", dev->name);
- switch (plat->clk_id) {
- case CLK_DDR:
- rkclk_configure_ddr(priv->cru, priv->grf, rate);
- break;
- default:
- return -ENOENT;
- }
-
- return 0;
-}
-
static ulong rockchip_mmc_get_clk(struct rk3288_cru *cru, uint gclk_rate,
int periph)
{
return rockchip_spi_get_clk(cru, gclk_rate, periph);
}
-static ulong rk3288_get_periph_rate(struct udevice *dev, int periph)
+static ulong rk3288_clk_get_rate(struct clk *clk)
{
- struct rk3288_clk_priv *priv = dev_get_priv(dev);
- struct udevice *gclk;
+ struct rk3288_clk_priv *priv = dev_get_priv(clk->dev);
ulong new_rate, gclk_rate;
- int ret;
- ret = rkclk_get_clk(CLK_GENERAL, &gclk);
- if (ret)
- return ret;
- gclk_rate = clk_get_rate(gclk);
- switch (periph) {
+ gclk_rate = rkclk_pll_get_rate(priv->cru, CLK_GENERAL);
+ switch (clk->id) {
+ case 0 ... 63:
+ new_rate = rkclk_pll_get_rate(priv->cru, clk->id);
+ break;
case HCLK_EMMC:
case HCLK_SDMMC:
case HCLK_SDIO0:
- new_rate = rockchip_mmc_get_clk(priv->cru, gclk_rate, periph);
+ new_rate = rockchip_mmc_get_clk(priv->cru, gclk_rate, clk->id);
break;
case SCLK_SPI0:
case SCLK_SPI1:
case SCLK_SPI2:
- new_rate = rockchip_spi_get_clk(priv->cru, gclk_rate, periph);
+ new_rate = rockchip_spi_get_clk(priv->cru, gclk_rate, clk->id);
break;
case PCLK_I2C0:
case PCLK_I2C1:
return new_rate;
}
-static ulong rk3288_set_periph_rate(struct udevice *dev, int periph, ulong rate)
+static ulong rk3288_clk_set_rate(struct clk *clk, ulong rate)
{
- struct rk3288_clk_priv *priv = dev_get_priv(dev);
+ struct rk3288_clk_priv *priv = dev_get_priv(clk->dev);
struct rk3288_cru *cru = priv->cru;
- struct udevice *gclk;
ulong new_rate, gclk_rate;
- int ret;
- ret = rkclk_get_clk(CLK_GENERAL, &gclk);
- if (ret)
- return ret;
- gclk_rate = clk_get_rate(gclk);
- switch (periph) {
+ gclk_rate = rkclk_pll_get_rate(priv->cru, CLK_GENERAL);
+ switch (clk->id) {
+ case CLK_DDR:
+ new_rate = rkclk_configure_ddr(priv->cru, priv->grf, rate);
+ break;
case HCLK_EMMC:
case HCLK_SDMMC:
case HCLK_SDIO0:
- new_rate = rockchip_mmc_set_clk(cru, gclk_rate, periph, rate);
+ new_rate = rockchip_mmc_set_clk(cru, gclk_rate, clk->id, rate);
break;
case SCLK_SPI0:
case SCLK_SPI1:
case SCLK_SPI2:
- new_rate = rockchip_spi_set_clk(cru, gclk_rate, periph, rate);
+ new_rate = rockchip_spi_set_clk(cru, gclk_rate, clk->id, rate);
break;
#ifndef CONFIG_SPL_BUILD
+ case SCLK_MAC:
+ new_rate = rockchip_mac_set_clk(priv->cru, clk->id, rate);
+ break;
case DCLK_VOP0:
case DCLK_VOP1:
- new_rate = rockchip_vop_set_clk(cru, priv->grf, periph, rate);
+ new_rate = rockchip_vop_set_clk(cru, priv->grf, clk->id, rate);
break;
case SCLK_EDP_24M:
/* clk_edp_24M source: 24M */
div = CPLL_HZ / rate;
assert((div - 1 < 64) && (div * rate == CPLL_HZ));
- switch (periph) {
+ switch (clk->id) {
case ACLK_VOP0:
rk_clrsetreg(&cru->cru_clksel_con[31],
3 << 6 | 0x1f << 0,
static struct clk_ops rk3288_clk_ops = {
.get_rate = rk3288_clk_get_rate,
.set_rate = rk3288_clk_set_rate,
- .set_periph_rate = rk3288_set_periph_rate,
- .get_periph_rate = rk3288_get_periph_rate,
};
static int rk3288_clk_probe(struct udevice *dev)
{
- struct rk3288_clk_plat *plat = dev_get_platdata(dev);
struct rk3288_clk_priv *priv = dev_get_priv(dev);
- if (plat->clk_id != CLK_OSC) {
- struct rk3288_clk_priv *parent_priv = dev_get_priv(dev->parent);
-
- priv->cru = parent_priv->cru;
- priv->grf = parent_priv->grf;
- return 0;
- }
priv->cru = (struct rk3288_cru *)dev_get_addr(dev);
priv->grf = syscon_get_first_range(ROCKCHIP_SYSCON_GRF);
#ifdef CONFIG_SPL_BUILD
return 0;
}
-static const char *const clk_name[CLK_COUNT] = {
- "osc",
- "apll",
- "dpll",
- "cpll",
- "gpll",
- "npll",
-};
-
static int rk3288_clk_bind(struct udevice *dev)
{
- struct rk3288_clk_plat *plat = dev_get_platdata(dev);
- int pll, ret;
-
- /* We only need to set up the root clock */
- if (dev->of_offset == -1) {
- plat->clk_id = CLK_OSC;
- return 0;
- }
-
- /* Create devices for P main clocks */
- for (pll = 1; pll < CLK_COUNT; pll++) {
- struct udevice *child;
- struct rk3288_clk_plat *cplat;
-
- debug("%s %s\n", __func__, clk_name[pll]);
- ret = device_bind_driver(dev, "clk_rk3288", clk_name[pll],
- &child);
- if (ret)
- return ret;
- cplat = dev_get_platdata(child);
- cplat->clk_id = pll;
- }
+ int ret;
/* The reset driver does not have a device node, so bind it here */
- ret = device_bind_driver(gd->dm_root, "rk3288_reset", "reset", &dev);
+ ret = device_bind_driver(gd->dm_root, "rk3288_sysreset", "reset", &dev);
if (ret)
debug("Warning: No RK3288 reset driver: ret=%d\n", ret);
.id = UCLASS_CLK,
.of_match = rk3288_clk_ids,
.priv_auto_alloc_size = sizeof(struct rk3288_clk_priv),
- .platdata_auto_alloc_size = sizeof(struct rk3288_clk_plat),
.ops = &rk3288_clk_ops,
.bind = rk3288_clk_bind,
.probe = rk3288_clk_probe,