]>
Commit | Line | Data |
---|---|---|
2d67a095 RS |
1 | // SPDX-License-Identifier: BSD-2-Clause |
2 | /* | |
3 | * Cadence DDR Controller | |
4 | * | |
5 | * Copyright (C) 2015 Renesas Electronics Europe Ltd | |
6 | */ | |
7 | ||
8 | /* | |
9 | * The Cadence DDR Controller has a huge number of registers that principally | |
10 | * cover two aspects, DDR specific timing information and AXI bus interfacing. | |
11 | * Cadence's TCL script generates all of the register values for specific | |
12 | * DDR devices operating at a specific frequency. The TCL script uses Denali | |
13 | * SOMA files as inputs. The tool also generates the AXI bus register values as | |
14 | * well, however this driver assumes that users will want to modifiy these to | |
15 | * meet a specific application's needs. | |
16 | * Therefore, this driver is passed two arrays containing register values for | |
17 | * the DDR device specific information, and explicity sets the AXI registers. | |
18 | * | |
19 | * AXI bus interfacing: | |
20 | * The controller has four AXI slaves connections, and each of these can be | |
21 | * programmed to accept requests from specific AXI masters (using their IDs). | |
22 | * The regions of DDR that can be accessed by each AXI slave can be set such | |
23 | * as to isolate DDR used by one AXI master from another. Further, the maximum | |
24 | * bandwidth allocated to each AXI slave can be set. | |
25 | */ | |
26 | ||
d678a59d | 27 | #include <common.h> |
2d67a095 RS |
28 | #include <linux/delay.h> |
29 | #include <linux/sizes.h> | |
30 | #include <asm/io.h> | |
31 | #include <wait_bit.h> | |
32 | #include <renesas/ddr_ctrl.h> | |
33 | ||
34 | /* avoid warning for real pr_debug in <linux/printk.h> */ | |
35 | #ifdef pr_debug | |
36 | #undef pr_debug | |
37 | #endif | |
38 | ||
39 | #ifdef DEBUG | |
40 | #define pr_debug(fmt, args...) printf(fmt, ##args) | |
41 | #define pr_debug2(fmt, args...) printf(fmt, ##args) | |
42 | #else | |
43 | #define pr_debug(fmt, args...) | |
44 | #define pr_debug2(fmt, args...) | |
45 | #endif | |
46 | ||
47 | #define DDR_NR_AXI_PORTS 4 | |
48 | #define DDR_NR_ENTRIES 16 | |
49 | ||
50 | #define DDR_START_REG (0) /* DENALI_CTL_00 */ | |
51 | #define DDR_CS0_MR1_REG (32 * 4) /* DENALI_CTL_32 */ | |
52 | #define DDR_CS0_MR2_REG (32 * 4 + 2) /* DENALI_CTL_32 */ | |
53 | #define DDR_CS1_MR1_REG (34 * 4 + 2) /* DENALI_CTL_34 */ | |
54 | #define DDR_CS1_MR2_REG (35 * 4) /* DENALI_CTL_35 */ | |
55 | #define DDR_ECC_ENABLE_REG (36 * 4 + 2) /* DENALI_CTL_36 */ | |
56 | #define DDR_ECC_DISABLE_W_UC_ERR_REG (37 * 4 + 2) /* DENALI_CTL_37 */ | |
57 | #define DDR_HALF_DATAPATH_REG (54 * 4) /* DENALI_CTL_54 */ | |
58 | #define DDR_INTERRUPT_STATUS (56 * 4) /* DENALI_CTL_56 */ | |
59 | #define DDR_INTERRUPT_ACK (57 * 4) /* DENALI_CTL_57 */ | |
60 | #define DDR_INTERRUPT_MASK (58 * 4) /* DENALI_CTL_58 */ | |
61 | #define DDR_CS0_ODT_MAP_REG (62 * 4 + 2) /* DENALI_CTL_62 */ | |
62 | #define DDR_CS1_ODT_MAP_REG (63 * 4) /* DENALI_CTL_63 */ | |
63 | #define DDR_ODT_TODTL_2CMD (63 * 4 + 2) /* DENALI_CTL_63 */ | |
64 | #define DDR_ODT_TODTH_WR (63 * 4 + 3) /* DENALI_CTL_63 */ | |
65 | #define DDR_ODT_TODTH_RD (64 * 4 + 0) /* DENALI_CTL_64 */ | |
66 | #define DDR_ODT_EN (64 * 4 + 1) /* DENALI_CTL_64 */ | |
67 | #define DDR_ODT_WR_TO_ODTH (64 * 4 + 2) /* DENALI_CTL_64 */ | |
68 | #define DDR_ODT_RD_TO_ODTH (64 * 4 + 3) /* DENALI_CTL_64 */ | |
69 | #define DDR_DIFF_CS_DELAY_REG (66 * 4) /* DENALI_CTL_66 */ | |
70 | #define DDR_SAME_CS_DELAY_REG (67 * 4) /* DENALI_CTL_67 */ | |
71 | #define DDR_RW_PRIORITY_REGS (87 * 4 + 2) /* DENALI_CTL_87 */ | |
72 | #define DDR_RW_FIFO_TYPE_REGS (88 * 4) /* DENALI_CTL_88 */ | |
73 | #define DDR_AXI_PORT_PROT_ENABLE_REG (90 * 4 + 3) /* DENALI_CTL_90 */ | |
74 | #define DDR_ADDR_RANGE_REGS (91 * 4) /* DENALI_CTL_91 */ | |
75 | #define DDR_RANGE_PROT_REGS (218 * 4 + 2) /* DENALI_CTL_218 */ | |
76 | #define DDR_ARB_CMD_Q_THRESHOLD_REG (346 * 4 + 2) /* DENALI_CTL_346 */ | |
77 | #define DDR_AXI_PORT_BANDWIDTH_REG (346 * 4 + 3) /* DENALI_CTL_346 */ | |
78 | #define DDR_OPT_RMODW_REG (372 * 4 + 3) /* DENALI_CTL_372 */ | |
79 | ||
80 | static void ddrc_writeb(u8 val, void *p) | |
81 | { | |
82 | pr_debug2("DDR: %p = 0x%02x\n", p, val); | |
83 | writeb(val, p); | |
84 | } | |
85 | ||
86 | static void ddrc_writew(u16 val, void *p) | |
87 | { | |
88 | pr_debug2("DDR: %p = 0x%04x\n", p, val); | |
89 | writew(val, p); | |
90 | } | |
91 | ||
92 | static void ddrc_writel(u32 val, void *p) | |
93 | { | |
94 | pr_debug2("DDR: %p = 0x%08x\n", p, val); | |
95 | writel(val, p); | |
96 | } | |
97 | ||
98 | void cdns_ddr_set_mr1(void *base, int cs, u16 odt_impedance, u16 drive_strength) | |
99 | { | |
100 | void *reg; | |
101 | u16 tmp; | |
102 | ||
103 | if (cs == 0) | |
104 | reg = (u8 *)base + DDR_CS0_MR1_REG; | |
105 | else | |
106 | reg = (u8 *)base + DDR_CS1_MR1_REG; | |
107 | ||
108 | tmp = readw(reg); | |
109 | ||
110 | tmp &= ~MODE_REGISTER_MASK; | |
111 | tmp |= MODE_REGISTER_MR1; | |
112 | ||
113 | tmp &= ~MR1_ODT_IMPEDANCE_MASK; | |
114 | tmp |= odt_impedance; | |
115 | ||
116 | tmp &= ~MR1_DRIVE_STRENGTH_MASK; | |
117 | tmp |= drive_strength; | |
118 | ||
119 | writew(tmp, reg); | |
120 | } | |
121 | ||
122 | void cdns_ddr_set_mr2(void *base, int cs, u16 dynamic_odt, u16 self_refresh_temp) | |
123 | { | |
124 | void *reg; | |
125 | u16 tmp; | |
126 | ||
127 | if (cs == 0) | |
128 | reg = (u8 *)base + DDR_CS0_MR2_REG; | |
129 | else | |
130 | reg = (u8 *)base + DDR_CS1_MR2_REG; | |
131 | ||
132 | tmp = readw(reg); | |
133 | ||
134 | tmp &= ~MODE_REGISTER_MASK; | |
135 | tmp |= MODE_REGISTER_MR2; | |
136 | ||
137 | tmp &= ~MR2_DYNAMIC_ODT_MASK; | |
138 | tmp |= dynamic_odt; | |
139 | ||
140 | tmp &= ~MR2_SELF_REFRESH_TEMP_MASK; | |
141 | tmp |= self_refresh_temp; | |
142 | ||
143 | writew(tmp, reg); | |
144 | } | |
145 | ||
146 | void cdns_ddr_set_odt_map(void *base, int cs, u16 odt_map) | |
147 | { | |
148 | void *reg; | |
149 | ||
150 | if (cs == 0) | |
151 | reg = (u8 *)base + DDR_CS0_ODT_MAP_REG; | |
152 | else | |
153 | reg = (u8 *)base + DDR_CS1_ODT_MAP_REG; | |
154 | ||
155 | writew(odt_map, reg); | |
156 | } | |
157 | ||
158 | void cdns_ddr_set_odt_times(void *base, u8 TODTL_2CMD, u8 TODTH_WR, u8 TODTH_RD, | |
159 | u8 WR_TO_ODTH, u8 RD_TO_ODTH) | |
160 | { | |
161 | writeb(TODTL_2CMD, (u8 *)base + DDR_ODT_TODTL_2CMD); | |
162 | writeb(TODTH_WR, (u8 *)base + DDR_ODT_TODTH_WR); | |
163 | writeb(TODTH_RD, (u8 *)base + DDR_ODT_TODTH_RD); | |
164 | writeb(1, (u8 *)base + DDR_ODT_EN); | |
165 | writeb(WR_TO_ODTH, (u8 *)base + DDR_ODT_WR_TO_ODTH); | |
166 | writeb(RD_TO_ODTH, (u8 *)base + DDR_ODT_RD_TO_ODTH); | |
167 | } | |
168 | ||
169 | void cdns_ddr_set_same_cs_delays(void *base, u8 r2r, u8 r2w, u8 w2r, u8 w2w) | |
170 | { | |
171 | u32 val = (w2w << 24) | (w2r << 16) | (r2w << 8) | r2r; | |
172 | ||
173 | writel(val, (u8 *)base + DDR_SAME_CS_DELAY_REG); | |
174 | } | |
175 | ||
176 | void cdns_ddr_set_diff_cs_delays(void *base, u8 r2r, u8 r2w, u8 w2r, u8 w2w) | |
177 | { | |
178 | u32 val = (w2w << 24) | (w2r << 16) | (r2w << 8) | r2r; | |
179 | ||
180 | writel(val, (u8 *)base + DDR_DIFF_CS_DELAY_REG); | |
181 | } | |
182 | ||
183 | void cdns_ddr_set_port_rw_priority(void *base, int port, | |
184 | u8 read_pri, u8 write_pri) | |
185 | { | |
186 | u8 *reg8 = (u8 *)base + DDR_RW_PRIORITY_REGS; | |
187 | ||
188 | reg8 += (port * 3); | |
189 | pr_debug("%s port %d (reg8=%p, DENALI_CTL_%d)\n", | |
190 | __func__, port, reg8, (reg8 - (u8 *)base) / 4); | |
191 | ||
192 | ddrc_writeb(read_pri, reg8++); | |
193 | ddrc_writeb(write_pri, reg8++); | |
194 | } | |
195 | ||
196 | /* The DDR Controller has 16 entries. Each entry can specify an allowed address | |
197 | * range (with 16KB resolution) for one of the 4 AXI slave ports. | |
198 | */ | |
199 | void cdns_ddr_enable_port_addr_range(void *base, int port, int entry, | |
200 | u32 addr_start, u32 size) | |
201 | { | |
202 | u32 addr_end; | |
203 | u32 *reg32 = (u32 *)((u8 *)base + DDR_ADDR_RANGE_REGS); | |
204 | u32 tmp; | |
205 | ||
206 | reg32 += (port * DDR_NR_ENTRIES * 2); | |
207 | reg32 += (entry * 2); | |
208 | pr_debug("%s port %d, entry %d (reg32=%p, DENALI_CTL_%d)\n", | |
209 | __func__, port, entry, reg32, ((u8 *)reg32 - (u8 *)base) / 4); | |
210 | ||
211 | /* These registers represent 16KB address blocks */ | |
212 | addr_start /= SZ_16K; | |
213 | size /= SZ_16K; | |
214 | if (size) | |
215 | addr_end = addr_start + size - 1; | |
216 | else | |
217 | addr_end = addr_start; | |
218 | ||
219 | ddrc_writel(addr_start, reg32++); | |
220 | ||
221 | /* | |
222 | * end_addr: Ensure we only set the bottom 18-bits as DENALI_CTL_218 | |
223 | * also contains the AXI0 range protection bits. | |
224 | */ | |
225 | tmp = readl(reg32); | |
226 | tmp &= ~(BIT(18) - 1); | |
227 | tmp |= addr_end; | |
228 | ddrc_writel(tmp, reg32); | |
229 | } | |
230 | ||
231 | void cdns_ddr_enable_addr_range(void *base, int entry, | |
232 | u32 addr_start, u32 size) | |
233 | { | |
234 | int axi; | |
235 | ||
236 | for (axi = 0; axi < DDR_NR_AXI_PORTS; axi++) | |
237 | cdns_ddr_enable_port_addr_range(base, axi, entry, | |
238 | addr_start, size); | |
239 | } | |
240 | ||
241 | void cdns_ddr_enable_port_prot(void *base, int port, int entry, | |
242 | enum cdns_ddr_range_prot range_protection_bits, | |
243 | u16 range_RID_check_bits, | |
244 | u16 range_WID_check_bits, | |
245 | u8 range_RID_check_bits_ID_lookup, | |
246 | u8 range_WID_check_bits_ID_lookup) | |
247 | { | |
248 | /* | |
249 | * Technically, the offset here points to the byte before the start of | |
250 | * the range protection registers. However, all entries consist of 8 | |
251 | * bytes, except the first one (which is missing a padding byte) so we | |
252 | * work around that subtlely. | |
253 | */ | |
254 | u8 *reg8 = (u8 *)base + DDR_RANGE_PROT_REGS; | |
255 | ||
256 | reg8 += (port * DDR_NR_ENTRIES * 8); | |
257 | reg8 += (entry * 8); | |
258 | pr_debug("%s port %d, entry %d (reg8=%p, DENALI_CTL_%d)\n", | |
259 | __func__, port, entry, reg8, (reg8 - (u8 *)base) / 4); | |
260 | ||
261 | if (port == 0 && entry == 0) | |
262 | ddrc_writeb(range_protection_bits, reg8 + 1); | |
263 | else | |
264 | ddrc_writeb(range_protection_bits, reg8); | |
265 | ||
266 | ddrc_writew(range_RID_check_bits, reg8 + 2); | |
267 | ddrc_writew(range_WID_check_bits, reg8 + 4); | |
268 | ddrc_writeb(range_RID_check_bits_ID_lookup, reg8 + 6); | |
269 | ddrc_writeb(range_WID_check_bits_ID_lookup, reg8 + 7); | |
270 | } | |
271 | ||
272 | void cdns_ddr_enable_prot(void *base, int entry, | |
273 | enum cdns_ddr_range_prot range_protection_bits, | |
274 | u16 range_RID_check_bits, | |
275 | u16 range_WID_check_bits, | |
276 | u8 range_RID_check_bits_ID_lookup, | |
277 | u8 range_WID_check_bits_ID_lookup) | |
278 | { | |
279 | int axi; | |
280 | ||
281 | for (axi = 0; axi < DDR_NR_AXI_PORTS; axi++) | |
282 | cdns_ddr_enable_port_prot(base, axi, entry, | |
283 | range_protection_bits, | |
284 | range_RID_check_bits, | |
285 | range_WID_check_bits, | |
286 | range_RID_check_bits_ID_lookup, | |
287 | range_WID_check_bits_ID_lookup); | |
288 | } | |
289 | ||
290 | void cdns_ddr_set_port_bandwidth(void *base, int port, | |
291 | u8 max_percent, u8 overflow_ok) | |
292 | { | |
293 | u8 *reg8 = (u8 *)base + DDR_AXI_PORT_BANDWIDTH_REG; | |
294 | ||
295 | reg8 += (port * 3); | |
296 | pr_debug("%s port %d, (reg8=%p, DENALI_CTL_%d)\n", | |
297 | __func__, port, reg8, (reg8 - (u8 *)base) / 4); | |
298 | ||
299 | ddrc_writeb(max_percent, reg8++); /* Maximum bandwidth percentage */ | |
300 | ddrc_writeb(overflow_ok, reg8++); /* Bandwidth overflow allowed */ | |
301 | } | |
302 | ||
303 | void cdns_ddr_ctrl_init(void *ddr_ctrl_basex, int async, | |
304 | const u32 *reg0, const u32 *reg350, | |
305 | u32 ddr_start_addr, u32 ddr_size, | |
306 | int enable_ecc, int enable_8bit) | |
307 | { | |
308 | int i, axi, entry; | |
309 | u32 *ddr_ctrl_base = (u32 *)ddr_ctrl_basex; | |
310 | u8 *base8 = (u8 *)ddr_ctrl_basex; | |
311 | ||
312 | ddrc_writel(*reg0, ddr_ctrl_base + 0); | |
313 | /* 1 to 6 are read only */ | |
314 | for (i = 7; i <= 26; i++) | |
315 | ddrc_writel(*(reg0 + i), ddr_ctrl_base + i); | |
316 | /* 27 to 29 are not changed */ | |
317 | for (i = 30; i <= 87; i++) | |
318 | ddrc_writel(*(reg0 + i), ddr_ctrl_base + i); | |
319 | ||
320 | /* Enable/disable ECC */ | |
321 | if (enable_ecc) { | |
322 | pr_debug("%s enabling ECC\n", __func__); | |
323 | ddrc_writeb(1, base8 + DDR_ECC_ENABLE_REG); | |
324 | } else { | |
325 | ddrc_writeb(0, base8 + DDR_ECC_ENABLE_REG); | |
326 | } | |
327 | ||
328 | /* ECC: Disable corruption for read/modify/write operations */ | |
329 | ddrc_writeb(1, base8 + DDR_ECC_DISABLE_W_UC_ERR_REG); | |
330 | ||
331 | /* Set 8/16-bit data width using reduce bit (enable half datapath)*/ | |
332 | if (enable_8bit) { | |
333 | pr_debug("%s using 8-bit data\n", __func__); | |
334 | ddrc_writeb(1, base8 + DDR_HALF_DATAPATH_REG); | |
335 | } else { | |
336 | ddrc_writeb(0, base8 + DDR_HALF_DATAPATH_REG); | |
337 | } | |
338 | ||
339 | /* Threshold for command queue */ | |
340 | ddrc_writeb(4, base8 + DDR_ARB_CMD_Q_THRESHOLD_REG); | |
341 | ||
342 | /* AXI port protection => enable */ | |
343 | ddrc_writeb(0x01, base8 + DDR_AXI_PORT_PROT_ENABLE_REG); | |
344 | ||
345 | /* Set port interface type, default port priority and bandwidths */ | |
346 | for (axi = 0; axi < DDR_NR_AXI_PORTS; axi++) { | |
347 | /* port interface type: synchronous or asynchronous AXI clock */ | |
348 | u8 *fifo_reg = base8 + DDR_RW_FIFO_TYPE_REGS + (axi * 3); | |
349 | ||
350 | if (async) | |
351 | ddrc_writeb(0, fifo_reg); | |
352 | else | |
353 | ddrc_writeb(3, fifo_reg); | |
354 | ||
355 | /* R/W priorities */ | |
356 | cdns_ddr_set_port_rw_priority(ddr_ctrl_base, axi, 2, 2); | |
357 | ||
358 | /* AXI bandwidth */ | |
359 | cdns_ddr_set_port_bandwidth(ddr_ctrl_base, axi, 50, 1); | |
360 | } | |
361 | ||
362 | /* | |
363 | * The hardware requires that the valid address ranges must not overlap. | |
364 | * So, we initialise all address ranges to be above the DDR, length 0. | |
365 | */ | |
366 | for (entry = 0; entry < DDR_NR_ENTRIES; entry++) | |
367 | cdns_ddr_enable_addr_range(ddr_ctrl_base, entry, | |
368 | ddr_start_addr + ddr_size, 0); | |
369 | ||
370 | for (i = 350; i <= 374; i++) | |
371 | ddrc_writel(*(reg350 - 350 + i), ddr_ctrl_base + i); | |
372 | ||
373 | /* Disable optimised read-modify-write logic */ | |
374 | ddrc_writeb(0, base8 + DDR_OPT_RMODW_REG); | |
375 | ||
376 | /* | |
377 | * Disable all interrupts, we are not handling them. | |
378 | * For detail of the interrupt mask, ack and status bits, see the | |
379 | * manual's description of the 'int_status' parameter. | |
380 | */ | |
381 | ddrc_writel(0, base8 + DDR_INTERRUPT_MASK); | |
382 | ||
383 | /* | |
384 | * Default settings to enable full access to the entire DDR. | |
385 | * Users can set different ranges and access rights by calling these | |
386 | * functions before calling cdns_ddr_ctrl_start(). | |
387 | */ | |
388 | cdns_ddr_enable_addr_range(ddr_ctrl_base, 0, | |
389 | ddr_start_addr, ddr_size); | |
390 | cdns_ddr_enable_prot(ddr_ctrl_base, 0, CDNS_DDR_RANGE_PROT_BITS_FULL, | |
391 | 0xffff, 0xffff, 0x0f, 0x0f); | |
392 | } | |
393 | ||
394 | void cdns_ddr_ctrl_start(void *ddr_ctrl_basex) | |
395 | { | |
396 | u32 *ddr_ctrl_base = (u32 *)ddr_ctrl_basex; | |
397 | u8 *base8 = (u8 *)ddr_ctrl_basex; | |
398 | ||
399 | /* Start */ | |
400 | ddrc_writeb(1, base8 + DDR_START_REG); | |
401 | ||
402 | /* Wait for controller to be ready (interrupt status) */ | |
403 | wait_for_bit_le32(base8 + DDR_INTERRUPT_STATUS, 0x100, true, 1000, false); | |
404 | ||
405 | /* clear all interrupts */ | |
406 | ddrc_writel(~0, base8 + DDR_INTERRUPT_ACK); | |
407 | ||
408 | /* Step 19 Wait 500us from MRESETB=1 */ | |
409 | udelay(500); | |
410 | ||
411 | /* Step 20 tCKSRX wait (From supply stable clock for MCK) */ | |
412 | /* DENALI_CTL_19 TREF_ENABLE=0x1(=1), AREFRESH=0x1(=1) */ | |
413 | ddrc_writel(0x01000100, ddr_ctrl_base + 19); | |
414 | } |