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