All of lore.kernel.org
 help / color / mirror / Atom feed
From: Minkyu Kang <mk7.kang@samsung.com>
To: u-boot@lists.denx.de
Subject: [U-Boot] [PATCH 2/4 v3] s5pc1xx: support onenand driver
Date: Tue, 22 Sep 2009 21:35:55 +0900	[thread overview]
Message-ID: <4AB8C4AB.4020105@samsung.com> (raw)
In-Reply-To: <1f3430fb0909141940o48908950ydfcb58fabadf43b1@mail.gmail.com>

This patch includes the onenand driver for s5pc100

Signed-off-by: Minkyu Kang <mk7.kang@samsung.com>
Signed-off-by: Kyungmin Park <kyungmin.park@samsung.com>
---
Changes since v1:
- move samsung_onenand.h to include/linux/mtd/
- make C struct instead of base+offset
- Remove the "1 &&" in while loop

Changes since v2:
- drop blank lines
- adds some comments
- modify to lower case letter in C struct

 drivers/mtd/onenand/Makefile        |    1 +
 drivers/mtd/onenand/samsung.c       |  622 +++++++++++++++++++++++++++++++++++
 include/linux/mtd/onenand.h         |    1 +
 include/linux/mtd/onenand_regs.h    |    4 +
 include/linux/mtd/samsung_onenand.h |  131 ++++++++
 5 files changed, 759 insertions(+), 0 deletions(-)
 create mode 100644 drivers/mtd/onenand/samsung.c
 create mode 100644 include/linux/mtd/samsung_onenand.h

diff --git a/drivers/mtd/onenand/Makefile b/drivers/mtd/onenand/Makefile
index 1d35a57..2571df0 100644
--- a/drivers/mtd/onenand/Makefile
+++ b/drivers/mtd/onenand/Makefile
@@ -26,6 +26,7 @@ include $(TOPDIR)/config.mk
 LIB	:= $(obj)libonenand.a
 
 COBJS-$(CONFIG_CMD_ONENAND)	:= onenand_uboot.o onenand_base.o onenand_bbt.o
+COBJS-$(CONFIG_SAMSUNG_ONENAND)	+= samsung.o
 
 COBJS	:= $(COBJS-y)
 SRCS	:= $(COBJS:.o=.c)
diff --git a/drivers/mtd/onenand/samsung.c b/drivers/mtd/onenand/samsung.c
new file mode 100644
index 0000000..5433f19
--- /dev/null
+++ b/drivers/mtd/onenand/samsung.c
@@ -0,0 +1,622 @@
+/*
+ * S3C64XX/S5PC100 OneNAND driver at U-Boot
+ *
+ *  Copyright (C) 2008-2009 Samsung Electronics
+ *  Kyungmin Park <kyungmin.park@samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Implementation:
+ *	Emulate the pseudo BufferRAM
+ */
+
+#include <common.h>
+#include <malloc.h>
+#include <linux/mtd/compat.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/onenand.h>
+#include <linux/mtd/samsung_onenand.h>
+
+#include <asm/io.h>
+#include <asm/errno.h>
+
+#ifdef ONENAND_DEBUG
+#define DPRINTK(format, args...)					\
+do {									\
+	printf("%s[%d]: " format "\n", __func__, __LINE__, ##args);	\
+} while (0)
+#else
+#define DPRINTK(...)			do { } while (0)
+#endif
+
+#define ONENAND_ERASE_STATUS		0x00
+#define ONENAND_MULTI_ERASE_SET		0x01
+#define ONENAND_ERASE_START		0x03
+#define ONENAND_UNLOCK_START		0x08
+#define ONENAND_UNLOCK_END		0x09
+#define ONENAND_LOCK_START		0x0A
+#define ONENAND_LOCK_END		0x0B
+#define ONENAND_LOCK_TIGHT_START	0x0C
+#define ONENAND_LOCK_TIGHT_END		0x0D
+#define ONENAND_UNLOCK_ALL		0x0E
+#define ONENAND_OTP_ACCESS		0x12
+#define ONENAND_SPARE_ACCESS_ONLY	0x13
+#define ONENAND_MAIN_ACCESS_ONLY	0x14
+#define ONENAND_ERASE_VERIFY		0x15
+#define ONENAND_MAIN_SPARE_ACCESS	0x16
+#define ONENAND_PIPELINE_READ		0x4000
+
+#if defined(CONFIG_S3C64XX)
+#define MAP_00				(0x0 << 24)
+#define MAP_01				(0x1 << 24)
+#define MAP_10				(0x2 << 24)
+#define MAP_11				(0x3 << 24)
+#elif defined(CONFIG_S5PC1XX)
+#define MAP_00				(0x0 << 26)
+#define MAP_01				(0x1 << 26)
+#define MAP_10				(0x2 << 26)
+#define MAP_11				(0x3 << 26)
+#endif
+
+/* read/write of XIP buffer */
+#define CMD_MAP_00(mem_addr)		(MAP_00 | ((mem_addr) << 1))
+/* read/write to the memory device */
+#define CMD_MAP_01(mem_addr)		(MAP_01 | (mem_addr))
+/* control special functions of the memory device */
+#define CMD_MAP_10(mem_addr)		(MAP_10 | (mem_addr))
+/* direct interface(direct access) with the memory device */
+#define CMD_MAP_11(mem_addr)		(MAP_11 | ((mem_addr) << 2))
+
+struct s3c_onenand {
+	struct mtd_info	*mtd;
+	void __iomem	*base;
+	void __iomem	*ahb_addr;
+	int		bootram_command;
+	void __iomem	*page_buf;
+	void __iomem	*oob_buf;
+	unsigned int	(*mem_addr)(int fba, int fpa, int fsa);
+	struct samsung_onenand *reg;
+};
+
+static struct s3c_onenand *onenand;
+
+static int s3c_read_cmd(unsigned int cmd)
+{
+	return readl(onenand->ahb_addr + cmd);
+}
+
+static void s3c_write_cmd(int value, unsigned int cmd)
+{
+	writel(value, onenand->ahb_addr + cmd);
+}
+
+/*
+ * MEM_ADDR
+ *
+ * fba: flash block address
+ * fpa: flash page address
+ * fsa: flash sector address
+ *
+ * return the buffer address on the memory device
+ * It will be combined with CMD_MAP_XX
+ */
+#if defined(CONFIG_S3C64XX)
+static unsigned int s3c_mem_addr(int fba, int fpa, int fsa)
+{
+	return (fba << 12) | (fpa << 6) | (fsa << 4);
+}
+#elif defined(CONFIG_S5PC1XX)
+static unsigned int s3c_mem_addr(int fba, int fpa, int fsa)
+{
+	return (fba << 13) | (fpa << 7) | (fsa << 5);
+}
+#endif
+
+static void s3c_onenand_reset(void)
+{
+	unsigned long timeout = 0x10000;
+	int stat;
+
+	writel(ONENAND_MEM_RESET_COLD, &onenand->reg->mem_reset);
+	while (timeout--) {
+		stat = readl(&onenand->reg->int_err_stat);
+		if (stat & RST_CMP)
+			break;
+	}
+	stat = readl(&onenand->reg->int_err_stat);
+	writel(stat, &onenand->reg->int_err_ack);
+
+	/* Clear interrupt */
+	writel(0x0, &onenand->reg->int_err_ack);
+	/* Clear the ECC status */
+	writel(0x0, &onenand->reg->ecc_err_stat);
+}
+
+static unsigned short s3c_onenand_readw(void __iomem *addr)
+{
+	struct onenand_chip *this = onenand->mtd->priv;
+	int reg = addr - this->base;
+	int word_addr = reg >> 1;
+	int value;
+
+	/* It's used for probing time */
+	switch (reg) {
+	case ONENAND_REG_MANUFACTURER_ID:
+		return readl(&onenand->reg->manufact_id);
+	case ONENAND_REG_DEVICE_ID:
+		return readl(&onenand->reg->device_id);
+	case ONENAND_REG_VERSION_ID:
+		return readl(&onenand->reg->flash_ver_id);
+	case ONENAND_REG_DATA_BUFFER_SIZE:
+		return readl(&onenand->reg->data_buf_size);
+	case ONENAND_REG_TECHNOLOGY:
+		return readl(&onenand->reg->tech);
+	case ONENAND_REG_SYS_CFG1:
+		return readl(&onenand->reg->mem_cfg);
+
+	/* Used at unlock all status */
+	case ONENAND_REG_CTRL_STATUS:
+		return 0;
+
+	case ONENAND_REG_WP_STATUS:
+		return ONENAND_WP_US;
+
+	default:
+		break;
+	}
+
+	/* BootRAM access control */
+	if (reg < ONENAND_DATARAM && onenand->bootram_command) {
+		if (word_addr == 0)
+			return readl(&onenand->reg->manufact_id);
+		if (word_addr == 1)
+			return readl(&onenand->reg->device_id);
+		if (word_addr == 2)
+			return readl(&onenand->reg->flash_ver_id);
+	}
+
+	value = s3c_read_cmd(CMD_MAP_11(word_addr)) & 0xffff;
+	printk(KERN_INFO "s3c_onenand_readw:  Illegal access"
+		" at reg 0x%x, value 0x%x\n", word_addr, value);
+	return value;
+}
+
+static void s3c_onenand_writew(unsigned short value, void __iomem *addr)
+{
+	struct onenand_chip *this = onenand->mtd->priv;
+	int reg = addr - this->base;
+	int word_addr = reg >> 1;
+
+	/* It's used for probing time */
+	switch (reg) {
+	case ONENAND_REG_SYS_CFG1:
+		writel(value, &onenand->reg->mem_cfg);
+		return;
+
+	case ONENAND_REG_START_ADDRESS1:
+	case ONENAND_REG_START_ADDRESS2:
+		return;
+
+	/* Lock/lock-tight/unlock/unlock_all */
+	case ONENAND_REG_START_BLOCK_ADDRESS:
+		return;
+
+	default:
+		break;
+	}
+
+	/* BootRAM access control */
+	if (reg < ONENAND_DATARAM) {
+		if (value == ONENAND_CMD_READID) {
+			onenand->bootram_command = 1;
+			return;
+		}
+		if (value == ONENAND_CMD_RESET) {
+			writel(ONENAND_MEM_RESET_COLD,
+					&onenand->reg->mem_reset);
+			onenand->bootram_command = 0;
+			return;
+		}
+	}
+
+	printk(KERN_INFO "s3c_onenand_writew: Illegal access"
+		" at reg 0x%x, value 0x%x\n", word_addr, value);
+
+	s3c_write_cmd(value, CMD_MAP_11(word_addr));
+}
+
+static int s3c_onenand_wait(struct mtd_info *mtd, int state)
+{
+	unsigned int flags = INT_ACT;
+	unsigned int stat, ecc;
+	unsigned long timeout = 0x100000;
+
+	switch (state) {
+	case FL_READING:
+		flags |= BLK_RW_CMP | LOAD_CMP;
+		break;
+	case FL_WRITING:
+		flags |= BLK_RW_CMP | PGM_CMP;
+		break;
+	case FL_ERASING:
+		flags |= BLK_RW_CMP | ERS_CMP;
+		break;
+	case FL_LOCKING:
+		flags |= BLK_RW_CMP;
+		break;
+	default:
+		break;
+	}
+
+	while (timeout--) {
+		stat = readl(&onenand->reg->int_err_stat);
+		if (stat & flags)
+			break;
+	}
+
+	/* To get correct interrupt status in timeout case */
+	stat = readl(&onenand->reg->int_err_stat);
+	writel(stat, &onenand->reg->int_err_ack);
+
+	/*
+	 * In the Spec. it checks the controller status first
+	 * However if you get the correct information in case of
+	 * power off recovery (POR) test, it should read ECC status first
+	 */
+	if (stat & LOAD_CMP) {
+		ecc = readl(&onenand->reg->ecc_err_stat);
+		if (ecc & ONENAND_ECC_4BIT_UNCORRECTABLE) {
+			printk(KERN_INFO "%s: ECC error = 0x%04x\n",
+					__func__, ecc);
+			mtd->ecc_stats.failed++;
+			return -EBADMSG;
+		}
+	}
+
+	if (stat & (LOCKED_BLK | ERS_FAIL | PGM_FAIL | LD_FAIL_ECC_ERR)) {
+		printk(KERN_INFO "%s: controller error = 0x%04x\n",
+				__func__, stat);
+		if (stat & LOCKED_BLK)
+			printk(KERN_INFO "%s: it's locked error = 0x%04x\n",
+					__func__, stat);
+
+		return -EIO;
+	}
+
+	return 0;
+}
+
+static int s3c_onenand_command(struct mtd_info *mtd, int cmd,
+		loff_t addr, size_t len)
+{
+	struct onenand_chip *this = mtd->priv;
+	unsigned int *m, *s;
+	int fba, fpa, fsa = 0;
+	unsigned int mem_addr;
+	int i, mcount, scount;
+	int index;
+
+	fba = (int) (addr >> this->erase_shift);
+	fpa = (int) (addr >> this->page_shift);
+	fpa &= this->page_mask;
+
+	mem_addr = onenand->mem_addr(fba, fpa, fsa);
+
+	switch (cmd) {
+	case ONENAND_CMD_READ:
+	case ONENAND_CMD_READOOB:
+	case ONENAND_CMD_BUFFERRAM:
+		ONENAND_SET_NEXT_BUFFERRAM(this);
+	default:
+		break;
+	}
+
+	index = ONENAND_CURRENT_BUFFERRAM(this);
+
+	/*
+	 * Emulate Two BufferRAMs and access with 4 bytes pointer
+	 */
+	m = (unsigned int *) onenand->page_buf;
+	s = (unsigned int *) onenand->oob_buf;
+
+	if (index) {
+		m += (this->writesize >> 2);
+		s += (mtd->oobsize >> 2);
+	}
+
+	mcount = mtd->writesize >> 2;
+	scount = mtd->oobsize >> 2;
+
+	switch (cmd) {
+	case ONENAND_CMD_READ:
+		/* Main */
+		for (i = 0; i < mcount; i++)
+			*m++ = s3c_read_cmd(CMD_MAP_01(mem_addr));
+		return 0;
+
+	case ONENAND_CMD_READOOB:
+		writel(TSRF, &onenand->reg->trans_spare);
+		/* Main */
+		for (i = 0; i < mcount; i++)
+			*m++ = s3c_read_cmd(CMD_MAP_01(mem_addr));
+
+		/* Spare */
+		for (i = 0; i < scount; i++)
+			*s++ = s3c_read_cmd(CMD_MAP_01(mem_addr));
+
+		writel(0, &onenand->reg->trans_spare);
+		return 0;
+
+	case ONENAND_CMD_PROG:
+		/* Main */
+		for (i = 0; i < mcount; i++)
+			s3c_write_cmd(*m++, CMD_MAP_01(mem_addr));
+		return 0;
+
+	case ONENAND_CMD_PROGOOB:
+		writel(TSRF, &onenand->reg->trans_spare);
+
+		/* Main - dummy write */
+		for (i = 0; i < mcount; i++)
+			s3c_write_cmd(0xffffffff, CMD_MAP_01(mem_addr));
+
+		/* Spare */
+		for (i = 0; i < scount; i++)
+			s3c_write_cmd(*s++, CMD_MAP_01(mem_addr));
+
+		writel(0, &onenand->reg->trans_spare);
+		return 0;
+
+	case ONENAND_CMD_UNLOCK_ALL:
+		s3c_write_cmd(ONENAND_UNLOCK_ALL, CMD_MAP_10(mem_addr));
+		return 0;
+
+	case ONENAND_CMD_ERASE:
+		s3c_write_cmd(ONENAND_ERASE_START, CMD_MAP_10(mem_addr));
+		return 0;
+
+	case ONENAND_CMD_MULTIBLOCK_ERASE:
+		s3c_write_cmd(ONENAND_MULTI_ERASE_SET, CMD_MAP_10(mem_addr));
+		return 0;
+
+	case ONENAND_CMD_ERASE_VERIFY:
+		s3c_write_cmd(ONENAND_ERASE_VERIFY, CMD_MAP_10(mem_addr));
+		return 0;
+
+	default:
+		break;
+	}
+
+	return 0;
+}
+
+static unsigned char *s3c_get_bufferram(struct mtd_info *mtd, int area)
+{
+	struct onenand_chip *this = mtd->priv;
+	int index = ONENAND_CURRENT_BUFFERRAM(this);
+	unsigned char *p;
+
+	if (area == ONENAND_DATARAM) {
+		p = (unsigned char *) onenand->page_buf;
+		if (index == 1)
+			p += this->writesize;
+	} else {
+		p = (unsigned char *) onenand->oob_buf;
+		if (index == 1)
+			p += mtd->oobsize;
+	}
+
+	return p;
+}
+
+static int onenand_read_bufferram(struct mtd_info *mtd, loff_t addr, int area,
+				  unsigned char *buffer, int offset,
+				  size_t count)
+{
+	unsigned char *p;
+
+	p = s3c_get_bufferram(mtd, area);
+	memcpy(buffer, p + offset, count);
+	return 0;
+}
+
+static int onenand_write_bufferram(struct mtd_info *mtd, loff_t addr, int area,
+				   const unsigned char *buffer, int offset,
+				   size_t count)
+{
+	unsigned char *p;
+
+	p = s3c_get_bufferram(mtd, area);
+	memcpy(p + offset, buffer, count);
+	return 0;
+}
+
+static int s3c_onenand_bbt_wait(struct mtd_info *mtd, int state)
+{
+	struct samsung_onenand *reg = (struct samsung_onenand *)onenand->base;
+	unsigned int flags = INT_ACT | LOAD_CMP;
+	unsigned int stat;
+	unsigned long timeout = 0x10000;
+
+	while (timeout--) {
+		stat = readl(&reg->int_err_stat);
+		if (stat & flags)
+			break;
+	}
+	/* To get correct interrupt status in timeout case */
+	stat = readl(&onenand->reg->int_err_stat);
+	writel(stat, &onenand->reg->int_err_ack);
+
+	if (stat & LD_FAIL_ECC_ERR) {
+		s3c_onenand_reset();
+		return ONENAND_BBT_READ_ERROR;
+	}
+
+	if (stat & LOAD_CMP) {
+		int ecc = readl(&onenand->reg->ecc_err_stat);
+		if (ecc & ONENAND_ECC_4BIT_UNCORRECTABLE) {
+			s3c_onenand_reset();
+			return ONENAND_BBT_READ_ERROR;
+		}
+	}
+
+	return 0;
+}
+
+static void s3c_onenand_check_lock_status(struct mtd_info *mtd)
+{
+	struct onenand_chip *this = mtd->priv;
+	unsigned int block, end;
+	int tmp;
+
+	end = this->chipsize >> this->erase_shift;
+
+	for (block = 0; block < end; block++) {
+		tmp = s3c_read_cmd(CMD_MAP_01(onenand->mem_addr(block, 0, 0)));
+
+		if (readl(&onenand->reg->int_err_stat) & LOCKED_BLK) {
+			printf("block %d is write-protected!\n", block);
+			writel(LOCKED_BLK, &onenand->reg->int_err_ack);
+		}
+	}
+}
+
+static void s3c_onenand_do_lock_cmd(struct mtd_info *mtd, loff_t ofs,
+		size_t len, int cmd)
+{
+	struct onenand_chip *this = mtd->priv;
+	int start, end, start_mem_addr, end_mem_addr;
+
+	start = ofs >> this->erase_shift;
+	start_mem_addr = onenand->mem_addr(start, 0, 0);
+	end = start + (len >> this->erase_shift) - 1;
+	end_mem_addr = onenand->mem_addr(end, 0, 0);
+
+	if (cmd == ONENAND_CMD_LOCK) {
+		s3c_write_cmd(ONENAND_LOCK_START, CMD_MAP_10(start_mem_addr));
+		s3c_write_cmd(ONENAND_LOCK_END, CMD_MAP_10(end_mem_addr));
+	} else {
+		s3c_write_cmd(ONENAND_UNLOCK_START, CMD_MAP_10(start_mem_addr));
+		s3c_write_cmd(ONENAND_UNLOCK_END, CMD_MAP_10(end_mem_addr));
+	}
+
+	this->wait(mtd, FL_LOCKING);
+}
+
+static void s3c_onenand_unlock_all(struct mtd_info *mtd)
+{
+	struct onenand_chip *this = mtd->priv;
+	loff_t ofs = 0;
+	size_t len = this->chipsize;
+
+	/* FIXME workaround */
+	this->subpagesize = mtd->writesize;
+	mtd->subpage_sft = 0;
+
+	if (this->options & ONENAND_HAS_UNLOCK_ALL) {
+		/* Write unlock command */
+		this->command(mtd, ONENAND_CMD_UNLOCK_ALL, 0, 0);
+
+		/* No need to check return value */
+		this->wait(mtd, FL_LOCKING);
+
+		/* Workaround for all block unlock in DDP */
+		if (!ONENAND_IS_DDP(this)) {
+			s3c_onenand_check_lock_status(mtd);
+			return;
+		}
+
+		/* All blocks on another chip */
+		ofs = this->chipsize >> 1;
+		len = this->chipsize >> 1;
+	}
+
+	s3c_onenand_do_lock_cmd(mtd, ofs, len, ONENAND_CMD_UNLOCK);
+	s3c_onenand_check_lock_status(mtd);
+}
+
+#ifdef CONFIG_S3C64XX
+static void s3c_set_width_regs(struct onenand_chip *this)
+{
+	int dev_id, density;
+	int fba, fpa, fsa;
+	int dbs_dfs;
+
+	dev_id = DEVICE_ID0_REG;
+
+	density = (dev_id >> ONENAND_DEVICE_DENSITY_SHIFT) & 0xf;
+	dbs_dfs = !!(dev_id & ONENAND_DEVICE_IS_DDP);
+
+	fba = density + 7;
+	if (dbs_dfs)
+		fba--;		/* Decrease the fba */
+	fpa = 6;
+	if (density >= ONENAND_DEVICE_DENSITY_512Mb)
+		fsa = 2;
+	else
+		fsa = 1;
+
+	DPRINTK("FBA %lu, FPA %lu, FSA %lu, DDP %lu",
+		FBA_WIDTH0_REG, FPA_WIDTH0_REG, FSA_WIDTH0_REG,
+		DDP_DEVICE_REG);
+
+	DPRINTK("mem_cfg0 0x%lx, sync mode %lu, "
+		"dev_page_size %lu, BURST LEN %lu",
+		MEM_CFG0_REG, SYNC_MODE_REG,
+		DEV_PAGE_SIZE_REG, BURST_LEN0_REG);
+
+	DEV_PAGE_SIZE_REG = 0x1;
+
+	FBA_WIDTH0_REG = fba;
+	FPA_WIDTH0_REG = fpa;
+	FSA_WIDTH0_REG = fsa;
+	DBS_DFS_WIDTH0_REG = dbs_dfs;
+}
+#endif
+
+void s3c_onenand_init(struct mtd_info *mtd)
+{
+	struct onenand_chip *this = mtd->priv;
+	u32 size = (4 << 10);	/* 4 KiB */
+
+	onenand = malloc(sizeof(struct s3c_onenand));
+	if (!onenand)
+		return;
+
+	onenand->page_buf = malloc(size * sizeof(char));
+	if (!onenand->page_buf)
+		return;
+	memset(onenand->page_buf, 0xff, size);
+
+	onenand->oob_buf = malloc(128 * sizeof(char));
+	if (!onenand->oob_buf)
+		return;
+	memset(onenand->oob_buf, 0xff, 128);
+
+	onenand->mtd = mtd;
+
+#if defined(CONFIG_S3C64XX)
+	onenand->base = (void *)0x70100000;
+	onenand->ahb_addr = (void *)0x20000000;
+#elif defined(CONFIG_S5PC1XX)
+	onenand->base = (void *)0xE7100000;
+	onenand->ahb_addr = (void *)0xB0000000;
+#endif
+	onenand->mem_addr = s3c_mem_addr;
+	onenand->reg = (struct samsung_onenand *)onenand->base;
+
+	this->read_word = s3c_onenand_readw;
+	this->write_word = s3c_onenand_writew;
+
+	this->wait = s3c_onenand_wait;
+	this->bbt_wait = s3c_onenand_bbt_wait;
+	this->unlock_all = s3c_onenand_unlock_all;
+	this->command = s3c_onenand_command;
+
+	this->read_bufferram = onenand_read_bufferram;
+	this->write_bufferram = onenand_write_bufferram;
+
+	this->options |= ONENAND_RUNTIME_BADBLOCK_CHECK;
+}
diff --git a/include/linux/mtd/onenand.h b/include/linux/mtd/onenand.h
index 06f7baf..9a6f317 100644
--- a/include/linux/mtd/onenand.h
+++ b/include/linux/mtd/onenand.h
@@ -135,6 +135,7 @@ struct onenand_chip {
 #define ONENAND_HAS_CONT_LOCK		(0x0001)
 #define ONENAND_HAS_UNLOCK_ALL		(0x0002)
 #define ONENAND_HAS_2PLANE		(0x0004)
+#define ONENAND_RUNTIME_BADBLOCK_CHECK	(0x0200)
 #define ONENAND_PAGEBUF_ALLOC		(0x1000)
 #define ONENAND_OOBBUF_ALLOC		(0x2000)
 
diff --git a/include/linux/mtd/onenand_regs.h b/include/linux/mtd/onenand_regs.h
index fc63380..07fed1c 100644
--- a/include/linux/mtd/onenand_regs.h
+++ b/include/linux/mtd/onenand_regs.h
@@ -121,6 +121,8 @@
 #define ONENAND_CMD_LOCK_TIGHT		(0x2C)
 #define ONENAND_CMD_UNLOCK_ALL		(0x27)
 #define ONENAND_CMD_ERASE		(0x94)
+#define ONENAND_CMD_MULTIBLOCK_ERASE	(0x95)
+#define ONENAND_CMD_ERASE_VERIFY	(0x71)
 #define ONENAND_CMD_RESET		(0xF0)
 #define ONENAND_CMD_READID		(0x90)
 
@@ -184,7 +186,9 @@
  * ECC Status Reigser FF00h (R)
  */
 #define ONENAND_ECC_1BIT		(1 << 0)
+#define ONENAND_ECC_1BIT_ALL		(0x5555)
 #define ONENAND_ECC_2BIT		(1 << 1)
 #define ONENAND_ECC_2BIT_ALL		(0xAAAA)
+#define ONENAND_ECC_4BIT_UNCORRECTABLE	(0x1010)
 
 #endif				/* __ONENAND_REG_H */
diff --git a/include/linux/mtd/samsung_onenand.h b/include/linux/mtd/samsung_onenand.h
new file mode 100644
index 0000000..9865780
--- /dev/null
+++ b/include/linux/mtd/samsung_onenand.h
@@ -0,0 +1,131 @@
+/*
+ *  Copyright (C) 2005-2009 Samsung Electronics
+ *  Minkyu Kang <mk7.kang@samsung.com>
+ *  Kyungmin Park <kyungmin.park@samsung.com>
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#ifndef __SAMSUNG_ONENAND_H__
+#define __SAMSUNG_ONENAND_H__
+
+/*
+ * OneNAND Controller
+ */
+
+#ifndef __ASSEMBLY__
+struct samsung_onenand {
+	unsigned long	mem_cfg;	/* 0x0000 */
+	unsigned char	res1[0xc];
+	unsigned long	burst_len;	/* 0x0010 */
+	unsigned char	res2[0xc];
+	unsigned long	mem_reset;	/* 0x0020 */
+	unsigned char	res3[0xc];
+	unsigned long	int_err_stat;	/* 0x0030 */
+	unsigned char	res4[0xc];
+	unsigned long	int_err_mask;	/* 0x0040 */
+	unsigned char	res5[0xc];
+	unsigned long	int_err_ack;	/* 0x0050 */
+	unsigned char	res6[0xc];
+	unsigned long	ecc_err_stat;	/* 0x0060 */
+	unsigned char	res7[0xc];
+	unsigned long	manufact_id;	/* 0x0070 */
+	unsigned char	res8[0xc];
+	unsigned long	device_id;	/* 0x0080 */
+	unsigned char	res9[0xc];
+	unsigned long	data_buf_size;	/* 0x0090 */
+	unsigned char	res10[0xc];
+	unsigned long	boot_buf_size;	/* 0x00A0 */
+	unsigned char	res11[0xc];
+	unsigned long	buf_amount;	/* 0x00B0 */
+	unsigned char	res12[0xc];
+	unsigned long	tech;		/* 0x00C0 */
+	unsigned char	res13[0xc];
+	unsigned long	fba;		/* 0x00D0 */
+	unsigned char	res14[0xc];
+	unsigned long	fpa;		/* 0x00E0 */
+	unsigned char	res15[0xc];
+	unsigned long	fsa;		/* 0x00F0 */
+	unsigned char	res16[0x3c];
+	unsigned long	sync_mode;	/* 0x0130 */
+	unsigned char	res17[0xc];
+	unsigned long	trans_spare;	/* 0x0140 */
+	unsigned char	res18[0x3c];
+	unsigned long	err_page_addr;	/* 0x0180 */
+	unsigned char	res19[0x1c];
+	unsigned long	int_pin_en;	/* 0x01A0 */
+	unsigned char	res20[0x1c];
+	unsigned long	acc_clock;	/* 0x01C0 */
+	unsigned char	res21[0x1c];
+	unsigned long	err_blk_addr;	/* 0x01E0 */
+	unsigned char	res22[0xc];
+	unsigned long	flash_ver_id;	/* 0x01F0 */
+	unsigned char	res23[0x6c];
+	unsigned long	watchdog_cnt_low;	/* 0x0260 */
+	unsigned char	res24[0xc];
+	unsigned long	watchdog_cnt_hi;	/* 0x0270 */
+	unsigned char	res25[0xc];
+	unsigned long	sync_write;	/* 0x0280 */
+	unsigned char	res26[0x1c];
+	unsigned long	cold_reset;	/* 0x02A0 */
+	unsigned char	res27[0xc];
+	unsigned long	ddp_device;	/* 0x02B0 */
+	unsigned char	res28[0xc];
+	unsigned long	multi_plane;	/* 0x02C0 */
+	unsigned char	res29[0x1c];
+	unsigned long	trans_mode;	/* 0x02E0 */
+	unsigned char	res30[0x1c];
+	unsigned long	ecc_err_stat2;	/* 0x0300 */
+	unsigned char	res31[0xc];
+	unsigned long	ecc_err_stat3;	/* 0x0310 */
+	unsigned char	res32[0xc];
+	unsigned long	ecc_err_stat4;	/* 0x0320 */
+	unsigned char	res33[0x1c];
+	unsigned long	dev_page_size;	/* 0x0340 */
+	unsigned char	res34[0x4c];
+	unsigned long	int_mon_status;	/* 0x0390 */
+};
+#endif
+
+#define ONENAND_MEM_RESET_HOT	0x3
+#define ONENAND_MEM_RESET_COLD	0x2
+#define ONENAND_MEM_RESET_WARM	0x1
+
+#define INT_ERR_ALL	0x3fff
+#define CACHE_OP_ERR    (1 << 13)
+#define RST_CMP         (1 << 12)
+#define RDY_ACT         (1 << 11)
+#define INT_ACT         (1 << 10)
+#define UNSUP_CMD       (1 << 9)
+#define LOCKED_BLK      (1 << 8)
+#define BLK_RW_CMP      (1 << 7)
+#define ERS_CMP         (1 << 6)
+#define PGM_CMP         (1 << 5)
+#define LOAD_CMP        (1 << 4)
+#define ERS_FAIL        (1 << 3)
+#define PGM_FAIL        (1 << 2)
+#define INT_TO          (1 << 1)
+#define LD_FAIL_ECC_ERR (1 << 0)
+
+#define TSRF		(1 << 0)
+
+/* common initialize function */
+extern void s3c_onenand_init(struct mtd_info *);
+
+#endif
-- 
1.5.4.3

  reply	other threads:[~2009-09-22 12:35 UTC|newest]

Thread overview: 13+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2009-09-10  7:35 [U-Boot] [PATCH 2/4 v2] s5pc1xx: support onenand driver Minkyu Kang
2009-09-10 11:16 ` Wolfgang Denk
2009-09-15  2:40   ` Minkyu Kang
2009-09-22 12:35     ` Minkyu Kang [this message]
2009-09-22 14:48       ` [U-Boot] [PATCH 2/4 v3] " Tom
2009-09-23 10:49         ` Minkyu Kang
2009-09-23 23:46           ` Kyungmin Park
2009-09-24  1:17             ` Tom
2009-09-24 13:27         ` Wolfgang Denk
2009-09-28 17:55           ` Scott Wood
2009-10-01  8:20             ` [U-Boot] [PATCH 2/4 v4] " Minkyu Kang
2009-10-09  3:10               ` Minkyu Kang
2009-10-03 23:25             ` [U-Boot] [PATCH 2/4 v3] " Wolfgang Denk

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=4AB8C4AB.4020105@samsung.com \
    --to=mk7.kang@samsung.com \
    --cc=u-boot@lists.denx.de \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.