1 // SPDX-License-Identifier: GPL-2.0
3 * Copyright (C) 2020 MediaTek Inc.
5 * Author: Weijie Gao <weijie.gao@mediatek.com>
9 #include <linux/bitops.h>
11 #include <linux/sizes.h>
15 #define DDR_BW_TEST_PAT 0xaa5555aa
17 static const u32 dram_size[] = {
22 [DRAM_128MB] = SZ_128M,
23 [DRAM_256MB] = SZ_256M,
26 static void dram_test_write(u32 addr, u32 val)
28 volatile ulong *target = (volatile ulong *)(KSEG1 + addr);
35 static u32 dram_test_read(u32 addr)
37 volatile ulong *target = (volatile ulong *)(KSEG1 + addr);
47 static int dram_addr_test_bit(u32 bit)
51 dram_test_write(0, 0);
52 dram_test_write(BIT(bit), DDR_BW_TEST_PAT);
53 val = dram_test_read(0);
55 if (val == DDR_BW_TEST_PAT)
61 static void mc_ddr_init(void __iomem *memc, const struct mc_ddr_cfg *cfg,
62 u32 dq_dly, u32 dqs_dly, mc_reset_t mc_reset, u32 bw)
70 clrbits_32(memc + MEMCTL_SDRAM_CFG1_REG, RBC_MAPPING);
72 writel(cfg->cfg2, memc + MEMCTL_DDR_CFG2_REG);
73 writel(cfg->cfg3, memc + MEMCTL_DDR_CFG3_REG);
74 writel(cfg->cfg4, memc + MEMCTL_DDR_CFG4_REG);
75 writel(dq_dly, memc + MEMCTL_DDR_DQ_DLY_REG);
76 writel(dqs_dly, memc + MEMCTL_DDR_DQS_DLY_REG);
78 writel(cfg->cfg0, memc + MEMCTL_DDR_CFG0_REG);
82 val &= ~IND_SDRAM_WIDTH_M;
83 val |= (bw << IND_SDRAM_WIDTH_S) & IND_SDRAM_WIDTH_M;
86 writel(val, memc + MEMCTL_DDR_CFG1_REG);
88 clrsetbits_32(memc + MEMCTL_PWR_SAVE_CNT_REG, SR_TAR_CNT_M,
91 setbits_32(memc + MEMCTL_DDR_SELF_REFRESH_REG, SR_AUTO_EN);
94 void ddr1_init(struct mc_ddr_init_param *param)
99 /* First initialization, determine bus width */
100 mc_ddr_init(param->memc, ¶m->cfgs[DRAM_8MB], param->dq_dly,
101 param->dqs_dly, param->mc_reset, IND_SDRAM_WIDTH_16BIT);
104 dram_test_write(0, DDR_BW_TEST_PAT);
105 if (dram_test_read(0) == DDR_BW_TEST_PAT)
106 bw = IND_SDRAM_WIDTH_16BIT;
108 bw = IND_SDRAM_WIDTH_8BIT;
110 /* Second initialization, determine DDR capacity */
111 mc_ddr_init(param->memc, ¶m->cfgs[DRAM_128MB], param->dq_dly,
112 param->dqs_dly, param->mc_reset, bw);
114 if (dram_addr_test_bit(9)) {
117 if (dram_addr_test_bit(10)) {
118 if (dram_addr_test_bit(23))
123 if (dram_addr_test_bit(24))
130 /* Final initialization, with DDR calibration */
131 mc_ddr_init(param->memc, ¶m->cfgs[sz], param->dq_dly,
132 param->dqs_dly, param->mc_reset, bw);
134 /* Return actual DDR configuration */
135 param->memsize = dram_size[sz];
136 param->bus_width = bw;
139 void ddr2_init(struct mc_ddr_init_param *param)
141 enum mc_dram_size sz;
144 /* First initialization, determine bus width */
145 mc_ddr_init(param->memc, ¶m->cfgs[DRAM_32MB], param->dq_dly,
146 param->dqs_dly, param->mc_reset, IND_SDRAM_WIDTH_16BIT);
149 dram_test_write(0, DDR_BW_TEST_PAT);
150 if (dram_test_read(0) == DDR_BW_TEST_PAT)
151 bw = IND_SDRAM_WIDTH_16BIT;
153 bw = IND_SDRAM_WIDTH_8BIT;
155 /* Second initialization, determine DDR capacity */
156 mc_ddr_init(param->memc, ¶m->cfgs[DRAM_256MB], param->dq_dly,
157 param->dqs_dly, param->mc_reset, bw);
159 if (bw == IND_SDRAM_WIDTH_16BIT) {
160 if (dram_addr_test_bit(10)) {
163 if (dram_addr_test_bit(24)) {
164 if (dram_addr_test_bit(27))
173 if (dram_addr_test_bit(23)) {
176 if (dram_addr_test_bit(24)) {
177 if (dram_addr_test_bit(27))
187 /* Final initialization, with DDR calibration */
188 mc_ddr_init(param->memc, ¶m->cfgs[sz], param->dq_dly,
189 param->dqs_dly, param->mc_reset, bw);
191 /* Return actual DDR configuration */
192 param->memsize = dram_size[sz];
193 param->bus_width = bw;