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