* [U-Boot] [PATCH 2/4 v2] s5pc1xx: support onenand driver
@ 2009-09-10 7:35 Minkyu Kang
2009-09-10 11:16 ` Wolfgang Denk
0 siblings, 1 reply; 13+ messages in thread
From: Minkyu Kang @ 2009-09-10 7:35 UTC (permalink / raw)
To: u-boot
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>
---
drivers/mtd/onenand/Makefile | 2 +
drivers/mtd/onenand/samsung.c | 626 +++++++++++++++++++++++++++++++++++
include/linux/mtd/onenand.h | 1 +
include/linux/mtd/onenand_regs.h | 4 +
include/linux/mtd/samsung_onenand.h | 132 ++++++++
5 files changed, 765 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..9317341 100644
--- a/drivers/mtd/onenand/Makefile
+++ b/drivers/mtd/onenand/Makefile
@@ -26,6 +26,8 @@ include $(TOPDIR)/config.mk
LIB := $(obj)libonenand.a
COBJS-$(CONFIG_CMD_ONENAND) := onenand_uboot.o onenand_base.o onenand_bbt.o
+COBJS-$(CONFIG_S3C64XX) += samsung.o
+COBJS-$(CONFIG_S5PC1XX) += 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..03dfff8
--- /dev/null
+++ b/drivers/mtd/onenand/samsung.c
@@ -0,0 +1,626 @@
+/*
+ * 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
+
+/* The 'addr' is byte address. It makes a 16-bit word */
+#define CMD_MAP_00(addr) (MAP_00 | ((addr) << 1))
+#define CMD_MAP_01(mem_addr) (MAP_01 | (mem_addr))
+#define CMD_MAP_10(mem_addr) (MAP_10 | (mem_addr))
+#define CMD_MAP_11(addr) (MAP_11 | ((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);
+}
+
+/*
+ * 1Gb: FBA[21:12] FPA[11:6] FSA[5:4]
+ * 2Gb: FBA[22:12] FPA[11:6] FSA[5:4]
+ * 4Gb: FBA[23:12] FPA[11:6] FSA[5:4]
+ */
+static unsigned int s3c64xx_mem_addr(int fba, int fpa, int fsa)
+{
+ return (fba << 12) | (fpa << 6) | (fsa << 4);
+}
+
+/*
+ * 1Gb: FBA[22:13] FPA[12:7] FSA[6:5]
+ * 2Gb: FBA[23:13] FPA[12:7] FSA[6:5]
+ * 4Gb: FBA[24:13] FPA[12:7] FSA[6:5]
+ */
+static unsigned int s5pc100_mem_addr(int fba, int fpa, int fsa)
+{
+ return (fba << 13) | (fpa << 7) | (fsa << 5);
+}
+
+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(®->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;
+
+ onenand = malloc(sizeof(struct s3c_onenand));
+ if (!onenand)
+ return;
+
+ onenand->page_buf = malloc(SZ_4K * sizeof(char));
+ if (!onenand->page_buf)
+ return;
+ memset(onenand->page_buf, 0xFF, SZ_4K);
+
+ onenand->oob_buf = malloc(128 * sizeof(char));
+ if (!onenand->oob_buf)
+ return;
+ memset(onenand->oob_buf, 0xFF, 128);
+
+ onenand->mtd = mtd;
+
+#ifdef CONFIG_S5PC1XX
+ /* S5PC100 specific values */
+ onenand->base = (void *) 0xE7100000;
+ onenand->ahb_addr = (void *) 0xB0000000;
+ onenand->mem_addr = s5pc100_mem_addr;
+#else
+ onenand->base = (void *) 0x70100000;
+ onenand->ahb_addr = (void *) 0x20000000;
+ onenand->mem_addr = s3c64xx_mem_addr;
+#endif
+ 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..d389606
--- /dev/null
+++ b/include/linux/mtd/samsung_onenand.h
@@ -0,0 +1,132 @@
+/*
+ * 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__
+
+#include <asm/hardware.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 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
^ permalink raw reply related [flat|nested] 13+ messages in thread
* [U-Boot] [PATCH 2/4 v2] s5pc1xx: support onenand driver
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
0 siblings, 1 reply; 13+ messages in thread
From: Wolfgang Denk @ 2009-09-10 11:16 UTC (permalink / raw)
To: u-boot
Dear Minkyu Kang,
In message <4AA8AC3B.5000604@samsung.com> you wrote:
> 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>
...
> +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;
> +};
Please drop these blank lines.
> +/*
> + * 1Gb: FBA[21:12] FPA[11:6] FSA[5:4]
> + * 2Gb: FBA[22:12] FPA[11:6] FSA[5:4]
> + * 4Gb: FBA[23:12] FPA[11:6] FSA[5:4]
> + */
> +static unsigned int s3c64xx_mem_addr(int fba, int fpa, int fsa)
> +{
> + return (fba << 12) | (fpa << 6) | (fsa << 4);
> +}
> +
> +/*
> + * 1Gb: FBA[22:13] FPA[12:7] FSA[6:5]
> + * 2Gb: FBA[23:13] FPA[12:7] FSA[6:5]
> + * 4Gb: FBA[24:13] FPA[12:7] FSA[6:5]
> + */
> +static unsigned int s5pc100_mem_addr(int fba, int fpa, int fsa)
> +{
> + return (fba << 13) | (fpa << 7) | (fsa << 5);
> +}
Hm... when I wrote "This function needs explanation. Please add a
comment what it does, and how." I meant some comment that really
explains what is goong on here - what the arguments are, what the
return value is, and which sort of transformation the function
performs. Your comment is not exactly helpful.
I can see what the code is doing, but I have no idea what that means -
reading your comments don't help my understanding.
What I see raises just additional questions: should there be no error
checking? I mean, something like
... ((fpa & 0x3f) << 7) | ((fsa & 3) << 5)
?
> diff --git a/include/linux/mtd/samsung_onenand.h b/include/linux/mtd/samsung_onenand.h
> new file mode 100644
> index 0000000..d389606
> --- /dev/null
> +++ b/include/linux/mtd/samsung_onenand.h
...
> +#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];
...
Upper case vaiable names are not allowed. Upper case identifiers are
reserved for macros only. Please use lower case names.
Best regards,
Wolfgang Denk
--
DENX Software Engineering GmbH, MD: Wolfgang Denk & Detlev Zundel
HRB 165235 Munich, Office: Kirchenstr.5, D-82194 Groebenzell, Germany
Phone: (+49)-8142-66989-10 Fax: (+49)-8142-66989-80 Email: wd at denx.de
That's the thing about people who think they hate computers. What
they really hate is lousy programmers.
- Larry Niven and Jerry Pournelle in "Oath of Fealty"
^ permalink raw reply [flat|nested] 13+ messages in thread
* [U-Boot] [PATCH 2/4 v2] s5pc1xx: support onenand driver
2009-09-10 11:16 ` Wolfgang Denk
@ 2009-09-15 2:40 ` Minkyu Kang
2009-09-22 12:35 ` [U-Boot] [PATCH 2/4 v3] " Minkyu Kang
0 siblings, 1 reply; 13+ messages in thread
From: Minkyu Kang @ 2009-09-15 2:40 UTC (permalink / raw)
To: u-boot
Dear Wolfgang
2009/9/10 Wolfgang Denk <wd@denx.de>:
> Dear Minkyu Kang,
>
> In message <4AA8AC3B.5000604@samsung.com> you wrote:
>> 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>
> ...
>> +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;
>> +};
>
> Please drop these blank lines.
>
ok.
>
>> +/*
>> + * 1Gb: FBA[21:12] FPA[11:6] FSA[5:4]
>> + * 2Gb: FBA[22:12] FPA[11:6] FSA[5:4]
>> + * 4Gb: FBA[23:12] FPA[11:6] FSA[5:4]
>> + */
>> +static unsigned int s3c64xx_mem_addr(int fba, int fpa, int fsa)
>> +{
>> + ? ? return (fba << 12) | (fpa << 6) | (fsa << 4);
>> +}
>> +
>> +/*
>> + * 1Gb: FBA[22:13] FPA[12:7] FSA[6:5]
>> + * 2Gb: FBA[23:13] FPA[12:7] FSA[6:5]
>> + * 4Gb: FBA[24:13] FPA[12:7] FSA[6:5]
>> + */
>> +static unsigned int s5pc100_mem_addr(int fba, int fpa, int fsa)
>> +{
>> + ? ? return (fba << 13) | (fpa << 7) | (fsa << 5);
>> +}
>
> Hm... when I wrote "This function needs explanation. Please add a
> comment what it does, and how." I meant some comment that really
> explains what is goong on here - what the arguments are, what the
> return value is, and which sort of transformation the function
> performs. Your comment is not exactly helpful.
>
> I can see what the code is doing, but I have no idea what that means -
> reading your comments don't help my understanding.
>
ok I'll write more comments.
> What I see raises just additional questions: should there be no error
> checking? I mean, something like
>
> ? ? ? ?... ((fpa & 0x3f) << 7) | ((fsa & 3) << 5)
>
> ?
>
hm.. I think no need.
because of each capacity have different offset
and each argument is got from mtd.
Kyungmin, how you think?
>
>> diff --git a/include/linux/mtd/samsung_onenand.h b/include/linux/mtd/samsung_onenand.h
>> new file mode 100644
>> index 0000000..d389606
>> --- /dev/null
>> +++ b/include/linux/mtd/samsung_onenand.h
> ...
>> +#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];
> ...
>
> Upper case vaiable names are not allowed. Upper case identifiers are
> reserved for macros only. Please use lower case names.
sure i do.
>
> Best regards,
>
> Wolfgang Denk
>
> --
> DENX Software Engineering GmbH, ? ? MD: Wolfgang Denk & Detlev Zundel
> HRB 165235 Munich, Office: Kirchenstr.5, D-82194 Groebenzell, Germany
> Phone: (+49)-8142-66989-10 Fax: (+49)-8142-66989-80 Email: wd at denx.de
> That's the thing about people who think ?they ?hate ?computers. ?What
> they really hate is lousy programmers.
> - Larry Niven and Jerry Pournelle in "Oath of Fealty"
> _______________________________________________
> U-Boot mailing list
> U-Boot at lists.denx.de
> http://lists.denx.de/mailman/listinfo/u-boot
>
thanks
Minkyu Kang
--
from. prom.
www.promsoft.net
^ permalink raw reply [flat|nested] 13+ messages in thread
* [U-Boot] [PATCH 2/4 v3] s5pc1xx: support onenand driver
2009-09-15 2:40 ` Minkyu Kang
@ 2009-09-22 12:35 ` Minkyu Kang
2009-09-22 14:48 ` Tom
0 siblings, 1 reply; 13+ messages in thread
From: Minkyu Kang @ 2009-09-22 12:35 UTC (permalink / raw)
To: u-boot
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(®->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
^ permalink raw reply related [flat|nested] 13+ messages in thread
* [U-Boot] [PATCH 2/4 v3] s5pc1xx: support onenand driver
2009-09-22 12:35 ` [U-Boot] [PATCH 2/4 v3] " Minkyu Kang
@ 2009-09-22 14:48 ` Tom
2009-09-23 10:49 ` Minkyu Kang
2009-09-24 13:27 ` Wolfgang Denk
0 siblings, 2 replies; 13+ messages in thread
From: Tom @ 2009-09-22 14:48 UTC (permalink / raw)
To: u-boot
Minkyu Kang wrote:
> 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.
Add full GPL 2 copyright.
> + *
> + * Implementation:
> + * Emulate the pseudo BufferRAM
> + */
> +
<snip>
> +
> +#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
This and other struct, #defines may be better handled in a H file.
Why did you include them all here?
Otherwise fine.
Just fix the copyright.
Tom
^ permalink raw reply [flat|nested] 13+ messages in thread
* [U-Boot] [PATCH 2/4 v3] s5pc1xx: support onenand driver
2009-09-22 14:48 ` Tom
@ 2009-09-23 10:49 ` Minkyu Kang
2009-09-23 23:46 ` Kyungmin Park
2009-09-24 13:27 ` Wolfgang Denk
1 sibling, 1 reply; 13+ messages in thread
From: Minkyu Kang @ 2009-09-23 10:49 UTC (permalink / raw)
To: u-boot
Dear Tom.
2009/9/22 Tom <Tom.Rix@windriver.com>:
> Minkyu Kang wrote:
>> 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.
>
> Add full GPL 2 copyright.
Ok, thanks
>
>> + *
>> + * Implementation:
>> + * ? Emulate the pseudo BufferRAM
>> + */
>> +
> <snip>
>
>> +
>> +#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
>
> This and other struct, #defines may be better handled in a H file.
> Why did you include them all here?
It will be moved H file thanks
>
> Otherwise fine.
> Just fix the copyright.
>
> Tom
> _______________________________________________
> U-Boot mailing list
> U-Boot at lists.denx.de
> http://lists.denx.de/mailman/listinfo/u-boot
>
Thanks
Minkyu Kang
--
from. prom.
www.promsoft.net
^ permalink raw reply [flat|nested] 13+ messages in thread
* [U-Boot] [PATCH 2/4 v3] s5pc1xx: support onenand driver
2009-09-23 10:49 ` Minkyu Kang
@ 2009-09-23 23:46 ` Kyungmin Park
2009-09-24 1:17 ` Tom
0 siblings, 1 reply; 13+ messages in thread
From: Kyungmin Park @ 2009-09-23 23:46 UTC (permalink / raw)
To: u-boot
On Wed, Sep 23, 2009 at 7:49 PM, Minkyu Kang <promsoft@gmail.com> wrote:
> Dear Tom.
>
> 2009/9/22 Tom <Tom.Rix@windriver.com>:
>> Minkyu Kang wrote:
>>> 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.
>>
>> Add full GPL 2 copyright.
>
> Ok, thanks
>
>>
>>> + *
>>> + * Implementation:
>>> + * ? Emulate the pseudo BufferRAM
>>> + */
>>> +
>> <snip>
>>
>>> +
>>> +#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
>>
>> This and other struct, #defines may be better handled in a H file.
>> Why did you include them all here?
>
> It will be moved H file thanks
No, No. Please leave it. User must know that which MAP bit are used.
Later I will remove #ifdef.
Thank you,
Kyungmin Park
^ permalink raw reply [flat|nested] 13+ messages in thread
* [U-Boot] [PATCH 2/4 v3] s5pc1xx: support onenand driver
2009-09-23 23:46 ` Kyungmin Park
@ 2009-09-24 1:17 ` Tom
0 siblings, 0 replies; 13+ messages in thread
From: Tom @ 2009-09-24 1:17 UTC (permalink / raw)
To: u-boot
Kyungmin Park wrote:
> On Wed, Sep 23, 2009 at 7:49 PM, Minkyu Kang <promsoft@gmail.com> wrote:
>> Dear Tom.
>>
>> 2009/9/22 Tom <Tom.Rix@windriver.com>:
>>> Minkyu Kang wrote:
>>>> 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.
>>> Add full GPL 2 copyright.
>> Ok, thanks
>>
>>>> + *
>>>> + * Implementation:
>>>> + * Emulate the pseudo BufferRAM
>>>> + */
>>>> +
>>> <snip>
>>>
>>>> +
>>>> +#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
>>> This and other struct, #defines may be better handled in a H file.
>>> Why did you include them all here?
>> It will be moved H file thanks
>
> No, No. Please leave it. User must know that which MAP bit are used.
> Later I will remove #ifdef.
>
I was not referring to just the MAP bits.
There is in general a large number of #defines and other information
that may be better handled by moving them to an H file.
Moving them in not a requirement.
Please resubmit with just the copyright change if you do not
want to do the move.
Tom
> Thank you,
> Kyungmin Park
^ permalink raw reply [flat|nested] 13+ messages in thread
* [U-Boot] [PATCH 2/4 v3] s5pc1xx: support onenand driver
2009-09-22 14:48 ` Tom
2009-09-23 10:49 ` Minkyu Kang
@ 2009-09-24 13:27 ` Wolfgang Denk
2009-09-28 17:55 ` Scott Wood
1 sibling, 1 reply; 13+ messages in thread
From: Wolfgang Denk @ 2009-09-24 13:27 UTC (permalink / raw)
To: u-boot
Dear Tom, Kyungmin & Minkyu,
In message <4AB8E3CA.6060301@windriver.com> Tom Rix wrote:
>
...
> > + * 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.
>
> Add full GPL 2 copyright.
To avoid misunderstandings: the required phrase is "GPL, either
version 2, or (at your option) any later version"; please see note 1
at http://www.denx.de/wiki/U-Boot/Patches for details.
Best regards,
Wolfgang Denk
--
DENX Software Engineering GmbH, MD: Wolfgang Denk & Detlev Zundel
HRB 165235 Munich, Office: Kirchenstr.5, D-82194 Groebenzell, Germany
Phone: (+49)-8142-66989-10 Fax: (+49)-8142-66989-80 Email: wd at denx.de
In the beginning there was nothing.
And the Lord said "Let There Be Light!"
And still there was nothing, but at least now you could see it.
^ permalink raw reply [flat|nested] 13+ messages in thread
* [U-Boot] [PATCH 2/4 v3] s5pc1xx: support onenand driver
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-03 23:25 ` [U-Boot] [PATCH 2/4 v3] " Wolfgang Denk
0 siblings, 2 replies; 13+ messages in thread
From: Scott Wood @ 2009-09-28 17:55 UTC (permalink / raw)
To: u-boot
On Thu, Sep 24, 2009 at 03:27:29PM +0200, Wolfgang Denk wrote:
> Dear Tom, Kyungmin & Minkyu,
>
> In message <4AB8E3CA.6060301@windriver.com> Tom Rix wrote:
> >
> ...
> > > + * 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.
> >
> > Add full GPL 2 copyright.
>
> To avoid misunderstandings: the required phrase is "GPL, either
> version 2, or (at your option) any later version"; please see note 1
> at http://www.denx.de/wiki/U-Boot/Patches for details.
Does this mean you will not accept any more patches that import new NAND
code from Linux, as that code is v2-only?
-Scott
^ permalink raw reply [flat|nested] 13+ messages in thread
* [U-Boot] [PATCH 2/4 v4] s5pc1xx: support onenand driver
2009-09-28 17:55 ` Scott Wood
@ 2009-10-01 8:20 ` Minkyu Kang
2009-10-09 3:10 ` Minkyu Kang
2009-10-03 23:25 ` [U-Boot] [PATCH 2/4 v3] " Wolfgang Denk
1 sibling, 1 reply; 13+ messages in thread
From: Minkyu Kang @ 2009-10-01 8:20 UTC (permalink / raw)
To: u-boot
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
Changes since v3:
- fix the copyright
drivers/mtd/onenand/Makefile | 1 +
drivers/mtd/onenand/samsung.c | 636 +++++++++++++++++++++++++++++++++++
include/linux/mtd/onenand.h | 1 +
include/linux/mtd/onenand_regs.h | 4 +
include/linux/mtd/samsung_onenand.h | 131 +++++++
5 files changed, 773 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..f2be687
--- /dev/null
+++ b/drivers/mtd/onenand/samsung.c
@@ -0,0 +1,636 @@
+/*
+ * S3C64XX/S5PC100 OneNAND driver at U-Boot
+ *
+ * Copyright (C) 2008-2009 Samsung Electronics
+ * Kyungmin Park <kyungmin.park@samsung.com>
+ *
+ * Implementation:
+ * Emulate the pseudo BufferRAM
+ *
+ * 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
+ */
+
+#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(®->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
^ permalink raw reply related [flat|nested] 13+ messages in thread
* [U-Boot] [PATCH 2/4 v3] s5pc1xx: support onenand driver
2009-09-28 17:55 ` Scott Wood
2009-10-01 8:20 ` [U-Boot] [PATCH 2/4 v4] " Minkyu Kang
@ 2009-10-03 23:25 ` Wolfgang Denk
1 sibling, 0 replies; 13+ messages in thread
From: Wolfgang Denk @ 2009-10-03 23:25 UTC (permalink / raw)
To: u-boot
Dear Scott Wood,
In message <20090928175506.GA2860@b07421-ec1.am.freescale.net> you wrote:
>
> > To avoid misunderstandings: the required phrase is "GPL, either
> > version 2, or (at your option) any later version"; please see note 1
> > at http://www.denx.de/wiki/U-Boot/Patches for details.
>
> Does this mean you will not accept any more patches that import new NAND
> code from Linux, as that code is v2-only?
Importing code from Linux is one big exception - well knowing, that we
will have to solve these issues in some future time.
Best regards,
Wolfgang Denk
--
DENX Software Engineering GmbH, MD: Wolfgang Denk & Detlev Zundel
HRB 165235 Munich, Office: Kirchenstr.5, D-82194 Groebenzell, Germany
Phone: (+49)-8142-66989-10 Fax: (+49)-8142-66989-80 Email: wd at denx.de
There's no sense in being precise when you don't even know what
you're talking about. -- John von Neumann
^ permalink raw reply [flat|nested] 13+ messages in thread
* [U-Boot] [PATCH 2/4 v4] s5pc1xx: support onenand driver
2009-10-01 8:20 ` [U-Boot] [PATCH 2/4 v4] " Minkyu Kang
@ 2009-10-09 3:10 ` Minkyu Kang
0 siblings, 0 replies; 13+ messages in thread
From: Minkyu Kang @ 2009-10-09 3:10 UTC (permalink / raw)
To: u-boot
Minkyu Kang wrote:
> 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
>
> Changes since v3:
> - fix the copyright
>
> drivers/mtd/onenand/Makefile | 1 +
> drivers/mtd/onenand/samsung.c | 636 +++++++++++++++++++++++++++++++++++
> include/linux/mtd/onenand.h | 1 +
> include/linux/mtd/onenand_regs.h | 4 +
> include/linux/mtd/samsung_onenand.h | 131 +++++++
> 5 files changed, 773 insertions(+), 0 deletions(-)
> create mode 100644 drivers/mtd/onenand/samsung.c
> create mode 100644 include/linux/mtd/samsung_onenand.h
>
applied to u-boot-samsung
Minkyu Kang
^ permalink raw reply [flat|nested] 13+ messages in thread
end of thread, other threads:[~2009-10-09 3:10 UTC | newest]
Thread overview: 13+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
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 ` [U-Boot] [PATCH 2/4 v3] " Minkyu Kang
2009-09-22 14:48 ` 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
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.