blob: 3df106c9b79ad76055cb67fefa601d67767c9878 [file] [log] [blame]
Giulio Benetticd647fc2020-01-10 15:51:44 +01001// SPDX-License-Identifier: GPL-2.0+
2/*
3 * Copyright (C) 2019
4 * Author(s): Giulio Benetti <giulio.benetti@benettiengineering.com>
5 */
6
Giulio Benetticd647fc2020-01-10 15:51:44 +01007#include <clk.h>
8#include <dm.h>
Sean Anderson8d4c5962020-10-04 21:39:48 -04009#include <dm/device_compat.h>
Simon Glass691d7192020-05-10 11:40:02 -060010#include <init.h>
Simon Glassf7ae49f2020-05-10 11:40:05 -060011#include <log.h>
Giulio Benetticd647fc2020-01-10 15:51:44 +010012#include <ram.h>
13#include <asm/io.h>
Simon Glasscd93d622020-05-10 11:40:13 -060014#include <linux/bitops.h>
Simon Glassc05ed002020-05-10 11:40:11 -060015#include <linux/delay.h>
Simon Glassf2176512020-02-03 07:36:17 -070016#include <linux/err.h>
Simon Glass1e94b462023-09-14 18:21:46 -060017#include <linux/printk.h>
Giulio Benetticd647fc2020-01-10 15:51:44 +010018
19/* SDRAM Command Code */
20#define SD_CC_ARD 0x0 /* Master Bus (AXI) command - Read */
21#define SD_CC_AWR 0x1 /* Master Bus (AXI) command - Write */
22#define SD_CC_IRD 0x8 /* IP command - Read */
23#define SD_CC_IWR 0x9 /* IP command - Write */
24#define SD_CC_IMS 0xA /* IP command - Set Mode Register */
25#define SD_CC_IACT 0xB /* IP command - ACTIVE */
26#define SD_CC_IAF 0xC /* IP command - Auto Refresh */
27#define SD_CC_ISF 0xD /* IP Command - Self Refresh */
28#define SD_CC_IPRE 0xE /* IP command - Precharge */
29#define SD_CC_IPREA 0xF /* IP command - Precharge ALL */
30
31#define SEMC_MCR_MDIS BIT(1)
32#define SEMC_MCR_DQSMD BIT(2)
33
34#define SEMC_INTR_IPCMDERR BIT(1)
35#define SEMC_INTR_IPCMDDONE BIT(0)
36
37#define SEMC_IPCMD_KEY 0xA55A0000
38
39struct imxrt_semc_regs {
40 /* 0x0 */
41 u32 mcr;
42 u32 iocr;
43 u32 bmcr0;
44 u32 bmcr1;
45 u32 br[9];
46
47 /* 0x34 */
48 u32 res1;
49 u32 inten;
50 u32 intr;
51 /* 0x40 */
52 u32 sdramcr0;
53 u32 sdramcr1;
54 u32 sdramcr2;
55 u32 sdramcr3;
56 /* 0x50 */
57 u32 nandcr0;
58 u32 nandcr1;
59 u32 nandcr2;
60 u32 nandcr3;
61 /* 0x60 */
62 u32 norcr0;
63 u32 norcr1;
64 u32 norcr2;
65 u32 norcr3;
66 /* 0x70 */
67 u32 sramcr0;
68 u32 sramcr1;
69 u32 sramcr2;
70 u32 sramcr3;
71 /* 0x80 */
72 u32 dbicr0;
73 u32 dbicr1;
74 u32 res2[2];
75 /* 0x90 */
76 u32 ipcr0;
77 u32 ipcr1;
78 u32 ipcr2;
79 u32 ipcmd;
80 /* 0xA0 */
81 u32 iptxdat;
82 u32 res3[3];
83 /* 0xB0 */
84 u32 iprxdat;
85 u32 res4[3];
86 /* 0xC0 */
87 u32 sts[16];
88};
89
Jesse Taube7d9c6f12022-07-26 01:43:44 -040090#if !defined(TARGET_IMXRT1170_EVK)
Giulio Benetticd647fc2020-01-10 15:51:44 +010091#define SEMC_IOCR_MUX_A8_SHIFT 0
92#define SEMC_IOCR_MUX_CSX0_SHIFT 3
93#define SEMC_IOCR_MUX_CSX1_SHIFT 6
94#define SEMC_IOCR_MUX_CSX2_SHIFT 9
95#define SEMC_IOCR_MUX_CSX3_SHIFT 12
96#define SEMC_IOCR_MUX_RDY_SHIFT 15
Jesse Taube7d9c6f12022-07-26 01:43:44 -040097#else
98#define SEMC_IOCR_MUX_A8_SHIFT 0
99#define SEMC_IOCR_MUX_CSX0_SHIFT 4
100#define SEMC_IOCR_MUX_CSX1_SHIFT 8
101#define SEMC_IOCR_MUX_CSX2_SHIFT 12
102#define SEMC_IOCR_MUX_CSX3_SHIFT 16
103#define SEMC_IOCR_MUX_RDY_SHIFT 20
104#endif
Giulio Benetticd647fc2020-01-10 15:51:44 +0100105
106struct imxrt_sdram_mux {
107 u8 a8;
108 u8 csx0;
109 u8 csx1;
110 u8 csx2;
111 u8 csx3;
112 u8 rdy;
113};
114
115#define SEMC_SDRAMCR0_PS_SHIFT 0
116#define SEMC_SDRAMCR0_BL_SHIFT 4
117#define SEMC_SDRAMCR0_COL_SHIFT 8
118#define SEMC_SDRAMCR0_CL_SHIFT 10
119
120struct imxrt_sdram_control {
121 u8 memory_width;
122 u8 burst_len;
123 u8 no_columns;
124 u8 cas_latency;
125};
126
127#define SEMC_SDRAMCR1_PRE2ACT_SHIFT 0
128#define SEMC_SDRAMCR1_ACT2RW_SHIFT 4
129#define SEMC_SDRAMCR1_RFRC_SHIFT 8
130#define SEMC_SDRAMCR1_WRC_SHIFT 13
131#define SEMC_SDRAMCR1_CKEOFF_SHIFT 16
132#define SEMC_SDRAMCR1_ACT2PRE_SHIFT 20
133
134#define SEMC_SDRAMCR2_SRRC_SHIFT 0
135#define SEMC_SDRAMCR2_REF2REF_SHIFT 8
136#define SEMC_SDRAMCR2_ACT2ACT_SHIFT 16
137#define SEMC_SDRAMCR2_ITO_SHIFT 24
138
139#define SEMC_SDRAMCR3_REN BIT(0)
140#define SEMC_SDRAMCR3_REBL_SHIFT 1
141#define SEMC_SDRAMCR3_PRESCALE_SHIFT 8
142#define SEMC_SDRAMCR3_RT_SHIFT 16
143#define SEMC_SDRAMCR3_UT_SHIFT 24
144
145struct imxrt_sdram_timing {
146 u8 pre2act;
147 u8 act2rw;
148 u8 rfrc;
149 u8 wrc;
150 u8 ckeoff;
151 u8 act2pre;
152
153 u8 srrc;
154 u8 ref2ref;
155 u8 act2act;
156 u8 ito;
157
158 u8 rebl;
159 u8 prescale;
160 u8 rt;
161 u8 ut;
162};
163
164enum imxrt_semc_bank {
165 SDRAM_BANK1,
166 SDRAM_BANK2,
167 SDRAM_BANK3,
168 SDRAM_BANK4,
169 MAX_SDRAM_BANK,
170};
171
172#define SEMC_BR_VLD_MASK 1
173#define SEMC_BR_MS_SHIFT 1
174
175struct bank_params {
176 enum imxrt_semc_bank target_bank;
177 u32 base_address;
178 u32 memory_size;
179};
180
181struct imxrt_sdram_params {
182 struct imxrt_semc_regs *base;
183
184 struct imxrt_sdram_mux *sdram_mux;
185 struct imxrt_sdram_control *sdram_control;
186 struct imxrt_sdram_timing *sdram_timing;
187
188 struct bank_params bank_params[MAX_SDRAM_BANK];
189 u8 no_sdram_banks;
190};
191
192static int imxrt_sdram_wait_ipcmd_done(struct imxrt_semc_regs *regs)
193{
194 do {
195 readl(&regs->intr);
196
197 if (regs->intr & SEMC_INTR_IPCMDDONE)
198 return 0;
199 if (regs->intr & SEMC_INTR_IPCMDERR)
200 return -EIO;
201
202 mdelay(50);
203 } while (1);
204}
205
206static int imxrt_sdram_ipcmd(struct imxrt_semc_regs *regs, u32 mem_addr,
207 u32 ipcmd, u32 wd, u32 *rd)
208{
209 int ret;
210
211 if (ipcmd == SD_CC_IWR || ipcmd == SD_CC_IMS)
212 writel(wd, &regs->iptxdat);
213
214 /* set slave address for every command as specified on RM */
215 writel(mem_addr, &regs->ipcr0);
216
217 /* execute command */
218 writel(SEMC_IPCMD_KEY | ipcmd, &regs->ipcmd);
219
220 ret = imxrt_sdram_wait_ipcmd_done(regs);
221 if (ret < 0)
222 return ret;
223
224 if (ipcmd == SD_CC_IRD) {
225 if (!rd)
226 return -EINVAL;
227
228 *rd = readl(&regs->iprxdat);
229 }
230
231 return 0;
232}
233
234int imxrt_sdram_init(struct udevice *dev)
235{
Simon Glassc69cda22020-12-03 16:55:20 -0700236 struct imxrt_sdram_params *params = dev_get_plat(dev);
Giulio Benetticd647fc2020-01-10 15:51:44 +0100237 struct imxrt_sdram_mux *mux = params->sdram_mux;
238 struct imxrt_sdram_control *ctrl = params->sdram_control;
239 struct imxrt_sdram_timing *time = params->sdram_timing;
240 struct imxrt_semc_regs *regs = params->base;
241 struct bank_params *bank_params;
242 u32 rd;
243 int i;
244
245 /* enable the SEMC controller */
246 clrbits_le32(&regs->mcr, SEMC_MCR_MDIS);
247 /* set DQS mode from DQS pad */
248 setbits_le32(&regs->mcr, SEMC_MCR_DQSMD);
249
250 for (i = 0, bank_params = params->bank_params;
251 i < params->no_sdram_banks; bank_params++,
252 i++)
253 writel((bank_params->base_address & 0xfffff000)
254 | bank_params->memory_size << SEMC_BR_MS_SHIFT
255 | SEMC_BR_VLD_MASK,
256 &regs->br[bank_params->target_bank]);
257
258 writel(mux->a8 << SEMC_IOCR_MUX_A8_SHIFT
259 | mux->csx0 << SEMC_IOCR_MUX_CSX0_SHIFT
260 | mux->csx1 << SEMC_IOCR_MUX_CSX1_SHIFT
261 | mux->csx2 << SEMC_IOCR_MUX_CSX2_SHIFT
262 | mux->csx3 << SEMC_IOCR_MUX_CSX3_SHIFT
263 | mux->rdy << SEMC_IOCR_MUX_RDY_SHIFT,
264 &regs->iocr);
265
266 writel(ctrl->memory_width << SEMC_SDRAMCR0_PS_SHIFT
267 | ctrl->burst_len << SEMC_SDRAMCR0_BL_SHIFT
268 | ctrl->no_columns << SEMC_SDRAMCR0_COL_SHIFT
269 | ctrl->cas_latency << SEMC_SDRAMCR0_CL_SHIFT,
270 &regs->sdramcr0);
271
272 writel(time->pre2act << SEMC_SDRAMCR1_PRE2ACT_SHIFT
273 | time->act2rw << SEMC_SDRAMCR1_ACT2RW_SHIFT
274 | time->rfrc << SEMC_SDRAMCR1_RFRC_SHIFT
275 | time->wrc << SEMC_SDRAMCR1_WRC_SHIFT
276 | time->ckeoff << SEMC_SDRAMCR1_CKEOFF_SHIFT
277 | time->act2pre << SEMC_SDRAMCR1_ACT2PRE_SHIFT,
278 &regs->sdramcr1);
279
280 writel(time->srrc << SEMC_SDRAMCR2_SRRC_SHIFT
281 | time->ref2ref << SEMC_SDRAMCR2_REF2REF_SHIFT
282 | time->act2act << SEMC_SDRAMCR2_ACT2ACT_SHIFT
283 | time->ito << SEMC_SDRAMCR2_ITO_SHIFT,
284 &regs->sdramcr2);
285
286 writel(time->rebl << SEMC_SDRAMCR3_REBL_SHIFT
287 | time->prescale << SEMC_SDRAMCR3_PRESCALE_SHIFT
288 | time->rt << SEMC_SDRAMCR3_RT_SHIFT
289 | time->ut << SEMC_SDRAMCR3_UT_SHIFT
290 | SEMC_SDRAMCR3_REN,
291 &regs->sdramcr3);
292
293 writel(2, &regs->ipcr1);
294
295 for (i = 0, bank_params = params->bank_params;
296 i < params->no_sdram_banks; bank_params++,
297 i++) {
298 mdelay(250);
299 imxrt_sdram_ipcmd(regs, bank_params->base_address, SD_CC_IPREA,
300 0, &rd);
301 imxrt_sdram_ipcmd(regs, bank_params->base_address, SD_CC_IAF,
302 0, &rd);
303 imxrt_sdram_ipcmd(regs, bank_params->base_address, SD_CC_IAF,
304 0, &rd);
305 imxrt_sdram_ipcmd(regs, bank_params->base_address, SD_CC_IMS,
306 ctrl->burst_len | (ctrl->cas_latency << 4),
307 &rd);
308 mdelay(250);
309 }
310
311 return 0;
312}
313
Simon Glassd1998a92020-12-03 16:55:21 -0700314static int imxrt_semc_of_to_plat(struct udevice *dev)
Giulio Benetticd647fc2020-01-10 15:51:44 +0100315{
Simon Glassc69cda22020-12-03 16:55:20 -0700316 struct imxrt_sdram_params *params = dev_get_plat(dev);
Giulio Benetticd647fc2020-01-10 15:51:44 +0100317 ofnode bank_node;
318 u8 bank = 0;
319
320 params->sdram_mux =
321 (struct imxrt_sdram_mux *)
322 dev_read_u8_array_ptr(dev,
323 "fsl,sdram-mux",
324 sizeof(struct imxrt_sdram_mux));
325 if (!params->sdram_mux) {
326 pr_err("fsl,sdram-mux not found");
327 return -EINVAL;
328 }
329
330 params->sdram_control =
331 (struct imxrt_sdram_control *)
332 dev_read_u8_array_ptr(dev,
333 "fsl,sdram-control",
334 sizeof(struct imxrt_sdram_control));
335 if (!params->sdram_control) {
336 pr_err("fsl,sdram-control not found");
337 return -EINVAL;
338 }
339
340 params->sdram_timing =
341 (struct imxrt_sdram_timing *)
342 dev_read_u8_array_ptr(dev,
343 "fsl,sdram-timing",
344 sizeof(struct imxrt_sdram_timing));
345 if (!params->sdram_timing) {
346 pr_err("fsl,sdram-timing not found");
347 return -EINVAL;
348 }
349
350 dev_for_each_subnode(bank_node, dev) {
351 struct bank_params *bank_params;
352 char *bank_name;
353 int ret;
354
355 /* extract the bank index from DT */
356 bank_name = (char *)ofnode_get_name(bank_node);
357 strsep(&bank_name, "@");
358 if (!bank_name) {
359 pr_err("missing sdram bank index");
360 return -EINVAL;
361 }
362
363 bank_params = &params->bank_params[bank];
364 strict_strtoul(bank_name, 10,
365 (unsigned long *)&bank_params->target_bank);
366 if (bank_params->target_bank >= MAX_SDRAM_BANK) {
367 pr_err("Found bank %d , but only bank 0,1,2,3 are supported",
368 bank_params->target_bank);
369 return -EINVAL;
370 }
371
372 ret = ofnode_read_u32(bank_node,
373 "fsl,memory-size",
374 &bank_params->memory_size);
375 if (ret < 0) {
376 pr_err("fsl,memory-size not found");
377 return -EINVAL;
378 }
379
380 ret = ofnode_read_u32(bank_node,
381 "fsl,base-address",
382 &bank_params->base_address);
383 if (ret < 0) {
384 pr_err("fsl,base-address not found");
385 return -EINVAL;
386 }
387
388 debug("Found bank %s %u\n", bank_name,
389 bank_params->target_bank);
390 bank++;
391 }
392
393 params->no_sdram_banks = bank;
394 debug("%s, no of banks = %d\n", __func__, params->no_sdram_banks);
395
396 return 0;
397}
398
399static int imxrt_semc_probe(struct udevice *dev)
400{
Simon Glassc69cda22020-12-03 16:55:20 -0700401 struct imxrt_sdram_params *params = dev_get_plat(dev);
Giulio Benetticd647fc2020-01-10 15:51:44 +0100402 int ret;
403 fdt_addr_t addr;
404
405 addr = dev_read_addr(dev);
406 if (addr == FDT_ADDR_T_NONE)
407 return -EINVAL;
408
409 params->base = (struct imxrt_semc_regs *)addr;
410
411#ifdef CONFIG_CLK
412 struct clk clk;
413
414 ret = clk_get_by_index(dev, 0, &clk);
415 if (ret < 0)
416 return ret;
417
418 ret = clk_enable(&clk);
419
420 if (ret) {
421 dev_err(dev, "failed to enable clock\n");
422 return ret;
423 }
424#endif
425 ret = imxrt_sdram_init(dev);
426 if (ret)
427 return ret;
428
429 return 0;
430}
431
432static int imxrt_semc_get_info(struct udevice *dev, struct ram_info *info)
433{
434 return 0;
435}
436
437static struct ram_ops imxrt_semc_ops = {
438 .get_info = imxrt_semc_get_info,
439};
440
441static const struct udevice_id imxrt_semc_ids[] = {
442 { .compatible = "fsl,imxrt-semc", .data = 0 },
443 { }
444};
445
446U_BOOT_DRIVER(imxrt_semc) = {
447 .name = "imxrt_semc",
448 .id = UCLASS_RAM,
449 .of_match = imxrt_semc_ids,
450 .ops = &imxrt_semc_ops,
Simon Glassd1998a92020-12-03 16:55:21 -0700451 .of_to_plat = imxrt_semc_of_to_plat,
Giulio Benetticd647fc2020-01-10 15:51:44 +0100452 .probe = imxrt_semc_probe,
Simon Glasscaa4daa2020-12-03 16:55:18 -0700453 .plat_auto = sizeof(struct imxrt_sdram_params),
Giulio Benetticd647fc2020-01-10 15:51:44 +0100454};