s5pc1xx: support onenand driver

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>
master
Minkyu Kang 15 years ago committed by Tom Rix
parent 399e5ae0d0
commit 4678d674f0
  1. 1
      drivers/mtd/onenand/Makefile
  2. 636
      drivers/mtd/onenand/samsung.c
  3. 1
      include/linux/mtd/onenand.h
  4. 4
      include/linux/mtd/onenand_regs.h
  5. 131
      include/linux/mtd/samsung_onenand.h

@ -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)

@ -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(&reg->int_err_stat);
if (stat & flags)
break;
}
/* To get correct interrupt status in timeout case */
stat = readl(&onenand->reg->int_err_stat);
writel(stat, &onenand->reg->int_err_ack);
if (stat & LD_FAIL_ECC_ERR) {
s3c_onenand_reset();
return ONENAND_BBT_READ_ERROR;
}
if (stat & LOAD_CMP) {
int ecc = readl(&onenand->reg->ecc_err_stat);
if (ecc & ONENAND_ECC_4BIT_UNCORRECTABLE) {
s3c_onenand_reset();
return ONENAND_BBT_READ_ERROR;
}
}
return 0;
}
static void s3c_onenand_check_lock_status(struct mtd_info *mtd)
{
struct onenand_chip *this = mtd->priv;
unsigned int block, end;
int tmp;
end = this->chipsize >> this->erase_shift;
for (block = 0; block < end; block++) {
tmp = s3c_read_cmd(CMD_MAP_01(onenand->mem_addr(block, 0, 0)));
if (readl(&onenand->reg->int_err_stat) & LOCKED_BLK) {
printf("block %d is write-protected!\n", block);
writel(LOCKED_BLK, &onenand->reg->int_err_ack);
}
}
}
static void s3c_onenand_do_lock_cmd(struct mtd_info *mtd, loff_t ofs,
size_t len, int cmd)
{
struct onenand_chip *this = mtd->priv;
int start, end, start_mem_addr, end_mem_addr;
start = ofs >> this->erase_shift;
start_mem_addr = onenand->mem_addr(start, 0, 0);
end = start + (len >> this->erase_shift) - 1;
end_mem_addr = onenand->mem_addr(end, 0, 0);
if (cmd == ONENAND_CMD_LOCK) {
s3c_write_cmd(ONENAND_LOCK_START, CMD_MAP_10(start_mem_addr));
s3c_write_cmd(ONENAND_LOCK_END, CMD_MAP_10(end_mem_addr));
} else {
s3c_write_cmd(ONENAND_UNLOCK_START, CMD_MAP_10(start_mem_addr));
s3c_write_cmd(ONENAND_UNLOCK_END, CMD_MAP_10(end_mem_addr));
}
this->wait(mtd, FL_LOCKING);
}
static void s3c_onenand_unlock_all(struct mtd_info *mtd)
{
struct onenand_chip *this = mtd->priv;
loff_t ofs = 0;
size_t len = this->chipsize;
/* FIXME workaround */
this->subpagesize = mtd->writesize;
mtd->subpage_sft = 0;
if (this->options & ONENAND_HAS_UNLOCK_ALL) {
/* Write unlock command */
this->command(mtd, ONENAND_CMD_UNLOCK_ALL, 0, 0);
/* No need to check return value */
this->wait(mtd, FL_LOCKING);
/* Workaround for all block unlock in DDP */
if (!ONENAND_IS_DDP(this)) {
s3c_onenand_check_lock_status(mtd);
return;
}
/* All blocks on another chip */
ofs = this->chipsize >> 1;
len = this->chipsize >> 1;
}
s3c_onenand_do_lock_cmd(mtd, ofs, len, ONENAND_CMD_UNLOCK);
s3c_onenand_check_lock_status(mtd);
}
#ifdef CONFIG_S3C64XX
static void s3c_set_width_regs(struct onenand_chip *this)
{
int dev_id, density;
int fba, fpa, fsa;
int dbs_dfs;
dev_id = DEVICE_ID0_REG;
density = (dev_id >> ONENAND_DEVICE_DENSITY_SHIFT) & 0xf;
dbs_dfs = !!(dev_id & ONENAND_DEVICE_IS_DDP);
fba = density + 7;
if (dbs_dfs)
fba--; /* Decrease the fba */
fpa = 6;
if (density >= ONENAND_DEVICE_DENSITY_512Mb)
fsa = 2;
else
fsa = 1;
DPRINTK("FBA %lu, FPA %lu, FSA %lu, DDP %lu",
FBA_WIDTH0_REG, FPA_WIDTH0_REG, FSA_WIDTH0_REG,
DDP_DEVICE_REG);
DPRINTK("mem_cfg0 0x%lx, sync mode %lu, "
"dev_page_size %lu, BURST LEN %lu",
MEM_CFG0_REG, SYNC_MODE_REG,
DEV_PAGE_SIZE_REG, BURST_LEN0_REG);
DEV_PAGE_SIZE_REG = 0x1;
FBA_WIDTH0_REG = fba;
FPA_WIDTH0_REG = fpa;
FSA_WIDTH0_REG = fsa;
DBS_DFS_WIDTH0_REG = dbs_dfs;
}
#endif
void s3c_onenand_init(struct mtd_info *mtd)
{
struct onenand_chip *this = mtd->priv;
u32 size = (4 << 10); /* 4 KiB */
onenand = malloc(sizeof(struct s3c_onenand));
if (!onenand)
return;
onenand->page_buf = malloc(size * sizeof(char));
if (!onenand->page_buf)
return;
memset(onenand->page_buf, 0xff, size);
onenand->oob_buf = malloc(128 * sizeof(char));
if (!onenand->oob_buf)
return;
memset(onenand->oob_buf, 0xff, 128);
onenand->mtd = mtd;
#if defined(CONFIG_S3C64XX)
onenand->base = (void *)0x70100000;
onenand->ahb_addr = (void *)0x20000000;
#elif defined(CONFIG_S5PC1XX)
onenand->base = (void *)0xE7100000;
onenand->ahb_addr = (void *)0xB0000000;
#endif
onenand->mem_addr = s3c_mem_addr;
onenand->reg = (struct samsung_onenand *)onenand->base;
this->read_word = s3c_onenand_readw;
this->write_word = s3c_onenand_writew;
this->wait = s3c_onenand_wait;
this->bbt_wait = s3c_onenand_bbt_wait;
this->unlock_all = s3c_onenand_unlock_all;
this->command = s3c_onenand_command;
this->read_bufferram = onenand_read_bufferram;
this->write_bufferram = onenand_write_bufferram;
this->options |= ONENAND_RUNTIME_BADBLOCK_CHECK;
}

@ -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)

@ -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 */

@ -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
Loading…
Cancel
Save