diff options
Diffstat (limited to 'drivers')
36 files changed, 1932 insertions, 228 deletions
diff --git a/drivers/clk/Kconfig b/drivers/clk/Kconfig index baa60a52e68..f6644ee6d16 100644 --- a/drivers/clk/Kconfig +++ b/drivers/clk/Kconfig @@ -46,6 +46,14 @@ config CLK_BOSTON help Enable this to support the clocks +config CLK_STM32F + bool "Enable clock driver support for STM32F family" + depends on CLK && (STM32F7 || STM32F4) + default y + help + This clock driver adds support for RCC clock management + for STM32F4 and STM32F7 SoCs. + config CLK_ZYNQ bool "Enable clock driver support for Zynq" depends on CLK && ARCH_ZYNQ diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile index 83fe88ce9f5..bcc8f82fb65 100644 --- a/drivers/clk/Makefile +++ b/drivers/clk/Makefile @@ -21,5 +21,5 @@ obj-$(CONFIG_CLK_AT91) += at91/ obj-$(CONFIG_CLK_BCM6345) += clk_bcm6345.o obj-$(CONFIG_CLK_BOSTON) += clk_boston.o obj-$(CONFIG_ARCH_ASPEED) += aspeed/ -obj-$(CONFIG_STM32F7) += clk_stm32f7.o +obj-$(CONFIG_CLK_STM32F) += clk_stm32f.o obj-$(CONFIG_STM32H7) += clk_stm32h7.o diff --git a/drivers/clk/at91/Kconfig b/drivers/clk/at91/Kconfig index c6c57618c14..fd56f200b9f 100644 --- a/drivers/clk/at91/Kconfig +++ b/drivers/clk/at91/Kconfig @@ -14,11 +14,11 @@ config CLK_AT91 config AT91_UTMI bool "Support UTMI PLL Clock" - depends on CLK_AT91 && SPL_DM + depends on CLK_AT91 select REGMAP - select SPL_REGMAP + select SPL_REGMAP if SPL_DM select SYSCON - select SPL_SYSCON + select SPL_SYSCON if SPL_DM help This option is used to enable the AT91 UTMI PLL clock driver. It is the clock provider of USB, and UPLLCK is the diff --git a/drivers/clk/at91/clk-generated.c b/drivers/clk/at91/clk-generated.c index 8c9a3cb053a..2aacbaef0c0 100644 --- a/drivers/clk/at91/clk-generated.c +++ b/drivers/clk/at91/clk-generated.c @@ -53,16 +53,17 @@ static ulong generic_clk_get_rate(struct clk *clk) struct clk parent; ulong clk_rate; u32 tmp, gckdiv; - u8 parent_id; + u8 clock_source, parent_index; int ret; writel(clk->id & AT91_PMC_PCR_PID_MASK, &pmc->pcr); tmp = readl(&pmc->pcr); - parent_id = (tmp >> AT91_PMC_PCR_GCKCSS_OFFSET) & + clock_source = (tmp >> AT91_PMC_PCR_GCKCSS_OFFSET) & AT91_PMC_PCR_GCKCSS_MASK; gckdiv = (tmp >> AT91_PMC_PCR_GCKDIV_OFFSET) & AT91_PMC_PCR_GCKDIV_MASK; - ret = clk_get_by_index(dev_get_parent(clk->dev), parent_id, &parent); + parent_index = clock_source - 1; + ret = clk_get_by_index(dev_get_parent(clk->dev), parent_index, &parent); if (ret) return 0; @@ -82,7 +83,7 @@ static ulong generic_clk_set_rate(struct clk *clk, ulong rate) ulong tmp_rate, best_rate = rate, parent_rate; int tmp_diff, best_diff = -1; u32 div, best_div = 0; - u8 best_parent_id = 0; + u8 best_parent_index, best_clock_source = 0; u8 i; u32 tmp; int ret; @@ -98,9 +99,7 @@ static ulong generic_clk_set_rate(struct clk *clk, ulong rate) for (div = 1; div < GENERATED_MAX_DIV + 2; div++) { tmp_rate = DIV_ROUND_CLOSEST(parent_rate, div); - if (rate < tmp_rate) - continue; - tmp_diff = rate - tmp_rate; + tmp_diff = abs(rate - tmp_rate); if (best_diff < 0 || best_diff > tmp_diff) { best_rate = tmp_rate; @@ -108,7 +107,8 @@ static ulong generic_clk_set_rate(struct clk *clk, ulong rate) best_div = div - 1; best_parent = parent; - best_parent_id = i; + best_parent_index = i; + best_clock_source = best_parent_index + 1; } if (!best_diff || tmp_rate < rate) @@ -129,7 +129,7 @@ static ulong generic_clk_set_rate(struct clk *clk, ulong rate) writel(clk->id & AT91_PMC_PCR_PID_MASK, &pmc->pcr); tmp = readl(&pmc->pcr); tmp &= ~(AT91_PMC_PCR_GCKDIV | AT91_PMC_PCR_GCKCSS); - tmp |= AT91_PMC_PCR_GCKCSS_(best_parent_id) | + tmp |= AT91_PMC_PCR_GCKCSS_(best_clock_source) | AT91_PMC_PCR_CMD_WRITE | AT91_PMC_PCR_GCKDIV_(best_div) | AT91_PMC_PCR_GCKEN; diff --git a/drivers/clk/clk_stm32f7.c b/drivers/clk/clk_stm32f.c index f1a9e9ca44e..634f0717c68 100644 --- a/drivers/clk/clk_stm32f7.c +++ b/drivers/clk/clk_stm32f.c @@ -8,10 +8,12 @@ #include <common.h> #include <clk-uclass.h> #include <dm.h> +#include <stm32_rcc.h> + #include <asm/io.h> -#include <asm/arch/rcc.h> #include <asm/arch/stm32.h> #include <asm/arch/stm32_periph.h> +#include <asm/arch/stm32_pwr.h> #include <dt-bindings/mfd/stm32f7-rcc.h> @@ -22,6 +24,8 @@ #define RCC_CR_CSSON BIT(19) #define RCC_CR_PLLON BIT(24) #define RCC_CR_PLLRDY BIT(25) +#define RCC_CR_PLLSAION BIT(28) +#define RCC_CR_PLLSAIRDY BIT(29) #define RCC_PLLCFGR_PLLM_MASK GENMASK(5, 0) #define RCC_PLLCFGR_PLLN_MASK GENMASK(14, 6) @@ -52,75 +56,87 @@ #define RCC_CFGR_PPRE1_SHIFT 10 #define RCC_CFGR_PPRE2_SHIFT 13 +#define RCC_PLLCFGR_PLLSAIN_MASK GENMASK(14, 6) +#define RCC_PLLCFGR_PLLSAIP_MASK GENMASK(17, 16) +#define RCC_PLLSAICFGR_PLLSAIN_SHIFT 6 +#define RCC_PLLSAICFGR_PLLSAIP_SHIFT 16 +#define RCC_PLLSAICFGR_PLLSAIP_4 BIT(17) +#define RCC_PLLSAICFGR_PLLSAIQ_4 BIT(26) +#define RCC_PLLSAICFGR_PLLSAIR_2 BIT(29) + +#define RCC_DCKCFGRX_CK48MSEL BIT(27) +#define RCC_DCKCFGRX_SDMMC1SEL BIT(28) +#define RCC_DCKCFGR2_SDMMC2SEL BIT(29) + +#define RCC_APB2ENR_SAI1EN BIT(22) + +/* + * RCC AHB1ENR specific definitions + */ +#define RCC_AHB1ENR_ETHMAC_EN BIT(25) +#define RCC_AHB1ENR_ETHMAC_TX_EN BIT(26) +#define RCC_AHB1ENR_ETHMAC_RX_EN BIT(27) + /* - * Offsets of some PWR registers + * RCC APB1ENR specific definitions */ -#define PWR_CR1_ODEN BIT(16) -#define PWR_CR1_ODSWEN BIT(17) -#define PWR_CSR1_ODRDY BIT(16) -#define PWR_CSR1_ODSWRDY BIT(17) - -struct pll_psc { - u8 pll_m; - u16 pll_n; - u8 pll_p; - u8 pll_q; - u8 ahb_psc; - u8 apb1_psc; - u8 apb2_psc; +#define RCC_APB1ENR_TIM2EN BIT(0) +#define RCC_APB1ENR_PWREN BIT(28) + +/* + * RCC APB2ENR specific definitions + */ +#define RCC_APB2ENR_SYSCFGEN BIT(14) + +struct stm32_clk_info stm32f4_clk_info = { + /* 180 MHz */ + .sys_pll_psc = { + .pll_m = 8, + .pll_n = 360, + .pll_p = 2, + .pll_q = 8, + .ahb_psc = AHB_PSC_1, + .apb1_psc = APB_PSC_4, + .apb2_psc = APB_PSC_2, + }, + .has_overdrive = false, + .v2 = false, }; -#define AHB_PSC_1 0 -#define AHB_PSC_2 0x8 -#define AHB_PSC_4 0x9 -#define AHB_PSC_8 0xA -#define AHB_PSC_16 0xB -#define AHB_PSC_64 0xC -#define AHB_PSC_128 0xD -#define AHB_PSC_256 0xE -#define AHB_PSC_512 0xF - -#define APB_PSC_1 0 -#define APB_PSC_2 0x4 -#define APB_PSC_4 0x5 -#define APB_PSC_8 0x6 -#define APB_PSC_16 0x7 +struct stm32_clk_info stm32f7_clk_info = { + /* 200 MHz */ + .sys_pll_psc = { + .pll_m = 25, + .pll_n = 400, + .pll_p = 2, + .pll_q = 8, + .ahb_psc = AHB_PSC_1, + .apb1_psc = APB_PSC_4, + .apb2_psc = APB_PSC_2, + }, + .has_overdrive = true, + .v2 = true, +}; struct stm32_clk { struct stm32_rcc_regs *base; + struct stm32_pwr_regs *pwr_regs; + struct stm32_clk_info *info; }; -#if !defined(CONFIG_STM32_HSE_HZ) -#error "CONFIG_STM32_HSE_HZ not defined!" -#else -#if (CONFIG_STM32_HSE_HZ == 25000000) -#if (CONFIG_SYS_CLK_FREQ == 200000000) -/* 200 MHz */ -struct pll_psc sys_pll_psc = { - .pll_m = 25, - .pll_n = 400, - .pll_p = 2, - .pll_q = 8, - .ahb_psc = AHB_PSC_1, - .apb1_psc = APB_PSC_4, - .apb2_psc = APB_PSC_2 -}; -#endif -#else -#error "No PLL/Prescaler configuration for given CONFIG_STM32_HSE_HZ exists" -#endif -#endif - static int configure_clocks(struct udevice *dev) { struct stm32_clk *priv = dev_get_priv(dev); struct stm32_rcc_regs *regs = priv->base; + struct stm32_pwr_regs *pwr = priv->pwr_regs; + struct pll_psc sys_pll_psc = priv->info->sys_pll_psc; + u32 pllsaicfgr = 0; /* Reset RCC configuration */ setbits_le32(®s->cr, RCC_CR_HSION); writel(0, ®s->cfgr); /* Reset CFGR */ clrbits_le32(®s->cr, (RCC_CR_HSEON | RCC_CR_CSSON - | RCC_CR_PLLON)); + | RCC_CR_PLLON | RCC_CR_PLLSAION)); writel(0x24003010, ®s->pllcfgr); /* Reset value from RM */ clrbits_le32(®s->cr, RCC_CR_HSEBYP); writel(0, ®s->cir); /* Disable all interrupts */ @@ -146,23 +162,57 @@ static int configure_clocks(struct udevice *dev) clrsetbits_le32(®s->pllcfgr, RCC_PLLCFGR_PLLQ_MASK, sys_pll_psc.pll_q << RCC_PLLCFGR_PLLQ_SHIFT); + /* Configure the SAI PLL to get a 48 MHz source */ + pllsaicfgr = RCC_PLLSAICFGR_PLLSAIR_2 | RCC_PLLSAICFGR_PLLSAIQ_4 | + RCC_PLLSAICFGR_PLLSAIP_4; + pllsaicfgr |= 192 << RCC_PLLSAICFGR_PLLSAIN_SHIFT; + writel(pllsaicfgr, ®s->pllsaicfgr); + /* Enable the main PLL */ setbits_le32(®s->cr, RCC_CR_PLLON); while (!(readl(®s->cr) & RCC_CR_PLLRDY)) ; - /* Enable high performance mode, System frequency up to 200 MHz */ - setbits_le32(®s->apb1enr, RCC_APB1ENR_PWREN); - setbits_le32(&STM32_PWR->cr1, PWR_CR1_ODEN); - /* Infinite wait! */ - while (!(readl(&STM32_PWR->csr1) & PWR_CSR1_ODRDY)) - ; - /* Enable the Over-drive switch */ - setbits_le32(&STM32_PWR->cr1, PWR_CR1_ODSWEN); - /* Infinite wait! */ - while (!(readl(&STM32_PWR->csr1) & PWR_CSR1_ODSWRDY)) + if (priv->info->v2) { /*stm32f7 case */ + /* select PLLSAI as 48MHz clock source */ + setbits_le32(®s->dckcfgr2, RCC_DCKCFGRX_CK48MSEL); + + /* select 48MHz as SDMMC1 clock source */ + clrbits_le32(®s->dckcfgr2, RCC_DCKCFGRX_SDMMC1SEL); + + /* select 48MHz as SDMMC2 clock source */ + clrbits_le32(®s->dckcfgr2, RCC_DCKCFGR2_SDMMC2SEL); + } else { /* stm32f4 case */ + /* select PLLSAI as 48MHz clock source */ + setbits_le32(®s->dckcfgr, RCC_DCKCFGRX_CK48MSEL); + + /* select 48MHz as SDMMC1 clock source */ + clrbits_le32(®s->dckcfgr, RCC_DCKCFGRX_SDMMC1SEL); + } + + /* Enable the SAI PLL */ + setbits_le32(®s->cr, RCC_CR_PLLSAION); + while (!(readl(®s->cr) & RCC_CR_PLLSAIRDY)) ; + setbits_le32(®s->apb1enr, RCC_APB1ENR_PWREN); + + if (priv->info->has_overdrive) { + /* + * Enable high performance mode + * System frequency up to 200 MHz + */ + setbits_le32(&pwr->cr1, PWR_CR1_ODEN); + /* Infinite wait! */ + while (!(readl(&pwr->csr1) & PWR_CSR1_ODRDY)) + ; + /* Enable the Over-drive switch */ + setbits_le32(&pwr->cr1, PWR_CR1_ODSWEN); + /* Infinite wait! */ + while (!(readl(&pwr->csr1) & PWR_CSR1_ODSWRDY)) + ; + } + stm32_flash_latency_cfg(5); clrbits_le32(®s->cfgr, (RCC_CFGR_SW0 | RCC_CFGR_SW1)); setbits_le32(®s->cfgr, RCC_CFGR_SW_PLL); @@ -170,16 +220,47 @@ static int configure_clocks(struct udevice *dev) while ((readl(®s->cfgr) & RCC_CFGR_SWS_MASK) != RCC_CFGR_SWS_PLL) ; + /* gate the SAI clock, needed for MMC 1&2 clocks */ + setbits_le32(®s->apb2enr, RCC_APB2ENR_SAI1EN); return 0; } +static unsigned long stm32_clk_pll48clk_rate(struct stm32_clk *priv, + u32 sysclk) +{ + struct stm32_rcc_regs *regs = priv->base; + u16 pllq, pllm, pllsain, pllsaip; + bool pllsai; + + pllq = (readl(®s->pllcfgr) & RCC_PLLCFGR_PLLQ_MASK) + >> RCC_PLLCFGR_PLLQ_SHIFT; + + if (priv->info->v2) /*stm32f7 case */ + pllsai = readl(®s->dckcfgr2) & RCC_DCKCFGRX_CK48MSEL; + else + pllsai = readl(®s->dckcfgr) & RCC_DCKCFGRX_CK48MSEL; + + if (pllsai) { + /* PLL48CLK is selected from PLLSAI, get PLLSAI value */ + pllm = (readl(®s->pllcfgr) & RCC_PLLCFGR_PLLM_MASK); + pllsain = ((readl(®s->pllsaicfgr) & RCC_PLLCFGR_PLLSAIN_MASK) + >> RCC_PLLSAICFGR_PLLSAIN_SHIFT); + pllsaip = ((((readl(®s->pllsaicfgr) & RCC_PLLCFGR_PLLSAIP_MASK) + >> RCC_PLLSAICFGR_PLLSAIP_SHIFT) + 1) << 1); + return ((CONFIG_STM32_HSE_HZ / pllm) * pllsain) / pllsaip; + } + /* PLL48CLK is selected from PLLQ */ + return sysclk / pllq; +} + static unsigned long stm32_clk_get_rate(struct clk *clk) { struct stm32_clk *priv = dev_get_priv(clk->dev); struct stm32_rcc_regs *regs = priv->base; u32 sysclk = 0; u32 shift = 0; + u16 pllm, plln, pllp; /* Prescaler table lookups for clock computation */ u8 ahb_psc_table[16] = { 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 4, 6, 7, 8, 9 @@ -190,7 +271,6 @@ static unsigned long stm32_clk_get_rate(struct clk *clk) if ((readl(®s->cfgr) & RCC_CFGR_SWS_MASK) == RCC_CFGR_SWS_PLL) { - u16 pllm, plln, pllp; pllm = (readl(®s->pllcfgr) & RCC_PLLCFGR_PLLM_MASK); plln = ((readl(®s->pllcfgr) & RCC_PLLCFGR_PLLN_MASK) >> RCC_PLLCFGR_PLLN_SHIFT); @@ -211,25 +291,43 @@ static unsigned long stm32_clk_get_rate(struct clk *clk) (readl(®s->cfgr) & RCC_CFGR_AHB_PSC_MASK) >> RCC_CFGR_HPRE_SHIFT)]; return sysclk >>= shift; - break; /* APB1 CLOCK */ case STM32F7_APB1_CLOCK(TIM2) ... STM32F7_APB1_CLOCK(UART8): shift = apb_psc_table[( (readl(®s->cfgr) & RCC_CFGR_APB1_PSC_MASK) >> RCC_CFGR_PPRE1_SHIFT)]; return sysclk >>= shift; - break; /* APB2 CLOCK */ case STM32F7_APB2_CLOCK(TIM1) ... STM32F7_APB2_CLOCK(LTDC): + /* + * particular case for SDMMC1 and SDMMC2 : + * 48Mhz source clock can be from main PLL or from + * SAI PLL + */ + switch (clk->id) { + case STM32F7_APB2_CLOCK(SDMMC1): + if (readl(®s->dckcfgr2) & RCC_DCKCFGRX_SDMMC1SEL) + /* System clock is selected as SDMMC1 clock */ + return sysclk; + else + return stm32_clk_pll48clk_rate(priv, sysclk); + break; + case STM32F7_APB2_CLOCK(SDMMC2): + if (readl(®s->dckcfgr2) & RCC_DCKCFGR2_SDMMC2SEL) + /* System clock is selected as SDMMC2 clock */ + return sysclk; + else + return stm32_clk_pll48clk_rate(priv, sysclk); + break; + } + shift = apb_psc_table[( (readl(®s->cfgr) & RCC_CFGR_APB2_PSC_MASK) >> RCC_CFGR_PPRE2_SHIFT)]; return sysclk >>= shift; - break; default: pr_err("clock index %ld out of range\n", clk->id); return -EINVAL; - break; } } @@ -268,17 +366,43 @@ void clock_setup(int peripheral) static int stm32_clk_probe(struct udevice *dev) { - debug("%s: stm32_clk_probe\n", __func__); + struct ofnode_phandle_args args; + int err; + + debug("%s\n", __func__); struct stm32_clk *priv = dev_get_priv(dev); fdt_addr_t addr; - addr = devfdt_get_addr(dev); + addr = dev_read_addr(dev); if (addr == FDT_ADDR_T_NONE) return -EINVAL; priv->base = (struct stm32_rcc_regs *)addr; + switch (dev_get_driver_data(dev)) { + case STM32F4: + priv->info = &stm32f4_clk_info; + break; + case STM32F7: + priv->info = &stm32f7_clk_info; + break; + default: + return -EINVAL; + } + + if (priv->info->has_overdrive) { + err = dev_read_phandle_with_args(dev, "st,syscfg", NULL, 0, 0, + &args); + if (err) { + debug("%s: can't find syscon device (%d)\n", __func__, + err); + return err; + } + + priv->pwr_regs = (struct stm32_pwr_regs *)ofnode_get_addr(args.node); + } + configure_clocks(dev); return 0; @@ -307,15 +431,9 @@ static struct clk_ops stm32_clk_ops = { .get_rate = stm32_clk_get_rate, }; -static const struct udevice_id stm32_clk_ids[] = { - { .compatible = "st,stm32f42xx-rcc"}, - {} -}; - -U_BOOT_DRIVER(stm32f7_clk) = { - .name = "stm32f7_clk", +U_BOOT_DRIVER(stm32fx_clk) = { + .name = "stm32fx_rcc_clock", .id = UCLASS_CLK, - .of_match = stm32_clk_ids, .ops = &stm32_clk_ops, .probe = stm32_clk_probe, .priv_auto_alloc_size = sizeof(struct stm32_clk), diff --git a/drivers/clk/renesas/clk-rcar-gen3.c b/drivers/clk/renesas/clk-rcar-gen3.c index c821bddc251..5abb171827e 100644 --- a/drivers/clk/renesas/clk-rcar-gen3.c +++ b/drivers/clk/renesas/clk-rcar-gen3.c @@ -490,6 +490,7 @@ static const struct mssr_mod_clk r8a7796_mod_clks[] = { DEF_MOD("sdif0", 314, R8A7796_CLK_SD0), DEF_MOD("pcie1", 318, R8A7796_CLK_S3D1), DEF_MOD("pcie0", 319, R8A7796_CLK_S3D1), + DEF_MOD("usb3-if0", 328, R8A7796_CLK_S3D1), DEF_MOD("usb-dmac0", 330, R8A7796_CLK_S3D1), DEF_MOD("usb-dmac1", 331, R8A7796_CLK_S3D1), DEF_MOD("rwdt", 402, R8A7796_CLK_R), @@ -1074,6 +1075,64 @@ static int gen3_clk_probe(struct udevice *dev) return 0; } +struct mstp_stop_table { + u32 dis; + u32 en; +}; + +static struct mstp_stop_table r8a7795_mstp_table[] = { + { 0x00640800, 0x0 }, { 0xF3EE9390, 0x0 }, + { 0x340FAFDC, 0x2040 }, { 0xD80C7CDF, 0x400 }, + { 0x80000184, 0x180 }, { 0x40BFFF46, 0x0 }, + { 0xE5FBEECF, 0x0 }, { 0x39FFFF0E, 0x0 }, + { 0x01F19FF4, 0x0 }, { 0xFFDFFFFF, 0x0 }, + { 0xFFFEFFE0, 0x0 }, { 0x00000000, 0x0 }, +}; + +static struct mstp_stop_table r8a7796_mstp_table[] = { + { 0x00200000, 0x0 }, { 0xFFFFFFFF, 0x0 }, + { 0x340E2FDC, 0x2040 }, { 0xFFFFFFDF, 0x400 }, + { 0x80000184, 0x180 }, { 0xC3FFFFFF, 0x0 }, + { 0xFFFFFFFF, 0x0 }, { 0xFFFFFFFF, 0x0 }, + { 0x01F1FFF7, 0x0 }, { 0xFFFFFFFE, 0x0 }, + { 0xFFFEFFE0, 0x0 }, { 0x000000B7, 0x0 }, +}; + +#define TSTR0 0x04 +#define TSTR0_STR0 BIT(0) + +static int gen3_clk_remove(struct udevice *dev) +{ + struct gen3_clk_priv *priv = dev_get_priv(dev); + enum gen3_clk_model model = dev_get_driver_data(dev); + struct mstp_stop_table *tbl; + unsigned int i, tbl_size; + + switch (model) { + case CLK_R8A7795: + tbl = r8a7795_mstp_table; + tbl_size = ARRAY_SIZE(r8a7795_mstp_table); + break; + case CLK_R8A7796: + tbl = r8a7796_mstp_table; + tbl_size = ARRAY_SIZE(r8a7796_mstp_table); + break; + default: + return -EINVAL; + } + + /* Stop TMU0 */ + clrbits_le32(TMU_BASE + TSTR0, TSTR0_STR0); + + /* Stop module clock */ + for (i = 0; i < tbl_size; i++) { + clrsetbits_le32(priv->base + SMSTPCR(i), tbl[i].dis, tbl[i].en); + clrsetbits_le32(priv->base + RMSTPCR(i), tbl[i].dis, 0x0); + } + + return 0; +} + static const struct udevice_id gen3_clk_ids[] = { { .compatible = "renesas,r8a7795-cpg-mssr", .data = CLK_R8A7795 }, { .compatible = "renesas,r8a7796-cpg-mssr", .data = CLK_R8A7796 }, @@ -1087,4 +1146,5 @@ U_BOOT_DRIVER(clk_gen3) = { .priv_auto_alloc_size = sizeof(struct gen3_clk_priv), .ops = &gen3_clk_ops, .probe = gen3_clk_probe, + .remove = gen3_clk_remove, }; diff --git a/drivers/clk/rockchip/Makefile b/drivers/clk/rockchip/Makefile index c50aff2e93d..eae0ef6a9fb 100644 --- a/drivers/clk/rockchip/Makefile +++ b/drivers/clk/rockchip/Makefile @@ -1,10 +1,11 @@ # -# Copyright (c) 2016 Google, Inc +# Copyright (c) 2017 Rockchip Electronics Co., Ltd # # SPDX-License-Identifier: GPL-2.0+ # obj-$(CONFIG_ROCKCHIP_RK3036) += clk_rk3036.o +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 diff --git a/drivers/clk/rockchip/clk_rk3128.c b/drivers/clk/rockchip/clk_rk3128.c new file mode 100644 index 00000000000..132d50dda38 --- /dev/null +++ b/drivers/clk/rockchip/clk_rk3128.c @@ -0,0 +1,596 @@ +/* + * (C) Copyright 2017 Rockchip Electronics Co., Ltd + * + * SPDX-License-Identifier: GPL-2.0 + */ + +#include <common.h> +#include <clk-uclass.h> +#include <dm.h> +#include <errno.h> +#include <syscon.h> +#include <asm/io.h> +#include <asm/arch/clock.h> +#include <asm/arch/cru_rk3128.h> +#include <asm/arch/hardware.h> +#include <bitfield.h> +#include <dm/lists.h> +#include <dt-bindings/clock/rk3128-cru.h> +#include <linux/log2.h> + +DECLARE_GLOBAL_DATA_PTR; + +enum { + VCO_MAX_HZ = 2400U * 1000000, + VCO_MIN_HZ = 600 * 1000000, + OUTPUT_MAX_HZ = 2400U * 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}; + +/* use integer mode*/ +static const struct pll_div apll_init_cfg = PLL_DIVISORS(APLL_HZ, 1, 3, 1); +static const struct pll_div gpll_init_cfg = PLL_DIVISORS(GPLL_HZ, 2, 2, 1); + +static int rkclk_set_pll(struct rk3128_cru *cru, enum rk_clk_id clk_id, + const struct pll_div *div) +{ + int pll_id = rk_pll_id(clk_id); + struct rk3128_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:fd=%d,rd=%d,pd1=%d,pd2=%d,vco=%uHz,output=%uHz\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); + /* 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); + + return 0; +} + +static int pll_para_config(u32 freq_hz, struct pll_div *div) +{ + u32 ref_khz = OSC_HZ / 1000, refdiv, fbdiv = 0; + u32 postdiv1, postdiv2 = 1; + u32 fref_khz; + u32 diff_khz, best_diff_khz; + const u32 max_refdiv = 63, max_fbdiv = 3200, min_fbdiv = 16; + const u32 max_postdiv1 = 7, max_postdiv2 = 7; + u32 vco_khz; + u32 freq_khz = freq_hz / 1000; + + if (!freq_hz) { + printf("%s: the frequency can't be 0 Hz\n", __func__); + return -1; + } + + postdiv1 = DIV_ROUND_UP(VCO_MIN_HZ / 1000, freq_khz); + if (postdiv1 > max_postdiv1) { + postdiv2 = DIV_ROUND_UP(postdiv1, max_postdiv1); + postdiv1 = DIV_ROUND_UP(postdiv1, postdiv2); + } + + vco_khz = freq_khz * postdiv1 * postdiv2; + + if (vco_khz < (VCO_MIN_HZ / 1000) || vco_khz > (VCO_MAX_HZ / 1000) || + postdiv2 > max_postdiv2) { + printf("%s: Cannot find out a supported VCO for Freq (%uHz)\n", + __func__, freq_hz); + return -1; + } + + div->postdiv1 = postdiv1; + div->postdiv2 = postdiv2; + + best_diff_khz = vco_khz; + for (refdiv = 1; refdiv < max_refdiv && best_diff_khz; refdiv++) { + fref_khz = ref_khz / refdiv; + + fbdiv = vco_khz / fref_khz; + if ((fbdiv >= max_fbdiv) || (fbdiv <= min_fbdiv)) + continue; + diff_khz = vco_khz - fbdiv * fref_khz; + if (fbdiv + 1 < max_fbdiv && diff_khz > fref_khz / 2) { + fbdiv++; + diff_khz = fref_khz - diff_khz; + } + + if (diff_khz >= best_diff_khz) + continue; + + best_diff_khz = diff_khz; + div->refdiv = refdiv; + div->fbdiv = fbdiv; + } + + if (best_diff_khz > 4 * (1000)) { + printf("%s: Failed to match output frequency %u bestis %u Hz\n", + __func__, freq_hz, + best_diff_khz * 1000); + return -1; + } + return 0; +} + +static void rkclk_init(struct rk3128_cru *cru) +{ + u32 aclk_div; + u32 hclk_div; + u32 pclk_div; + + /* pll enter slow-mode */ + rk_clrsetreg(&cru->cru_mode_con, + GPLL_MODE_MASK | APLL_MODE_MASK, + GPLL_MODE_SLOW << GPLL_MODE_SHIFT | + APLL_MODE_SLOW << APLL_MODE_SHIFT); + + /* init pll */ + rkclk_set_pll(cru, CLK_ARM, &apll_init_cfg); + rkclk_set_pll(cru, CLK_GENERAL, &gpll_init_cfg); + + /* + * select apll as cpu/core clock pll source and + * set up dependent divisors for PERI and ACLK clocks. + * core hz : apll = 1:1 + */ + aclk_div = APLL_HZ / CORE_ACLK_HZ - 1; + assert((aclk_div + 1) * CORE_ACLK_HZ == APLL_HZ && aclk_div < 0x7); + + pclk_div = APLL_HZ / CORE_PERI_HZ - 1; + assert((pclk_div + 1) * CORE_PERI_HZ == APLL_HZ && pclk_div < 0xf); + + rk_clrsetreg(&cru->cru_clksel_con[0], + CORE_CLK_PLL_SEL_MASK | CORE_DIV_CON_MASK, + CORE_CLK_PLL_SEL_APLL << CORE_CLK_PLL_SEL_SHIFT | + 0 << CORE_DIV_CON_SHIFT); + + rk_clrsetreg(&cru->cru_clksel_con[1], + CORE_ACLK_DIV_MASK | CORE_PERI_DIV_MASK, + aclk_div << CORE_ACLK_DIV_SHIFT | + pclk_div << CORE_PERI_DIV_SHIFT); + + /* + * select gpll as pd_bus bus clock source and + * set up dependent divisors for PCLK/HCLK and ACLK clocks. + */ + aclk_div = GPLL_HZ / BUS_ACLK_HZ - 1; + assert((aclk_div + 1) * BUS_ACLK_HZ == GPLL_HZ && aclk_div <= 0x1f); + + pclk_div = BUS_ACLK_HZ / BUS_PCLK_HZ - 1; + assert((pclk_div + 1) * BUS_PCLK_HZ == BUS_ACLK_HZ && pclk_div <= 0x7); + + hclk_div = BUS_ACLK_HZ / BUS_HCLK_HZ - 1; + assert((hclk_div + 1) * BUS_HCLK_HZ == BUS_ACLK_HZ && hclk_div <= 0x3); + + rk_clrsetreg(&cru->cru_clksel_con[0], + BUS_ACLK_PLL_SEL_MASK | BUS_ACLK_DIV_MASK, + BUS_ACLK_PLL_SEL_GPLL << BUS_ACLK_PLL_SEL_SHIFT | + aclk_div << BUS_ACLK_DIV_SHIFT); + + rk_clrsetreg(&cru->cru_clksel_con[1], + BUS_PCLK_DIV_MASK | BUS_HCLK_DIV_MASK, + pclk_div << BUS_PCLK_DIV_SHIFT | + hclk_div << BUS_HCLK_DIV_SHIFT); + + /* + * select gpll as pd_peri bus clock 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 < 0x8); + + rk_clrsetreg(&cru->cru_clksel_con[10], + PERI_PLL_SEL_MASK | PERI_PCLK_DIV_MASK | + PERI_HCLK_DIV_MASK | PERI_ACLK_DIV_MASK, + PERI_PLL_GPLL << PERI_PLL_SEL_SHIFT | + pclk_div << PERI_PCLK_DIV_SHIFT | + hclk_div << PERI_HCLK_DIV_SHIFT | + aclk_div << PERI_ACLK_DIV_SHIFT); + + /* PLL enter normal-mode */ + rk_clrsetreg(&cru->cru_mode_con, + GPLL_MODE_MASK | APLL_MODE_MASK | CPLL_MODE_MASK, + GPLL_MODE_NORM << GPLL_MODE_SHIFT | + APLL_MODE_NORM << APLL_MODE_SHIFT | + CPLL_MODE_NORM << CPLL_MODE_SHIFT); + + /*fix NAND controller working clock max to 150Mhz */ + rk_clrsetreg(&cru->cru_clksel_con[2], + NANDC_PLL_SEL_MASK | NANDC_CLK_DIV_MASK, + NANDC_PLL_SEL_GPLL << NANDC_PLL_SEL_SHIFT | + 3 << NANDC_CLK_DIV_SHIFT); +} + +/* Get pll rate by id */ +static u32 rkclk_pll_get_rate(struct rk3128_cru *cru, + enum rk_clk_id clk_id) +{ + u32 refdiv, fbdiv, postdiv1, postdiv2; + u32 con; + int pll_id = rk_pll_id(clk_id); + struct rk3128_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, 0xff + }; + static u32 clk_mask[CLK_COUNT] = { + 0xff, APLL_MODE_MASK, DPLL_MODE_MASK, CPLL_MODE_MASK, + GPLL_MODE_MASK, 0xff + }; + 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; + } +} + +static ulong rockchip_mmc_get_clk(struct rk3128_cru *cru, uint clk_general_rate, + int periph) +{ + uint src_rate; + uint div, mux; + u32 con; + + switch (periph) { + case HCLK_EMMC: + case SCLK_EMMC: + case SCLK_EMMC_SAMPLE: + con = readl(&cru->cru_clksel_con[12]); + mux = (con & EMMC_PLL_MASK) >> EMMC_PLL_SHIFT; + div = (con & EMMC_DIV_MASK) >> EMMC_DIV_SHIFT; + break; + case HCLK_SDMMC: + case SCLK_SDMMC: + con = readl(&cru->cru_clksel_con[11]); + mux = (con & MMC0_PLL_MASK) >> MMC0_PLL_SHIFT; + div = (con & MMC0_DIV_MASK) >> MMC0_DIV_SHIFT; + break; + default: + return -EINVAL; + } + + src_rate = mux == EMMC_SEL_24M ? OSC_HZ : clk_general_rate; + return DIV_TO_RATE(src_rate, div); +} + +static ulong rockchip_mmc_set_clk(struct rk3128_cru *cru, uint clk_general_rate, + int periph, uint freq) +{ + int src_clk_div; + int mux; + + debug("%s: clk_general_rate=%u\n", __func__, clk_general_rate); + + /* mmc clock defaulg div 2 internal, need provide double in cru */ + src_clk_div = DIV_ROUND_UP(clk_general_rate / 2, freq); + + if (src_clk_div > 128) { + src_clk_div = DIV_ROUND_UP(OSC_HZ / 2, freq); + mux = EMMC_SEL_24M; + } else { + mux = EMMC_SEL_GPLL; + } + + switch (periph) { + case HCLK_EMMC: + rk_clrsetreg(&cru->cru_clksel_con[12], + EMMC_PLL_MASK | EMMC_DIV_MASK, + mux << EMMC_PLL_SHIFT | + (src_clk_div - 1) << EMMC_DIV_SHIFT); + break; + case HCLK_SDMMC: + case SCLK_SDMMC: + rk_clrsetreg(&cru->cru_clksel_con[11], + MMC0_PLL_MASK | MMC0_DIV_MASK, + mux << MMC0_PLL_SHIFT | + (src_clk_div - 1) << MMC0_DIV_SHIFT); + break; + default: + return -EINVAL; + } + + return rockchip_mmc_get_clk(cru, clk_general_rate, periph); +} + +static ulong rk3128_peri_get_pclk(struct rk3128_cru *cru, ulong clk_id) +{ + u32 div, con; + + switch (clk_id) { + case PCLK_I2C0: + case PCLK_I2C1: + case PCLK_I2C2: + case PCLK_I2C3: + case PCLK_PWM: + con = readl(&cru->cru_clksel_con[10]); + div = con >> 12 & 0x3; + break; + default: + printf("do not support this peripheral bus\n"); + return -EINVAL; + } + + return DIV_TO_RATE(PERI_ACLK_HZ, div); +} + +static ulong rk3128_peri_set_pclk(struct rk3128_cru *cru, ulong clk_id, uint hz) +{ + int src_clk_div; + + src_clk_div = PERI_ACLK_HZ / hz; + assert(src_clk_div - 1 < 4); + + switch (clk_id) { + case PCLK_I2C0: + case PCLK_I2C1: + case PCLK_I2C2: + case PCLK_I2C3: + case PCLK_PWM: + rk_setreg(&cru->cru_clksel_con[10], + ((src_clk_div - 1) << 12)); + break; + default: + printf("do not support this peripheral bus\n"); + return -EINVAL; + } + + return DIV_TO_RATE(PERI_ACLK_HZ, src_clk_div); +} + +static ulong rk3128_saradc_get_clk(struct rk3128_cru *cru) +{ + u32 div, val; + + val = readl(&cru->cru_clksel_con[24]); + div = bitfield_extract(val, SARADC_DIV_CON_SHIFT, + SARADC_DIV_CON_WIDTH); + + return DIV_TO_RATE(OSC_HZ, div); +} + +static ulong rk3128_saradc_set_clk(struct rk3128_cru *cru, uint hz) +{ + int src_clk_div; + + src_clk_div = DIV_ROUND_UP(OSC_HZ, hz) - 1; + assert(src_clk_div < 128); + + rk_clrsetreg(&cru->cru_clksel_con[24], + SARADC_DIV_CON_MASK, + src_clk_div << SARADC_DIV_CON_SHIFT); + + return rk3128_saradc_get_clk(cru); +} + +static ulong rk3128_vop_set_clk(struct rk3128_cru *cru, ulong clk_id, uint hz) +{ + int src_clk_div; + struct pll_div cpll_config = {0}; + + src_clk_div = GPLL_HZ / hz; + assert(src_clk_div - 1 < 31); + + switch (clk_id) { + case ACLK_VIO0: + rk_clrsetreg(&cru->cru_clksel_con[31], + VIO0_PLL_MASK | VIO0_DIV_MASK, + VIO0_SEL_GPLL << VIO0_PLL_SHIFT | + (src_clk_div - 1) << VIO0_DIV_SHIFT); + break; + case ACLK_VIO1: + rk_clrsetreg(&cru->cru_clksel_con[31], + VIO1_PLL_MASK | VIO1_DIV_MASK, + VIO1_SEL_GPLL << VIO1_PLL_SHIFT | + (src_clk_div - 1) << VIO1_DIV_SHIFT); + break; + case DCLK_LCDC: + if (pll_para_config(hz, &cpll_config)) + return -1; + rkclk_set_pll(cru, CLK_CODEC, &cpll_config); + + rk_clrsetreg(&cru->cru_clksel_con[27], + DCLK_VOP_SEL_MASK | DCLK_VOP_DIV_CON_MASK, + DCLK_VOP_PLL_SEL_CPLL << DCLK_VOP_SEL_SHIFT | + (1 - 1) << DCLK_VOP_DIV_CON_SHIFT); + break; + default: + printf("do not support this vop freq\n"); + return -EINVAL; + } + + return hz; +} + +static ulong rk3128_vop_get_rate(struct rk3128_cru *cru, ulong clk_id) +{ + u32 div, con, parent; + + switch (clk_id) { + case ACLK_VIO0: + con = readl(&cru->cru_clksel_con[31]); + div = con & 0x1f; + parent = GPLL_HZ; + break; + case ACLK_VIO1: + con = readl(&cru->cru_clksel_con[31]); + div = (con >> 8) & 0x1f; + parent = GPLL_HZ; + break; + case DCLK_LCDC: + con = readl(&cru->cru_clksel_con[27]); + div = (con >> 8) & 0xfff; + parent = rkclk_pll_get_rate(cru, CLK_CODEC); + break; + default: + return -ENOENT; + } + return DIV_TO_RATE(parent, div); +} + +static ulong rk3128_clk_get_rate(struct clk *clk) +{ + struct rk3128_clk_priv *priv = dev_get_priv(clk->dev); + + switch (clk->id) { + case 0 ... 63: + return rkclk_pll_get_rate(priv->cru, clk->id); + case PCLK_I2C0: + case PCLK_I2C1: + case PCLK_I2C2: + case PCLK_I2C3: + case PCLK_PWM: + return rk3128_peri_get_pclk(priv->cru, clk->id); + case SCLK_SARADC: + return rk3128_saradc_get_clk(priv->cru); + case DCLK_LCDC: + case ACLK_VIO0: + case ACLK_VIO1: + return rk3128_vop_get_rate(priv->cru, clk->id); + default: + return -ENOENT; + } +} + +static ulong rk3128_clk_set_rate(struct clk *clk, ulong rate) +{ + struct rk3128_clk_priv *priv = dev_get_priv(clk->dev); + ulong new_rate, gclk_rate; + + gclk_rate = rkclk_pll_get_rate(priv->cru, CLK_GENERAL); + switch (clk->id) { + case 0 ... 63: + return 0; + case DCLK_LCDC: + case ACLK_VIO0: + case ACLK_VIO1: + new_rate = rk3128_vop_set_clk(priv->cru, + clk->id, rate); + break; + case HCLK_EMMC: + new_rate = rockchip_mmc_set_clk(priv->cru, gclk_rate, + clk->id, rate); + break; + case PCLK_I2C0: + case PCLK_I2C1: + case PCLK_I2C2: + case PCLK_I2C3: + case PCLK_PWM: + new_rate = rk3128_peri_set_pclk(priv->cru, clk->id, rate); + break; + case SCLK_SARADC: + new_rate = rk3128_saradc_set_clk(priv->cru, rate); + break; + default: + return -ENOENT; + } + + return new_rate; +} + +static struct clk_ops rk3128_clk_ops = { + .get_rate = rk3128_clk_get_rate, + .set_rate = rk3128_clk_set_rate, +}; + +static int rk3128_clk_probe(struct udevice *dev) +{ + struct rk3128_clk_priv *priv = dev_get_priv(dev); + + priv->cru = (struct rk3128_cru *)dev_read_addr(dev); + rkclk_init(priv->cru); + + return 0; +} + +static int rk3128_clk_bind(struct udevice *dev) +{ + int ret; + struct udevice *sys_child; + struct sysreset_reg *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 rk3128_cru, + cru_glb_srst_fst_value); + priv->glb_srst_snd_value = offsetof(struct rk3128_cru, + cru_glb_srst_snd_value); + sys_child->priv = priv; + } + + return 0; +} + +static const struct udevice_id rk3128_clk_ids[] = { + { .compatible = "rockchip,rk3128-cru" }, + { .compatible = "rockchip,rk3126-cru" }, + { } +}; + +U_BOOT_DRIVER(rockchip_rk3128_cru) = { + .name = "clk_rk3128", + .id = UCLASS_CLK, + .of_match = rk3128_clk_ids, + .priv_auto_alloc_size = sizeof(struct rk3128_clk_priv), + .ops = &rk3128_clk_ops, + .bind = rk3128_clk_bind, + .probe = rk3128_clk_probe, +}; diff --git a/drivers/firmware/psci.c b/drivers/firmware/psci.c index 451fbdebba3..cef8adc8175 100644 --- a/drivers/firmware/psci.c +++ b/drivers/firmware/psci.c @@ -13,6 +13,7 @@ #include <libfdt.h> #include <linux/arm-smccc.h> #include <linux/errno.h> +#include <linux/printk.h> #include <linux/psci.h> psci_fn *invoke_psci_fn; @@ -48,7 +49,7 @@ static int psci_bind(struct udevice *dev) ret = device_bind_driver(dev, "psci-sysreset", "psci-sysreset", NULL); if (ret) - debug("PSCI System Reset was not bound.\n"); + pr_debug("PSCI System Reset was not bound.\n"); } return 0; @@ -62,7 +63,7 @@ static int psci_probe(struct udevice *dev) method = fdt_stringlist_get(gd->fdt_blob, dev_of_offset(dev), "method", 0, NULL); if (!method) { - printf("missing \"method\" property\n"); + pr_warn("missing \"method\" property\n"); return -ENXIO; } @@ -71,7 +72,7 @@ static int psci_probe(struct udevice *dev) } else if (!strcmp("smc", method)) { invoke_psci_fn = __invoke_psci_fn_smc; } else { - printf("invalid \"method\" property: %s\n", method); + pr_warn("invalid \"method\" property: %s\n", method); return -EINVAL; } diff --git a/drivers/gpio/gpio-rcar.c b/drivers/gpio/gpio-rcar.c index 8504dceb849..cb9f4258842 100644 --- a/drivers/gpio/gpio-rcar.c +++ b/drivers/gpio/gpio-rcar.c @@ -10,6 +10,7 @@ #include <errno.h> #include <asm/gpio.h> #include <asm/io.h> +#include "../pinctrl/renesas/sh_pfc.h" #define GPIO_IOINTSEL 0x00 /* General IO/Interrupt Switching Register */ #define GPIO_INOUTSEL 0x04 /* General Input/Output Switching Register */ @@ -29,7 +30,8 @@ DECLARE_GLOBAL_DATA_PTR; struct rcar_gpio_priv { - void __iomem *regs; + void __iomem *regs; + int pfc_offset; }; static int rcar_gpio_get_value(struct udevice *dev, unsigned offset) @@ -113,7 +115,22 @@ static int rcar_gpio_get_function(struct udevice *dev, unsigned offset) return GPIOF_INPUT; } +static int rcar_gpio_request(struct udevice *dev, unsigned offset, + const char *label) +{ + struct rcar_gpio_priv *priv = dev_get_priv(dev); + struct udevice *pctldev; + int ret; + + ret = uclass_get_device(UCLASS_PINCTRL, 0, &pctldev); + if (ret) + return ret; + + return sh_pfc_config_mux_for_gpio(pctldev, priv->pfc_offset + offset); +} + static const struct dm_gpio_ops rcar_gpio_ops = { + .request = rcar_gpio_request, .direction_input = rcar_gpio_direction_input, .direction_output = rcar_gpio_direction_output, .get_value = rcar_gpio_get_value, @@ -135,6 +152,7 @@ static int rcar_gpio_probe(struct udevice *dev) ret = fdtdec_parse_phandle_with_args(gd->fdt_blob, node, "gpio-ranges", NULL, 3, 0, &args); + priv->pfc_offset = ret == 0 ? args.args[1] : -1; uc_priv->gpio_count = ret == 0 ? args.args[2] : RCAR_MAX_GPIO_PER_BANK; ret = clk_get_by_index(dev, 0, &clk); diff --git a/drivers/i2c/Kconfig b/drivers/i2c/Kconfig index 1989f8eb572..cc370b9c57c 100644 --- a/drivers/i2c/Kconfig +++ b/drivers/i2c/Kconfig @@ -157,6 +157,12 @@ config SYS_I2C_OMAP24XX help Add support for the OMAP2+ I2C driver. +config SYS_I2C_RCAR_IIC + bool "Renesas RCar Gen3 IIC driver" + depends on RCAR_GEN3 && DM_I2C + help + Support for Renesas RCar Gen3 IIC controller. + config SYS_I2C_ROCKCHIP bool "Rockchip I2C driver" depends on DM_I2C diff --git a/drivers/i2c/Makefile b/drivers/i2c/Makefile index 733cd3e92fa..169a2f1d7a9 100644 --- a/drivers/i2c/Makefile +++ b/drivers/i2c/Makefile @@ -31,6 +31,7 @@ obj-$(CONFIG_SYS_I2C_MXC) += mxc_i2c.o obj-$(CONFIG_SYS_I2C_MXS) += mxs_i2c.o obj-$(CONFIG_SYS_I2C_OMAP24XX) += omap24xx_i2c.o obj-$(CONFIG_SYS_I2C_RCAR) += rcar_i2c.o +obj-$(CONFIG_SYS_I2C_RCAR_IIC) += rcar_iic.o obj-$(CONFIG_SYS_I2C_ROCKCHIP) += rk_i2c.o obj-$(CONFIG_SYS_I2C_S3C24X0) += s3c24x0_i2c.o exynos_hs_i2c.o obj-$(CONFIG_SYS_I2C_SANDBOX) += sandbox_i2c.o i2c-emul-uclass.o diff --git a/drivers/i2c/rcar_iic.c b/drivers/i2c/rcar_iic.c new file mode 100644 index 00000000000..57ae2f51fca --- /dev/null +++ b/drivers/i2c/rcar_iic.c @@ -0,0 +1,271 @@ +/* + * Renesas RCar IIC driver + * + * Copyright (C) 2017 Marek Vasut <marek.vasut@gmail.com> + * + * Based on + * Copyright (C) 2011, 2013 Renesas Solutions Corp. + * Copyright (C) 2011, 2013 Nobuhiro Iwamatsu <nobuhiro.iwamatsu.yj@renesas.com> + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <common.h> +#include <clk.h> +#include <dm.h> +#include <i2c.h> +#include <asm/io.h> + +struct rcar_iic_priv { + void __iomem *base; + struct clk clk; + u8 iccl; + u8 icch; +}; + +#define RCAR_IIC_ICDR 0x00 +#define RCAR_IIC_ICCR 0x04 +#define RCAR_IIC_ICSR 0x08 +#define RCAR_IIC_ICIC 0x0c +#define RCAR_IIC_ICCL 0x10 +#define RCAR_IIC_ICCH 0x14 + +/* ICCR */ +#define RCAR_IIC_ICCR_ICE BIT(7) +#define RCAR_IIC_ICCR_RACK BIT(6) +#define RCAR_IIC_ICCR_RTS BIT(4) +#define RCAR_IIC_ICCR_BUSY BIT(2) +#define RCAR_IIC_ICCR_SCP BIT(0) + +/* ICSR / ICIC */ +#define RCAR_IC_BUSY BIT(4) +#define RCAR_IC_TACK BIT(2) +#define RCAR_IC_DTE BIT(0) + +#define IRQ_WAIT 1000 + +static void sh_irq_dte(struct udevice *dev) +{ + struct rcar_iic_priv *priv = dev_get_priv(dev); + int i; + + for (i = 0; i < IRQ_WAIT; i++) { + if (RCAR_IC_DTE & readb(priv->base + RCAR_IIC_ICSR)) + break; + udelay(10); + } +} + +static int sh_irq_dte_with_tack(struct udevice *dev) +{ + struct rcar_iic_priv *priv = dev_get_priv(dev); + int i; + + for (i = 0; i < IRQ_WAIT; i++) { + if (RCAR_IC_DTE & readb(priv->base + RCAR_IIC_ICSR)) + break; + if (RCAR_IC_TACK & readb(priv->base + RCAR_IIC_ICSR)) + return -ETIMEDOUT; + udelay(10); + } + return 0; +} + +static void sh_irq_busy(struct udevice *dev) +{ + struct rcar_iic_priv *priv = dev_get_priv(dev); + int i; + + for (i = 0; i < IRQ_WAIT; i++) { + if (!(RCAR_IC_BUSY & readb(priv->base + RCAR_IIC_ICSR))) + break; + udelay(10); + } +} + +static int rcar_iic_set_addr(struct udevice *dev, u8 chip, u8 read) +{ + struct rcar_iic_priv *priv = dev_get_priv(dev); + + clrbits_8(priv->base + RCAR_IIC_ICCR, RCAR_IIC_ICCR_ICE); + setbits_8(priv->base + RCAR_IIC_ICCR, RCAR_IIC_ICCR_ICE); + + writeb(priv->iccl, priv->base + RCAR_IIC_ICCL); + writeb(priv->icch, priv->base + RCAR_IIC_ICCH); + writeb(RCAR_IC_TACK, priv->base + RCAR_IIC_ICIC); + + writeb(RCAR_IIC_ICCR_ICE | RCAR_IIC_ICCR_RTS | RCAR_IIC_ICCR_BUSY, + priv->base + RCAR_IIC_ICCR); + sh_irq_dte(dev); + + clrbits_8(priv->base + RCAR_IIC_ICSR, RCAR_IC_TACK); + writeb(chip << 1 | read, priv->base + RCAR_IIC_ICDR); + return sh_irq_dte_with_tack(dev); +} + +static void rcar_iic_finish(struct udevice *dev) +{ + struct rcar_iic_priv *priv = dev_get_priv(dev); + + writeb(0, priv->base + RCAR_IIC_ICSR); + clrbits_8(priv->base + RCAR_IIC_ICCR, RCAR_IIC_ICCR_ICE); +} + +static int rcar_iic_read_common(struct udevice *dev, struct i2c_msg *msg) +{ + struct rcar_iic_priv *priv = dev_get_priv(dev); + int i, ret = -EREMOTEIO; + + if (rcar_iic_set_addr(dev, msg->addr, 1) != 0) + goto err; + + udelay(10); + + writeb(RCAR_IIC_ICCR_ICE | RCAR_IIC_ICCR_SCP, + priv->base + RCAR_IIC_ICCR); + + for (i = 0; i < msg->len; i++) { + if (sh_irq_dte_with_tack(dev) != 0) + goto err; + + msg->buf[i] = readb(priv->base + RCAR_IIC_ICDR) & 0xff; + + if (msg->len - 1 == i) { + writeb(RCAR_IIC_ICCR_ICE | RCAR_IIC_ICCR_RACK, + priv->base + RCAR_IIC_ICCR); + } + } + + sh_irq_busy(dev); + ret = 0; + +err: + rcar_iic_finish(dev); + return ret; +} + +static int rcar_iic_write_common(struct udevice *dev, struct i2c_msg *msg) +{ + struct rcar_iic_priv *priv = dev_get_priv(dev); + int i, ret = -EREMOTEIO; + + if (rcar_iic_set_addr(dev, msg->addr, 0) != 0) + goto err; + + udelay(10); + + for (i = 0; i < msg->len; i++) { + writeb(msg->buf[i], priv->base + RCAR_IIC_ICDR); + if (sh_irq_dte_with_tack(dev) != 0) + goto err; + } + + if (msg->flags & I2C_M_STOP) { + writeb(RCAR_IIC_ICCR_ICE | RCAR_IIC_ICCR_RTS, + priv->base + RCAR_IIC_ICCR); + if (sh_irq_dte_with_tack(dev) != 0) + goto err; + } + + sh_irq_busy(dev); + ret = 0; + +err: + rcar_iic_finish(dev); + return ret; +} + +static int rcar_iic_xfer(struct udevice *dev, struct i2c_msg *msg, int nmsgs) +{ + int ret; + + for (; nmsgs > 0; nmsgs--, msg++) { + if (msg->flags & I2C_M_RD) + ret = rcar_iic_read_common(dev, msg); + else + ret = rcar_iic_write_common(dev, msg); + + if (ret) + return -EREMOTEIO; + } + + return ret; +} + +static int rcar_iic_set_speed(struct udevice *dev, uint speed) +{ + struct rcar_iic_priv *priv = dev_get_priv(dev); + const unsigned int ratio_high = 4; + const unsigned int ratio_low = 5; + int clkrate, denom; + + clkrate = clk_get_rate(&priv->clk); + if (clkrate < 0) + return clkrate; + + /* + * Calculate the value for ICCL and ICCH. From the data sheet: + * iccl = (p-clock / transfer-rate) * (L / (L + H)) + * icch = (p clock / transfer rate) * (H / (L + H)) + * where L and H are the SCL low and high ratio. + */ + denom = speed * (ratio_high + ratio_low); + priv->iccl = DIV_ROUND_CLOSEST(clkrate * ratio_low, denom); + priv->icch = DIV_ROUND_CLOSEST(clkrate * ratio_high, denom); + + return 0; +} + +static int rcar_iic_probe_chip(struct udevice *dev, uint addr, uint flags) +{ + struct rcar_iic_priv *priv = dev_get_priv(dev); + int ret; + + rcar_iic_set_addr(dev, addr, 1); + writeb(RCAR_IIC_ICCR_ICE | RCAR_IIC_ICCR_SCP, + priv->base + RCAR_IIC_ICCR); + ret = sh_irq_dte_with_tack(dev); + rcar_iic_finish(dev); + + return ret; +} + +static int rcar_iic_probe(struct udevice *dev) +{ + struct rcar_iic_priv *priv = dev_get_priv(dev); + int ret; + + priv->base = dev_read_addr_ptr(dev); + + ret = clk_get_by_index(dev, 0, &priv->clk); + if (ret) + return ret; + + ret = clk_enable(&priv->clk); + if (ret) + return ret; + + rcar_iic_finish(dev); + + return rcar_iic_set_speed(dev, 100000); +} + +static const struct dm_i2c_ops rcar_iic_ops = { + .xfer = rcar_iic_xfer, + .probe_chip = rcar_iic_probe_chip, + .set_bus_speed = rcar_iic_set_speed, +}; + +static const struct udevice_id rcar_iic_ids[] = { + { .compatible = "renesas,rmobile-iic" }, + { } +}; + +U_BOOT_DRIVER(iic_rcar) = { + .name = "iic_rcar", + .id = UCLASS_I2C, + .of_match = rcar_iic_ids, + .probe = rcar_iic_probe, + .priv_auto_alloc_size = sizeof(struct rcar_iic_priv), + .ops = &rcar_iic_ops, +}; diff --git a/drivers/misc/stm32_rcc.c b/drivers/misc/stm32_rcc.c index 32d39719d81..87d9928362b 100644 --- a/drivers/misc/stm32_rcc.c +++ b/drivers/misc/stm32_rcc.c @@ -8,31 +8,63 @@ #include <common.h> #include <dm.h> #include <misc.h> +#include <stm32_rcc.h> +#include <dm/device-internal.h> #include <dm/lists.h> +struct stm32_rcc_clk stm32_rcc_clk_f4 = { + .drv_name = "stm32fx_rcc_clock", + .soc = STM32F4, +}; + +struct stm32_rcc_clk stm32_rcc_clk_f7 = { + .drv_name = "stm32fx_rcc_clock", + .soc = STM32F7, +}; + +struct stm32_rcc_clk stm32_rcc_clk_h7 = { + .drv_name = "stm32h7_rcc_clock", +}; + static int stm32_rcc_bind(struct udevice *dev) { - int ret; struct udevice *child; + struct driver *drv; + struct stm32_rcc_clk *rcc_clk = + (struct stm32_rcc_clk *)dev_get_driver_data(dev); + int ret; debug("%s(dev=%p)\n", __func__, dev); - ret = device_bind_driver_to_node(dev, "stm32h7_rcc_clock", - "stm32h7_rcc_clock", - dev_ofnode(dev), &child); + drv = lists_driver_lookup_name(rcc_clk->drv_name); + if (!drv) { + debug("Cannot find driver '%s'\n", rcc_clk->drv_name); + return -ENOENT; + } + + ret = device_bind_with_driver_data(dev, drv, rcc_clk->drv_name, + rcc_clk->soc, + dev_ofnode(dev), &child); + if (ret) return ret; +#ifdef CONFIG_SPL_BUILD + return 0; +#else return device_bind_driver_to_node(dev, "stm32_rcc_reset", "stm32_rcc_reset", dev_ofnode(dev), &child); +#endif } static const struct misc_ops stm32_rcc_ops = { }; static const struct udevice_id stm32_rcc_ids[] = { - {.compatible = "st,stm32h743-rcc"}, + {.compatible = "st,stm32f42xx-rcc", .data = (ulong)&stm32_rcc_clk_f4 }, + {.compatible = "st,stm32f746-rcc", .data = (ulong)&stm32_rcc_clk_f7 }, + {.compatible = "st,stm32h743-rcc", .data = (ulong)&stm32_rcc_clk_h7 }, { } }; diff --git a/drivers/mmc/Kconfig b/drivers/mmc/Kconfig index 62ce0af7d3c..8fbeaa740d6 100644 --- a/drivers/mmc/Kconfig +++ b/drivers/mmc/Kconfig @@ -401,6 +401,18 @@ config STM32_SDMMC2 If you have a board based on such a SoC and with a SD/MMC slot, say Y or M here. +config MMC_NDS32 + bool "Andestech SD/MMC controller support" + depends on DM_MMC && OF_CONTROL && BLK && FTSDC010 + help + This enables support for the Andestech SD/MMM controller, which is + based on Faraday IP. + +config FTSDC010 + bool "Ftsdc010 SD/MMC controller Support" + help + This SD/MMC controller is present in Andestech SoCs which is based on Faraday IP. + endif config TEGRA124_MMC_DISABLE_EXT_LOOPBACK diff --git a/drivers/mmc/Makefile b/drivers/mmc/Makefile index d505f37f019..9af375b044a 100644 --- a/drivers/mmc/Makefile +++ b/drivers/mmc/Makefile @@ -44,6 +44,7 @@ obj-$(CONFIG_MMC_SANDBOX) += sandbox_mmc.o obj-$(CONFIG_SH_MMCIF) += sh_mmcif.o obj-$(CONFIG_SH_SDHI) += sh_sdhi.o obj-$(CONFIG_STM32_SDMMC2) += stm32_sdmmc2.o +obj-$(CONFIG_MMC_NDS32) += nds32_mmc.o # SDHCI obj-$(CONFIG_MMC_SDHCI) += sdhci.o diff --git a/drivers/mmc/atmel_sdhci.c b/drivers/mmc/atmel_sdhci.c index c19a1f36b69..9b37e32c8db 100644 --- a/drivers/mmc/atmel_sdhci.c +++ b/drivers/mmc/atmel_sdhci.c @@ -13,6 +13,7 @@ #include <asm/arch/clk.h> #define ATMEL_SDHC_MIN_FREQ 400000 +#define ATMEL_SDHC_GCK_RATE 240000000 #ifndef CONFIG_DM_MMC int atmel_sdhci_init(void *regbase, u32 id) @@ -57,9 +58,6 @@ static int atmel_sdhci_probe(struct udevice *dev) struct atmel_sdhci_plat *plat = dev_get_platdata(dev); struct sdhci_host *host = dev_get_priv(dev); u32 max_clk; - u32 caps, caps_1; - u32 clk_base, clk_mul; - ulong gck_rate; struct clk clk; int ret; @@ -78,17 +76,11 @@ static int atmel_sdhci_probe(struct udevice *dev) host->bus_width = fdtdec_get_int(gd->fdt_blob, dev_of_offset(dev), "bus-width", 4); - caps = sdhci_readl(host, SDHCI_CAPABILITIES); - clk_base = (caps & SDHCI_CLOCK_V3_BASE_MASK) >> SDHCI_CLOCK_BASE_SHIFT; - caps_1 = sdhci_readl(host, SDHCI_CAPABILITIES_1); - clk_mul = (caps_1 & SDHCI_CLOCK_MUL_MASK) >> SDHCI_CLOCK_MUL_SHIFT; - gck_rate = clk_base * 1000000 * (clk_mul + 1); - ret = clk_get_by_index(dev, 1, &clk); if (ret) return ret; - ret = clk_set_rate(&clk, gck_rate); + ret = clk_set_rate(&clk, ATMEL_SDHC_GCK_RATE); if (ret) return ret; diff --git a/drivers/mmc/ftsdc010_mci.c b/drivers/mmc/ftsdc010_mci.c index 652a718467a..6ac4f83bd1c 100644 --- a/drivers/mmc/ftsdc010_mci.c +++ b/drivers/mmc/ftsdc010_mci.c @@ -12,24 +12,15 @@ #include <part.h> #include <mmc.h> -#include <asm/io.h> +#include <linux/io.h> #include <linux/errno.h> #include <asm/byteorder.h> #include <faraday/ftsdc010.h> +#include "ftsdc010_mci.h" #define CFG_CMD_TIMEOUT (CONFIG_SYS_HZ >> 4) /* 250 ms */ #define CFG_RST_TIMEOUT CONFIG_SYS_HZ /* 1 sec reset timeout */ -struct ftsdc010_chip { - void __iomem *regs; - uint32_t wprot; /* write protected (locked) */ - uint32_t rate; /* actual SD clock in Hz */ - uint32_t sclk; /* FTSDC010 source clock in Hz */ - uint32_t fifo; /* fifo depth in bytes */ - uint32_t acmd; - struct mmc_config cfg; /* mmc configuration */ -}; - static inline int ftsdc010_send_cmd(struct mmc *mmc, struct mmc_cmd *mmc_cmd) { struct ftsdc010_chip *chip = mmc->priv; @@ -127,9 +118,8 @@ static void ftsdc010_clkset(struct mmc *mmc, uint32_t rate) static int ftsdc010_wait(struct ftsdc010_mmc __iomem *regs, uint32_t mask) { int ret = -ETIMEDOUT; - uint32_t st, ts; - - for (ts = get_timer(0); get_timer(ts) < CFG_CMD_TIMEOUT; ) { + uint32_t st, timeout = 10000000; + while (timeout--) { st = readl(®s->status); if (!(st & mask)) continue; @@ -138,8 +128,9 @@ static int ftsdc010_wait(struct ftsdc010_mmc __iomem *regs, uint32_t mask) break; } - if (ret) + if (ret){ debug("ftsdc010: wait st(0x%x) timeout\n", mask); + } return ret; } @@ -147,10 +138,16 @@ static int ftsdc010_wait(struct ftsdc010_mmc __iomem *regs, uint32_t mask) /* * u-boot mmc api */ - +#ifdef CONFIG_DM_MMC +static int ftsdc010_request(struct udevice *dev, struct mmc_cmd *cmd, + struct mmc_data *data) +{ + struct mmc *mmc = mmc_get_mmc_dev(dev); +#else static int ftsdc010_request(struct mmc *mmc, struct mmc_cmd *cmd, struct mmc_data *data) { +#endif int ret = -EOPNOTSUPP; uint32_t len = 0; struct ftsdc010_chip *chip = mmc->priv; @@ -245,14 +242,20 @@ static int ftsdc010_request(struct mmc *mmc, struct mmc_cmd *cmd, if (!ret) { ret = ftsdc010_wait(regs, - FTSDC010_STATUS_DATA_END | FTSDC010_STATUS_DATA_ERROR); + FTSDC010_STATUS_DATA_END | FTSDC010_STATUS_DATA_CRC_OK); } return ret; } +#ifdef CONFIG_DM_MMC +static int ftsdc010_set_ios(struct udevice *dev) +{ + struct mmc *mmc = mmc_get_mmc_dev(dev); +#else static int ftsdc010_set_ios(struct mmc *mmc) { +#endif struct ftsdc010_chip *chip = mmc->priv; struct ftsdc010_mmc __iomem *regs = chip->regs; @@ -274,20 +277,43 @@ static int ftsdc010_set_ios(struct mmc *mmc) return 0; } -static int ftsdc010_init(struct mmc *mmc) +#ifdef CONFIG_DM_MMC +static int ftsdc010_get_cd(struct udevice *dev) +{ + struct mmc *mmc = mmc_get_mmc_dev(dev); +#else +static int ftsdc010_get_cd(struct mmc *mmc) { +#endif struct ftsdc010_chip *chip = mmc->priv; struct ftsdc010_mmc __iomem *regs = chip->regs; - uint32_t ts; - - if (readl(®s->status) & FTSDC010_STATUS_CARD_DETECT) - return -ENOMEDIUM; + return !(readl(®s->status) & FTSDC010_STATUS_CARD_DETECT); +} +#ifdef CONFIG_DM_MMC +static int ftsdc010_get_wp(struct udevice *dev) +{ + struct mmc *mmc = mmc_get_mmc_dev(dev); +#else +static int ftsdc010_get_wp(struct mmc *mmc) +{ +#endif + struct ftsdc010_chip *chip = mmc->priv; + struct ftsdc010_mmc __iomem *regs = chip->regs; if (readl(®s->status) & FTSDC010_STATUS_WRITE_PROT) { printf("ftsdc010: write protected\n"); chip->wprot = 1; } + return 0; +} + +static int ftsdc010_init(struct mmc *mmc) +{ + struct ftsdc010_chip *chip = mmc->priv; + struct ftsdc010_mmc __iomem *regs = chip->regs; + uint32_t ts; + chip->fifo = (readl(®s->feature) & 0xff) << 2; /* 1. chip reset */ @@ -311,11 +337,69 @@ static int ftsdc010_init(struct mmc *mmc) return 0; } +#ifdef CONFIG_DM_MMC +int ftsdc010_probe(struct udevice *dev) +{ + struct mmc *mmc = mmc_get_mmc_dev(dev); + return ftsdc010_init(mmc); +} + +const struct dm_mmc_ops dm_ftsdc010_ops = { + .send_cmd = ftsdc010_request, + .set_ios = ftsdc010_set_ios, + .get_cd = ftsdc010_get_cd, + .get_wp = ftsdc010_get_wp, +}; + +#else static const struct mmc_ops ftsdc010_ops = { .send_cmd = ftsdc010_request, .set_ios = ftsdc010_set_ios, + .getcd = ftsdc010_get_cd, + .getwp = ftsdc010_get_wp, .init = ftsdc010_init, }; +#endif + +void ftsdc_setup_cfg(struct mmc_config *cfg, const char *name, int buswidth, + uint caps, u32 max_clk, u32 min_clk) +{ + cfg->name = name; + cfg->f_min = min_clk; + cfg->f_max = max_clk; + cfg->voltages = MMC_VDD_32_33 | MMC_VDD_33_34 | MMC_VDD_165_195; + cfg->host_caps = caps; + if (buswidth == 8) { + cfg->host_caps |= MMC_MODE_8BIT; + cfg->host_caps &= ~MMC_MODE_4BIT; + } else { + cfg->host_caps |= MMC_MODE_4BIT; + cfg->host_caps &= ~MMC_MODE_8BIT; + } + cfg->part_type = PART_TYPE_DOS; + cfg->b_max = CONFIG_SYS_MMC_MAX_BLK_COUNT; +} + +void set_bus_width(struct ftsdc010_mmc __iomem *regs, struct mmc_config *cfg) +{ + switch (readl(®s->bwr) & FTSDC010_BWR_CAPS_MASK) { + case FTSDC010_BWR_CAPS_4BIT: + cfg->host_caps |= MMC_MODE_4BIT; + break; + case FTSDC010_BWR_CAPS_8BIT: + cfg->host_caps |= MMC_MODE_4BIT | MMC_MODE_8BIT; + break; + default: + break; + } +} + +#ifdef CONFIG_BLK +int ftsdc010_bind(struct udevice *dev, struct mmc *mmc, struct mmc_config *cfg) +{ + return mmc_bind(dev, mmc, cfg); +} +#else int ftsdc010_mmc_init(int devid) { @@ -345,19 +429,11 @@ int ftsdc010_mmc_init(int devid) #endif chip->cfg.name = "ftsdc010"; +#ifndef CONFIG_DM_MMC chip->cfg.ops = &ftsdc010_ops; +#endif chip->cfg.host_caps = MMC_MODE_HS | MMC_MODE_HS_52MHz; - switch (readl(®s->bwr) & FTSDC010_BWR_CAPS_MASK) { - case FTSDC010_BWR_CAPS_4BIT: - chip->cfg.host_caps |= MMC_MODE_4BIT; - break; - case FTSDC010_BWR_CAPS_8BIT: - chip->cfg.host_caps |= MMC_MODE_4BIT | MMC_MODE_8BIT; - break; - default: - break; - } - + set_bus_width(regs , &chip->cfg); chip->cfg.voltages = MMC_VDD_32_33 | MMC_VDD_33_34; chip->cfg.f_max = chip->sclk / 2; chip->cfg.f_min = chip->sclk / 0x100; @@ -373,3 +449,4 @@ int ftsdc010_mmc_init(int devid) return 0; } +#endif diff --git a/drivers/mmc/ftsdc010_mci.h b/drivers/mmc/ftsdc010_mci.h new file mode 100644 index 00000000000..31a27fd7728 --- /dev/null +++ b/drivers/mmc/ftsdc010_mci.h @@ -0,0 +1,53 @@ +/* + * Faraday FTSDC010 Secure Digital Memory Card Host Controller + * + * Copyright (C) 2011 Andes Technology Corporation + * Macpaul Lin, Andes Technology Corporation <macpaul@andestech.com> + * + * SPDX-License-Identifier: GPL-2.0+ + */ +#include <mmc.h> + +#ifndef __FTSDC010_MCI_H +#define __FTSDC010_MCI_H + +struct ftsdc010_chip { + void __iomem *regs; + uint32_t wprot; /* write protected (locked) */ + uint32_t rate; /* actual SD clock in Hz */ + uint32_t sclk; /* FTSDC010 source clock in Hz */ + uint32_t fifo; /* fifo depth in bytes */ + uint32_t acmd; + struct mmc_config cfg; /* mmc configuration */ + const char *name; + void *ioaddr; + unsigned int caps; + unsigned int version; + unsigned int clock; + unsigned int bus_hz; + unsigned int div; + int dev_index; + int dev_id; + int buswidth; + u32 fifoth_val; + struct mmc *mmc; + void *priv; + bool fifo_mode; +}; + + +#ifdef CONFIG_DM_MMC +/* Export the operations to drivers */ +int ftsdc010_probe(struct udevice *dev); +extern const struct dm_mmc_ops dm_ftsdc010_ops; +#endif +void ftsdc_setup_cfg(struct mmc_config *cfg, const char *name, int buswidth, + uint caps, u32 max_clk, u32 min_clk); +void set_bus_width(struct ftsdc010_mmc __iomem *regs, struct mmc_config *cfg); + +#ifdef CONFIG_BLK +int ftsdc010_bind(struct udevice *dev, struct mmc *mmc, struct mmc_config *cfg); +#endif + + +#endif /* __FTSDC010_MCI_H */ diff --git a/drivers/mmc/nds32_mmc.c b/drivers/mmc/nds32_mmc.c new file mode 100644 index 00000000000..6d3c8572e50 --- /dev/null +++ b/drivers/mmc/nds32_mmc.c @@ -0,0 +1,136 @@ +/* + * Andestech ATFSDC010 SD/MMC driver + * + * (C) Copyright 2017 + * Rick Chen, NDS32 Software Engineering, rick@andestech.com + + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <common.h> +#include <clk.h> +#include <dm.h> +#include <dt-structs.h> +#include <errno.h> +#include <mapmem.h> +#include <mmc.h> +#include <pwrseq.h> +#include <syscon.h> +#include <linux/err.h> +#include <faraday/ftsdc010.h> +#include "ftsdc010_mci.h" + +DECLARE_GLOBAL_DATA_PTR; + +#if CONFIG_IS_ENABLED(OF_PLATDATA) +struct nds_mmc { + fdt32_t bus_width; + bool cap_mmc_highspeed; + bool cap_sd_highspeed; + fdt32_t clock_freq_min_max[2]; + struct phandle_2_cell clocks[4]; + fdt32_t fifo_depth; + fdt32_t reg[2]; +}; +#endif + +struct nds_mmc_plat { +#if CONFIG_IS_ENABLED(OF_PLATDATA) + struct nds_mmc dtplat; +#endif + struct mmc_config cfg; + struct mmc mmc; +}; + +struct ftsdc_priv { + struct clk clk; + struct ftsdc010_chip chip; + int fifo_depth; + bool fifo_mode; + u32 minmax[2]; +}; + +static int nds32_mmc_ofdata_to_platdata(struct udevice *dev) +{ +#if !CONFIG_IS_ENABLED(OF_PLATDATA) + struct ftsdc_priv *priv = dev_get_priv(dev); + struct ftsdc010_chip *chip = &priv->chip; + chip->name = dev->name; + chip->ioaddr = (void *)devfdt_get_addr(dev); + chip->buswidth = fdtdec_get_int(gd->fdt_blob, dev_of_offset(dev), + "bus-width", 4); + chip->priv = dev; + priv->fifo_depth = fdtdec_get_int(gd->fdt_blob, dev_of_offset(dev), + "fifo-depth", 0); + priv->fifo_mode = fdtdec_get_bool(gd->fdt_blob, dev_of_offset(dev), + "fifo-mode"); + if (fdtdec_get_int_array(gd->fdt_blob, dev_of_offset(dev), + "clock-freq-min-max", priv->minmax, 2)) { + int val = fdtdec_get_int(gd->fdt_blob, dev_of_offset(dev), + "max-frequency", -EINVAL); + if (val < 0) + return val; + + priv->minmax[0] = 400000; /* 400 kHz */ + priv->minmax[1] = val; + } else { + debug("%s: 'clock-freq-min-max' property was deprecated.\n", + __func__); + } +#endif + chip->sclk = priv->minmax[1]; + chip->regs = chip->ioaddr; + return 0; +} + +static int nds32_mmc_probe(struct udevice *dev) +{ + struct nds_mmc_plat *plat = dev_get_platdata(dev); + struct mmc_uclass_priv *upriv = dev_get_uclass_priv(dev); + struct ftsdc_priv *priv = dev_get_priv(dev); + struct ftsdc010_chip *chip = &priv->chip; + struct udevice *pwr_dev __maybe_unused; +#if CONFIG_IS_ENABLED(OF_PLATDATA) + int ret; + struct nds_mmc *dtplat = &plat->dtplat; + chip->name = dev->name; + chip->ioaddr = map_sysmem(dtplat->reg[0], dtplat->reg[1]); + chip->buswidth = dtplat->bus_width; + chip->priv = dev; + chip->dev_index = 1; + memcpy(priv->minmax, dtplat->clock_freq_min_max, sizeof(priv->minmax)); + ret = clk_get_by_index_platdata(dev, 0, dtplat->clocks, &priv->clk); + if (ret < 0) + return ret; +#endif + ftsdc_setup_cfg(&plat->cfg, dev->name, chip->buswidth, chip->caps, + priv->minmax[1] , priv->minmax[0]); + chip->mmc = &plat->mmc; + chip->mmc->priv = &priv->chip; + chip->mmc->dev = dev; + upriv->mmc = chip->mmc; + return ftsdc010_probe(dev); +} + +static int nds32_mmc_bind(struct udevice *dev) +{ + struct nds_mmc_plat *plat = dev_get_platdata(dev); + return ftsdc010_bind(dev, &plat->mmc, &plat->cfg); +} + +static const struct udevice_id nds32_mmc_ids[] = { + { .compatible = "andestech,atsdc010" }, + { } +}; + +U_BOOT_DRIVER(nds32_mmc_drv) = { + .name = "nds32_mmc", + .id = UCLASS_MMC, + .of_match = nds32_mmc_ids, + .ofdata_to_platdata = nds32_mmc_ofdata_to_platdata, + .ops = &dm_ftsdc010_ops, + .bind = nds32_mmc_bind, + .probe = nds32_mmc_probe, + .priv_auto_alloc_size = sizeof(struct ftsdc_priv), + .platdata_auto_alloc_size = sizeof(struct nds_mmc_plat), +}; diff --git a/drivers/mtd/nand/pxa3xx_nand.c b/drivers/mtd/nand/pxa3xx_nand.c index 6ab3c8a25ad..cedbb239b68 100644 --- a/drivers/mtd/nand/pxa3xx_nand.c +++ b/drivers/mtd/nand/pxa3xx_nand.c @@ -233,6 +233,7 @@ static struct pxa3xx_nand_flash builtin_flash_types[] = { { 0xba20, 16, 16, &timing[3] }, }; +#ifdef CONFIG_SYS_NAND_USE_FLASH_BBT static u8 bbt_pattern[] = {'M', 'V', 'B', 'b', 't', '0' }; static u8 bbt_mirror_pattern[] = {'1', 't', 'b', 'B', 'V', 'M' }; @@ -255,6 +256,7 @@ static struct nand_bbt_descr bbt_mirror_descr = { .maxblocks = 8, /* Last 8 blocks in each chip */ .pattern = bbt_mirror_pattern }; +#endif static struct nand_ecclayout ecc_layout_2KB_bch4bit = { .eccbytes = 32, diff --git a/drivers/net/ravb.c b/drivers/net/ravb.c index dc7a52534e5..26d95f178f7 100644 --- a/drivers/net/ravb.c +++ b/drivers/net/ravb.c @@ -492,8 +492,8 @@ static int ravb_probe(struct udevice *dev) if (ret < 0) goto err_mdio_alloc; - gpio_request_by_name_nodev(dev_ofnode(dev), "reset-gpios", 0, - ð->reset_gpio, GPIOD_IS_OUT); + gpio_request_by_name(dev, "reset-gpios", 0, ð->reset_gpio, + GPIOD_IS_OUT); mdiodev = mdio_alloc(); if (!mdiodev) { @@ -528,7 +528,8 @@ static int ravb_remove(struct udevice *dev) free(eth->phydev); mdio_unregister(eth->bus); mdio_free(eth->bus); - dm_gpio_free(dev, ð->reset_gpio); + if (dm_gpio_is_valid(ð->reset_gpio)) + dm_gpio_free(dev, ð->reset_gpio); unmap_physmem(eth->iobase, MAP_NOCACHE); return 0; diff --git a/drivers/pinctrl/Kconfig b/drivers/pinctrl/Kconfig index afca56dff1f..7e8e4b0b276 100644 --- a/drivers/pinctrl/Kconfig +++ b/drivers/pinctrl/Kconfig @@ -168,6 +168,16 @@ config PINCTRL_ROCKCHIP_RK3036 the GPIO definitions and pin control functions for each available multiplex function. +config PINCTRL_ROCKCHIP_RK3128 + bool "Rockchip rk3128 pin control driver" + depends on DM + help + Support pin multiplexing control on Rockchip rk3128 SoCs. + + The driver is controlled by a device tree node which contains both + the GPIO definitions and pin control functions for each available + multiplex function. + config PINCTRL_ROCKCHIP_RK3188 bool "Rockchip rk3188 pin control driver" depends on DM diff --git a/drivers/pinctrl/renesas/pfc.c b/drivers/pinctrl/renesas/pfc.c index 1675485d669..66700725045 100644 --- a/drivers/pinctrl/renesas/pfc.c +++ b/drivers/pinctrl/renesas/pfc.c @@ -448,6 +448,51 @@ static const char *sh_pfc_pinctrl_get_function_name(struct udevice *dev, return priv->pfc.info->functions[selector].name; } +int sh_pfc_config_mux_for_gpio(struct udevice *dev, unsigned pin_selector) +{ + struct sh_pfc_pinctrl_priv *priv = dev_get_priv(dev); + struct sh_pfc_pinctrl *pmx = &priv->pmx; + struct sh_pfc *pfc = &priv->pfc; + struct sh_pfc_pin_config *cfg; + const struct sh_pfc_pin *pin = NULL; + int i, idx; + + for (i = 1; i < pfc->info->nr_pins; i++) { + if (priv->pfc.info->pins[i].pin != pin_selector) + continue; + + pin = &priv->pfc.info->pins[i]; + break; + } + + if (!pin) + return -EINVAL; + + idx = sh_pfc_get_pin_index(pfc, pin->pin); + cfg = &pmx->configs[idx]; + + if (cfg->type != PINMUX_TYPE_NONE) + return -EBUSY; + + return sh_pfc_config_mux(pfc, pin->enum_id, PINMUX_TYPE_GPIO); +} + +static int sh_pfc_pinctrl_pin_set(struct udevice *dev, unsigned pin_selector, + unsigned func_selector) +{ + struct sh_pfc_pinctrl_priv *priv = dev_get_priv(dev); + struct sh_pfc_pinctrl *pmx = &priv->pmx; + struct sh_pfc *pfc = &priv->pfc; + const struct sh_pfc_pin *pin = &priv->pfc.info->pins[pin_selector]; + int idx = sh_pfc_get_pin_index(pfc, pin->pin); + struct sh_pfc_pin_config *cfg = &pmx->configs[idx]; + + if (cfg->type != PINMUX_TYPE_NONE) + return -EBUSY; + + return sh_pfc_config_mux(pfc, pin->enum_id, PINMUX_TYPE_FUNCTION); +} + static int sh_pfc_pinctrl_group_set(struct udevice *dev, unsigned group_selector, unsigned func_selector) { @@ -642,6 +687,19 @@ static int sh_pfc_pinconf_set(struct sh_pfc_pinctrl *pmx, unsigned _pin, return 0; } +static int sh_pfc_pinconf_pin_set(struct udevice *dev, + unsigned int pin_selector, + unsigned int param, unsigned int arg) +{ + struct sh_pfc_pinctrl_priv *priv = dev_get_priv(dev); + struct sh_pfc_pinctrl *pmx = &priv->pmx; + struct sh_pfc *pfc = &priv->pfc; + const struct sh_pfc_pin *pin = &pfc->info->pins[pin_selector]; + + sh_pfc_pinconf_set(pmx, pin->pin, param, arg); + + return 0; +} static int sh_pfc_pinconf_group_set(struct udevice *dev, unsigned int group_selector, @@ -671,8 +729,10 @@ static struct pinctrl_ops sh_pfc_pinctrl_ops = { #if CONFIG_IS_ENABLED(PINCONF) .pinconf_num_params = ARRAY_SIZE(sh_pfc_pinconf_params), .pinconf_params = sh_pfc_pinconf_params, + .pinconf_set = sh_pfc_pinconf_pin_set, .pinconf_group_set = sh_pfc_pinconf_group_set, #endif + .pinmux_set = sh_pfc_pinctrl_pin_set, .pinmux_group_set = sh_pfc_pinctrl_group_set, .set_state = pinctrl_generic_set_state, }; diff --git a/drivers/pinctrl/renesas/sh_pfc.h b/drivers/pinctrl/renesas/sh_pfc.h index 7aef2d360b2..f82417b1a34 100644 --- a/drivers/pinctrl/renesas/sh_pfc.h +++ b/drivers/pinctrl/renesas/sh_pfc.h @@ -243,6 +243,7 @@ void sh_pfc_write_reg(struct sh_pfc *pfc, u32 reg, unsigned int width, u32 data) const struct sh_pfc_bias_info * sh_pfc_pin_to_bias_info(const struct sh_pfc_bias_info *info, unsigned int num, unsigned int pin); +int sh_pfc_config_mux_for_gpio(struct udevice *dev, unsigned pin_selector); extern const struct sh_pfc_soc_info r8a7795_pinmux_info; extern const struct sh_pfc_soc_info r8a7796_pinmux_info; diff --git a/drivers/pinctrl/rockchip/Makefile b/drivers/pinctrl/rockchip/Makefile index 5251771a106..f09c6e17b4b 100644 --- a/drivers/pinctrl/rockchip/Makefile +++ b/drivers/pinctrl/rockchip/Makefile @@ -1,11 +1,11 @@ # -# Copyright (c) 2015 Google, Inc -# Written by Simon Glass <sjg@chromium.org> +# Copyright (c) 2017 Rockchip Electronics Co., Ltd # # SPDX-License-Identifier: GPL-2.0+ # obj-$(CONFIG_PINCTRL_ROCKCHIP_RK3036) += pinctrl_rk3036.o +obj-$(CONFIG_PINCTRL_ROCKCHIP_RK3128) += pinctrl_rk3128.o obj-$(CONFIG_PINCTRL_ROCKCHIP_RK3188) += pinctrl_rk3188.o obj-$(CONFIG_PINCTRL_ROCKCHIP_RK322X) += pinctrl_rk322x.o obj-$(CONFIG_PINCTRL_ROCKCHIP_RK3288) += pinctrl_rk3288.o diff --git a/drivers/pinctrl/rockchip/pinctrl_rk3128.c b/drivers/pinctrl/rockchip/pinctrl_rk3128.c new file mode 100644 index 00000000000..b1c32ac592a --- /dev/null +++ b/drivers/pinctrl/rockchip/pinctrl_rk3128.c @@ -0,0 +1,187 @@ +/* + * Pinctrl driver for Rockchip 3128 SoCs + * (C) Copyright 2017 Rockchip Electronics Co., Ltd + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <common.h> +#include <dm.h> +#include <errno.h> +#include <syscon.h> +#include <asm/io.h> +#include <asm/arch/clock.h> +#include <asm/arch/grf_rk3128.h> +#include <asm/arch/hardware.h> +#include <asm/arch/periph.h> +#include <dm/pinctrl.h> + +DECLARE_GLOBAL_DATA_PTR; + +struct rk3128_pinctrl_priv { + struct rk3128_grf *grf; +}; + +static void pinctrl_rk3128_i2c_config(struct rk3128_grf *grf, int i2c_id) +{ + switch (i2c_id) { + case PERIPH_ID_I2C0: + rk_clrsetreg(&grf->gpio0a_iomux, + GPIO0A1_MASK | GPIO0A0_MASK, + GPIO0A1_I2C0_SDA << GPIO0A1_SHIFT | + GPIO0A0_I2C0_SCL << GPIO0A0_SHIFT); + + break; + case PERIPH_ID_I2C1: + rk_clrsetreg(&grf->gpio0a_iomux, + GPIO0A3_MASK | GPIO0A2_MASK, + GPIO0A3_I2C1_SDA << GPIO0A3_SHIFT | + GPIO0A2_I2C1_SCL << GPIO0A2_SHIFT); + break; + case PERIPH_ID_I2C2: + rk_clrsetreg(&grf->gpio2c_iomux2, + GPIO2C5_MASK | GPIO2C4_MASK, + GPIO2C5_I2C2_SCL << GPIO2C5_SHIFT | + GPIO2C4_I2C2_SDA << GPIO2C4_SHIFT); + break; + case PERIPH_ID_I2C3: + rk_clrsetreg(&grf->gpio0a_iomux, + GPIO0A7_MASK | GPIO0A6_MASK, + GPIO0A7_I2C3_SDA << GPIO0A7_SHIFT | + GPIO0A6_I2C3_SCL << GPIO0A6_SHIFT); + + break; + } +} + +static void pinctrl_rk3128_sdmmc_config(struct rk3128_grf *grf, int mmc_id) +{ + switch (mmc_id) { + case PERIPH_ID_EMMC: + rk_clrsetreg(&grf->gpio1d_iomux, 0xffff, + GPIO1D7_EMMC_D7 << GPIO1D7_SHIFT | + GPIO1D6_EMMC_D6 << GPIO1D6_SHIFT | + GPIO1D5_EMMC_D5 << GPIO1D5_SHIFT | + GPIO1D4_EMMC_D4 << GPIO1D4_SHIFT | + GPIO1D3_EMMC_D3 << GPIO1D3_SHIFT | + GPIO1D2_EMMC_D2 << GPIO1D2_SHIFT | + GPIO1D1_EMMC_D1 << GPIO1D1_SHIFT | + GPIO1D0_EMMC_D0 << GPIO1D0_SHIFT); + rk_clrsetreg(&grf->gpio2a_iomux, + GPIO2A5_MASK | GPIO2A7_MASK, + GPIO2A5_EMMC_PWREN << GPIO2A5_SHIFT | + GPIO2A7_EMMC_CLKOUT << GPIO2A7_SHIFT); + break; + case PERIPH_ID_SDCARD: + rk_clrsetreg(&grf->gpio1c_iomux, 0x0fff, + GPIO1C5_MMC0_D3 << GPIO1C5_SHIFT | + GPIO1C4_MMC0_D2 << GPIO1C4_SHIFT | + GPIO1C3_MMC0_D1 << GPIO1C3_SHIFT | + GPIO1C2_MMC0_D0 << GPIO1C2_SHIFT | + GPIO1C1_MMC0_DETN << GPIO1C1_SHIFT | + GPIO1C0_MMC0_CLKOUT << GPIO1C0_SHIFT); + break; + } +} + +static int rk3128_pinctrl_request(struct udevice *dev, int func, int flags) +{ + struct rk3128_pinctrl_priv *priv = dev_get_priv(dev); + + debug("%s: func=%x, flags=%x\n", __func__, func, flags); + switch (func) { + case PERIPH_ID_I2C0: + case PERIPH_ID_I2C1: + case PERIPH_ID_I2C2: + case PERIPH_ID_I2C3: + pinctrl_rk3128_i2c_config(priv->grf, func); + break; + case PERIPH_ID_SDMMC0: + case PERIPH_ID_SDMMC1: + pinctrl_rk3128_sdmmc_config(priv->grf, func); + break; + default: + return -EINVAL; + } + + return 0; +} + +static int rk3128_pinctrl_get_periph_id(struct udevice *dev, + struct udevice *periph) +{ + u32 cell[3]; + int ret; + + ret = fdtdec_get_int_array(gd->fdt_blob, dev_of_offset(periph), + "interrupts", cell, ARRAY_SIZE(cell)); + if (ret < 0) + return -EINVAL; + + switch (cell[1]) { + case 14: + return PERIPH_ID_SDCARD; + case 16: + return PERIPH_ID_EMMC; + case 20: + return PERIPH_ID_UART0; + case 21: + return PERIPH_ID_UART1; + case 22: + return PERIPH_ID_UART2; + case 23: + return PERIPH_ID_SPI0; + case 24: + return PERIPH_ID_I2C0; + case 25: + return PERIPH_ID_I2C1; + case 26: + return PERIPH_ID_I2C2; + case 27: + return PERIPH_ID_I2C3; + case 30: + return PERIPH_ID_PWM0; + } + return -ENOENT; +} + +static int rk3128_pinctrl_set_state_simple(struct udevice *dev, + struct udevice *periph) +{ + int func; + + func = rk3128_pinctrl_get_periph_id(dev, periph); + if (func < 0) + return func; + return rk3128_pinctrl_request(dev, func, 0); +} + +static struct pinctrl_ops rk3128_pinctrl_ops = { + .set_state_simple = rk3128_pinctrl_set_state_simple, + .request = rk3128_pinctrl_request, + .get_periph_id = rk3128_pinctrl_get_periph_id, +}; + +static int rk3128_pinctrl_probe(struct udevice *dev) +{ + struct rk3128_pinctrl_priv *priv = dev_get_priv(dev); + + priv->grf = syscon_get_first_range(ROCKCHIP_SYSCON_GRF); + debug("%s: grf=%p\n", __func__, priv->grf); + return 0; +} + +static const struct udevice_id rk3128_pinctrl_ids[] = { + { .compatible = "rockchip,rk3128-pinctrl" }, + { } +}; + +U_BOOT_DRIVER(pinctrl_rk3128) = { + .name = "pinctrl_rk3128", + .id = UCLASS_PINCTRL, + .of_match = rk3128_pinctrl_ids, + .priv_auto_alloc_size = sizeof(struct rk3128_pinctrl_priv), + .ops = &rk3128_pinctrl_ops, + .bind = dm_scan_fdt_dev, + .probe = rk3128_pinctrl_probe, +}; diff --git a/drivers/ram/rockchip/Makefile b/drivers/ram/rockchip/Makefile index 45b5fe72471..1a1e5578ca4 100644 --- a/drivers/ram/rockchip/Makefile +++ b/drivers/ram/rockchip/Makefile @@ -5,6 +5,7 @@ # obj-$(CONFIG_ROCKCHIP_RK3368) = dmc-rk3368.o +obj-$(CONFIG_ROCKCHIP_RK3128) = sdram_rk3128.o obj-$(CONFIG_ROCKCHIP_RK3188) = sdram_rk3188.o obj-$(CONFIG_ROCKCHIP_RK322X) = sdram_rk322x.o obj-$(CONFIG_ROCKCHIP_RK3288) = sdram_rk3288.o diff --git a/drivers/ram/rockchip/sdram_rk3128.c b/drivers/ram/rockchip/sdram_rk3128.c new file mode 100644 index 00000000000..a33127f4b05 --- /dev/null +++ b/drivers/ram/rockchip/sdram_rk3128.c @@ -0,0 +1,59 @@ +/* + * (C) Copyright 2017 Rockchip Electronics Co., Ltd. + * + * SPDX-License-Identifier: GPL-2.0 + */ + +#include <common.h> +#include <dm.h> +#include <ram.h> +#include <syscon.h> +#include <asm/arch/clock.h> +#include <asm/arch/grf_rk3128.h> +#include <asm/arch/sdram_common.h> + +DECLARE_GLOBAL_DATA_PTR; +struct dram_info { + struct ram_info info; + struct rk3128_grf *grf; +}; + +static int rk3128_dmc_probe(struct udevice *dev) +{ + struct dram_info *priv = dev_get_priv(dev); + + priv->grf = syscon_get_first_range(ROCKCHIP_SYSCON_GRF); + debug("%s: grf=%p\n", __func__, priv->grf); + priv->info.base = CONFIG_SYS_SDRAM_BASE; + priv->info.size = rockchip_sdram_size( + (phys_addr_t)&priv->grf->os_reg[1]); + + return 0; +} + +static int rk3128_dmc_get_info(struct udevice *dev, struct ram_info *info) +{ + struct dram_info *priv = dev_get_priv(dev); + + *info = priv->info; + + return 0; +} + +static struct ram_ops rk3128_dmc_ops = { + .get_info = rk3128_dmc_get_info, +}; + +static const struct udevice_id rk3128_dmc_ids[] = { + { .compatible = "rockchip,rk3128-dmc" }, + { } +}; + +U_BOOT_DRIVER(dmc_rk3128) = { + .name = "rockchip_rk3128_dmc", + .id = UCLASS_RAM, + .of_match = rk3128_dmc_ids, + .ops = &rk3128_dmc_ops, + .probe = rk3128_dmc_probe, + .priv_auto_alloc_size = sizeof(struct dram_info), +}; diff --git a/drivers/serial/serial_sh.h b/drivers/serial/serial_sh.h index 4d271222434..1b8d742f1cf 100644 --- a/drivers/serial/serial_sh.h +++ b/drivers/serial/serial_sh.h @@ -226,8 +226,7 @@ struct uart_port { # define SCSCR_INIT(port) 0x38 /* TIE=0,RIE=0,TE=1,RE=1,REIE=1 */ #elif defined(CONFIG_R8A7790) || defined(CONFIG_R8A7791) || \ defined(CONFIG_R8A7792) || defined(CONFIG_R8A7793) || \ - defined(CONFIG_R8A7794) || defined(CONFIG_R8A7795) || \ - defined(CONFIG_R8A7796) + defined(CONFIG_R8A7794) || defined(CONFIG_RCAR_GEN3) # if defined(CONFIG_SCIF_A) # define SCIF_ORER 0x0200 # else diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig index 88da9a4c8e7..494639fb019 100644 --- a/drivers/spi/Kconfig +++ b/drivers/spi/Kconfig @@ -210,12 +210,12 @@ config FSL_QSPI used to access the SPI NOR flash on platforms embedding this Freescale IP core. -config NDS_AE3XX_SPI - bool "Andestech AE3XX SPI driver" +config ATCSPI200_SPI + bool "Andestech ATCSPI200 SPI driver" help - Enable the Andestech AE3XX SPI driver. This driver can be - used to access the SPI flash on platforms embedding this - Andestech IP core. + Enable the Andestech ATCSPI200 SPI driver. This driver can be + used to access the SPI flash on AE3XX and AE250 platforms embedding + this Andestech IP core. config TI_QSPI bool "TI QSPI driver" diff --git a/drivers/spi/Makefile b/drivers/spi/Makefile index ad56203cd6f..e3184db67f5 100644 --- a/drivers/spi/Makefile +++ b/drivers/spi/Makefile @@ -34,7 +34,7 @@ obj-$(CONFIG_MPC8XXX_SPI) += mpc8xxx_spi.o obj-$(CONFIG_MVEBU_A3700_SPI) += mvebu_a3700_spi.o obj-$(CONFIG_MXC_SPI) += mxc_spi.o obj-$(CONFIG_MXS_SPI) += mxs_spi.o -obj-$(CONFIG_NDS_AE3XX_SPI) += nds_ae3xx_spi.o +obj-$(CONFIG_ATCSPI200_SPI) += atcspi200_spi.o obj-$(CONFIG_OMAP3_SPI) += omap3_spi.o obj-$(CONFIG_PIC32_SPI) += pic32_spi.o obj-$(CONFIG_ROCKCHIP_SPI) += rk_spi.o diff --git a/drivers/spi/nds_ae3xx_spi.c b/drivers/spi/atcspi200_spi.c index f5bd99a605b..3e29df03a4d 100644 --- a/drivers/spi/nds_ae3xx_spi.c +++ b/drivers/spi/atcspi200_spi.c @@ -1,5 +1,5 @@ /* - * NDS SPI controller driver. + * Andestech ATCSPI200 SPI controller driver. * * Copyright 2017 Andes Technology, Inc. * Author: Rick Chen (rick@andestech.com) @@ -25,7 +25,7 @@ DECLARE_GLOBAL_DATA_PTR; #define SPI1_BASE 0xf0f00000 #define NSPI_MAX_CS_NUM 1 -struct ae3xx_spi_regs { +struct atcspi200_spi_regs { u32 rev; u32 reserve1[3]; u32 format; /* 0x10 */ @@ -78,7 +78,7 @@ struct nds_spi_slave { #ifndef CONFIG_DM_SPI struct spi_slave slave; #endif - volatile struct ae3xx_spi_regs *regs; + volatile struct atcspi200_spi_regs *regs; int to; unsigned int freq; ulong clock; @@ -94,7 +94,7 @@ struct nds_spi_slave { unsigned int max_transfer_length; }; -static int __ae3xx_spi_set_speed(struct nds_spi_slave *ns) +static int __atcspi200_spi_set_speed(struct nds_spi_slave *ns) { u32 tm; u8 div; @@ -117,7 +117,7 @@ static int __ae3xx_spi_set_speed(struct nds_spi_slave *ns) } -static int __ae3xx_spi_claim_bus(struct nds_spi_slave *ns) +static int __atcspi200_spi_claim_bus(struct nds_spi_slave *ns) { unsigned int format=0; ns->regs->ctrl |= (TXFRST|RXFRST|SPIRST); @@ -128,18 +128,18 @@ static int __ae3xx_spi_claim_bus(struct nds_spi_slave *ns) ns->cmd_len = 0; format = ns->mode|DATA_LENGTH(8); ns->regs->format = format; - __ae3xx_spi_set_speed(ns); + __atcspi200_spi_set_speed(ns); return 0; } -static int __ae3xx_spi_release_bus(struct nds_spi_slave *ns) +static int __atcspi200_spi_release_bus(struct nds_spi_slave *ns) { /* do nothing */ return 0; } -static int __ae3xx_spi_start(struct nds_spi_slave *ns) +static int __atcspi200_spi_start(struct nds_spi_slave *ns) { int i,olen=0; int tc = ns->regs->tctrl; @@ -168,7 +168,7 @@ static int __ae3xx_spi_start(struct nds_spi_slave *ns) return 0; } -static int __ae3xx_spi_stop(struct nds_spi_slave *ns) +static int __atcspi200_spi_stop(struct nds_spi_slave *ns) { ns->regs->timing = ns->mtiming; while ((ns->regs->status & SPIBSY)&&(ns->to--)) @@ -190,7 +190,7 @@ static int __nspi_espi_rx(struct nds_spi_slave *ns, void *din, unsigned int byte } -static int __ae3xx_spi_xfer(struct nds_spi_slave *ns, +static int __atcspi200_spi_xfer(struct nds_spi_slave *ns, unsigned int bitlen, const void *data_out, void *data_in, unsigned long flags) { @@ -230,7 +230,7 @@ static int __ae3xx_spi_xfer(struct nds_spi_slave *ns, memcpy(cmd_buf, data_out, cmd_len); data_out = 0; data_len = 0; - __ae3xx_spi_start(ns); + __atcspi200_spi_start(ns); break; } debug("spi_xfer: data_out %08X(%p) data_in %08X(%p) data_len %u\n", @@ -245,7 +245,7 @@ static int __ae3xx_spi_xfer(struct nds_spi_slave *ns, num_bytes = (tran_len) % CHUNK_SIZE; if(num_bytes == 0) num_bytes = CHUNK_SIZE; - __ae3xx_spi_start(ns); + __atcspi200_spi_start(ns); while (num_blks) { event = in_le32(&ns->regs->status); @@ -279,9 +279,9 @@ static int __ae3xx_spi_xfer(struct nds_spi_slave *ns, ns->cmd_buf[3] += ((tran_len)&0xff); ns->data_len = data_len; } - ret = __ae3xx_spi_stop(ns); + ret = __atcspi200_spi_stop(ns); } - ret = __ae3xx_spi_stop(ns); + ret = __atcspi200_spi_stop(ns); return ret; } @@ -300,11 +300,11 @@ struct spi_slave *spi_setup_slave(unsigned int bus, unsigned int cs, switch (bus) { case SPI0_BUS: - ns->regs = (struct ae3xx_spi_regs *)SPI0_BASE; + ns->regs = (struct atcspi200_spi_regs *)SPI0_BASE; break; case SPI1_BUS: - ns->regs = (struct ae3xx_spi_regs *)SPI1_BASE; + ns->regs = (struct atcspi200_spi_regs *)SPI1_BASE; break; default: @@ -336,20 +336,20 @@ void spi_init(void) int spi_claim_bus(struct spi_slave *slave) { struct nds_spi_slave *ns = to_nds_spi_slave(slave); - return __ae3xx_spi_claim_bus(ns); + return __atcspi200_spi_claim_bus(ns); } void spi_release_bus(struct spi_slave *slave) { struct nds_spi_slave *ns = to_nds_spi_slave(slave); - __ae3xx_spi_release_bus(ns); + __atcspi200_spi_release_bus(ns); } int spi_xfer(struct spi_slave *slave, unsigned int bitlen, const void *data_out, void *data_in, unsigned long flags) { struct nds_spi_slave *ns = to_nds_spi_slave(slave); - return __ae3xx_spi_xfer(ns, bitlen, data_out, data_in, flags); + return __atcspi200_spi_xfer(ns, bitlen, data_out, data_in, flags); } int spi_cs_is_valid(unsigned int bus, unsigned int cs) @@ -360,28 +360,28 @@ int spi_cs_is_valid(unsigned int bus, unsigned int cs) void spi_cs_activate(struct spi_slave *slave) { struct nds_spi_slave *ns = to_nds_spi_slave(slave); - __ae3xx_spi_start(ns); + __atcspi200_spi_start(ns); } void spi_cs_deactivate(struct spi_slave *slave) { struct nds_spi_slave *ns = to_nds_spi_slave(slave); - __ae3xx_spi_stop(ns); + __atcspi200_spi_stop(ns); } #else -static int ae3xx_spi_set_speed(struct udevice *bus, uint max_hz) +static int atcspi200_spi_set_speed(struct udevice *bus, uint max_hz) { struct nds_spi_slave *ns = dev_get_priv(bus); debug("%s speed %u\n", __func__, max_hz); ns->freq = max_hz; - __ae3xx_spi_set_speed(ns); + __atcspi200_spi_set_speed(ns); return 0; } -static int ae3xx_spi_set_mode(struct udevice *bus, uint mode) +static int atcspi200_spi_set_mode(struct udevice *bus, uint mode) { struct nds_spi_slave *ns = dev_get_priv(bus); @@ -391,7 +391,7 @@ static int ae3xx_spi_set_mode(struct udevice *bus, uint mode) return 0; } -static int ae3xx_spi_claim_bus(struct udevice *dev) +static int atcspi200_spi_claim_bus(struct udevice *dev) { struct dm_spi_slave_platdata *slave_plat = dev_get_parent_platdata(dev); @@ -403,27 +403,27 @@ static int ae3xx_spi_claim_bus(struct udevice *dev) return -EINVAL; } - return __ae3xx_spi_claim_bus(ns); + return __atcspi200_spi_claim_bus(ns); } -static int ae3xx_spi_release_bus(struct udevice *dev) +static int atcspi200_spi_release_bus(struct udevice *dev) { struct nds_spi_slave *ns = dev_get_priv(dev->parent); - return __ae3xx_spi_release_bus(ns); + return __atcspi200_spi_release_bus(ns); } -static int ae3xx_spi_xfer(struct udevice *dev, unsigned int bitlen, +static int atcspi200_spi_xfer(struct udevice *dev, unsigned int bitlen, const void *dout, void *din, unsigned long flags) { struct udevice *bus = dev->parent; struct nds_spi_slave *ns = dev_get_priv(bus); - return __ae3xx_spi_xfer(ns, bitlen, dout, din, flags); + return __atcspi200_spi_xfer(ns, bitlen, dout, din, flags); } -static int ae3xx_spi_get_clk(struct udevice *bus) +static int atcspi200_spi_get_clk(struct udevice *bus) { struct nds_spi_slave *ns = dev_get_priv(bus); struct clk clk; @@ -444,26 +444,26 @@ static int ae3xx_spi_get_clk(struct udevice *bus) return 0; } -static int ae3xx_spi_probe(struct udevice *bus) +static int atcspi200_spi_probe(struct udevice *bus) { struct nds_spi_slave *ns = dev_get_priv(bus); ns->to = SPI_TIMEOUT; ns->max_transfer_length = MAX_TRANSFER_LEN; ns->mtiming = ns->regs->timing; - ae3xx_spi_get_clk(bus); + atcspi200_spi_get_clk(bus); return 0; } -static int ae3xx_ofdata_to_platadata(struct udevice *bus) +static int atcspi200_ofdata_to_platadata(struct udevice *bus) { struct nds_spi_slave *ns = dev_get_priv(bus); const void *blob = gd->fdt_blob; int node = dev_of_offset(bus); ns->regs = map_physmem(devfdt_get_addr(bus), - sizeof(struct ae3xx_spi_regs), + sizeof(struct atcspi200_spi_regs), MAP_NOCACHE); if (!ns->regs) { printf("%s: could not map device address\n", __func__); @@ -474,26 +474,26 @@ static int ae3xx_ofdata_to_platadata(struct udevice *bus) return 0; } -static const struct dm_spi_ops ae3xx_spi_ops = { - .claim_bus = ae3xx_spi_claim_bus, - .release_bus = ae3xx_spi_release_bus, - .xfer = ae3xx_spi_xfer, - .set_speed = ae3xx_spi_set_speed, - .set_mode = ae3xx_spi_set_mode, +static const struct dm_spi_ops atcspi200_spi_ops = { + .claim_bus = atcspi200_spi_claim_bus, + .release_bus = atcspi200_spi_release_bus, + .xfer = atcspi200_spi_xfer, + .set_speed = atcspi200_spi_set_speed, + .set_mode = atcspi200_spi_set_mode, }; -static const struct udevice_id ae3xx_spi_ids[] = { +static const struct udevice_id atcspi200_spi_ids[] = { { .compatible = "andestech,atcspi200" }, { } }; -U_BOOT_DRIVER(ae3xx_spi) = { - .name = "ae3xx_spi", +U_BOOT_DRIVER(atcspi200_spi) = { + .name = "atcspi200_spi", .id = UCLASS_SPI, - .of_match = ae3xx_spi_ids, - .ops = &ae3xx_spi_ops, - .ofdata_to_platdata = ae3xx_ofdata_to_platadata, + .of_match = atcspi200_spi_ids, + .ops = &atcspi200_spi_ops, + .ofdata_to_platdata = atcspi200_ofdata_to_platadata, .priv_auto_alloc_size = sizeof(struct nds_spi_slave), - .probe = ae3xx_spi_probe, + .probe = atcspi200_spi_probe, }; #endif diff --git a/drivers/timer/Kconfig b/drivers/timer/Kconfig index 6305bbf01cd..3a1f8311c12 100644 --- a/drivers/timer/Kconfig +++ b/drivers/timer/Kconfig @@ -105,11 +105,12 @@ config AG101P_TIMER help Select this to enable a timer for AG01P devices. -config AE3XX_TIMER - bool "AE3XX timer support" - depends on TIMER && NDS32 +config ATCPIT100_TIMER + bool "ATCPIT100 timer support" + depends on TIMER help - Select this to enable a timer for AE3XX devices. + Select this to enable a ATCPIT100 timer which will be embeded + in AE3XX, AE250 boards. config ROCKCHIP_TIMER bool "Rockchip timer support" diff --git a/drivers/timer/Makefile b/drivers/timer/Makefile index 69e8961a7ba..15e515407e3 100644 --- a/drivers/timer/Makefile +++ b/drivers/timer/Makefile @@ -13,6 +13,6 @@ obj-$(CONFIG_AST_TIMER) += ast_timer.o obj-$(CONFIG_STI_TIMER) += sti-timer.o obj-$(CONFIG_ARC_TIMER) += arc_timer.o obj-$(CONFIG_AG101P_TIMER) += ag101p_timer.o -obj-$(CONFIG_AE3XX_TIMER) += ae3xx_timer.o +obj-$(CONFIG_ATCPIT100_TIMER) += atcpit100_timer.o obj-$(CONFIG_ROCKCHIP_TIMER) += rockchip_timer.o obj-$(CONFIG_ATMEL_PIT_TIMER) += atmel_pit_timer.o diff --git a/drivers/timer/ae3xx_timer.c b/drivers/timer/atcpit100_timer.c index bcc07a0c864..963f978d206 100644 --- a/drivers/timer/ae3xx_timer.c +++ b/drivers/timer/atcpit100_timer.c @@ -14,7 +14,7 @@ DECLARE_GLOBAL_DATA_PTR; -#define REG32_TMR(x) (*(unsigned long *) ((plat->regs) + (x>>2))) +#define REG32_TMR(x) (*(u32 *) ((plat->regs) + (x>>2))) /* * Definition of register offsets @@ -67,51 +67,51 @@ struct atctmr_timer_regs { u32 int_mask; /* 0x38 */ }; -struct atftmr_timer_platdata { - unsigned long *regs; +struct atcpit_timer_platdata { + u32 *regs; }; -static int atftmr_timer_get_count(struct udevice *dev, u64 *count) +static int atcpit_timer_get_count(struct udevice *dev, u64 *count) { - struct atftmr_timer_platdata *plat = dev->platdata; + struct atcpit_timer_platdata *plat = dev_get_platdata(dev); u32 val; val = ~(REG32_TMR(CH_CNT(1))+0xffffffff); *count = timer_conv_64(val); return 0; } -static int atctmr_timer_probe(struct udevice *dev) +static int atcpit_timer_probe(struct udevice *dev) { - struct atftmr_timer_platdata *plat = dev->platdata; + struct atcpit_timer_platdata *plat = dev_get_platdata(dev); REG32_TMR(CH_REL(1)) = 0xffffffff; REG32_TMR(CH_CTL(1)) = APB_CLK|TMR_32; REG32_TMR(CH_EN) |= CH_TMR_EN(1 , 0); return 0; } -static int atctme_timer_ofdata_to_platdata(struct udevice *dev) +static int atcpit_timer_ofdata_to_platdata(struct udevice *dev) { - struct atftmr_timer_platdata *plat = dev_get_platdata(dev); + struct atcpit_timer_platdata *plat = dev_get_platdata(dev); plat->regs = map_physmem(devfdt_get_addr(dev) , 0x100 , MAP_NOCACHE); return 0; } -static const struct timer_ops ag101p_timer_ops = { - .get_count = atftmr_timer_get_count, +static const struct timer_ops atcpit_timer_ops = { + .get_count = atcpit_timer_get_count, }; -static const struct udevice_id ag101p_timer_ids[] = { +static const struct udevice_id atcpit_timer_ids[] = { { .compatible = "andestech,atcpit100" }, {} }; -U_BOOT_DRIVER(altera_timer) = { - .name = "ae3xx_timer", +U_BOOT_DRIVER(atcpit100_timer) = { + .name = "atcpit100_timer", .id = UCLASS_TIMER, - .of_match = ag101p_timer_ids, - .ofdata_to_platdata = atctme_timer_ofdata_to_platdata, - .platdata_auto_alloc_size = sizeof(struct atftmr_timer_platdata), - .probe = atctmr_timer_probe, - .ops = &ag101p_timer_ops, + .of_match = atcpit_timer_ids, + .ofdata_to_platdata = atcpit_timer_ofdata_to_platdata, + .platdata_auto_alloc_size = sizeof(struct atcpit_timer_platdata), + .probe = atcpit_timer_probe, + .ops = &atcpit_timer_ops, .flags = DM_FLAG_PRE_RELOC, }; |