]> git.kernelconcepts.de Git - karo-tx-uboot.git/blob - drivers/mtd/onenand/samsung.c
s5pc1xx: support onenand driver
[karo-tx-uboot.git] / drivers / mtd / onenand / samsung.c
1 /*
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...)                                        \
41 do {                                                                    \
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
86 struct 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
97 static struct s3c_onenand *onenand;
98
99 static int s3c_read_cmd(unsigned int cmd)
100 {
101         return readl(onenand->ahb_addr + cmd);
102 }
103
104 static 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)
120 static 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)
125 static unsigned int s3c_mem_addr(int fba, int fpa, int fsa)
126 {
127         return (fba << 13) | (fpa << 7) | (fsa << 5);
128 }
129 #endif
130
131 static 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
151 static 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
200 static 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
244 static 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
305 static 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
409 static 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
428 static 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
439 static 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
450 static 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
482 static 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
500 static 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
522 static 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
555 static 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
593 void 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 }