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