blob: df04c2bb481b4e4bc0dc841100d3e7b3a1c0be64 [file] [log] [blame]
Minkyu Kang4678d672009-10-01 17:20:08 +09001/*
Benoît Thébaudeaue5323222013-04-11 09:36:00 +00002 * S5PC100 OneNAND driver at U-Boot
Minkyu Kang4678d672009-10-01 17:20:08 +09003 *
4 * Copyright (C) 2008-2009 Samsung Electronics
5 * Kyungmin Park <kyungmin.park@samsung.com>
6 *
7 * Implementation:
8 * Emulate the pseudo BufferRAM
9 *
Wolfgang Denk1a459662013-07-08 09:37:19 +020010 * SPDX-License-Identifier: GPL-2.0+
Minkyu Kang4678d672009-10-01 17:20:08 +090011 */
12
13#include <common.h>
14#include <malloc.h>
Mike Frysinger7b15e2b2012-04-09 13:39:55 +000015#include <linux/compat.h>
Minkyu Kang4678d672009-10-01 17:20:08 +090016#include <linux/mtd/mtd.h>
17#include <linux/mtd/onenand.h>
18#include <linux/mtd/samsung_onenand.h>
19
20#include <asm/io.h>
21#include <asm/errno.h>
22
23#ifdef ONENAND_DEBUG
24#define DPRINTK(format, args...) \
25do { \
26 printf("%s[%d]: " format "\n", __func__, __LINE__, ##args); \
27} while (0)
28#else
29#define DPRINTK(...) do { } while (0)
30#endif
31
32#define ONENAND_ERASE_STATUS 0x00
33#define ONENAND_MULTI_ERASE_SET 0x01
34#define ONENAND_ERASE_START 0x03
35#define ONENAND_UNLOCK_START 0x08
36#define ONENAND_UNLOCK_END 0x09
37#define ONENAND_LOCK_START 0x0A
38#define ONENAND_LOCK_END 0x0B
39#define ONENAND_LOCK_TIGHT_START 0x0C
40#define ONENAND_LOCK_TIGHT_END 0x0D
41#define ONENAND_UNLOCK_ALL 0x0E
42#define ONENAND_OTP_ACCESS 0x12
43#define ONENAND_SPARE_ACCESS_ONLY 0x13
44#define ONENAND_MAIN_ACCESS_ONLY 0x14
45#define ONENAND_ERASE_VERIFY 0x15
46#define ONENAND_MAIN_SPARE_ACCESS 0x16
47#define ONENAND_PIPELINE_READ 0x4000
48
Benoît Thébaudeaue5323222013-04-11 09:36:00 +000049#if defined(CONFIG_S5P)
Minkyu Kang4678d672009-10-01 17:20:08 +090050#define MAP_00 (0x0 << 26)
51#define MAP_01 (0x1 << 26)
52#define MAP_10 (0x2 << 26)
53#define MAP_11 (0x3 << 26)
54#endif
55
56/* read/write of XIP buffer */
57#define CMD_MAP_00(mem_addr) (MAP_00 | ((mem_addr) << 1))
58/* read/write to the memory device */
59#define CMD_MAP_01(mem_addr) (MAP_01 | (mem_addr))
60/* control special functions of the memory device */
61#define CMD_MAP_10(mem_addr) (MAP_10 | (mem_addr))
62/* direct interface(direct access) with the memory device */
63#define CMD_MAP_11(mem_addr) (MAP_11 | ((mem_addr) << 2))
64
65struct s3c_onenand {
66 struct mtd_info *mtd;
67 void __iomem *base;
68 void __iomem *ahb_addr;
69 int bootram_command;
70 void __iomem *page_buf;
71 void __iomem *oob_buf;
72 unsigned int (*mem_addr)(int fba, int fpa, int fsa);
73 struct samsung_onenand *reg;
74};
75
76static struct s3c_onenand *onenand;
77
78static int s3c_read_cmd(unsigned int cmd)
79{
80 return readl(onenand->ahb_addr + cmd);
81}
82
83static void s3c_write_cmd(int value, unsigned int cmd)
84{
85 writel(value, onenand->ahb_addr + cmd);
86}
87
88/*
89 * MEM_ADDR
90 *
91 * fba: flash block address
92 * fpa: flash page address
93 * fsa: flash sector address
94 *
95 * return the buffer address on the memory device
96 * It will be combined with CMD_MAP_XX
97 */
Benoît Thébaudeaue5323222013-04-11 09:36:00 +000098#if defined(CONFIG_S5P)
Minkyu Kang4678d672009-10-01 17:20:08 +090099static unsigned int s3c_mem_addr(int fba, int fpa, int fsa)
100{
101 return (fba << 13) | (fpa << 7) | (fsa << 5);
102}
103#endif
104
105static void s3c_onenand_reset(void)
106{
107 unsigned long timeout = 0x10000;
108 int stat;
109
110 writel(ONENAND_MEM_RESET_COLD, &onenand->reg->mem_reset);
111 while (timeout--) {
112 stat = readl(&onenand->reg->int_err_stat);
113 if (stat & RST_CMP)
114 break;
115 }
116 stat = readl(&onenand->reg->int_err_stat);
117 writel(stat, &onenand->reg->int_err_ack);
118
119 /* Clear interrupt */
120 writel(0x0, &onenand->reg->int_err_ack);
121 /* Clear the ECC status */
122 writel(0x0, &onenand->reg->ecc_err_stat);
123}
124
125static unsigned short s3c_onenand_readw(void __iomem *addr)
126{
127 struct onenand_chip *this = onenand->mtd->priv;
128 int reg = addr - this->base;
129 int word_addr = reg >> 1;
130 int value;
131
132 /* It's used for probing time */
133 switch (reg) {
134 case ONENAND_REG_MANUFACTURER_ID:
135 return readl(&onenand->reg->manufact_id);
136 case ONENAND_REG_DEVICE_ID:
137 return readl(&onenand->reg->device_id);
138 case ONENAND_REG_VERSION_ID:
139 return readl(&onenand->reg->flash_ver_id);
140 case ONENAND_REG_DATA_BUFFER_SIZE:
141 return readl(&onenand->reg->data_buf_size);
142 case ONENAND_REG_TECHNOLOGY:
143 return readl(&onenand->reg->tech);
144 case ONENAND_REG_SYS_CFG1:
145 return readl(&onenand->reg->mem_cfg);
146
147 /* Used at unlock all status */
148 case ONENAND_REG_CTRL_STATUS:
149 return 0;
150
151 case ONENAND_REG_WP_STATUS:
152 return ONENAND_WP_US;
153
154 default:
155 break;
156 }
157
158 /* BootRAM access control */
159 if (reg < ONENAND_DATARAM && onenand->bootram_command) {
160 if (word_addr == 0)
161 return readl(&onenand->reg->manufact_id);
162 if (word_addr == 1)
163 return readl(&onenand->reg->device_id);
164 if (word_addr == 2)
165 return readl(&onenand->reg->flash_ver_id);
166 }
167
168 value = s3c_read_cmd(CMD_MAP_11(word_addr)) & 0xffff;
169 printk(KERN_INFO "s3c_onenand_readw: Illegal access"
170 " at reg 0x%x, value 0x%x\n", word_addr, value);
171 return value;
172}
173
174static void s3c_onenand_writew(unsigned short value, void __iomem *addr)
175{
176 struct onenand_chip *this = onenand->mtd->priv;
177 int reg = addr - this->base;
178 int word_addr = reg >> 1;
179
180 /* It's used for probing time */
181 switch (reg) {
182 case ONENAND_REG_SYS_CFG1:
183 writel(value, &onenand->reg->mem_cfg);
184 return;
185
186 case ONENAND_REG_START_ADDRESS1:
187 case ONENAND_REG_START_ADDRESS2:
188 return;
189
190 /* Lock/lock-tight/unlock/unlock_all */
191 case ONENAND_REG_START_BLOCK_ADDRESS:
192 return;
193
194 default:
195 break;
196 }
197
198 /* BootRAM access control */
199 if (reg < ONENAND_DATARAM) {
200 if (value == ONENAND_CMD_READID) {
201 onenand->bootram_command = 1;
202 return;
203 }
204 if (value == ONENAND_CMD_RESET) {
205 writel(ONENAND_MEM_RESET_COLD,
206 &onenand->reg->mem_reset);
207 onenand->bootram_command = 0;
208 return;
209 }
210 }
211
212 printk(KERN_INFO "s3c_onenand_writew: Illegal access"
213 " at reg 0x%x, value 0x%x\n", word_addr, value);
214
215 s3c_write_cmd(value, CMD_MAP_11(word_addr));
216}
217
218static int s3c_onenand_wait(struct mtd_info *mtd, int state)
219{
220 unsigned int flags = INT_ACT;
221 unsigned int stat, ecc;
222 unsigned long timeout = 0x100000;
223
224 switch (state) {
225 case FL_READING:
226 flags |= BLK_RW_CMP | LOAD_CMP;
227 break;
228 case FL_WRITING:
229 flags |= BLK_RW_CMP | PGM_CMP;
230 break;
231 case FL_ERASING:
232 flags |= BLK_RW_CMP | ERS_CMP;
233 break;
234 case FL_LOCKING:
235 flags |= BLK_RW_CMP;
236 break;
237 default:
238 break;
239 }
240
241 while (timeout--) {
242 stat = readl(&onenand->reg->int_err_stat);
243 if (stat & flags)
244 break;
245 }
246
247 /* To get correct interrupt status in timeout case */
248 stat = readl(&onenand->reg->int_err_stat);
249 writel(stat, &onenand->reg->int_err_ack);
250
251 /*
252 * In the Spec. it checks the controller status first
253 * However if you get the correct information in case of
254 * power off recovery (POR) test, it should read ECC status first
255 */
256 if (stat & LOAD_CMP) {
257 ecc = readl(&onenand->reg->ecc_err_stat);
258 if (ecc & ONENAND_ECC_4BIT_UNCORRECTABLE) {
259 printk(KERN_INFO "%s: ECC error = 0x%04x\n",
260 __func__, ecc);
261 mtd->ecc_stats.failed++;
262 return -EBADMSG;
263 }
264 }
265
266 if (stat & (LOCKED_BLK | ERS_FAIL | PGM_FAIL | LD_FAIL_ECC_ERR)) {
267 printk(KERN_INFO "%s: controller error = 0x%04x\n",
268 __func__, stat);
269 if (stat & LOCKED_BLK)
270 printk(KERN_INFO "%s: it's locked error = 0x%04x\n",
271 __func__, stat);
272
273 return -EIO;
274 }
275
276 return 0;
277}
278
279static int s3c_onenand_command(struct mtd_info *mtd, int cmd,
280 loff_t addr, size_t len)
281{
282 struct onenand_chip *this = mtd->priv;
283 unsigned int *m, *s;
284 int fba, fpa, fsa = 0;
285 unsigned int mem_addr;
286 int i, mcount, scount;
287 int index;
288
289 fba = (int) (addr >> this->erase_shift);
290 fpa = (int) (addr >> this->page_shift);
291 fpa &= this->page_mask;
292
293 mem_addr = onenand->mem_addr(fba, fpa, fsa);
294
295 switch (cmd) {
296 case ONENAND_CMD_READ:
297 case ONENAND_CMD_READOOB:
298 case ONENAND_CMD_BUFFERRAM:
299 ONENAND_SET_NEXT_BUFFERRAM(this);
300 default:
301 break;
302 }
303
304 index = ONENAND_CURRENT_BUFFERRAM(this);
305
306 /*
307 * Emulate Two BufferRAMs and access with 4 bytes pointer
308 */
309 m = (unsigned int *) onenand->page_buf;
310 s = (unsigned int *) onenand->oob_buf;
311
312 if (index) {
313 m += (this->writesize >> 2);
314 s += (mtd->oobsize >> 2);
315 }
316
317 mcount = mtd->writesize >> 2;
318 scount = mtd->oobsize >> 2;
319
320 switch (cmd) {
321 case ONENAND_CMD_READ:
322 /* Main */
323 for (i = 0; i < mcount; i++)
324 *m++ = s3c_read_cmd(CMD_MAP_01(mem_addr));
325 return 0;
326
327 case ONENAND_CMD_READOOB:
328 writel(TSRF, &onenand->reg->trans_spare);
329 /* Main */
330 for (i = 0; i < mcount; i++)
331 *m++ = s3c_read_cmd(CMD_MAP_01(mem_addr));
332
333 /* Spare */
334 for (i = 0; i < scount; i++)
335 *s++ = s3c_read_cmd(CMD_MAP_01(mem_addr));
336
337 writel(0, &onenand->reg->trans_spare);
338 return 0;
339
340 case ONENAND_CMD_PROG:
341 /* Main */
342 for (i = 0; i < mcount; i++)
343 s3c_write_cmd(*m++, CMD_MAP_01(mem_addr));
344 return 0;
345
346 case ONENAND_CMD_PROGOOB:
347 writel(TSRF, &onenand->reg->trans_spare);
348
349 /* Main - dummy write */
350 for (i = 0; i < mcount; i++)
351 s3c_write_cmd(0xffffffff, CMD_MAP_01(mem_addr));
352
353 /* Spare */
354 for (i = 0; i < scount; i++)
355 s3c_write_cmd(*s++, CMD_MAP_01(mem_addr));
356
357 writel(0, &onenand->reg->trans_spare);
358 return 0;
359
360 case ONENAND_CMD_UNLOCK_ALL:
361 s3c_write_cmd(ONENAND_UNLOCK_ALL, CMD_MAP_10(mem_addr));
362 return 0;
363
364 case ONENAND_CMD_ERASE:
365 s3c_write_cmd(ONENAND_ERASE_START, CMD_MAP_10(mem_addr));
366 return 0;
367
368 case ONENAND_CMD_MULTIBLOCK_ERASE:
369 s3c_write_cmd(ONENAND_MULTI_ERASE_SET, CMD_MAP_10(mem_addr));
370 return 0;
371
372 case ONENAND_CMD_ERASE_VERIFY:
373 s3c_write_cmd(ONENAND_ERASE_VERIFY, CMD_MAP_10(mem_addr));
374 return 0;
375
376 default:
377 break;
378 }
379
380 return 0;
381}
382
383static unsigned char *s3c_get_bufferram(struct mtd_info *mtd, int area)
384{
385 struct onenand_chip *this = mtd->priv;
386 int index = ONENAND_CURRENT_BUFFERRAM(this);
387 unsigned char *p;
388
389 if (area == ONENAND_DATARAM) {
390 p = (unsigned char *) onenand->page_buf;
391 if (index == 1)
392 p += this->writesize;
393 } else {
394 p = (unsigned char *) onenand->oob_buf;
395 if (index == 1)
396 p += mtd->oobsize;
397 }
398
399 return p;
400}
401
402static int onenand_read_bufferram(struct mtd_info *mtd, loff_t addr, int area,
403 unsigned char *buffer, int offset,
404 size_t count)
405{
406 unsigned char *p;
407
408 p = s3c_get_bufferram(mtd, area);
409 memcpy(buffer, p + offset, count);
410 return 0;
411}
412
413static int onenand_write_bufferram(struct mtd_info *mtd, loff_t addr, int area,
414 const unsigned char *buffer, int offset,
415 size_t count)
416{
417 unsigned char *p;
418
419 p = s3c_get_bufferram(mtd, area);
420 memcpy(p + offset, buffer, count);
421 return 0;
422}
423
424static int s3c_onenand_bbt_wait(struct mtd_info *mtd, int state)
425{
426 struct samsung_onenand *reg = (struct samsung_onenand *)onenand->base;
427 unsigned int flags = INT_ACT | LOAD_CMP;
428 unsigned int stat;
429 unsigned long timeout = 0x10000;
430
431 while (timeout--) {
432 stat = readl(&reg->int_err_stat);
433 if (stat & flags)
434 break;
435 }
436 /* To get correct interrupt status in timeout case */
437 stat = readl(&onenand->reg->int_err_stat);
438 writel(stat, &onenand->reg->int_err_ack);
439
440 if (stat & LD_FAIL_ECC_ERR) {
441 s3c_onenand_reset();
442 return ONENAND_BBT_READ_ERROR;
443 }
444
445 if (stat & LOAD_CMP) {
446 int ecc = readl(&onenand->reg->ecc_err_stat);
447 if (ecc & ONENAND_ECC_4BIT_UNCORRECTABLE) {
448 s3c_onenand_reset();
449 return ONENAND_BBT_READ_ERROR;
450 }
451 }
452
453 return 0;
454}
455
456static void s3c_onenand_check_lock_status(struct mtd_info *mtd)
457{
458 struct onenand_chip *this = mtd->priv;
459 unsigned int block, end;
Minkyu Kang4678d672009-10-01 17:20:08 +0900460
461 end = this->chipsize >> this->erase_shift;
462
463 for (block = 0; block < end; block++) {
Anatolij Gustschin67fad9f2011-11-19 13:12:10 +0000464 s3c_read_cmd(CMD_MAP_01(onenand->mem_addr(block, 0, 0)));
Minkyu Kang4678d672009-10-01 17:20:08 +0900465
466 if (readl(&onenand->reg->int_err_stat) & LOCKED_BLK) {
467 printf("block %d is write-protected!\n", block);
468 writel(LOCKED_BLK, &onenand->reg->int_err_ack);
469 }
470 }
471}
472
473static void s3c_onenand_do_lock_cmd(struct mtd_info *mtd, loff_t ofs,
474 size_t len, int cmd)
475{
476 struct onenand_chip *this = mtd->priv;
477 int start, end, start_mem_addr, end_mem_addr;
478
479 start = ofs >> this->erase_shift;
480 start_mem_addr = onenand->mem_addr(start, 0, 0);
481 end = start + (len >> this->erase_shift) - 1;
482 end_mem_addr = onenand->mem_addr(end, 0, 0);
483
484 if (cmd == ONENAND_CMD_LOCK) {
485 s3c_write_cmd(ONENAND_LOCK_START, CMD_MAP_10(start_mem_addr));
486 s3c_write_cmd(ONENAND_LOCK_END, CMD_MAP_10(end_mem_addr));
487 } else {
488 s3c_write_cmd(ONENAND_UNLOCK_START, CMD_MAP_10(start_mem_addr));
489 s3c_write_cmd(ONENAND_UNLOCK_END, CMD_MAP_10(end_mem_addr));
490 }
491
492 this->wait(mtd, FL_LOCKING);
493}
494
495static void s3c_onenand_unlock_all(struct mtd_info *mtd)
496{
497 struct onenand_chip *this = mtd->priv;
498 loff_t ofs = 0;
499 size_t len = this->chipsize;
500
501 /* FIXME workaround */
502 this->subpagesize = mtd->writesize;
503 mtd->subpage_sft = 0;
504
505 if (this->options & ONENAND_HAS_UNLOCK_ALL) {
506 /* Write unlock command */
507 this->command(mtd, ONENAND_CMD_UNLOCK_ALL, 0, 0);
508
509 /* No need to check return value */
510 this->wait(mtd, FL_LOCKING);
511
512 /* Workaround for all block unlock in DDP */
513 if (!ONENAND_IS_DDP(this)) {
514 s3c_onenand_check_lock_status(mtd);
515 return;
516 }
517
518 /* All blocks on another chip */
519 ofs = this->chipsize >> 1;
520 len = this->chipsize >> 1;
521 }
522
523 s3c_onenand_do_lock_cmd(mtd, ofs, len, ONENAND_CMD_UNLOCK);
524 s3c_onenand_check_lock_status(mtd);
525}
526
Lukasz Majewski6b3967b2011-11-09 11:25:32 +0100527int s5pc110_chip_probe(struct mtd_info *mtd)
528{
529 return 0;
530}
531
532int s5pc210_chip_probe(struct mtd_info *mtd)
533{
534 return 0;
535}
536
Minkyu Kang4678d672009-10-01 17:20:08 +0900537void s3c_onenand_init(struct mtd_info *mtd)
538{
539 struct onenand_chip *this = mtd->priv;
540 u32 size = (4 << 10); /* 4 KiB */
541
542 onenand = malloc(sizeof(struct s3c_onenand));
543 if (!onenand)
544 return;
545
546 onenand->page_buf = malloc(size * sizeof(char));
547 if (!onenand->page_buf)
548 return;
549 memset(onenand->page_buf, 0xff, size);
550
551 onenand->oob_buf = malloc(128 * sizeof(char));
552 if (!onenand->oob_buf)
553 return;
554 memset(onenand->oob_buf, 0xff, 128);
555
556 onenand->mtd = mtd;
557
Benoît Thébaudeaue5323222013-04-11 09:36:00 +0000558#if defined(CONFIG_S5P)
Minkyu Kang4678d672009-10-01 17:20:08 +0900559 onenand->base = (void *)0xE7100000;
560 onenand->ahb_addr = (void *)0xB0000000;
561#endif
562 onenand->mem_addr = s3c_mem_addr;
563 onenand->reg = (struct samsung_onenand *)onenand->base;
564
565 this->read_word = s3c_onenand_readw;
566 this->write_word = s3c_onenand_writew;
567
568 this->wait = s3c_onenand_wait;
569 this->bbt_wait = s3c_onenand_bbt_wait;
570 this->unlock_all = s3c_onenand_unlock_all;
571 this->command = s3c_onenand_command;
572
573 this->read_bufferram = onenand_read_bufferram;
574 this->write_bufferram = onenand_write_bufferram;
575
576 this->options |= ONENAND_RUNTIME_BADBLOCK_CHECK;
577}