diff options
Diffstat (limited to 'drivers/clk/rockchip/clk_rk3066.c')
| -rw-r--r-- | drivers/clk/rockchip/clk_rk3066.c | 717 |
1 files changed, 717 insertions, 0 deletions
diff --git a/drivers/clk/rockchip/clk_rk3066.c b/drivers/clk/rockchip/clk_rk3066.c new file mode 100644 index 00000000000..2c12f6e0441 --- /dev/null +++ b/drivers/clk/rockchip/clk_rk3066.c @@ -0,0 +1,717 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * (C) Copyright 2015 Google, Inc + * (C) Copyright 2016 Heiko Stuebner <heiko@sntech.de> + */ + +#include <bitfield.h> +#include <common.h> +#include <clk-uclass.h> +#include <dm.h> +#include <dt-structs.h> +#include <errno.h> +#include <log.h> +#include <malloc.h> +#include <mapmem.h> +#include <syscon.h> +#include <asm/io.h> +#include <asm/arch-rockchip/clock.h> +#include <asm/arch-rockchip/cru_rk3066.h> +#include <asm/arch-rockchip/grf_rk3066.h> +#include <asm/arch-rockchip/hardware.h> +#include <dt-bindings/clock/rk3066a-cru.h> +#include <dm/device_compat.h> +#include <dm/device-internal.h> +#include <dm/lists.h> +#include <dm/uclass-internal.h> +#include <linux/delay.h> +#include <linux/err.h> +#include <linux/log2.h> +#include <linux/stringify.h> + +struct rk3066_clk_plat { +#if CONFIG_IS_ENABLED(OF_PLATDATA) + struct dtd_rockchip_rk3066a_cru dtd; +#endif +}; + +struct pll_div { + u32 nr; + u32 nf; + u32 no; +}; + +enum { + VCO_MAX_HZ = 1416U * 1000000, + VCO_MIN_HZ = 300 * 1000000, + OUTPUT_MAX_HZ = 1416U * 1000000, + OUTPUT_MIN_HZ = 30 * 1000000, + FREF_MAX_HZ = 1416U * 1000000, + FREF_MIN_HZ = 30 * 1000, +}; + +enum { + /* PLL CON0 */ + PLL_OD_MASK = GENMASK(3, 0), + + /* PLL CON1 */ + PLL_NF_MASK = GENMASK(12, 0), + + /* PLL CON2 */ + PLL_BWADJ_MASK = GENMASK(11, 0), + + /* PLL CON3 */ + PLL_RESET_SHIFT = 5, + + /* GRF_SOC_STATUS0 */ + SOCSTS_DPLL_LOCK = BIT(4), + SOCSTS_APLL_LOCK = BIT(5), + SOCSTS_CPLL_LOCK = BIT(6), + SOCSTS_GPLL_LOCK = BIT(7), +}; + +#define DIV_TO_RATE(input_rate, div) ((input_rate) / ((div) + 1)) + +#define PLL_DIVISORS(hz, _nr, _no) {\ + .nr = _nr, .nf = (u32)((u64)hz * _nr * _no / OSC_HZ), .no = _no};\ + _Static_assert(((u64)hz * _nr * _no / OSC_HZ) * OSC_HZ /\ + (_nr * _no) == hz, #hz "Hz cannot be hit with PLL "\ + "divisors on line " __stringify(__LINE__)) + +/* Keep divisors as low as possible to reduce jitter and power usage. */ +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); + +static int rk3066_clk_set_pll(struct rk3066_cru *cru, enum rk_clk_id clk_id, + const struct pll_div *div) +{ + int pll_id = rk_pll_id(clk_id); + struct rk3066_pll *pll = &cru->pll[pll_id]; + /* All PLLs have the 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("%s: PLL at %x: nf=%d, nr=%d, no=%d, vco=%u Hz, output=%u Hz\n", __func__, + (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, BIT(PLL_RESET_SHIFT)); + + rk_clrsetreg(&pll->con0, + CLKR_MASK | 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); + + /* Exit reset. */ + rk_clrreg(&pll->con3, BIT(PLL_RESET_SHIFT)); + + return 0; +} + +static int rk3066_clk_configure_ddr(struct rk3066_cru *cru, struct rk3066_grf *grf, + unsigned int hz) +{ + static const struct pll_div dpll_cfg[] = { + {.nf = 25, .nr = 2, .no = 1}, + {.nf = 400, .nr = 9, .no = 2}, + {.nf = 500, .nr = 9, .no = 2}, + {.nf = 100, .nr = 3, .no = 1}, + }; + int cfg; + + switch (hz) { + case 300000000: + cfg = 0; + break; + case 533000000: /* actually 533.3P MHz */ + cfg = 1; + break; + case 666000000: /* actually 666.6P MHz */ + cfg = 2; + break; + case 800000000: + cfg = 3; + break; + default: + debug("%s: unsupported SDRAM frequency", __func__); + return -EINVAL; + } + + /* Enter PLL slow mode. */ + rk_clrsetreg(&cru->cru_mode_con, DPLL_MODE_MASK, + PLL_MODE_SLOW << DPLL_MODE_SHIFT); + + rk3066_clk_set_pll(cru, CLK_DDR, &dpll_cfg[cfg]); + + /* Wait for PLL lock. */ + while (!(readl(&grf->soc_status0) & SOCSTS_DPLL_LOCK)) + udelay(1); + + /* Enter PLL normal mode. */ + rk_clrsetreg(&cru->cru_mode_con, DPLL_MODE_MASK, + PLL_MODE_NORMAL << DPLL_MODE_SHIFT); + + return 0; +} + +static int rk3066_clk_configure_cpu(struct rk3066_cru *cru, struct rk3066_grf *grf, + unsigned int hz) +{ + static const struct pll_div apll_cfg[] = { + {.nf = 50, .nr = 1, .no = 2}, + {.nf = 59, .nr = 1, .no = 1}, + }; + int div_core_peri, div_cpu_aclk, cfg; + + /* + * We support two possible frequencies, the safe 600MHz + * which will work with default pmic settings and will + * be set to get away from the 24MHz default and + * the maximum of 1.416Ghz, 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_cpu_aclk = 3; + break; + case APLL_HZ: + cfg = 1; + div_core_peri = 2; + div_cpu_aclk = 3; + break; + default: + debug("unsupported ARMCLK frequency"); + return -EINVAL; + } + + /* Enter PLL slow mode. */ + rk_clrsetreg(&cru->cru_mode_con, APLL_MODE_MASK, + PLL_MODE_SLOW << APLL_MODE_SHIFT); + + rk3066_clk_set_pll(cru, CLK_ARM, &apll_cfg[cfg]); + + /* Wait 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, + div_core_peri << CORE_PERI_DIV_SHIFT); + + /* Set up dependent divisor for cpu_aclk. */ + rk_clrsetreg(&cru->cru_clksel_con[1], + CPU_ACLK_DIV_MASK, + div_cpu_aclk << CPU_ACLK_DIV_SHIFT); + + /* Enter PLL normal mode. */ + rk_clrsetreg(&cru->cru_mode_con, APLL_MODE_MASK, + PLL_MODE_NORMAL << APLL_MODE_SHIFT); + + return hz; +} + +static uint32_t rk3066_clk_pll_get_rate(struct rk3066_cru *cru, + enum rk_clk_id clk_id) +{ + u32 nr, no, nf; + u32 con; + int pll_id = rk_pll_id(clk_id); + struct rk3066_pll *pll = &cru->pll[pll_id]; + static u8 clk_shift[CLK_COUNT] = { + 0xff, APLL_MODE_SHIFT, DPLL_MODE_SHIFT, CPLL_MODE_SHIFT, + GPLL_MODE_SHIFT + }; + uint shift; + + con = readl(&cru->cru_mode_con); + shift = clk_shift[clk_id]; + switch (FIELD_GET(APLL_MODE_MASK, con >> shift)) { + case PLL_MODE_SLOW: + return OSC_HZ; + case PLL_MODE_NORMAL: + /* normal mode */ + con = readl(&pll->con0); + no = bitfield_extract_by_mask(con, CLKOD_MASK) + 1; + nr = bitfield_extract_by_mask(con, CLKR_MASK) + 1; + con = readl(&pll->con1); + nf = bitfield_extract_by_mask(con, CLKF_MASK) + 1; + + return (OSC_HZ * nf) / (nr * no); + case PLL_MODE_DEEP: + default: + return 32768; + } +} + +static ulong rk3066_clk_mmc_get_clk(struct rk3066_cru *cru, uint gclk_rate, + int periph) +{ + uint div; + u32 con; + + switch (periph) { + case HCLK_EMMC: + case SCLK_EMMC: + con = readl(&cru->cru_clksel_con[12]); + div = bitfield_extract_by_mask(con, EMMC_DIV_MASK); + break; + case HCLK_SDMMC: + case SCLK_SDMMC: + con = readl(&cru->cru_clksel_con[11]); + div = bitfield_extract_by_mask(con, MMC0_DIV_MASK); + break; + case HCLK_SDIO: + case SCLK_SDIO: + con = readl(&cru->cru_clksel_con[12]); + div = bitfield_extract_by_mask(con, SDIO_DIV_MASK); + break; + default: + return -EINVAL; + } + + return DIV_TO_RATE(gclk_rate, div) / 2; +} + +static ulong rk3066_clk_mmc_set_clk(struct rk3066_cru *cru, uint gclk_rate, + int periph, uint freq) +{ + int src_clk_div; + + debug("%s: gclk_rate=%u\n", __func__, gclk_rate); + /* MMC clock by default divides by 2 internally, so need to 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, + src_clk_div << EMMC_DIV_SHIFT); + break; + case HCLK_SDMMC: + case SCLK_SDMMC: + rk_clrsetreg(&cru->cru_clksel_con[11], + MMC0_DIV_MASK, + src_clk_div << MMC0_DIV_SHIFT); + break; + case HCLK_SDIO: + case SCLK_SDIO: + rk_clrsetreg(&cru->cru_clksel_con[12], + SDIO_DIV_MASK, + src_clk_div << SDIO_DIV_SHIFT); + break; + default: + return -EINVAL; + } + + return rk3066_clk_mmc_get_clk(cru, gclk_rate, periph); +} + +static ulong rk3066_clk_spi_get_clk(struct rk3066_cru *cru, uint gclk_rate, + int periph) +{ + uint div; + u32 con; + + switch (periph) { + case SCLK_SPI0: + con = readl(&cru->cru_clksel_con[25]); + div = bitfield_extract_by_mask(con, SPI0_DIV_MASK); + break; + case SCLK_SPI1: + con = readl(&cru->cru_clksel_con[25]); + div = bitfield_extract_by_mask(con, SPI1_DIV_MASK); + break; + default: + return -EINVAL; + } + + return DIV_TO_RATE(gclk_rate, div); +} + +static ulong rk3066_clk_spi_set_clk(struct rk3066_cru *cru, uint gclk_rate, + int periph, uint 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 >> SPI0_DIV_SHIFT); + rk_clrsetreg(&cru->cru_clksel_con[25], + SPI0_DIV_MASK, + src_clk_div << SPI0_DIV_SHIFT); + break; + case SCLK_SPI1: + assert(src_clk_div <= SPI1_DIV_MASK >> SPI1_DIV_SHIFT); + rk_clrsetreg(&cru->cru_clksel_con[25], + SPI1_DIV_MASK, + src_clk_div << SPI1_DIV_SHIFT); + break; + default: + return -EINVAL; + } + + return rk3066_clk_spi_get_clk(cru, gclk_rate, periph); +} + +static ulong rk3066_clk_saradc_get_clk(struct rk3066_cru *cru, int periph) +{ + u32 div, con; + + switch (periph) { + case SCLK_SARADC: + con = readl(&cru->cru_clksel_con[24]); + div = bitfield_extract_by_mask(con, SARADC_DIV_MASK); + break; + case SCLK_TSADC: + con = readl(&cru->cru_clksel_con[34]); + div = bitfield_extract_by_mask(con, TSADC_DIV_MASK); + break; + default: + return -EINVAL; + } + return DIV_TO_RATE(PERI_PCLK_HZ, div); +} + +static ulong rk3066_clk_saradc_set_clk(struct rk3066_cru *cru, uint hz, + int periph) +{ + int src_clk_div; + + src_clk_div = DIV_ROUND_UP(PERI_PCLK_HZ, hz) - 1; + assert(src_clk_div < 128); + + switch (periph) { + case SCLK_SARADC: + rk_clrsetreg(&cru->cru_clksel_con[24], + SARADC_DIV_MASK, + src_clk_div << SARADC_DIV_SHIFT); + break; + case SCLK_TSADC: + rk_clrsetreg(&cru->cru_clksel_con[34], + SARADC_DIV_MASK, + src_clk_div << SARADC_DIV_SHIFT); + break; + default: + return -EINVAL; + } + + return rk3066_clk_saradc_get_clk(cru, periph); +} + +static void rk3066_clk_init(struct rk3066_cru *cru, struct rk3066_grf *grf) +{ + u32 aclk_div, hclk_div, pclk_div, h2p_div; + + /* Enter PLL slow mode. */ + rk_clrsetreg(&cru->cru_mode_con, + GPLL_MODE_MASK | + CPLL_MODE_MASK, + PLL_MODE_SLOW << GPLL_MODE_SHIFT | + PLL_MODE_SLOW << CPLL_MODE_SHIFT); + + /* Init PLL. */ + rk3066_clk_set_pll(cru, CLK_GENERAL, &gpll_init_cfg); + rk3066_clk_set_pll(cru, CLK_CODEC, &cpll_init_cfg); + + /* Wait for PLL lock. */ + while ((readl(&grf->soc_status0) & + (SOCSTS_CPLL_LOCK | SOCSTS_GPLL_LOCK)) != + (SOCSTS_CPLL_LOCK | SOCSTS_GPLL_LOCK)) + udelay(1); + + /* + * Select CPU clock PLL source and + * reparent aclk_cpu_pre from APPL to GPLL. + * Set up dependent divisors for PCLK/HCLK and ACLK clocks. + */ + 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 | + A9_CORE_DIV_MASK, + CPU_ACLK_PLL_SELECT_GPLL << CPU_ACLK_PLL_SHIFT | + aclk_div << A9_CORE_DIV_SHIFT); + + hclk_div = ilog2(CPU_ACLK_HZ / CPU_HCLK_HZ); + assert((1 << hclk_div) * CPU_HCLK_HZ == CPU_ACLK_HZ && hclk_div < 0x3); + pclk_div = ilog2(CPU_ACLK_HZ / CPU_PCLK_HZ); + assert((1 << pclk_div) * CPU_PCLK_HZ == CPU_ACLK_HZ && pclk_div < 0x4); + h2p_div = ilog2(CPU_HCLK_HZ / CPU_H2P_HZ); + assert((1 << h2p_div) * CPU_H2P_HZ == CPU_HCLK_HZ && pclk_div < 0x3); + + rk_clrsetreg(&cru->cru_clksel_con[1], + AHB2APB_DIV_MASK | + CPU_PCLK_DIV_MASK | + CPU_HCLK_DIV_MASK, + h2p_div << AHB2APB_DIV_SHIFT | + pclk_div << CPU_PCLK_DIV_SHIFT | + hclk_div << CPU_HCLK_DIV_SHIFT); + + /* + * Select PERI clock PLL source and + * set up dependent divisors for PCLK/HCLK and ACLK clocks. + */ + aclk_div = GPLL_HZ / PERI_ACLK_HZ - 1; + assert((aclk_div + 1) * PERI_ACLK_HZ == GPLL_HZ && aclk_div < 0x1f); + + hclk_div = ilog2(PERI_ACLK_HZ / PERI_HCLK_HZ); + assert((1 << hclk_div) * PERI_HCLK_HZ == + PERI_ACLK_HZ && (hclk_div < 0x4)); + + pclk_div = ilog2(PERI_ACLK_HZ / PERI_PCLK_HZ); + assert((1 << pclk_div) * PERI_PCLK_HZ == + PERI_ACLK_HZ && (pclk_div < 0x4)); + + rk_clrsetreg(&cru->cru_clksel_con[10], + PERI_PCLK_DIV_MASK | + PERI_HCLK_DIV_MASK | + PERI_ACLK_DIV_MASK, + PERI_SEL_GPLL << PERI_SEL_PLL_SHIFT | + pclk_div << PERI_PCLK_DIV_SHIFT | + hclk_div << PERI_HCLK_DIV_SHIFT | + aclk_div << PERI_ACLK_DIV_SHIFT); + + /* Enter PLL normal mode. */ + rk_clrsetreg(&cru->cru_mode_con, + GPLL_MODE_MASK | + CPLL_MODE_MASK, + PLL_MODE_NORMAL << GPLL_MODE_SHIFT | + PLL_MODE_NORMAL << CPLL_MODE_SHIFT); + + rk3066_clk_mmc_set_clk(cru, PERI_HCLK_HZ, HCLK_SDMMC, 16000000); +} + +static ulong rk3066_clk_get_rate(struct clk *clk) +{ + struct rk3066_clk_priv *priv = dev_get_priv(clk->dev); + ulong new_rate, gclk_rate; + + gclk_rate = rk3066_clk_pll_get_rate(priv->cru, CLK_GENERAL); + switch (clk->id) { + case 1 ... 4: + new_rate = rk3066_clk_pll_get_rate(priv->cru, clk->id); + break; + case HCLK_EMMC: + case HCLK_SDMMC: + case HCLK_SDIO: + case SCLK_EMMC: + case SCLK_SDMMC: + case SCLK_SDIO: + new_rate = rk3066_clk_mmc_get_clk(priv->cru, PERI_HCLK_HZ, + clk->id); + break; + case SCLK_SPI0: + case SCLK_SPI1: + new_rate = rk3066_clk_spi_get_clk(priv->cru, PERI_PCLK_HZ, + clk->id); + break; + case PCLK_I2C0: + case PCLK_I2C1: + case PCLK_I2C2: + case PCLK_I2C3: + case PCLK_I2C4: + return gclk_rate; + case SCLK_SARADC: + case SCLK_TSADC: + new_rate = rk3066_clk_saradc_get_clk(priv->cru, clk->id); + break; + case SCLK_TIMER0: + case SCLK_TIMER1: + case SCLK_TIMER2: + case SCLK_UART0: + case SCLK_UART1: + case SCLK_UART2: + case SCLK_UART3: + return OSC_HZ; + default: + return -ENOENT; + } + + return new_rate; +} + +static ulong rk3066_clk_set_rate(struct clk *clk, ulong rate) +{ + struct rk3066_clk_priv *priv = dev_get_priv(clk->dev); + struct rk3066_cru *cru = priv->cru; + ulong new_rate; + + switch (clk->id) { + case PLL_APLL: + new_rate = rk3066_clk_configure_cpu(priv->cru, priv->grf, rate); + break; + case CLK_DDR: + new_rate = rk3066_clk_configure_ddr(priv->cru, priv->grf, rate); + break; + case HCLK_EMMC: + case HCLK_SDMMC: + case HCLK_SDIO: + case SCLK_EMMC: + case SCLK_SDMMC: + case SCLK_SDIO: + new_rate = rk3066_clk_mmc_set_clk(cru, PERI_HCLK_HZ, + clk->id, rate); + break; + case SCLK_SPI0: + case SCLK_SPI1: + new_rate = rk3066_clk_spi_set_clk(cru, PERI_PCLK_HZ, + clk->id, rate); + break; + case SCLK_SARADC: + case SCLK_TSADC: + new_rate = rk3066_clk_saradc_set_clk(cru, rate, clk->id); + break; + case PLL_CPLL: + case PLL_GPLL: + case ACLK_CPU: + case HCLK_CPU: + case PCLK_CPU: + case ACLK_PERI: + case HCLK_PERI: + case PCLK_PERI: + return 0; + default: + return -ENOENT; + } + + return new_rate; +} + +static int rk3066_clk_enable(struct clk *clk) +{ + struct rk3066_clk_priv *priv = dev_get_priv(clk->dev); + + switch (clk->id) { + case HCLK_NANDC0: + rk_clrreg(&priv->cru->cru_clkgate_con[5], BIT(9)); + break; + case HCLK_SDMMC: + rk_clrreg(&priv->cru->cru_clkgate_con[5], BIT(10)); + break; + case HCLK_SDIO: + rk_clrreg(&priv->cru->cru_clkgate_con[5], BIT(11)); + break; + } + + return 0; +} + +static int rk3066_clk_disable(struct clk *clk) +{ + struct rk3066_clk_priv *priv = dev_get_priv(clk->dev); + + switch (clk->id) { + case HCLK_NANDC0: + rk_setreg(&priv->cru->cru_clkgate_con[5], BIT(9)); + break; + case HCLK_SDMMC: + rk_setreg(&priv->cru->cru_clkgate_con[5], BIT(10)); + break; + case HCLK_SDIO: + rk_setreg(&priv->cru->cru_clkgate_con[5], BIT(11)); + break; + } + + return 0; +} + +static struct clk_ops rk3066_clk_ops = { + .disable = rk3066_clk_disable, + .enable = rk3066_clk_enable, + .get_rate = rk3066_clk_get_rate, + .set_rate = rk3066_clk_set_rate, +}; + +static int rk3066_clk_of_to_plat(struct udevice *dev) +{ + if (CONFIG_IS_ENABLED(OF_REAL)) { + struct rk3066_clk_priv *priv = dev_get_priv(dev); + + priv->cru = dev_read_addr_ptr(dev); + } + + return 0; +} + +static int rk3066_clk_probe(struct udevice *dev) +{ + struct rk3066_clk_priv *priv = dev_get_priv(dev); + + priv->grf = syscon_get_first_range(ROCKCHIP_SYSCON_GRF); + if (IS_ERR(priv->grf)) + return PTR_ERR(priv->grf); + +#if CONFIG_IS_ENABLED(OF_PLATDATA) + struct rk3066_clk_plat *plat = dev_get_plat(dev); + + priv->cru = map_sysmem(plat->dtd.reg[0], plat->dtd.reg[1]); +#endif + + if (IS_ENABLED(CONFIG_TPL_BUILD)) { + rk3066_clk_init(priv->cru, priv->grf); + + /* Init CPU frequency. */ + rk3066_clk_configure_cpu(priv->cru, priv->grf, APLL_SAFE_HZ); + } + + return 0; +} + +static int rk3066_clk_bind(struct udevice *dev) +{ + struct udevice *sys_child; + struct sysreset_reg *priv; + int reg_offset, ret; + + /* The reset driver does not have a device node, so bind it here. */ + ret = device_bind(dev, DM_DRIVER_GET(sysreset_rockchip), "sysreset", + NULL, ofnode_null(), &sys_child); + if (ret) { + dev_dbg(dev, "Warning: No sysreset driver: ret=%d\n", ret); + } else { + priv = malloc(sizeof(struct sysreset_reg)); + priv->glb_srst_fst_value = offsetof(struct rk3066_cru, + cru_glb_srst_fst_value); + priv->glb_srst_snd_value = offsetof(struct rk3066_cru, + cru_glb_srst_snd_value); + dev_set_priv(sys_child, priv); + } + + if (CONFIG_IS_ENABLED(RESET_ROCKCHIP)) { + reg_offset = offsetof(struct rk3066_cru, cru_softrst_con[0]); + ret = rockchip_reset_bind(dev, reg_offset, 9); + if (ret) + dev_dbg(dev, "Warning: software reset driver bind failed\n"); + } + + return 0; +} + +static const struct udevice_id rk3066_clk_ids[] = { + { .compatible = "rockchip,rk3066a-cru" }, + { } +}; + +U_BOOT_DRIVER(rockchip_rk3066a_cru) = { + .name = "rockchip_rk3066a_cru", + .id = UCLASS_CLK, + .ops = &rk3066_clk_ops, + .probe = rk3066_clk_probe, + .bind = rk3066_clk_bind, + .of_match = rk3066_clk_ids, + .of_to_plat = rk3066_clk_of_to_plat, + .priv_auto = sizeof(struct rk3066_clk_priv), + .plat_auto = sizeof(struct rk3066_clk_plat), +}; |
