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