diff options
Diffstat (limited to 'arch/arm/mach-rockchip')
-rw-r--r-- | arch/arm/mach-rockchip/rk3036/Makefile | 2 | ||||
-rw-r--r-- | arch/arm/mach-rockchip/rk3036/clk_rk3036.c | 33 | ||||
-rw-r--r-- | arch/arm/mach-rockchip/rk3288/Kconfig | 3 | ||||
-rw-r--r-- | arch/arm/mach-rockchip/rk3288/clk_rk3288.c | 16 | ||||
-rw-r--r-- | arch/arm/mach-rockchip/rk3288/rk3288.c | 2 | ||||
-rw-r--r-- | arch/arm/mach-rockchip/rk3288/sdram_rk3288.c | 272 | ||||
-rw-r--r-- | arch/arm/mach-rockchip/rk3399/Makefile | 1 | ||||
-rw-r--r-- | arch/arm/mach-rockchip/rk3399/clk_rk3399.c | 33 | ||||
-rw-r--r-- | arch/arm/mach-rockchip/rk3399/rk3399.c | 14 |
9 files changed, 330 insertions, 46 deletions
diff --git a/arch/arm/mach-rockchip/rk3036/Makefile b/arch/arm/mach-rockchip/rk3036/Makefile index 916a7a4378..20d28f7c21 100644 --- a/arch/arm/mach-rockchip/rk3036/Makefile +++ b/arch/arm/mach-rockchip/rk3036/Makefile @@ -4,6 +4,8 @@ # SPDX-License-Identifier: GPL-2.0+ # +obj-y += clk_rk3036.o + ifndef CONFIG_SPL_BUILD obj-y += syscon_rk3036.o endif diff --git a/arch/arm/mach-rockchip/rk3036/clk_rk3036.c b/arch/arm/mach-rockchip/rk3036/clk_rk3036.c new file mode 100644 index 0000000000..6a06afb103 --- /dev/null +++ b/arch/arm/mach-rockchip/rk3036/clk_rk3036.c @@ -0,0 +1,33 @@ +/* + * Copyright (C) 2016 Google, Inc + * Written by Simon Glass <sjg@chromium.org> + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <common.h> +#include <dm.h> +#include <syscon.h> +#include <asm/arch/clock.h> +#include <asm/arch/cru_rk3036.h> + +int rockchip_get_clk(struct udevice **devp) +{ + return uclass_get_device_by_driver(UCLASS_CLK, + DM_GET_DRIVER(rockchip_rk3036_cru), devp); +} + +void *rockchip_get_cru(void) +{ + struct rk3036_clk_priv *priv; + struct udevice *dev; + int ret; + + ret = rockchip_get_clk(&dev); + if (ret) + return ERR_PTR(ret); + + priv = dev_get_priv(dev); + + return priv->cru; +} diff --git a/arch/arm/mach-rockchip/rk3288/Kconfig b/arch/arm/mach-rockchip/rk3288/Kconfig index 94863a925e..c53d2e2033 100644 --- a/arch/arm/mach-rockchip/rk3288/Kconfig +++ b/arch/arm/mach-rockchip/rk3288/Kconfig @@ -81,9 +81,6 @@ config SPL_LIBCOMMON_SUPPORT config SPL_LIBGENERIC_SUPPORT default y -config SPL_MMC_SUPPORT - default y - config SPL_SERIAL_SUPPORT default y diff --git a/arch/arm/mach-rockchip/rk3288/clk_rk3288.c b/arch/arm/mach-rockchip/rk3288/clk_rk3288.c index 2099e349c1..a45b923a2c 100644 --- a/arch/arm/mach-rockchip/rk3288/clk_rk3288.c +++ b/arch/arm/mach-rockchip/rk3288/clk_rk3288.c @@ -9,9 +9,25 @@ #include <dm.h> #include <syscon.h> #include <asm/arch/clock.h> +#include <asm/arch/cru_rk3288.h> int rockchip_get_clk(struct udevice **devp) { return uclass_get_device_by_driver(UCLASS_CLK, DM_GET_DRIVER(rockchip_rk3288_cru), devp); } + +void *rockchip_get_cru(void) +{ + struct rk3288_clk_priv *priv; + struct udevice *dev; + int ret; + + ret = rockchip_get_clk(&dev); + if (ret) + return ERR_PTR(ret); + + priv = dev_get_priv(dev); + + return priv->cru; +} diff --git a/arch/arm/mach-rockchip/rk3288/rk3288.c b/arch/arm/mach-rockchip/rk3288/rk3288.c index 92f34bbbcb..acc3b7932a 100644 --- a/arch/arm/mach-rockchip/rk3288/rk3288.c +++ b/arch/arm/mach-rockchip/rk3288/rk3288.c @@ -6,7 +6,7 @@ #include <asm/io.h> #include <asm/arch/hardware.h> -#define GRF_SOC_CON2 0x24c +#define GRF_SOC_CON2 0xff77024c int arch_cpu_init(void) { diff --git a/arch/arm/mach-rockchip/rk3288/sdram_rk3288.c b/arch/arm/mach-rockchip/rk3288/sdram_rk3288.c index 8020e9c6e2..be3d713202 100644 --- a/arch/arm/mach-rockchip/rk3288/sdram_rk3288.c +++ b/arch/arm/mach-rockchip/rk3288/sdram_rk3288.c @@ -57,6 +57,10 @@ struct rk3288_sdram_params { struct regmap *map; }; +#define TEST_PATTEN 0x5aa5f00f +#define DQS_GATE_TRAINING_ERROR_RANK0 (1 << 4) +#define DQS_GATE_TRAINING_ERROR_RANK1 (2 << 4) + #ifdef CONFIG_SPL_BUILD static void copy_to_reg(u32 *dest, const u32 *src, u32 n) { @@ -214,7 +218,7 @@ static void ddr_set_en_bst_odt(struct rk3288_grf *grf, uint channel, } static void pctl_cfg(u32 channel, struct rk3288_ddr_pctl *pctl, - const struct rk3288_sdram_params *sdram_params, + struct rk3288_sdram_params *sdram_params, struct rk3288_grf *grf) { unsigned int burstlen; @@ -264,7 +268,7 @@ static void pctl_cfg(u32 channel, struct rk3288_ddr_pctl *pctl, } static void phy_cfg(const struct chan_info *chan, u32 channel, - const struct rk3288_sdram_params *sdram_params) + struct rk3288_sdram_params *sdram_params) { struct rk3288_ddr_publ *publ = chan->publ; struct rk3288_msch *msch = chan->msch; @@ -446,7 +450,7 @@ static void set_bandwidth_ratio(const struct chan_info *chan, u32 channel, } static int data_training(const struct chan_info *chan, u32 channel, - const struct rk3288_sdram_params *sdram_params) + struct rk3288_sdram_params *sdram_params) { unsigned int j; int ret = 0; @@ -549,7 +553,7 @@ static void move_to_access_state(const struct chan_info *chan) } static void dram_cfg_rbc(const struct chan_info *chan, u32 chnum, - const struct rk3288_sdram_params *sdram_params) + struct rk3288_sdram_params *sdram_params) { struct rk3288_ddr_publ *publ = chan->publ; @@ -563,7 +567,7 @@ static void dram_cfg_rbc(const struct chan_info *chan, u32 chnum, } static void dram_all_config(const struct dram_info *dram, - const struct rk3288_sdram_params *sdram_params) + struct rk3288_sdram_params *sdram_params) { unsigned int chan; u32 sys_reg = 0; @@ -589,9 +593,191 @@ static void dram_all_config(const struct dram_info *dram, writel(sys_reg, &dram->pmu->sys_reg[2]); rk_clrsetreg(&dram->sgrf->soc_con2, 0x1f, sdram_params->base.stride); } +const int ddrconf_table[] = { + /* row col,bw */ + 0, + ((1 << 4) | 1), + ((2 << 4) | 1), + ((3 << 4) | 1), + ((4 << 4) | 1), + ((1 << 4) | 2), + ((2 << 4) | 2), + ((3 << 4) | 2), + ((1 << 4) | 0), + ((2 << 4) | 0), + ((3 << 4) | 0), + 0, + 0, + 0, + 0, + ((4 << 4) | 2), +}; + +static int sdram_rank_bw_detect(struct dram_info *dram, int channel, + struct rk3288_sdram_params *sdram_params) +{ + int reg; + int need_trainig = 0; + const struct chan_info *chan = &dram->chan[channel]; + struct rk3288_ddr_publ *publ = chan->publ; + + if (-1 == data_training(chan, channel, sdram_params)) { + reg = readl(&publ->datx8[0].dxgsr[0]); + /* Check the result for rank 0 */ + if ((channel == 0) && (reg & DQS_GATE_TRAINING_ERROR_RANK0)) { + debug("data training fail!\n"); + return -EIO; + } else if ((channel == 1) && + (reg & DQS_GATE_TRAINING_ERROR_RANK0)) { + sdram_params->num_channels = 1; + } + + /* Check the result for rank 1 */ + if (reg & DQS_GATE_TRAINING_ERROR_RANK1) { + sdram_params->ch[channel].rank = 1; + clrsetbits_le32(&publ->pgcr, 0xF << 18, + sdram_params->ch[channel].rank << 18); + need_trainig = 1; + } + reg = readl(&publ->datx8[2].dxgsr[0]); + if (reg & (1 << 4)) { + sdram_params->ch[channel].bw = 1; + set_bandwidth_ratio(chan, channel, + sdram_params->ch[channel].bw, + dram->grf); + need_trainig = 1; + } + } + /* Assume the Die bit width are the same with the chip bit width */ + sdram_params->ch[channel].dbw = sdram_params->ch[channel].bw; + + if (need_trainig && + (-1 == data_training(chan, channel, sdram_params))) { + if (sdram_params->base.dramtype == LPDDR3) { + ddr_phy_ctl_reset(dram->cru, channel, 1); + udelay(10); + ddr_phy_ctl_reset(dram->cru, channel, 0); + udelay(10); + } + debug("2nd data training failed!"); + return -EIO; + } + + return 0; +} + +static int sdram_col_row_detect(struct dram_info *dram, int channel, + struct rk3288_sdram_params *sdram_params) +{ + int row, col; + unsigned int addr; + const struct chan_info *chan = &dram->chan[channel]; + struct rk3288_ddr_pctl *pctl = chan->pctl; + struct rk3288_ddr_publ *publ = chan->publ; + int ret = 0; + + /* Detect col */ + for (col = 11; col >= 9; col--) { + writel(0, CONFIG_SYS_SDRAM_BASE); + addr = CONFIG_SYS_SDRAM_BASE + + (1 << (col + sdram_params->ch[channel].bw - 1)); + writel(TEST_PATTEN, addr); + if ((readl(addr) == TEST_PATTEN) && + (readl(CONFIG_SYS_SDRAM_BASE) == 0)) + break; + } + if (col == 8) { + printf("Col detect error\n"); + ret = -EINVAL; + goto out; + } else { + sdram_params->ch[channel].col = col; + } + + move_to_config_state(publ, pctl); + writel(4, &chan->msch->ddrconf); + move_to_access_state(chan); + /* Detect row*/ + for (row = 16; row >= 12; row--) { + writel(0, CONFIG_SYS_SDRAM_BASE); + addr = CONFIG_SYS_SDRAM_BASE + (1 << (row + 15 - 1)); + writel(TEST_PATTEN, addr); + if ((readl(addr) == TEST_PATTEN) && + (readl(CONFIG_SYS_SDRAM_BASE) == 0)) + break; + } + if (row == 11) { + printf("Row detect error\n"); + ret = -EINVAL; + } else { + sdram_params->ch[channel].cs1_row = row; + sdram_params->ch[channel].row_3_4 = 0; + debug("chn %d col %d, row %d\n", channel, col, row); + sdram_params->ch[channel].cs0_row = row; + } + +out: + return ret; +} + +static int sdram_get_niu_config(struct rk3288_sdram_params *sdram_params) +{ + int i, tmp, size, ret = 0; + + tmp = sdram_params->ch[0].col - 9; + tmp -= (sdram_params->ch[0].bw == 2) ? 0 : 1; + tmp |= ((sdram_params->ch[0].cs0_row - 12) << 4); + size = sizeof(ddrconf_table)/sizeof(ddrconf_table[0]); + for (i = 0; i < size; i++) + if (tmp == ddrconf_table[i]) + break; + if (i >= size) { + printf("niu config not found\n"); + ret = -EINVAL; + } else { + sdram_params->base.ddrconfig = i; + } + + return ret; +} + +static int sdram_get_stride(struct rk3288_sdram_params *sdram_params) +{ + int stride = -1; + int ret = 0; + long cap = sdram_params->num_channels * (1u << + (sdram_params->ch[0].cs0_row + + sdram_params->ch[0].col + + (sdram_params->ch[0].rank - 1) + + sdram_params->ch[0].bw + + 3 - 20)); + + switch (cap) { + case 512: + stride = 0; + break; + case 1024: + stride = 5; + break; + case 2048: + stride = 9; + break; + case 4096: + stride = 0xd; + break; + default: + stride = -1; + printf("could not find correct stride, cap error!\n"); + ret = -EINVAL; + break; + } + sdram_params->base.stride = stride; + + return ret; +} static int sdram_init(struct dram_info *dram, - const struct rk3288_sdram_params *sdram_params) + struct rk3288_sdram_params *sdram_params) { int channel; int zqcr; @@ -619,12 +805,14 @@ static int sdram_init(struct dram_info *dram, struct rk3288_ddr_pctl *pctl = chan->pctl; struct rk3288_ddr_publ *publ = chan->publ; + /* map all the 4GB space to the current channel */ + if (channel) + rk_clrsetreg(&dram->sgrf->soc_con2, 0x1f, 0x17); + else + rk_clrsetreg(&dram->sgrf->soc_con2, 0x1f, 0x1a); phy_pctrl_reset(dram->cru, publ, channel); phy_dll_bypass_set(publ, sdram_params->base.ddr_freq); - if (channel >= sdram_params->num_channels) - continue; - dfi_cfg(pctl, sdram_params->base.dramtype); pctl_cfg(channel, pctl, sdram_params, dram->grf); @@ -658,16 +846,20 @@ static int sdram_init(struct dram_info *dram, udelay(1); } + /* Using 32bit bus width for detect */ + sdram_params->ch[channel].bw = 2; set_bandwidth_ratio(chan, channel, sdram_params->ch[channel].bw, dram->grf); /* - * set cs + * set cs, using n=3 for detect * CS0, n=1 * CS1, n=2 * CS0 & CS1, n = 3 */ + sdram_params->ch[channel].rank = 2, clrsetbits_le32(&publ->pgcr, 0xF << 18, (sdram_params->ch[channel].rank | 1) << 18); + /* DS=40ohm,ODT=155ohm */ zqcr = 1 << ZDEN_SHIFT | 2 << PU_ONDIE_SHIFT | 2 << PD_ONDIE_SHIFT | 0x19 << PU_OUTPUT_SHIFT | @@ -693,16 +885,8 @@ static int sdram_init(struct dram_info *dram, } } - if (-1 == data_training(chan, channel, sdram_params)) { - if (sdram_params->base.dramtype == LPDDR3) { - ddr_phy_ctl_reset(dram->cru, channel, 1); - udelay(10); - ddr_phy_ctl_reset(dram->cru, channel, 0); - udelay(10); - } - debug("failed!"); - return -EIO; - } + /* Detect the rank and bit-width with data-training */ + sdram_rank_bw_detect(dram, channel, sdram_params); if (sdram_params->base.dramtype == LPDDR3) { u32 i; @@ -710,12 +894,31 @@ static int sdram_init(struct dram_info *dram, for (i = 0; i < 17; i++) send_command_op(pctl, 1, MRR_CMD, i, 0); } + writel(15, &chan->msch->ddrconf); move_to_access_state(chan); + /* DDR3 and LPDDR3 are always 8 bank, no need detect */ + sdram_params->ch[channel].bk = 3; + /* Detect Col and Row number*/ + ret = sdram_col_row_detect(dram, channel, sdram_params); + if (ret) + goto error; } + /* Find NIU DDR configuration */ + ret = sdram_get_niu_config(sdram_params); + if (ret) + goto error; + /* Find stride setting */ + ret = sdram_get_stride(sdram_params); + if (ret) + goto error; + dram_all_config(dram, sdram_params); debug("%s done\n", __func__); return 0; +error: + printf("DRAM init failed!\n"); + hang(); } #endif /* CONFIG_SPL_BUILD */ @@ -743,7 +946,6 @@ size_t sdram_size_mb(struct rk3288_pmu *pmu) SYS_REG_BW_MASK)); row_3_4 = sys_reg >> SYS_REG_ROW_3_4_SHIFT(ch) & SYS_REG_ROW_3_4_MASK; - chipsize_mb = (1 << (cs0_row + col + bk + bw - 20)); if (rank > 1) @@ -815,21 +1017,10 @@ static int rk3288_dmc_ofdata_to_platdata(struct udevice *dev) struct rk3288_sdram_params *params = dev_get_platdata(dev); const void *blob = gd->fdt_blob; int node = dev->of_offset; - int i, ret; - - params->num_channels = fdtdec_get_int(blob, node, - "rockchip,num-channels", 1); - for (i = 0; i < params->num_channels; i++) { - ret = fdtdec_get_byte_array(blob, node, - "rockchip,sdram-channel", - (u8 *)¶ms->ch[i], - sizeof(params->ch[i])); - if (ret) { - debug("%s: Cannot read rockchip,sdram-channel\n", - __func__); - return -EINVAL; - } - } + int ret; + + /* Rk3288 supports dual-channel, set default channel num to 2 */ + params->num_channels = 2; ret = fdtdec_get_int_array(blob, node, "rockchip,pctl-timing", (u32 *)¶ms->pctl_timing, sizeof(params->pctl_timing) / sizeof(u32)); @@ -870,18 +1061,15 @@ static int conv_of_platdata(struct udevice *dev) { struct rk3288_sdram_params *plat = dev_get_platdata(dev); struct dtd_rockchip_rk3288_dmc *of_plat = &plat->of_plat; - int i, ret; + int ret; - for (i = 0; i < 2; i++) { - memcpy(&plat->ch[i], of_plat->rockchip_sdram_channel, - sizeof(plat->ch[i])); - } memcpy(&plat->pctl_timing, of_plat->rockchip_pctl_timing, sizeof(plat->pctl_timing)); memcpy(&plat->phy_timing, of_plat->rockchip_phy_timing, sizeof(plat->phy_timing)); memcpy(&plat->base, of_plat->rockchip_sdram_params, sizeof(plat->base)); - plat->num_channels = of_plat->rockchip_num_channels; + /* Rk3288 supports dual-channel, set default channel num to 2 */ + plat->num_channels = 2; ret = regmap_init_mem_platdata(dev, of_plat->reg, ARRAY_SIZE(of_plat->reg) / 2, &plat->map); diff --git a/arch/arm/mach-rockchip/rk3399/Makefile b/arch/arm/mach-rockchip/rk3399/Makefile index 607f9c9612..98ebeac340 100644 --- a/arch/arm/mach-rockchip/rk3399/Makefile +++ b/arch/arm/mach-rockchip/rk3399/Makefile @@ -4,5 +4,6 @@ # SPDX-License-Identifier: GPL-2.0+ # +obj-y += clk_rk3399.o obj-y += rk3399.o obj-y += syscon_rk3399.o diff --git a/arch/arm/mach-rockchip/rk3399/clk_rk3399.c b/arch/arm/mach-rockchip/rk3399/clk_rk3399.c new file mode 100644 index 0000000000..7663591154 --- /dev/null +++ b/arch/arm/mach-rockchip/rk3399/clk_rk3399.c @@ -0,0 +1,33 @@ +/* + * Copyright (C) 2016 Google, Inc + * Written by Simon Glass <sjg@chromium.org> + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <common.h> +#include <dm.h> +#include <syscon.h> +#include <asm/arch/clock.h> +#include <asm/arch/cru_rk3399.h> + +int rockchip_get_clk(struct udevice **devp) +{ + return uclass_get_device_by_driver(UCLASS_CLK, + DM_GET_DRIVER(rockchip_rk3399_pmuclk), devp); +} + +void *rockchip_get_cru(void) +{ + struct rk3399_clk_priv *priv; + struct udevice *dev; + int ret; + + ret = rockchip_get_clk(&dev); + if (ret) + return ERR_PTR(ret); + + priv = dev_get_priv(dev); + + return priv->cru; +} diff --git a/arch/arm/mach-rockchip/rk3399/rk3399.c b/arch/arm/mach-rockchip/rk3399/rk3399.c index b9d7629407..8bb950ebd1 100644 --- a/arch/arm/mach-rockchip/rk3399/rk3399.c +++ b/arch/arm/mach-rockchip/rk3399/rk3399.c @@ -6,6 +6,10 @@ #include <common.h> #include <asm/armv8/mmu.h> +#include <asm/io.h> +#include <asm/arch/hardware.h> + +#define GRF_EMMCCORE_CON11 0xff77f02c static struct mm_region rk3399_mem_map[] = { { @@ -28,3 +32,13 @@ static struct mm_region rk3399_mem_map[] = { }; struct mm_region *mem_map = rk3399_mem_map; + +int arch_cpu_init(void) +{ + /* We do some SoC one time setting here. */ + + /* Emmc clock generator: disable the clock multipilier */ + rk_clrreg(GRF_EMMCCORE_CON11, 0x0ff); + + return 0; +} |