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#include <linux/printk.h>
20
21#include <asm/io.h>
22#include <linux/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
57struct 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
68static struct s3c_onenand *onenand;
69
70static int s3c_read_cmd(unsigned int cmd)
71{
72	return readl(onenand->ahb_addr + cmd);
73}
74
75static 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)
91static unsigned int s3c_mem_addr(int fba, int fpa, int fsa)
92{
93	return (fba << 13) | (fpa << 7) | (fsa << 5);
94}
95#endif
96
97static 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
117static 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
166static 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
210static 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
271static 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
375static 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
394static 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
405static 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
416static 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
448static 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
465static 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
487static 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
519int s5pc110_chip_probe(struct mtd_info *mtd)
520{
521	return 0;
522}
523
524int s5pc210_chip_probe(struct mtd_info *mtd)
525{
526	return 0;
527}
528
529void 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}
570