diff options
author | Tom Rini <trini@konsulko.com> | 2020-04-27 17:50:35 -0400 |
---|---|---|
committer | Tom Rini <trini@konsulko.com> | 2020-04-27 17:50:35 -0400 |
commit | 9b20a794a71151a3a690242b5161b4ca5effd3e7 (patch) | |
tree | 6b212ab26b722b8fc7e92218e1eafa22073e96f2 /arch/mips/mach-mtmips/ddr_init.c | |
parent | 37b02289029853033fd662cd4b010336cfb282ad (diff) | |
parent | 3fd023143237a5271a21ccec4b94440df257a5a7 (diff) | |
download | u-boot-9b20a794a71151a3a690242b5161b4ca5effd3e7.zip u-boot-9b20a794a71151a3a690242b5161b4ca5effd3e7.tar.gz u-boot-9b20a794a71151a3a690242b5161b4ca5effd3e7.tar.bz2 |
Merge tag 'mips-pull-2020-04-27' of https://gitlab.denx.de/u-boot/custodians/u-boot-mips
- brcmnand: fix missing code path from Linux driver
- bmips: fix build error when disabling USB
- mips: add option to restore original exception vector base
- mips: fix off-by-one error when clearing gd_data
- mips: minor fixes for compatibility with generic SPL framework
- spl: refactor legacy image loading
- spl: add LZMA decompression support for legacy images
- Makefile: add target to build LZMA compressed U-Boot images
- mtmips: refactor and rewrite low-level init code
- mtmips: add and enable SPL support with LZMA
- mtmips: add support for MT7628 reference board
- mtmips: add support for VoCore/VoCore2 board
Diffstat (limited to 'arch/mips/mach-mtmips/ddr_init.c')
-rw-r--r-- | arch/mips/mach-mtmips/ddr_init.c | 194 |
1 files changed, 194 insertions, 0 deletions
diff --git a/arch/mips/mach-mtmips/ddr_init.c b/arch/mips/mach-mtmips/ddr_init.c new file mode 100644 index 0000000..cd355cc --- /dev/null +++ b/arch/mips/mach-mtmips/ddr_init.c @@ -0,0 +1,194 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2020 MediaTek Inc. + * + * Author: Weijie Gao <weijie.gao@mediatek.com> + */ + +#include <common.h> +#include <linux/bitops.h> +#include <linux/io.h> +#include <linux/sizes.h> +#include <mach/ddr.h> +#include <mach/mc.h> + +#define DDR_BW_TEST_PAT 0xaa5555aa + +static const u32 dram_size[] = { + [DRAM_8MB] = SZ_8M, + [DRAM_16MB] = SZ_16M, + [DRAM_32MB] = SZ_32M, + [DRAM_64MB] = SZ_64M, + [DRAM_128MB] = SZ_128M, + [DRAM_256MB] = SZ_256M, +}; + +static void dram_test_write(u32 addr, u32 val) +{ + volatile ulong *target = (volatile ulong *)(KSEG1 + addr); + + sync(); + *target = val; + sync(); +} + +static u32 dram_test_read(u32 addr) +{ + volatile ulong *target = (volatile ulong *)(KSEG1 + addr); + u32 val; + + sync(); + val = *target; + sync(); + + return val; +} + +static int dram_addr_test_bit(u32 bit) +{ + u32 val; + + dram_test_write(0, 0); + dram_test_write(BIT(bit), DDR_BW_TEST_PAT); + val = dram_test_read(0); + + if (val == DDR_BW_TEST_PAT) + return 1; + + return 0; +} + +static void mc_ddr_init(void __iomem *memc, const struct mc_ddr_cfg *cfg, + u32 dq_dly, u32 dqs_dly, mc_reset_t mc_reset, u32 bw) +{ + u32 val; + + mc_reset(1); + __udelay(200); + mc_reset(0); + + clrbits_32(memc + MEMCTL_SDRAM_CFG1_REG, RBC_MAPPING); + + writel(cfg->cfg2, memc + MEMCTL_DDR_CFG2_REG); + writel(cfg->cfg3, memc + MEMCTL_DDR_CFG3_REG); + writel(cfg->cfg4, memc + MEMCTL_DDR_CFG4_REG); + writel(dq_dly, memc + MEMCTL_DDR_DQ_DLY_REG); + writel(dqs_dly, memc + MEMCTL_DDR_DQS_DLY_REG); + + writel(cfg->cfg0, memc + MEMCTL_DDR_CFG0_REG); + + val = cfg->cfg1; + if (bw) { + val &= ~IND_SDRAM_WIDTH_M; + val |= (bw << IND_SDRAM_WIDTH_S) & IND_SDRAM_WIDTH_M; + } + + writel(val, memc + MEMCTL_DDR_CFG1_REG); + + clrsetbits_32(memc + MEMCTL_PWR_SAVE_CNT_REG, SR_TAR_CNT_M, + 1 << SR_TAR_CNT_S); + + setbits_32(memc + MEMCTL_DDR_SELF_REFRESH_REG, SR_AUTO_EN); +} + +void ddr1_init(struct mc_ddr_init_param *param) +{ + enum mc_dram_size sz; + u32 bw = 0; + + /* First initialization, determine bus width */ + mc_ddr_init(param->memc, ¶m->cfgs[DRAM_8MB], param->dq_dly, + param->dqs_dly, param->mc_reset, IND_SDRAM_WIDTH_16BIT); + + /* Test bus width */ + dram_test_write(0, DDR_BW_TEST_PAT); + if (dram_test_read(0) == DDR_BW_TEST_PAT) + bw = IND_SDRAM_WIDTH_16BIT; + else + bw = IND_SDRAM_WIDTH_8BIT; + + /* Second initialization, determine DDR capacity */ + mc_ddr_init(param->memc, ¶m->cfgs[DRAM_128MB], param->dq_dly, + param->dqs_dly, param->mc_reset, bw); + + if (dram_addr_test_bit(9)) { + sz = DRAM_8MB; + } else { + if (dram_addr_test_bit(10)) { + if (dram_addr_test_bit(23)) + sz = DRAM_16MB; + else + sz = DRAM_32MB; + } else { + if (dram_addr_test_bit(24)) + sz = DRAM_64MB; + else + sz = DRAM_128MB; + } + } + + /* Final initialization, with DDR calibration */ + mc_ddr_init(param->memc, ¶m->cfgs[sz], param->dq_dly, + param->dqs_dly, param->mc_reset, bw); + + /* Return actual DDR configuration */ + param->memsize = dram_size[sz]; + param->bus_width = bw; +} + +void ddr2_init(struct mc_ddr_init_param *param) +{ + enum mc_dram_size sz; + u32 bw = 0; + + /* First initialization, determine bus width */ + mc_ddr_init(param->memc, ¶m->cfgs[DRAM_32MB], param->dq_dly, + param->dqs_dly, param->mc_reset, IND_SDRAM_WIDTH_16BIT); + + /* Test bus width */ + dram_test_write(0, DDR_BW_TEST_PAT); + if (dram_test_read(0) == DDR_BW_TEST_PAT) + bw = IND_SDRAM_WIDTH_16BIT; + else + bw = IND_SDRAM_WIDTH_8BIT; + + /* Second initialization, determine DDR capacity */ + mc_ddr_init(param->memc, ¶m->cfgs[DRAM_256MB], param->dq_dly, + param->dqs_dly, param->mc_reset, bw); + + if (bw == IND_SDRAM_WIDTH_16BIT) { + if (dram_addr_test_bit(10)) { + sz = DRAM_32MB; + } else { + if (dram_addr_test_bit(24)) { + if (dram_addr_test_bit(27)) + sz = DRAM_64MB; + else + sz = DRAM_128MB; + } else { + sz = DRAM_256MB; + } + } + } else { + if (dram_addr_test_bit(23)) { + sz = DRAM_32MB; + } else { + if (dram_addr_test_bit(24)) { + if (dram_addr_test_bit(27)) + sz = DRAM_64MB; + else + sz = DRAM_128MB; + } else { + sz = DRAM_256MB; + } + } + } + + /* Final initialization, with DDR calibration */ + mc_ddr_init(param->memc, ¶m->cfgs[sz], param->dq_dly, + param->dqs_dly, param->mc_reset, bw); + + /* Return actual DDR configuration */ + param->memsize = dram_size[sz]; + param->bus_width = bw; +} |