clk: rockchip: add clk driver for rk3308

Add basic clock for px30 which including cpu, bus, emmc, i2c,
spi, pwm, saradc clock init.

Change-Id: Idd8542d7833e4997378bce99e0a464d5d16890fd
Signed-off-by: Andy Yan <andy.yan@rock-chips.com>
Signed-off-by: Finley Xiao <finley.xiao@rock-chips.com>
This commit is contained in:
Andy Yan 2018-02-28 14:11:38 +08:00 committed by Kever Yang
parent 3d78ac3e4e
commit 54d254fe97
4 changed files with 1243 additions and 14 deletions

View File

@ -11,24 +11,35 @@
#define MHz 1000000
#define OSC_HZ (24 * MHz)
#define APLL_HZ (816 * MHz)
#define GPLL_HZ (600 * MHz)
#define CPLL_HZ (594 * MHz)
#define CORE_PERI_HZ 204000000
#define CORE_ACLK_HZ 408000000
#define CORE_DBG_HZ 204000000
#define BUS_ACLK_HZ 148500000
#define BUS_HCLK_HZ 148500000
#define BUS_PCLK_HZ 74250000
#define BUS_ACLK_HZ 200000000
#define BUS_HCLK_HZ 100000000
#define BUS_PCLK_HZ 100000000
#define PERI_ACLK_HZ 148500000
#define PERI_HCLK_HZ 148500000
#define PERI_PCLK_HZ 74250000
#define PERI_ACLK_HZ 200000000
#define PERI_HCLK_HZ 100000000
#define PERI_PCLK_HZ 100000000
enum apll_frequencies {
APLL_816_MHZ,
APLL_600_MHZ,
#define AUDIO_HCLK_HZ 100000000
#define AUDIO_PCLK_HZ 100000000
/* RK3308 pll id */
enum rk3308_pll_id {
APLL,
DPLL,
VPLL0,
VPLL1,
PLL_COUNT,
};
struct pll_div {
u32 refdiv;
u32 fbdiv;
u32 postdiv1;
u32 postdiv2;
u32 frac;
};
/* Private data for the clock driver - used by rockchip_get_cru() */
@ -76,6 +87,145 @@ struct rk3308_cru {
unsigned int sdio_con[2];
unsigned int emmc_con[2];
};
enum {
/* PLLCON0*/
PLL_BP_SHIFT = 15,
PLL_POSTDIV1_SHIFT = 12,
PLL_POSTDIV1_MASK = 7 << PLL_POSTDIV1_SHIFT,
PLL_FBDIV_SHIFT = 0,
PLL_FBDIV_MASK = 0xfff,
/* PLLCON1 */
PLL_PDSEL_SHIFT = 15,
PLL_PD1_SHIFT = 14,
PLL_PD_SHIFT = 13,
PLL_PD_MASK = 1 << PLL_PD_SHIFT,
PLL_DSMPD_SHIFT = 12,
PLL_DSMPD_MASK = 1 << PLL_DSMPD_SHIFT,
PLL_LOCK_STATUS_SHIFT = 10,
PLL_LOCK_STATUS_MASK = 1 << PLL_LOCK_STATUS_SHIFT,
PLL_POSTDIV2_SHIFT = 6,
PLL_POSTDIV2_MASK = 7 << PLL_POSTDIV2_SHIFT,
PLL_REFDIV_SHIFT = 0,
PLL_REFDIV_MASK = 0x3f,
/* PLLCON2 */
PLL_FOUT4PHASEPD_SHIFT = 27,
PLL_FOUTVCOPD_SHIFT = 26,
PLL_FOUTPOSTDIVPD_SHIFT = 25,
PLL_DACPD_SHIFT = 24,
PLL_FRAC_DIV = 0xffffff,
/* CRU_MODE */
PLLMUX_FROM_XIN24M = 0,
PLLMUX_FROM_PLL,
PLLMUX_FROM_RTC32K,
USBPHY480M_MODE_SHIFT = 8,
USBPHY480M_MODE_MASK = 3 << USBPHY480M_MODE_SHIFT,
VPLL1_MODE_SHIFT = 6,
VPLL1_MODE_MASK = 3 << VPLL1_MODE_SHIFT,
VPLL0_MODE_SHIFT = 4,
VPLL0_MODE_MASK = 3 << VPLL0_MODE_SHIFT,
DPLL_MODE_SHIFT = 2,
DPLL_MODE_MASK = 3 << DPLL_MODE_SHIFT,
APLL_MODE_SHIFT = 0,
APLL_MODE_MASK = 3 << APLL_MODE_SHIFT,
/* CRU_CLK_SEL0_CON */
CORE_ACLK_DIV_SHIFT = 12,
CORE_ACLK_DIV_MASK = 0x7 << CORE_ACLK_DIV_SHIFT,
CORE_DBG_DIV_SHIFT = 8,
CORE_DBG_DIV_MASK = 0xf << CORE_DBG_DIV_SHIFT,
CORE_CLK_PLL_SEL_SHIFT = 6,
CORE_CLK_PLL_SEL_MASK = 0x3 << CORE_CLK_PLL_SEL_SHIFT,
CORE_CLK_PLL_SEL_APLL = 0,
CORE_CLK_PLL_SEL_VPLL0,
CORE_CLK_PLL_SEL_VPLL1,
CORE_DIV_CON_SHIFT = 0,
CORE_DIV_CON_MASK = 0x0f << CORE_DIV_CON_SHIFT,
/* CRU_CLK_SEL5_CON */
BUS_PLL_SEL_SHIFT = 6,
BUS_PLL_SEL_MASK = 0x3 << BUS_PLL_SEL_SHIFT,
BUS_PLL_SEL_DPLL = 0,
BUS_PLL_SEL_VPLL0,
BUS_PLL_SEL_VPLL1,
BUS_ACLK_DIV_SHIFT = 0,
BUS_ACLK_DIV_MASK = 0x1f << BUS_ACLK_DIV_SHIFT,
/* CRU_CLK_SEL6_CON */
BUS_PCLK_DIV_SHIFT = 8,
BUS_PCLK_DIV_MASK = 0x1f << BUS_PCLK_DIV_SHIFT,
BUS_HCLK_DIV_SHIFT = 0,
BUS_HCLK_DIV_MASK = 0x1f << BUS_HCLK_DIV_SHIFT,
/* CRU_CLK_SEL25_CON */
/* CRU_CLK_SEL26_CON */
/* CRU_CLK_SEL27_CON */
/* CRU_CLK_SEL28_CON */
CLK_I2C_PLL_SEL_SHIFT = 14,
CLK_I2C_PLL_SEL_MASK = 0x3 << CLK_I2C_PLL_SEL_SHIFT,
CLK_I2C_PLL_SEL_DPLL = 0,
CLK_I2C_PLL_SEL_VPLL0,
CLK_I2C_PLL_SEL_24M,
CLK_I2C_DIV_CON_SHIFT = 0,
CLK_I2C_DIV_CON_MASK = 0x7f << CLK_I2C_DIV_CON_SHIFT,
/* CRU_CLK_SEL29_CON */
CLK_PWM_PLL_SEL_SHIFT = 14,
CLK_PWM_PLL_SEL_MASK = 0x3 << CLK_PWM_PLL_SEL_SHIFT,
CLK_PWM_PLL_SEL_DPLL = 0,
CLK_PWM_PLL_SEL_VPLL0,
CLK_PWM_PLL_SEL_24M,
CLK_PWM_DIV_CON_SHIFT = 0,
CLK_PWM_DIV_CON_MASK = 0x7f << CLK_PWM_DIV_CON_SHIFT,
/* CRU_CLK_SEL30_CON */
/* CRU_CLK_SEL31_CON */
/* CRU_CLK_SEL32_CON */
CLK_SPI_PLL_SEL_SHIFT = 14,
CLK_SPI_PLL_SEL_MASK = 0x3 << CLK_SPI_PLL_SEL_SHIFT,
CLK_SPI_PLL_SEL_DPLL = 0,
CLK_SPI_PLL_SEL_VPLL0,
CLK_SPI_PLL_SEL_24M,
CLK_SPI_DIV_CON_SHIFT = 0,
CLK_SPI_DIV_CON_MASK = 0x7f << CLK_SPI_DIV_CON_SHIFT,
/* CRU_CLK_SEL34_CON */
CLK_SARADC_DIV_CON_SHIFT = 0,
CLK_SARADC_DIV_CON_MASK = 0x7ff << CLK_SARADC_DIV_CON_SHIFT,
/* CRU_CLK_SEL36_CON */
PERI_PLL_SEL_SHIFT = 6,
PERI_PLL_SEL_MASK = 0x3 << PERI_PLL_SEL_SHIFT,
PERI_PLL_DPLL = 0,
PERI_PLL_VPLL0,
PERI_PLL_VPLL1,
PERI_ACLK_DIV_SHIFT = 0,
PERI_ACLK_DIV_MASK = 0x1f << PERI_ACLK_DIV_SHIFT,
/* CRU_CLK_SEL37_CON */
PERI_PCLK_DIV_SHIFT = 8,
PERI_PCLK_DIV_MASK = 0x1f << PERI_PCLK_DIV_SHIFT,
PERI_HCLK_DIV_SHIFT = 0,
PERI_HCLK_DIV_MASK = 0x1f << PERI_HCLK_DIV_SHIFT,
/* CRU_CLKSEL41_CON */
EMMC_CLK_SEL_SHIFT = 15,
EMMC_CLK_SEL_MASK = 1 << EMMC_CLK_SEL_SHIFT,
EMMC_CLK_SEL_EMMC = 0,
EMMC_CLK_SEL_EMMC_DIV50,
EMMC_PLL_SHIFT = 8,
EMMC_PLL_MASK = 0x3 << EMMC_PLL_SHIFT,
EMMC_SEL_DPLL = 0,
EMMC_SEL_VPLL0,
EMMC_SEL_VPLL1,
EMMC_SEL_24M,
EMMC_DIV_SHIFT = 0,
EMMC_DIV_MASK = 0xff << EMMC_DIV_SHIFT,
};
check_member(rk3308_cru, emmc_con[1], 0x494);
#endif

View File

@ -11,6 +11,7 @@ obj-$(CONFIG_ROCKCHIP_RK3128) += clk_rk3128.o
obj-$(CONFIG_ROCKCHIP_RK3188) += clk_rk3188.o
obj-$(CONFIG_ROCKCHIP_RK322X) += clk_rk322x.o
obj-$(CONFIG_ROCKCHIP_RK3288) += clk_rk3288.o
obj-$(CONFIG_ROCKCHIP_RK3308) += clk_rk3308.o
obj-$(CONFIG_ROCKCHIP_RK3328) += clk_rk3328.o
obj-$(CONFIG_ROCKCHIP_RK3368) += clk_rk3368.o
obj-$(CONFIG_ROCKCHIP_RK3399) += clk_rk3399.o

View File

@ -0,0 +1,716 @@
/*
* (C) Copyright 2017 Rockchip Electronics Co., Ltd
*
* SPDX-License-Identifier: GPL-2.0
*/
#define DEBUG
#include <common.h>
#include <bitfield.h>
#include <clk-uclass.h>
#include <dm.h>
#include <errno.h>
#include <syscon.h>
#include <asm/arch/clock.h>
#include <asm/arch/cru_rk3308.h>
#include <asm/arch/hardware.h>
#include <asm/io.h>
#include <dm/lists.h>
#include <dt-bindings/clock/rk3308-cru.h>
DECLARE_GLOBAL_DATA_PTR;
enum {
VCO_MAX_HZ = 3200U * 1000000,
VCO_MIN_HZ = 800 * 1000000,
OUTPUT_MAX_HZ = 3200U * 1000000,
OUTPUT_MIN_HZ = 24 * 1000000,
};
#define DIV_TO_RATE(input_rate, div) ((input_rate) / ((div) + 1))
#define PLL_DIVISORS(hz, _refdiv, _postdiv1, _postdiv2) {\
.refdiv = _refdiv,\
.fbdiv = (u32)((u64)hz * _refdiv * _postdiv1 * _postdiv2 / OSC_HZ),\
.postdiv1 = _postdiv1, .postdiv2 = _postdiv2};
static const struct pll_div apll_816_cfg = PLL_DIVISORS(816 * MHz, 1, 2, 1);
static u8 pll_mode_shift[PLL_COUNT] = {
APLL_MODE_SHIFT, DPLL_MODE_SHIFT, VPLL0_MODE_SHIFT,
VPLL1_MODE_SHIFT
};
static u32 pll_mode_mask[PLL_COUNT] = {
APLL_MODE_MASK, DPLL_MODE_MASK, VPLL0_MODE_MASK,
VPLL1_MODE_MASK
};
static ulong apll_hz, dpll_hz, vpll0_hz;
/*
* How to calculate the PLL:
* Formulas also embedded within the Fractional PLL Verilog model:
* If DSMPD = 1 (DSM is disabled, "integer mode")
* FOUTVCO = FREF / REFDIV * FBDIV
* FOUTPOSTDIV = FOUTVCO / POSTDIV1 / POSTDIV2
* Where:
* FOUTVCO = Fractional PLL non-divided output frequency
* FOUTPOSTDIV = Fractional PLL divided output frequency
* (output of second post divider)
* FREF = Fractional PLL input reference frequency, (the OSC_HZ 24MHz input)
* REFDIV = Fractional PLL input reference clock divider
* FBDIV = Integer value programmed into feedback divide
*
*/
static void rkclk_set_pll(struct rk3308_cru *cru, enum rk3308_pll_id pll_id,
const struct pll_div *div)
{
struct rk3308_pll *pll;
unsigned int *mode;
/* 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;
pll = &cru->pll[pll_id];
mode = &cru->mode;
debug("PLL at %p: fb=%d, ref=%d, pst1=%d, pst2=%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);
/*
* When power on or changing PLL setting,
* we must force PLL into slow mode to ensure output stable clock.
*/
rk_clrsetreg(mode, pll_mode_mask[pll_id],
PLLMUX_FROM_XIN24M << pll_mode_shift[pll_id]);
/* use integer mode */
rk_setreg(&pll->con1, 1 << PLL_DSMPD_SHIFT);
/* Power down */
rk_setreg(&pll->con1, 1 << PLL_PD_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));
/* Power Up */
rk_clrreg(&pll->con1, 1 << PLL_PD_SHIFT);
/* waiting for pll lock */
while (!(readl(&pll->con1) & (1 << PLL_LOCK_STATUS_SHIFT)))
udelay(1);
rk_clrsetreg(mode, pll_mode_mask[pll_id],
PLLMUX_FROM_PLL << pll_mode_shift[pll_id]);
}
static uint32_t rkclk_pll_get_rate(struct rk3308_cru *cru,
enum rk3308_pll_id pll_id)
{
u32 refdiv, fbdiv, postdiv1, postdiv2;
u32 con;
struct rk3308_pll *pll;
uint shift;
uint mask;
pll = &cru->pll[pll_id];
con = readl(&cru->mode);
shift = pll_mode_shift[pll_id];
mask = pll_mode_mask[pll_id];
switch ((con & mask) >> shift) {
case PLLMUX_FROM_XIN24M:
return OSC_HZ;
case PLLMUX_FROM_PLL:
/* 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 PLLMUX_FROM_RTC32K:
default:
return 32768;
}
}
static void rkclk_init(struct rk3308_cru *cru)
{
u32 aclk_div, hclk_div, pclk_div;
/* init pll */
rkclk_set_pll(cru, APLL, &apll_816_cfg);
/*
* select apll as cpu/core clock pll source and
* set up dependent divisors for PCLK and ACLK clocks.
* core hz : apll = 1:1
*/
apll_hz = rkclk_pll_get_rate(cru, DPLL);
aclk_div = apll_hz / CORE_ACLK_HZ - 1;
pclk_div = apll_hz / CORE_DBG_HZ - 1;
rk_clrsetreg(&cru->clksel_con[0],
CORE_ACLK_DIV_MASK | CORE_DBG_DIV_MASK |
CORE_CLK_PLL_SEL_MASK | CORE_DIV_CON_MASK,
aclk_div << CORE_ACLK_DIV_SHIFT |
pclk_div << CORE_DIV_CON_SHIFT |
CORE_CLK_PLL_SEL_APLL << CORE_CLK_PLL_SEL_SHIFT |
0 << CORE_DIV_CON_SHIFT);
/*
* select dpll as pd_bus bus clock source and
* set up dependent divisors for PCLK/HCLK and ACLK clocks.
*/
dpll_hz = rkclk_pll_get_rate(cru, DPLL);
aclk_div = dpll_hz / BUS_ACLK_HZ - 1;
hclk_div = dpll_hz / BUS_HCLK_HZ - 1;
pclk_div = dpll_hz / BUS_PCLK_HZ - 1;
rk_clrsetreg(&cru->clksel_con[5],
BUS_PLL_SEL_MASK | BUS_ACLK_DIV_MASK,
BUS_PLL_SEL_DPLL << BUS_PLL_SEL_SHIFT |
aclk_div << BUS_ACLK_DIV_SHIFT);
rk_clrsetreg(&cru->clksel_con[6],
BUS_PCLK_DIV_MASK | BUS_HCLK_DIV_MASK,
pclk_div << BUS_PCLK_DIV_SHIFT |
hclk_div << BUS_HCLK_DIV_SHIFT);
/*
* select vpll0 as pd_peri bus clock source and
* set up dependent divisors for PCLK/HCLK and ACLK clocks.
*/
vpll0_hz = rkclk_pll_get_rate(cru, VPLL0);
aclk_div = vpll0_hz / PERI_ACLK_HZ - 1;
hclk_div = vpll0_hz / PERI_HCLK_HZ - 1;
pclk_div = vpll0_hz / PERI_PCLK_HZ - 1;
rk_clrsetreg(&cru->clksel_con[36],
PERI_PLL_SEL_MASK | PERI_ACLK_DIV_MASK,
PERI_PLL_VPLL0 << PERI_PLL_SEL_SHIFT |
aclk_div << PERI_ACLK_DIV_SHIFT);
rk_clrsetreg(&cru->clksel_con[37],
PERI_PCLK_DIV_MASK | PERI_HCLK_DIV_MASK,
pclk_div << PERI_PCLK_DIV_SHIFT |
hclk_div << PERI_HCLK_DIV_SHIFT);
}
static ulong rk3308_i2c_get_clk(struct rk3308_cru *cru, ulong clk_id)
{
u32 div, con, con_id;
switch (clk_id) {
case SCLK_I2C0:
con_id = 25;
break;
case SCLK_I2C1:
con_id = 26;
break;
case SCLK_I2C2:
con_id = 27;
break;
case SCLK_I2C3:
con_id = 28;
break;
default:
printf("do not support this i2c bus\n");
return -EINVAL;
}
con = readl(&cru->clksel_con[con_id]);
div = con >> CLK_I2C_DIV_CON_SHIFT & CLK_I2C_DIV_CON_MASK;
return DIV_TO_RATE(dpll_hz, div);
}
static ulong rk3308_i2c_set_clk(struct rk3308_cru *cru, ulong clk_id, uint hz)
{
u32 src_clk_div, con_id;
src_clk_div = dpll_hz / hz;
assert(src_clk_div - 1 < 127);
switch (clk_id) {
case SCLK_I2C0:
con_id = 25;
break;
case SCLK_I2C1:
con_id = 26;
break;
case SCLK_I2C2:
con_id = 27;
break;
case SCLK_I2C3:
con_id = 28;
break;
default:
printf("do not support this i2c bus\n");
return -EINVAL;
}
rk_clrsetreg(&cru->clksel_con[con_id],
CLK_I2C_PLL_SEL_MASK | CLK_I2C_DIV_CON_MASK,
CLK_I2C_PLL_SEL_DPLL << CLK_I2C_PLL_SEL_SHIFT |
(src_clk_div - 1) << CLK_I2C_DIV_CON_SHIFT);
return rk3308_i2c_get_clk(cru, clk_id);
}
static ulong rk3308_mmc_get_clk(struct rk3308_cru *cru, uint clk_id)
{
u32 div, con, con_id;
switch (clk_id) {
case HCLK_SDMMC:
case SCLK_SDMMC:
con_id = 39;
break;
case HCLK_EMMC:
case SCLK_EMMC:
case SCLK_EMMC_SAMPLE:
con_id = 41;
break;
default:
return -EINVAL;
}
con = readl(&cru->clksel_con[con_id]);
div = (con & EMMC_DIV_MASK) >> EMMC_DIV_SHIFT;
if ((con & EMMC_PLL_MASK) >> EMMC_PLL_SHIFT
== EMMC_SEL_24M)
return DIV_TO_RATE(OSC_HZ, div) / 2;
else
return DIV_TO_RATE(vpll0_hz, div) / 2;
}
static ulong rk3308_mmc_set_clk(struct rk3308_cru *cru,
ulong clk_id, ulong set_rate)
{
int src_clk_div;
u32 con_id;
debug("%s %ld %ld\n", __func__, clk_id, set_rate);
switch (clk_id) {
case HCLK_SDMMC:
case SCLK_SDMMC:
con_id = 39;
break;
case HCLK_EMMC:
case SCLK_EMMC:
con_id = 41;
break;
default:
return -EINVAL;
}
/* Select clk_sdmmc/emmc source from VPLL0 by default */
/* mmc clock defaulg div 2 internal, need provide double in cru */
src_clk_div = DIV_ROUND_UP(vpll0_hz / 2, set_rate);
if (src_clk_div > 127) {
/* use 24MHz source for 400KHz clock */
src_clk_div = DIV_ROUND_UP(OSC_HZ / 2, set_rate);
rk_clrsetreg(&cru->clksel_con[con_id],
EMMC_PLL_MASK | EMMC_DIV_MASK | EMMC_CLK_SEL_MASK,
EMMC_CLK_SEL_EMMC << EMMC_CLK_SEL_SHIFT |
EMMC_SEL_24M << EMMC_PLL_SHIFT |
(src_clk_div - 1) << EMMC_DIV_SHIFT);
} else {
rk_clrsetreg(&cru->clksel_con[con_id],
EMMC_PLL_MASK | EMMC_DIV_MASK | EMMC_CLK_SEL_MASK,
EMMC_CLK_SEL_EMMC << EMMC_CLK_SEL_SHIFT |
EMMC_SEL_VPLL0 << EMMC_PLL_SHIFT |
(src_clk_div - 1) << EMMC_DIV_SHIFT);
}
return rk3308_mmc_get_clk(cru, clk_id);
}
static ulong rk3308_saradc_get_clk(struct rk3308_cru *cru)
{
u32 div, con;
con = readl(&cru->clksel_con[34]);
div = con >> CLK_SARADC_DIV_CON_SHIFT & CLK_SARADC_DIV_CON_MASK;
return DIV_TO_RATE(OSC_HZ, div);
}
static ulong rk3308_saradc_set_clk(struct rk3308_cru *cru, uint hz)
{
int src_clk_div;
src_clk_div = OSC_HZ / hz;
assert(src_clk_div - 1 < 2047);
rk_clrsetreg(&cru->clksel_con[34],
CLK_SARADC_DIV_CON_MASK,
(src_clk_div - 1) << CLK_SARADC_DIV_CON_SHIFT);
return rk3308_saradc_get_clk(cru);
}
static ulong rk3308_spi_get_clk(struct rk3308_cru *cru, ulong clk_id)
{
u32 div, con, con_id;
switch (clk_id) {
case SCLK_SPI0:
con_id = 30;
break;
case SCLK_SPI1:
con_id = 31;
break;
case SCLK_SPI2:
con_id = 32;
break;
default:
printf("do not support this spi bus\n");
return -EINVAL;
}
con = readl(&cru->clksel_con[con_id]);
div = con >> CLK_SPI_DIV_CON_SHIFT & CLK_SPI_DIV_CON_MASK;
return DIV_TO_RATE(dpll_hz, div);
}
static ulong rk3308_spi_set_clk(struct rk3308_cru *cru, ulong clk_id, uint hz)
{
u32 src_clk_div, con_id;
src_clk_div = dpll_hz / hz;
assert(src_clk_div - 1 < 127);
switch (clk_id) {
case SCLK_SPI0:
con_id = 30;
break;
case SCLK_SPI1:
con_id = 31;
break;
case SCLK_SPI2:
con_id = 32;
break;
default:
printf("do not support this spi bus\n");
return -EINVAL;
}
rk_clrsetreg(&cru->clksel_con[con_id],
CLK_SPI_PLL_SEL_MASK | CLK_SPI_DIV_CON_MASK,
CLK_SPI_PLL_SEL_DPLL << CLK_SPI_PLL_SEL_SHIFT |
(src_clk_div - 1) << CLK_SPI_DIV_CON_SHIFT);
return rk3308_spi_get_clk(cru, clk_id);
}
static ulong rk3308_pwm_get_clk(struct rk3308_cru *cru)
{
u32 div, con;
con = readl(&cru->clksel_con[29]);
div = con >> CLK_PWM_DIV_CON_SHIFT & CLK_PWM_DIV_CON_MASK;
return DIV_TO_RATE(dpll_hz, div);
}
static ulong rk3308_pwm_set_clk(struct rk3308_cru *cru, uint hz)
{
int src_clk_div;
src_clk_div = dpll_hz / hz;
assert(src_clk_div - 1 < 127);
rk_clrsetreg(&cru->clksel_con[29],
CLK_PWM_PLL_SEL_MASK | CLK_PWM_DIV_CON_MASK,
CLK_PWM_PLL_SEL_DPLL << CLK_PWM_PLL_SEL_SHIFT |
(src_clk_div - 1) << CLK_PWM_DIV_CON_SHIFT);
return rk3308_pwm_get_clk(cru);
}
static ulong rk3308_clk_get_rate(struct clk *clk)
{
struct rk3308_clk_priv *priv = dev_get_priv(clk->dev);
ulong rate = 0;
debug("%s id:%ld\n", __func__, clk->id);
switch (clk->id) {
case 0 ... 15:
return 0;
case HCLK_SDMMC:
case HCLK_EMMC:
case SCLK_SDMMC:
case SCLK_EMMC:
case SCLK_EMMC_SAMPLE:
rate = rk3308_mmc_get_clk(priv->cru, clk->id);
break;
case SCLK_I2C0:
case SCLK_I2C1:
case SCLK_I2C2:
case SCLK_I2C3:
rate = rk3308_i2c_get_clk(priv->cru, clk->id);
break;
case SCLK_SARADC:
rate = rk3308_saradc_get_clk(priv->cru);
break;
case SCLK_SPI0:
case SCLK_SPI1:
rate = rk3308_spi_get_clk(priv->cru, clk->id);
break;
case SCLK_PWM:
rate = rk3308_pwm_get_clk(priv->cru);
break;
default:
return -ENOENT;
}
return rate;
}
static ulong rk3308_clk_set_rate(struct clk *clk, ulong rate)
{
struct rk3308_clk_priv *priv = dev_get_priv(clk->dev);
ulong ret = 0;
debug("%s %ld %ld\n", __func__, clk->id, rate);
switch (clk->id) {
case 0 ... 15:
return 0;
case HCLK_SDMMC:
case HCLK_EMMC:
case SCLK_SDMMC:
case SCLK_EMMC:
ret = rk3308_mmc_set_clk(priv->cru, clk->id, rate);
break;
case SCLK_I2C0:
case SCLK_I2C1:
case SCLK_I2C2:
case SCLK_I2C3:
ret = rk3308_i2c_set_clk(priv->cru, clk->id, rate);
break;
case SCLK_SARADC:
ret = rk3308_saradc_set_clk(priv->cru, rate);
break;
case SCLK_SPI0:
case SCLK_SPI1:
ret = rk3308_spi_set_clk(priv->cru, clk->id, rate);
break;
case SCLK_PWM:
ret = rk3308_pwm_set_clk(priv->cru, rate);
break;
default:
return -ENOENT;
}
return ret;
}
#define ROCKCHIP_MMC_DELAY_SEL BIT(11)
#define ROCKCHIP_MMC_DEGREE_OFFSET 1
#define ROCKCHIP_MMC_DEGREE_MASK (0x3 << ROCKCHIP_MMC_DEGREE_OFFSET)
#define ROCKCHIP_MMC_DELAYNUM_OFFSET 3
#define ROCKCHIP_MMC_DELAYNUM_MASK (0xff << ROCKCHIP_MMC_DELAYNUM_OFFSET)
#define PSECS_PER_SEC 1000000000000LL
/*
* Each fine delay is between 44ps-77ps. Assume each fine delay is 60ps to
* simplify calculations. So 45degs could be anywhere between 33deg and 57.8deg.
*/
#define ROCKCHIP_MMC_DELAY_ELEMENT_PSEC 60
int rockchip_mmc_get_phase(struct clk *clk)
{
struct rk3308_clk_priv *priv = dev_get_priv(clk->dev);
struct rk3308_cru *cru = priv->cru;
u32 raw_value, delay_num;
u16 degrees = 0;
ulong rate;
rate = rk3308_clk_get_rate(clk);
if (rate < 0)
return rate;
if (clk->id == SCLK_EMMC_SAMPLE)
raw_value = readl(&cru->emmc_con[1]);
else
raw_value = readl(&cru->sdmmc_con[1]);
raw_value &= ROCKCHIP_MMC_DEGREE_MASK;
degrees = (raw_value >> ROCKCHIP_MMC_DEGREE_OFFSET) * 90;
if (raw_value & ROCKCHIP_MMC_DELAY_SEL) {
/* degrees/delaynum * 10000 */
unsigned long factor = (ROCKCHIP_MMC_DELAY_ELEMENT_PSEC / 10) *
36 * (rate / 1000000);
delay_num = (raw_value & ROCKCHIP_MMC_DELAYNUM_MASK);
delay_num >>= ROCKCHIP_MMC_DELAYNUM_OFFSET;
degrees += DIV_ROUND_CLOSEST(delay_num * factor, 10000);
}
return degrees % 360;
}
int rockchip_mmc_set_phase(struct clk *clk, u32 degrees)
{
struct rk3308_clk_priv *priv = dev_get_priv(clk->dev);
struct rk3308_cru *cru = priv->cru;
u8 nineties, remainder, delay_num;
u32 raw_value, delay;
ulong rate;
rate = rk3308_clk_get_rate(clk);
if (rate < 0)
return rate;
nineties = degrees / 90;
remainder = (degrees % 90);
/*
* Convert to delay; do a little extra work to make sure we
* don't overflow 32-bit / 64-bit numbers.
*/
delay = 10000000; /* PSECS_PER_SEC / 10000 / 10 */
delay *= remainder;
delay = DIV_ROUND_CLOSEST(delay, (rate / 1000) * 36 *
(ROCKCHIP_MMC_DELAY_ELEMENT_PSEC / 10));
delay_num = (u8)min_t(u32, delay, 255);
raw_value = delay_num ? ROCKCHIP_MMC_DELAY_SEL : 0;
raw_value |= delay_num << ROCKCHIP_MMC_DELAYNUM_OFFSET;
raw_value |= nineties << ROCKCHIP_MMC_DEGREE_OFFSET;
if (clk->id == SCLK_EMMC_SAMPLE)
writel(raw_value | 0xffff0000, &cru->emmc_con[1]);
else
writel(raw_value | 0xffff0000, &cru->sdmmc_con[1]);
debug("mmc set_phase(%d) delay_nums=%u reg=%#x actual_degrees=%d\n",
degrees, delay_num, raw_value, rockchip_mmc_get_phase(clk));
return 0;
}
static int rk3308_clk_get_phase(struct clk *clk)
{
int ret;
switch (clk->id) {
case SCLK_EMMC_SAMPLE:
case SCLK_SDMMC_SAMPLE:
ret = rockchip_mmc_get_phase(clk);
break;
default:
return -ENOENT;
}
return ret;
}
static int rk3308_clk_set_phase(struct clk *clk, int degrees)
{
int ret;
switch (clk->id) {
case SCLK_EMMC_SAMPLE:
case SCLK_SDMMC_SAMPLE:
ret = rockchip_mmc_set_phase(clk, degrees);
break;
default:
return -ENOENT;
}
return ret;
}
static struct clk_ops rk3308_clk_ops = {
.get_rate = rk3308_clk_get_rate,
.set_rate = rk3308_clk_set_rate,
.get_phase = rk3308_clk_get_phase,
.set_phase = rk3308_clk_set_phase,
};
static int rk3308_clk_probe(struct udevice *dev)
{
struct rk3308_clk_priv *priv = dev_get_priv(dev);
rkclk_init(priv->cru);
return 0;
}
static int rk3308_clk_ofdata_to_platdata(struct udevice *dev)
{
struct rk3308_clk_priv *priv = dev_get_priv(dev);
priv->cru = dev_read_addr_ptr(dev);
return 0;
}
static int rk3308_clk_bind(struct udevice *dev)
{
int ret;
struct udevice *sys_child, *sf_child;
struct sysreset_reg *priv;
struct softreset_reg *sf_priv;
/* The reset driver does not have a device node, so bind it here */
ret = device_bind_driver(dev, "rockchip_sysreset", "sysreset",
&sys_child);
if (ret) {
debug("Warning: No sysreset driver: ret=%d\n", ret);
} else {
priv = malloc(sizeof(struct sysreset_reg));
priv->glb_srst_fst_value = offsetof(struct rk3308_cru,
glb_srst_fst);
priv->glb_srst_snd_value = offsetof(struct rk3308_cru,
glb_srst_snd);
sys_child->priv = priv;
}
ret = device_bind_driver_to_node(dev, "rockchip_reset", "reset",
dev_ofnode(dev), &sf_child);
if (ret) {
debug("Warning: No rockchip reset driver: ret=%d\n", ret);
} else {
sf_priv = malloc(sizeof(struct softreset_reg));
sf_priv->sf_reset_offset = offsetof(struct rk3308_cru,
softrst_con[0]);
sf_priv->sf_reset_num = 12;
sf_child->priv = sf_priv;
}
return 0;
}
static const struct udevice_id rk3308_clk_ids[] = {
{ .compatible = "rockchip,rk3308-cru" },
{ }
};
U_BOOT_DRIVER(rockchip_rk3308_cru) = {
.name = "rockchip_rk3308_cru",
.id = UCLASS_CLK,
.of_match = rk3308_clk_ids,
.priv_auto_alloc_size = sizeof(struct rk3308_clk_priv),
.ofdata_to_platdata = rk3308_clk_ofdata_to_platdata,
.ops = &rk3308_clk_ops,
.bind = rk3308_clk_bind,
.probe = rk3308_clk_probe,
};

View File

@ -0,0 +1,362 @@
/*
* Copyright (c) 2017 Rockchip Electronics Co. Ltd.
* Author: Finley Xiao <finley.xiao@rock-chips.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#ifndef _DT_BINDINGS_CLK_ROCKCHIP_RK3308_H
#define _DT_BINDINGS_CLK_ROCKCHIP_RK3308_H
/* core clocks */
#define PLL_APLL 1
#define PLL_DPLL 2
#define PLL_VPLL0 3
#define PLL_VPLL1 4
#define ARMCLK 5
/* sclk (special clocks) */
#define USB480M 14
#define SCLK_RTC32K 15
#define SCLK_PVTM_CORE 16
#define SCLK_UART0 17
#define SCLK_UART1 18
#define SCLK_UART2 19
#define SCLK_UART3 20
#define SCLK_UART4 21
#define SCLK_I2C0 22
#define SCLK_I2C1 23
#define SCLK_I2C2 24
#define SCLK_I2C3 25
#define SCLK_PWM 26
#define SCLK_SPI0 27
#define SCLK_SPI1 28
#define SCLK_SPI2 29
#define SCLK_TIMER0 30
#define SCLK_TIMER1 31
#define SCLK_TIMER2 32
#define SCLK_TIMER3 33
#define SCLK_TIMER4 34
#define SCLK_TIMER5 35
#define SCLK_TSADC 36
#define SCLK_SARADC 37
#define SCLK_OTP 38
#define SCLK_OTP_USR 39
#define SCLK_CPU_BOOST 40
#define SCLK_CRYPTO 41
#define SCLK_CRYPTO_APK 42
#define SCLK_NANDC_DIV 43
#define SCLK_NANDC_DIV50 44
#define SCLK_NANDC 45
#define SCLK_SDMMC_DIV 46
#define SCLK_SDMMC_DIV50 47
#define SCLK_SDMMC 48
#define SCLK_SDMMC_DRV 49
#define SCLK_SDMMC_SAMPLE 50
#define SCLK_SDIO_DIV 51
#define SCLK_SDIO_DIV50 52
#define SCLK_SDIO 53
#define SCLK_SDIO_DRV 54
#define SCLK_SDIO_SAMPLE 55
#define SCLK_EMMC_DIV 56
#define SCLK_EMMC_DIV50 57
#define SCLK_EMMC 58
#define SCLK_EMMC_DRV 59
#define SCLK_EMMC_SAMPLE 60
#define SCLK_SFC 61
#define SCLK_OTG_ADP 62
#define SCLK_GMAC_SRC 63
#define SCLK_GMAC 64
#define SCLK_MAC_REF 65
#define SCLK_GMAC_RX_TX 66
#define SCLK_GMAC_RMII 67
#define SCLK_DDR_MON_TIMER 68
#define SCLK_DDR_MON 69
#define SCLK_DDRCLK 70
#define SCLK_PMU 71
#define SCLK_USBPHY_REF 72
#define SCLK_WIFI 73
#define SCLK_PVTM_PMU 74
#define SCLK_PDM 75
#define SCLK_I2S0_8CH_TX 76
#define SCLK_I2S0_8CH_TX_OUT 77
#define SCLK_I2S0_8CH_RX 78
#define SCLK_I2S0_8CH_RX_OUT 79
#define SCLK_I2S1_8CH_TX 80
#define SCLK_I2S1_8CH_TX_OUT 81
#define SCLK_I2S1_8CH_RX 82
#define SCLK_I2S1_8CH_RX_OUT 83
#define SCLK_I2S2_8CH_TX 84
#define SCLK_I2S2_8CH_TX_OUT 85
#define SCLK_I2S2_8CH_RX 86
#define SCLK_I2S2_8CH_RX_OUT 87
#define SCLK_I2S3_8CH_TX 88
#define SCLK_I2S3_8CH_TX_OUT 89
#define SCLK_I2S3_8CH_RX 90
#define SCLK_I2S3_8CH_RX_OUT 91
#define SCLK_I2S0_2CH 92
#define SCLK_I2S0_2CH_OUT 93
#define SCLK_I2S1_2CH 94
#define SCLK_I2S1_2CH_OUT 95
#define SCLK_SPDIF_TX_DIV 96
#define SCLK_SPDIF_TX_DIV50 97
#define SCLK_SPDIF_TX 98
#define SCLK_SPDIF_RX_DIV 99
#define SCLK_SPDIF_RX_DIV50 100
#define SCLK_SPDIF_RX 101
/* dclk */
#define DCLK_VOP 120
/* aclk */
#define ACLK_CORE 130
#define ACLK_BUS 131
#define ACLK_PERI 132
#define ACLK_GMAC 133
#define ACLK_CRYPTO 134
#define ACLK_VOP 135
#define ACLK_GIC 136
/* hclk */
#define HCLK_BUS 150
#define HCLK_PERI 151
#define HCLK_AUDIO 152
#define HCLK_NANDC 153
#define HCLK_SDMMC 154
#define HCLK_SDIO 155
#define HCLK_EMMC 156
#define HCLK_SFC 157
#define HCLK_OTG 158
#define HCLK_HOST 159
#define HCLK_HOST_ARB 160
#define HCLK_PDM 161
#define HCLK_SPDIFTX 162
#define HCLK_SPDIFRX 163
#define HCLK_I2S0_8CH 164
#define HCLK_I2S1_8CH 165
#define HCLK_I2S2_8CH 166
#define HCLK_I2S3_8CH 167
#define HCLK_I2S0_2CH 168
#define HCLK_I2S1_2CH 169
#define HCLK_VAD 170
#define HCLK_CRYPTO 171
#define HCLK_VOP 172
/* pclk */
#define PCLK_BUS 190
#define PCLK_DDR 191
#define PCLK_PERI 192
#define PCLK_PMU 193
#define PCLK_AUDIO 194
#define PCLK_GMAC 195
#define PCLK_ACODEC 196
#define PCLK_UART0 197
#define PCLK_UART1 198
#define PCLK_UART2 199
#define PCLK_UART3 200
#define PCLK_UART4 201
#define PCLK_I2C0 202
#define PCLK_I2C1 203
#define PCLK_I2C2 204
#define PCLK_I2C3 205
#define PCLK_PWM 206
#define PCLK_SPI0 207
#define PCLK_SPI1 208
#define PCLK_SPI2 209
#define PCLK_SARADC 210
#define PCLK_TSADC 211
#define PCLK_TIMER 212
#define PCLK_OTP_NS 213
#define PCLK_WDT_NS 214
#define PCLK_GPIO0 215
#define PCLK_GPIO1 216
#define PCLK_GPIO2 217
#define PCLK_GPIO3 218
#define PCLK_GPIO4 219
#define PCLK_SGRF 220
#define PCLK_GRF 221
#define PCLK_USBSD_DET 222
#define PCLK_DDR_UPCTL 223
#define PCLK_DDR_MON 224
#define PCLK_DDRPHY 225
#define PCLK_DDR_STDBY 226
#define PCLK_USB_GRF 227
#define PCLK_CRU 228
#define PCLK_OTP_PHY 229
#define PCLK_CPU_BOOST 230
#define CLK_NR_CLKS (PCLK_CPU_BOOST + 1)
/* soft-reset indices */
/* cru_softrst_con0 */
#define SRST_CORE0_PO 0
#define SRST_CORE1_PO 1
#define SRST_CORE2_PO 2
#define SRST_CORE3_PO 3
#define SRST_CORE0 4
#define SRST_CORE1 5
#define SRST_CORE2 6
#define SRST_CORE3 7
#define SRST_CORE0_DBG 8
#define SRST_CORE1_DBG 9
#define SRST_CORE2_DBG 10
#define SRST_CORE3_DBG 11
#define SRST_TOPDBG 12
#define SRST_CORE_NOC 13
#define SRST_STRC_A 14
#define SRST_L2C 15
/* cru_softrst_con1 */
#define SRST_DAP 16
#define SRST_CORE_PVTM 17
#define SRST_CORE_PRF 18
#define SRST_CORE_GRF 19
#define SRST_DDRUPCTL 20
#define SRST_DDRUPCTL_P 22
#define SRST_MSCH 23
#define SRST_DDRMON_P 25
#define SRST_DDRSTDBY_P 26
#define SRST_DDRSTDBY 27
#define SRST_DDRPHY 28
#define SRST_DDRPHY_DIV 29
#define SRST_DDRPHY_P 30
/* cru_softrst_con2 */
#define SRST_BUS_NIU_H 32
#define SRST_USB_NIU_P 33
#define SRST_CRYPTO_A 34
#define SRST_CRYPTO_H 35
#define SRST_CRYPTO 36
#define SRST_CRYPTO_APK 37
#define SRST_VOP_A 38
#define SRST_VOP_H 39
#define SRST_VOP_D 40
#define SRST_INTMEM_A 41
#define SRST_ROM_H 42
#define SRST_GIC_A 43
#define SRST_UART0_P 44
#define SRST_UART0 45
#define SRST_UART1_P 46
#define SRST_UART1 47
/* cru_softrst_con3 */
#define SRST_UART2_P 48
#define SRST_UART2 49
#define SRST_UART3_P 50
#define SRST_UART3 51
#define SRST_UART4_P 52
#define SRST_UART4 53
#define SRST_I2C0_P 54
#define SRST_I2C0 55
#define SRST_I2C1_P 56
#define SRST_I2C1 57
#define SRST_I2C2_P 58
#define SRST_I2C2 59
#define SRST_I2C3_P 60
#define SRST_I2C3 61
#define SRST_PWM_P 62
#define SRST_PWM 63
/* cru_softrst_con4 */
#define SRST_SPI0_P 64
#define SRST_SPI0 65
#define SRST_SPI1_P 66
#define SRST_SPI1 67
#define SRST_SPI2_P 68
#define SRST_SPI2 69
#define SRST_SARADC_P 70
#define SRST_TSADC_P 71
#define SRST_TSADC 72
#define SRST_TIMER0_P 73
#define SRST_TIMER0 74
#define SRST_TIMER1 75
#define SRST_TIMER2 76
#define SRST_TIMER3 77
#define SRST_TIMER4 78
#define SRST_TIMER5 79
/* cru_softrst_con5 */
#define SRST_OTP_NS_P 80
#define SRST_OTP_NS_SBPI 81
#define SRST_OTP_NS_USR 82
#define SRST_OTP_PHY_P 83
#define SRST_OTP_PHY 84
#define SRST_GPIO0_P 86
#define SRST_GPIO1_P 87
#define SRST_GPIO2_P 88
#define SRST_GPIO3_P 89
#define SRST_GPIO4_P 90
#define SRST_GRF_P 91
#define SRST_USBSD_DET_P 92
#define SRST_PMU 93
#define SRST_PMU_PVTM 94
#define SRST_USB_GRF_P 95
/* cru_softrst_con6 */
#define SRST_CPU_BOOST 96
#define SRST_CPU_BOOST_P 97
#define SRST_PERI_NIU_A 104
#define SRST_PERI_NIU_H 105
#define SRST_PERI_NIU_p 106
#define SRST_USB2OTG_H 107
#define SRST_USB2OTG 108
#define SRST_USB2OTG_ADP 109
#define SRST_USB2HOST_H 110
#define SRST_USB2HOST_ARB_H 111
/* cru_softrst_con7 */
#define SRST_USB2HOST_AUX_H 112
#define SRST_USB2HOST_EHCI 113
#define SRST_USB2HOST 114
#define SRST_USBPHYPOR 115
#define SRST_UTMI0 116
#define SRST_UTMI1 117
#define SRST_SDIO_H 118
#define SRST_EMMC_H 119
#define SRST_SFC_H 120
#define SRST_SFC 121
#define SRST_SD_H 122
#define SRST_NANDC_H 123
#define SRST_NANDC_N 124
#define SRST_GMAC_A 125
/* cru_softrst_con8 */
#define SRST_AUDIO_NIU_H 128
#define SRST_AUDIO_NIU_P 129
#define SRST_PDM_H 130
#define SRST_PDM_M 131
#define SRST_SPDIFTX_H 132
#define SRST_SPDIFTX_M 133
#define SRST_SPDIFRX_H 134
#define SRST_SPDIFRX_M 135
#define SRST_I2S0_8CH_H 136
#define SRST_I2S0_8CH_TX_M 137
#define SRST_I2S0_8CH_RX_M 138
#define SRST_I2S1_8CH_H 139
#define SRST_I2S1_8CH_TX_M 140
#define SRST_I2S1_8CH_RX_M 141
#define SRST_I2S2_8CH_H 142
#define SRST_I2S2_8CH_TX_M 143
/* cru_softrst_con9 */
#define SRST_I2S2_8CH_RX_M 144
#define SRST_I2S3_8CH_H 145
#define SRST_I2S3_8CH_TX_M 146
#define SRST_I2S3_8CH_RX_M 147
#define SRST_I2S0_2CH_H 148
#define SRST_I2S0_2CH_M 149
#define SRST_I2S1_2CH_H 150
#define SRST_I2S1_2CH_M 151
#define SRST_VAD_H 152
#define SRST_ACODEC_P 153
#endif