blob: 9c986daea6f5c39afe0b0c4d38cc9aee9191d157 [file] [log] [blame]
Weijie Gao02cd4492020-04-21 09:28:34 +02001// SPDX-License-Identifier: GPL-2.0
2/*
3 * Copyright (C) 2020 MediaTek Inc.
4 *
5 * Author: Weijie Gao <weijie.gao@mediatek.com>
6 */
7
8#include <common.h>
9#include <linux/bitops.h>
Simon Glassc05ed002020-05-10 11:40:11 -060010#include <linux/delay.h>
Weijie Gao02cd4492020-04-21 09:28:34 +020011#include <linux/io.h>
12#include <linux/sizes.h>
13#include <mach/ddr.h>
14#include <mach/mc.h>
15
16#define DDR_BW_TEST_PAT 0xaa5555aa
17
Weijie Gaof0a865b2020-11-12 16:35:43 +080018static const u32 sdr_size_cfg1[] = {
19 [DRAM_8MB] = (1 << NUMROWS_S),
20 [DRAM_16MB] = (1 << NUMROWS_S) | (1 << NUMCOLS_S),
21 [DRAM_32MB] = (2 << NUMROWS_S) | (1 << NUMCOLS_S),
22 [DRAM_64MB] = (2 << NUMROWS_S) | (2 << NUMCOLS_S),
23};
24
Weijie Gao02cd4492020-04-21 09:28:34 +020025static const u32 dram_size[] = {
26 [DRAM_8MB] = SZ_8M,
27 [DRAM_16MB] = SZ_16M,
28 [DRAM_32MB] = SZ_32M,
29 [DRAM_64MB] = SZ_64M,
30 [DRAM_128MB] = SZ_128M,
31 [DRAM_256MB] = SZ_256M,
32};
33
34static void dram_test_write(u32 addr, u32 val)
35{
36 volatile ulong *target = (volatile ulong *)(KSEG1 + addr);
37
38 sync();
39 *target = val;
40 sync();
41}
42
43static u32 dram_test_read(u32 addr)
44{
45 volatile ulong *target = (volatile ulong *)(KSEG1 + addr);
46 u32 val;
47
48 sync();
49 val = *target;
50 sync();
51
52 return val;
53}
54
55static int dram_addr_test_bit(u32 bit)
56{
57 u32 val;
58
59 dram_test_write(0, 0);
60 dram_test_write(BIT(bit), DDR_BW_TEST_PAT);
61 val = dram_test_read(0);
62
63 if (val == DDR_BW_TEST_PAT)
64 return 1;
65
66 return 0;
67}
68
69static void mc_ddr_init(void __iomem *memc, const struct mc_ddr_cfg *cfg,
70 u32 dq_dly, u32 dqs_dly, mc_reset_t mc_reset, u32 bw)
71{
72 u32 val;
73
74 mc_reset(1);
75 __udelay(200);
76 mc_reset(0);
77
78 clrbits_32(memc + MEMCTL_SDRAM_CFG1_REG, RBC_MAPPING);
79
80 writel(cfg->cfg2, memc + MEMCTL_DDR_CFG2_REG);
81 writel(cfg->cfg3, memc + MEMCTL_DDR_CFG3_REG);
82 writel(cfg->cfg4, memc + MEMCTL_DDR_CFG4_REG);
83 writel(dq_dly, memc + MEMCTL_DDR_DQ_DLY_REG);
84 writel(dqs_dly, memc + MEMCTL_DDR_DQS_DLY_REG);
85
86 writel(cfg->cfg0, memc + MEMCTL_DDR_CFG0_REG);
87
88 val = cfg->cfg1;
89 if (bw) {
90 val &= ~IND_SDRAM_WIDTH_M;
91 val |= (bw << IND_SDRAM_WIDTH_S) & IND_SDRAM_WIDTH_M;
92 }
93
94 writel(val, memc + MEMCTL_DDR_CFG1_REG);
95
96 clrsetbits_32(memc + MEMCTL_PWR_SAVE_CNT_REG, SR_TAR_CNT_M,
97 1 << SR_TAR_CNT_S);
98
99 setbits_32(memc + MEMCTL_DDR_SELF_REFRESH_REG, SR_AUTO_EN);
100}
101
102void ddr1_init(struct mc_ddr_init_param *param)
103{
104 enum mc_dram_size sz;
105 u32 bw = 0;
106
107 /* First initialization, determine bus width */
108 mc_ddr_init(param->memc, &param->cfgs[DRAM_8MB], param->dq_dly,
109 param->dqs_dly, param->mc_reset, IND_SDRAM_WIDTH_16BIT);
110
111 /* Test bus width */
112 dram_test_write(0, DDR_BW_TEST_PAT);
113 if (dram_test_read(0) == DDR_BW_TEST_PAT)
114 bw = IND_SDRAM_WIDTH_16BIT;
115 else
116 bw = IND_SDRAM_WIDTH_8BIT;
117
118 /* Second initialization, determine DDR capacity */
119 mc_ddr_init(param->memc, &param->cfgs[DRAM_128MB], param->dq_dly,
120 param->dqs_dly, param->mc_reset, bw);
121
122 if (dram_addr_test_bit(9)) {
123 sz = DRAM_8MB;
124 } else {
125 if (dram_addr_test_bit(10)) {
126 if (dram_addr_test_bit(23))
127 sz = DRAM_16MB;
128 else
129 sz = DRAM_32MB;
130 } else {
131 if (dram_addr_test_bit(24))
132 sz = DRAM_64MB;
133 else
134 sz = DRAM_128MB;
135 }
136 }
137
138 /* Final initialization, with DDR calibration */
139 mc_ddr_init(param->memc, &param->cfgs[sz], param->dq_dly,
140 param->dqs_dly, param->mc_reset, bw);
141
142 /* Return actual DDR configuration */
143 param->memsize = dram_size[sz];
144 param->bus_width = bw;
145}
146
147void ddr2_init(struct mc_ddr_init_param *param)
148{
149 enum mc_dram_size sz;
150 u32 bw = 0;
151
152 /* First initialization, determine bus width */
153 mc_ddr_init(param->memc, &param->cfgs[DRAM_32MB], param->dq_dly,
154 param->dqs_dly, param->mc_reset, IND_SDRAM_WIDTH_16BIT);
155
156 /* Test bus width */
157 dram_test_write(0, DDR_BW_TEST_PAT);
158 if (dram_test_read(0) == DDR_BW_TEST_PAT)
159 bw = IND_SDRAM_WIDTH_16BIT;
160 else
161 bw = IND_SDRAM_WIDTH_8BIT;
162
163 /* Second initialization, determine DDR capacity */
164 mc_ddr_init(param->memc, &param->cfgs[DRAM_256MB], param->dq_dly,
165 param->dqs_dly, param->mc_reset, bw);
166
167 if (bw == IND_SDRAM_WIDTH_16BIT) {
168 if (dram_addr_test_bit(10)) {
169 sz = DRAM_32MB;
170 } else {
171 if (dram_addr_test_bit(24)) {
172 if (dram_addr_test_bit(27))
173 sz = DRAM_64MB;
174 else
175 sz = DRAM_128MB;
176 } else {
177 sz = DRAM_256MB;
178 }
179 }
180 } else {
181 if (dram_addr_test_bit(23)) {
182 sz = DRAM_32MB;
183 } else {
184 if (dram_addr_test_bit(24)) {
185 if (dram_addr_test_bit(27))
186 sz = DRAM_64MB;
187 else
188 sz = DRAM_128MB;
189 } else {
190 sz = DRAM_256MB;
191 }
192 }
193 }
194
195 /* Final initialization, with DDR calibration */
196 mc_ddr_init(param->memc, &param->cfgs[sz], param->dq_dly,
197 param->dqs_dly, param->mc_reset, bw);
198
199 /* Return actual DDR configuration */
200 param->memsize = dram_size[sz];
201 param->bus_width = bw;
202}
Weijie Gaof0a865b2020-11-12 16:35:43 +0800203
204static void mc_sdr_init(void __iomem *memc, mc_reset_t mc_reset, u32 cfg0,
205 u32 cfg1)
206{
207 mc_reset(1);
208 __udelay(200);
209 mc_reset(0);
210
211 writel(cfg0, memc + MEMCTL_SDRAM_CFG0_REG);
212 writel(cfg1, memc + MEMCTL_SDRAM_CFG1_REG);
213
214 while (!(readl(memc + MEMCTL_SDRAM_CFG1_REG) & SDRAM_INIT_DONE))
215 ;
216
217 clrsetbits_32(memc + MEMCTL_PWR_SAVE_CNT_REG, SR_TAR_CNT_M,
218 1 << SR_TAR_CNT_S);
219
220 setbits_32(memc + MEMCTL_DDR_SELF_REFRESH_REG, SR_AUTO_EN);
221}
222
223void sdr_init(struct mc_ddr_init_param *param)
224{
225 enum mc_dram_size sz;
226 u32 cfg1;
227
228 cfg1 = param->sdr_cfg1 | SDRAM_INIT_START;
229 cfg1 &= ~(NUMCOLS_M | NUMROWS_M);
230
231 /* First initialization, determine SDR capacity */
232 mc_sdr_init(param->memc, param->mc_reset, param->sdr_cfg0,
233 cfg1 | sdr_size_cfg1[DRAM_64MB]);
234
235 if (dram_addr_test_bit(9)) {
236 sz = DRAM_8MB;
237 } else {
238 if (dram_addr_test_bit(10)) {
239 if (dram_addr_test_bit(23))
240 sz = DRAM_16MB;
241 else
242 sz = DRAM_32MB;
243 } else {
244 sz = DRAM_64MB;
245 }
246 }
247
248 /* Final initialization */
249 mc_sdr_init(param->memc, param->mc_reset, param->sdr_cfg0,
250 cfg1 | sdr_size_cfg1[sz]);
251
252 /* Return actual DDR configuration */
253 param->memsize = dram_size[sz];
254}