From 3b85c3211ebde263a86c8cd3c7277fdd2e440310 Mon Sep 17 00:00:00 2001 From: David Woodhouse Date: Mon, 25 Sep 2006 17:06:53 +0100 Subject: [MTD NAND] Split nand_scan() into two parts; allow board driver to intervene Signed-off-by: David Woodhouse --- include/linux/mtd/nand.h | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'include/linux') diff --git a/include/linux/mtd/nand.h b/include/linux/mtd/nand.h index 0b4cd2fa64aa..88d690d79d77 100644 --- a/include/linux/mtd/nand.h +++ b/include/linux/mtd/nand.h @@ -27,6 +27,11 @@ struct mtd_info; /* Scan and identify a NAND device */ extern int nand_scan (struct mtd_info *mtd, int max_chips); +/* Separate phases of nand_scan(), allowing board driver to intervene + * and override command or ECC setup according to flash type */ +extern int nand_scan_ident(struct mtd_info *mtd, int max_chips); +extern int nand_scan_tail(struct mtd_info *mtd); + /* Free resources held by the NAND device */ extern void nand_release (struct mtd_info *mtd); -- cgit v1.2.3 From 4bf63fcb83dc761853f69a77b15e47712689020b Mon Sep 17 00:00:00 2001 From: David Woodhouse Date: Mon, 25 Sep 2006 17:08:04 +0100 Subject: [MTD NAND] Allocate chip->buffers separately to allow it to be overridden In particular, the board driver might need it to be DMAable. Signed-off-by: David Woodhouse --- drivers/mtd/nand/nand_base.c | 35 +++++++++++++++++++++-------------- drivers/mtd/nand/nand_bbt.c | 2 +- include/linux/mtd/nand.h | 6 ++++-- 3 files changed, 26 insertions(+), 17 deletions(-) (limited to 'include/linux') diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c index 492ff9d1a35c..e1e81a9543e8 100644 --- a/drivers/mtd/nand/nand_base.c +++ b/drivers/mtd/nand/nand_base.c @@ -767,8 +767,8 @@ static int nand_read_page_swecc(struct mtd_info *mtd, struct nand_chip *chip, int eccbytes = chip->ecc.bytes; int eccsteps = chip->ecc.steps; uint8_t *p = buf; - uint8_t *ecc_calc = chip->buffers.ecccalc; - uint8_t *ecc_code = chip->buffers.ecccode; + uint8_t *ecc_calc = chip->buffers->ecccalc; + uint8_t *ecc_code = chip->buffers->ecccode; int *eccpos = chip->ecc.layout->eccpos; nand_read_page_raw(mtd, chip, buf); @@ -809,8 +809,8 @@ static int nand_read_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip, int eccbytes = chip->ecc.bytes; int eccsteps = chip->ecc.steps; uint8_t *p = buf; - uint8_t *ecc_calc = chip->buffers.ecccalc; - uint8_t *ecc_code = chip->buffers.ecccode; + uint8_t *ecc_calc = chip->buffers->ecccalc; + uint8_t *ecc_code = chip->buffers->ecccode; int *eccpos = chip->ecc.layout->eccpos; for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize) { @@ -971,7 +971,7 @@ static int nand_do_read_ops(struct mtd_info *mtd, loff_t from, page = realpage & chip->pagemask; col = (int)(from & (mtd->writesize - 1)); - chip->oob_poi = chip->buffers.oobrbuf; + chip->oob_poi = chip->buffers->oobrbuf; buf = ops->datbuf; oob = ops->oobbuf; @@ -982,7 +982,7 @@ static int nand_do_read_ops(struct mtd_info *mtd, loff_t from, /* Is the current page in the buffer ? */ if (realpage != chip->pagebuf || oob) { - bufpoi = aligned ? buf : chip->buffers.databuf; + bufpoi = aligned ? buf : chip->buffers->databuf; if (likely(sndcmd)) { chip->cmdfunc(mtd, NAND_CMD_READ0, 0x00, page); @@ -997,7 +997,7 @@ static int nand_do_read_ops(struct mtd_info *mtd, loff_t from, /* Transfer not aligned data */ if (!aligned) { chip->pagebuf = realpage; - memcpy(buf, chip->buffers.databuf + col, bytes); + memcpy(buf, chip->buffers->databuf + col, bytes); } buf += bytes; @@ -1024,7 +1024,7 @@ static int nand_do_read_ops(struct mtd_info *mtd, loff_t from, nand_wait_ready(mtd); } } else { - memcpy(buf, chip->buffers.databuf + col, bytes); + memcpy(buf, chip->buffers->databuf + col, bytes); buf += bytes; } @@ -1267,7 +1267,7 @@ static int nand_do_read_oob(struct mtd_info *mtd, loff_t from, realpage = (int)(from >> chip->page_shift); page = realpage & chip->pagemask; - chip->oob_poi = chip->buffers.oobrbuf; + chip->oob_poi = chip->buffers->oobrbuf; while(1) { sndcmd = chip->ecc.read_oob(mtd, chip, page, sndcmd); @@ -1392,7 +1392,7 @@ static void nand_write_page_swecc(struct mtd_info *mtd, struct nand_chip *chip, int i, eccsize = chip->ecc.size; int eccbytes = chip->ecc.bytes; int eccsteps = chip->ecc.steps; - uint8_t *ecc_calc = chip->buffers.ecccalc; + uint8_t *ecc_calc = chip->buffers->ecccalc; const uint8_t *p = buf; int *eccpos = chip->ecc.layout->eccpos; @@ -1418,7 +1418,7 @@ static void nand_write_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip, int i, eccsize = chip->ecc.size; int eccbytes = chip->ecc.bytes; int eccsteps = chip->ecc.steps; - uint8_t *ecc_calc = chip->buffers.ecccalc; + uint8_t *ecc_calc = chip->buffers->ecccalc; const uint8_t *p = buf; int *eccpos = chip->ecc.layout->eccpos; @@ -1628,7 +1628,7 @@ static int nand_do_write_ops(struct mtd_info *mtd, loff_t to, (chip->pagebuf << chip->page_shift) < (to + ops->len)) chip->pagebuf = -1; - chip->oob_poi = chip->buffers.oobwbuf; + chip->oob_poi = chip->buffers->oobwbuf; while(1) { int cached = writelen > bytes && page != blockmask; @@ -1746,7 +1746,7 @@ static int nand_do_write_oob(struct mtd_info *mtd, loff_t to, if (page == chip->pagebuf) chip->pagebuf = -1; - chip->oob_poi = chip->buffers.oobwbuf; + chip->oob_poi = chip->buffers->oobwbuf; memset(chip->oob_poi, 0xff, mtd->oobsize); nand_fill_oob(chip, ops->oobbuf, ops); status = chip->ecc.write_oob(mtd, chip, page & chip->pagemask); @@ -2354,8 +2354,13 @@ int nand_scan_tail(struct mtd_info *mtd) int i; struct nand_chip *chip = mtd->priv; + if (!(chip->options & NAND_OWN_BUFFERS)) + chip->buffers = kmalloc(sizeof(*chip->buffers), GFP_KERNEL); + if (!chip->buffers) + return -ENOMEM; + /* Preset the internal oob write buffer */ - memset(chip->buffers.oobwbuf, 0xff, mtd->oobsize); + memset(chip->buffers->oobwbuf, 0xff, mtd->oobsize); /* * If no default placement scheme is given, select an appropriate one @@ -2559,6 +2564,8 @@ void nand_release(struct mtd_info *mtd) /* Free bad block table memory */ kfree(chip->bbt); + if (!(chip->options & NAND_OWN_BUFFERS)) + kfree(chip->buffers); } EXPORT_SYMBOL_GPL(nand_scan); diff --git a/drivers/mtd/nand/nand_bbt.c b/drivers/mtd/nand/nand_bbt.c index a612c4ea8194..9402653eb09b 100644 --- a/drivers/mtd/nand/nand_bbt.c +++ b/drivers/mtd/nand/nand_bbt.c @@ -759,7 +759,7 @@ static inline int nand_memory_bbt(struct mtd_info *mtd, struct nand_bbt_descr *b struct nand_chip *this = mtd->priv; bd->options &= ~NAND_BBT_SCANEMPTY; - return create_bbt(mtd, this->buffers.databuf, bd, -1); + return create_bbt(mtd, this->buffers->databuf, bd, -1); } /** diff --git a/include/linux/mtd/nand.h b/include/linux/mtd/nand.h index 88d690d79d77..cd4fe9ae8622 100644 --- a/include/linux/mtd/nand.h +++ b/include/linux/mtd/nand.h @@ -183,7 +183,9 @@ typedef enum { #define NAND_USE_FLASH_BBT 0x00010000 /* This option skips the bbt scan during initialization. */ #define NAND_SKIP_BBTSCAN 0x00020000 - +/* This option is defined if the board driver allocates its own buffers + (e.g. because it needs them DMA-coherent */ +#define NAND_OWN_BUFFERS 0x00040000 /* Options set by nand scan */ /* Nand scan has allocated controller struct */ #define NAND_CONTROLLER_ALLOC 0x80000000 @@ -385,7 +387,7 @@ struct nand_chip { struct nand_ecclayout *ecclayout; struct nand_ecc_ctrl ecc; - struct nand_buffers buffers; + struct nand_buffers *buffers; struct nand_hw_control hwcontrol; struct mtd_oob_ops ops; -- cgit v1.2.3 From 956e944c7690ea994757a8cbedbb6241e1d9138f Mon Sep 17 00:00:00 2001 From: David Woodhouse Date: Mon, 25 Sep 2006 17:12:39 +0100 Subject: [MTD NAND] Allow override of page read and write functions. - allow high-level nand_write_page() function to be overridden - likewise low-level write_page_raw() and read_page_raw() functions - Clean up the abuse of chip->ecc.{write,read}_page() with MTD_OOB_RAW Signed-off-by: David Woodhouse --- drivers/mtd/nand/nand_base.c | 44 +++++++++++++++++++++----------------------- include/linux/mtd/nand.h | 11 +++++++++++ 2 files changed, 32 insertions(+), 23 deletions(-) (limited to 'include/linux') diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c index e1e81a9543e8..baece61169f4 100644 --- a/drivers/mtd/nand/nand_base.c +++ b/drivers/mtd/nand/nand_base.c @@ -990,7 +990,10 @@ static int nand_do_read_ops(struct mtd_info *mtd, loff_t from, } /* Now read the page into the buffer */ - ret = chip->ecc.read_page(mtd, chip, bufpoi); + if (unlikely(ops->mode == MTD_OOB_RAW)) + ret = chip->ecc.read_page_raw(mtd, chip, bufpoi); + else + ret = chip->ecc.read_page(mtd, chip, bufpoi); if (ret < 0) break; @@ -1323,8 +1326,6 @@ static int nand_do_read_oob(struct mtd_info *mtd, loff_t from, static int nand_read_oob(struct mtd_info *mtd, loff_t from, struct mtd_oob_ops *ops) { - int (*read_page)(struct mtd_info *mtd, struct nand_chip *chip, - uint8_t *buf) = NULL; struct nand_chip *chip = mtd->priv; int ret = -ENOTSUPP; @@ -1342,12 +1343,7 @@ static int nand_read_oob(struct mtd_info *mtd, loff_t from, switch(ops->mode) { case MTD_OOB_PLACE: case MTD_OOB_AUTO: - break; - case MTD_OOB_RAW: - /* Replace the read_page algorithm temporary */ - read_page = chip->ecc.read_page; - chip->ecc.read_page = nand_read_page_raw; break; default: @@ -1359,8 +1355,6 @@ static int nand_read_oob(struct mtd_info *mtd, loff_t from, else ret = nand_do_read_ops(mtd, from, ops); - if (unlikely(ops->mode == MTD_OOB_RAW)) - chip->ecc.read_page = read_page; out: nand_release_device(mtd); return ret; @@ -1479,7 +1473,7 @@ static void nand_write_page_syndrome(struct mtd_info *mtd, } /** - * nand_write_page - [INTERNAL] write one page + * nand_write_page - [REPLACEABLE] write one page * @mtd: MTD device structure * @chip: NAND chip descriptor * @buf: the data to write @@ -1487,13 +1481,16 @@ static void nand_write_page_syndrome(struct mtd_info *mtd, * @cached: cached programming */ static int nand_write_page(struct mtd_info *mtd, struct nand_chip *chip, - const uint8_t *buf, int page, int cached) + const uint8_t *buf, int page, int cached, int raw) { int status; chip->cmdfunc(mtd, NAND_CMD_SEQIN, 0x00, page); - chip->ecc.write_page(mtd, chip, buf); + if (unlikely(raw)) + chip->ecc.write_page_raw(mtd, chip, buf); + else + chip->ecc.write_page(mtd, chip, buf); /* * Cached progamming disabled for now, Not sure if its worth the @@ -1636,7 +1633,8 @@ static int nand_do_write_ops(struct mtd_info *mtd, loff_t to, if (unlikely(oob)) oob = nand_fill_oob(chip, oob, ops); - ret = nand_write_page(mtd, chip, buf, page, cached); + ret = chip->write_page(mtd, chip, buf, page, cached, + (ops->mode == MTD_OOB_RAW)); if (ret) break; @@ -1769,8 +1767,6 @@ static int nand_do_write_oob(struct mtd_info *mtd, loff_t to, static int nand_write_oob(struct mtd_info *mtd, loff_t to, struct mtd_oob_ops *ops) { - void (*write_page)(struct mtd_info *mtd, struct nand_chip *chip, - const uint8_t *buf) = NULL; struct nand_chip *chip = mtd->priv; int ret = -ENOTSUPP; @@ -1788,12 +1784,7 @@ static int nand_write_oob(struct mtd_info *mtd, loff_t to, switch(ops->mode) { case MTD_OOB_PLACE: case MTD_OOB_AUTO: - break; - case MTD_OOB_RAW: - /* Replace the write_page algorithm temporary */ - write_page = chip->ecc.write_page; - chip->ecc.write_page = nand_write_page_raw; break; default: @@ -1805,8 +1796,6 @@ static int nand_write_oob(struct mtd_info *mtd, loff_t to, else ret = nand_do_write_ops(mtd, to, ops); - if (unlikely(ops->mode == MTD_OOB_RAW)) - chip->ecc.write_page = write_page; out: nand_release_device(mtd); return ret; @@ -2383,10 +2372,18 @@ int nand_scan_tail(struct mtd_info *mtd) } } + if (!chip->write_page) + chip->write_page = nand_write_page; + /* * check ECC mode, default to software if 3byte/512byte hardware ECC is * selected and we have 256 byte pagesize fallback to software ECC */ + if (!chip->ecc.read_page_raw) + chip->ecc.read_page_raw = nand_read_page_raw; + if (!chip->ecc.write_page_raw) + chip->ecc.write_page_raw = nand_write_page_raw; + switch (chip->ecc.mode) { case NAND_ECC_HW: /* Use standard hwecc read page function ? */ @@ -2444,6 +2441,7 @@ int nand_scan_tail(struct mtd_info *mtd) chip->ecc.size = mtd->writesize; chip->ecc.bytes = 0; break; + default: printk(KERN_WARNING "Invalid NAND_ECC_MODE %d\n", chip->ecc.mode); diff --git a/include/linux/mtd/nand.h b/include/linux/mtd/nand.h index cd4fe9ae8622..2bcbcc896835 100644 --- a/include/linux/mtd/nand.h +++ b/include/linux/mtd/nand.h @@ -235,6 +235,8 @@ struct nand_hw_control { * be provided if an hardware ECC is available * @calculate: function for ecc calculation or readback from ecc hardware * @correct: function for ecc correction, matching to ecc generator (sw/hw) + * @read_page_raw: function to read a raw page without ECC + * @write_page_raw: function to write a raw page without ECC * @read_page: function to read a page according to the ecc generator requirements * @write_page: function to write a page according to the ecc generator requirements * @read_oob: function to read chip OOB data @@ -256,6 +258,12 @@ struct nand_ecc_ctrl { int (*correct)(struct mtd_info *mtd, uint8_t *dat, uint8_t *read_ecc, uint8_t *calc_ecc); + int (*read_page_raw)(struct mtd_info *mtd, + struct nand_chip *chip, + uint8_t *buf); + void (*write_page_raw)(struct mtd_info *mtd, + struct nand_chip *chip, + const uint8_t *buf); int (*read_page)(struct mtd_info *mtd, struct nand_chip *chip, uint8_t *buf); @@ -344,6 +352,7 @@ struct nand_buffers { * @priv: [OPTIONAL] pointer to private chip date * @errstat: [OPTIONAL] hardware specific function to perform additional error status checks * (determine if errors are correctable) + * @write_page [REPLACEABLE] High-level page write function */ struct nand_chip { @@ -366,6 +375,8 @@ struct nand_chip { void (*erase_cmd)(struct mtd_info *mtd, int page); int (*scan_bbt)(struct mtd_info *mtd); int (*errstat)(struct mtd_info *mtd, struct nand_chip *this, int state, int status, int page); + int (*write_page)(struct mtd_info *mtd, struct nand_chip *chip, + const uint8_t *buf, int page, int cached, int raw); int chip_delay; unsigned int options; -- cgit v1.2.3 From b77d95c78fb0ec330cd53e0d297ffa4fd2975e32 Mon Sep 17 00:00:00 2001 From: David Woodhouse Date: Mon, 25 Sep 2006 21:58:50 +0100 Subject: [MTD NAND] Provide prototype for newly-exported nand_wait_ready() Signed-off-by: David Woodhouse --- include/linux/mtd/nand.h | 3 +++ 1 file changed, 3 insertions(+) (limited to 'include/linux') diff --git a/include/linux/mtd/nand.h b/include/linux/mtd/nand.h index 2bcbcc896835..70420bbae82b 100644 --- a/include/linux/mtd/nand.h +++ b/include/linux/mtd/nand.h @@ -35,6 +35,9 @@ extern int nand_scan_tail(struct mtd_info *mtd); /* Free resources held by the NAND device */ extern void nand_release (struct mtd_info *mtd); +/* Internal helper for board drivers which need to override command function */ +extern void nand_wait_ready(struct mtd_info *mtd); + /* The maximum number of NAND chips in an array */ #define NAND_MAX_CHIPS 8 -- cgit v1.2.3 From 28b79ff9661b22e4c41c0d00d4ab8503e810f13d Mon Sep 17 00:00:00 2001 From: Kyungmin Park Date: Tue, 26 Sep 2006 09:45:28 +0000 Subject: [MTD ONENAND] Check OneNAND lock scheme & all block unlock command support OneNAND lock scheme depends on density and process of chip. Some OneNAND chips support all block unlock Signed-off-by: Kyungmin Park Signed-off-by: David Woodhouse --- drivers/mtd/onenand/onenand_base.c | 137 ++++++++++++++++++++++++++++++++----- include/linux/mtd/onenand.h | 6 +- include/linux/mtd/onenand_regs.h | 4 +- 3 files changed, 125 insertions(+), 22 deletions(-) (limited to 'include/linux') diff --git a/drivers/mtd/onenand/onenand_base.c b/drivers/mtd/onenand/onenand_base.c index 09aefe2164aa..8ed68b28afe3 100644 --- a/drivers/mtd/onenand/onenand_base.c +++ b/drivers/mtd/onenand/onenand_base.c @@ -1,7 +1,7 @@ /* * linux/drivers/mtd/onenand/onenand_base.c * - * Copyright (C) 2005 Samsung Electronics + * Copyright (C) 2005-2006 Samsung Electronics * Kyungmin Park * * This program is free software; you can redistribute it and/or modify @@ -199,6 +199,7 @@ static int onenand_command(struct mtd_info *mtd, int cmd, loff_t addr, size_t le case ONENAND_CMD_UNLOCK: case ONENAND_CMD_LOCK: case ONENAND_CMD_LOCK_TIGHT: + case ONENAND_CMD_UNLOCK_ALL: block = -1; page = -1; break; @@ -1211,11 +1212,11 @@ static int onenand_unlock(struct mtd_info *mtd, loff_t ofs, size_t len) end = len >> this->erase_shift; /* Continuous lock scheme */ - if (this->options & ONENAND_CONT_LOCK) { + if (this->options & ONENAND_HAS_CONT_LOCK) { /* Set start block address */ this->write_word(start, this->base + ONENAND_REG_START_BLOCK_ADDRESS); /* Set end block address */ - this->write_word(end - 1, this->base + ONENAND_REG_END_BLOCK_ADDRESS); + this->write_word(start + end - 1, this->base + ONENAND_REG_END_BLOCK_ADDRESS); /* Write unlock command */ this->command(mtd, ONENAND_CMD_UNLOCK, 0, 0); @@ -1236,7 +1237,7 @@ static int onenand_unlock(struct mtd_info *mtd, loff_t ofs, size_t len) } /* Block lock scheme */ - for (block = start; block < end; block++) { + for (block = start; block < start + end; block++) { /* Set block address */ value = onenand_block_address(this, block); this->write_word(value, this->base + ONENAND_REG_START_ADDRESS1); @@ -1265,6 +1266,79 @@ static int onenand_unlock(struct mtd_info *mtd, loff_t ofs, size_t len) return 0; } +/** + * onenand_check_lock_status - [OneNAND Interface] Check lock status + * @param this onenand chip data structure + * + * Check lock status + */ +static void onenand_check_lock_status(struct onenand_chip *this) +{ + unsigned int value, block, status; + unsigned int end; + + end = this->chipsize >> this->erase_shift; + for (block = 0; block < end; block++) { + /* Set block address */ + value = onenand_block_address(this, block); + this->write_word(value, this->base + ONENAND_REG_START_ADDRESS1); + /* Select DataRAM for DDP */ + value = onenand_bufferram_address(this, block); + this->write_word(value, this->base + ONENAND_REG_START_ADDRESS2); + /* Set start block address */ + this->write_word(block, this->base + ONENAND_REG_START_BLOCK_ADDRESS); + + /* Check lock status */ + status = this->read_word(this->base + ONENAND_REG_WP_STATUS); + if (!(status & ONENAND_WP_US)) + printk(KERN_ERR "block = %d, wp status = 0x%x\n", block, status); + } +} + +/** + * onenand_unlock_all - [OneNAND Interface] unlock all blocks + * @param mtd MTD device structure + * + * Unlock all blocks + */ +static int onenand_unlock_all(struct mtd_info *mtd) +{ + struct onenand_chip *this = mtd->priv; + + if (this->options & ONENAND_HAS_UNLOCK_ALL) { + /* Write unlock command */ + this->command(mtd, ONENAND_CMD_UNLOCK_ALL, 0, 0); + + /* There's no return value */ + this->wait(mtd, FL_UNLOCKING); + + /* Sanity check */ + while (this->read_word(this->base + ONENAND_REG_CTRL_STATUS) + & ONENAND_CTRL_ONGO) + continue; + + /* Workaround for all block unlock in DDP */ + if (this->device_id & ONENAND_DEVICE_IS_DDP) { + loff_t ofs; + size_t len; + + /* 1st block on another chip */ + ofs = this->chipsize >> 1; + len = 1 << this->erase_shift; + + onenand_unlock(mtd, ofs, len); + } + + onenand_check_lock_status(this); + + return 0; + } + + mtd->unlock(mtd, 0x0, this->chipsize); + + return 0; +} + #ifdef CONFIG_MTD_ONENAND_OTP /* Interal OTP operation */ @@ -1563,13 +1637,44 @@ static int onenand_lock_user_prot_reg(struct mtd_info *mtd, loff_t from, } #endif /* CONFIG_MTD_ONENAND_OTP */ +/** + * onenand_lock_scheme - Check and set OneNAND lock scheme + * @param mtd MTD data structure + * + * Check and set OneNAND lock scheme + */ +static void onenand_lock_scheme(struct mtd_info *mtd) +{ + struct onenand_chip *this = mtd->priv; + unsigned int density, process; + + /* Lock scheme depends on density and process */ + density = this->device_id >> ONENAND_DEVICE_DENSITY_SHIFT; + process = this->version_id >> ONENAND_VERSION_PROCESS_SHIFT; + + /* Lock scheme */ + if (density >= ONENAND_DEVICE_DENSITY_1Gb) { + /* A-Die has all block unlock */ + if (process) { + printk(KERN_DEBUG "Chip support all block unlock\n"); + this->options |= ONENAND_HAS_UNLOCK_ALL; + } + } else { + /* Some OneNAND has continues lock scheme */ + if (!process) { + printk(KERN_DEBUG "Lock scheme is Continues Lock\n"); + this->options |= ONENAND_HAS_CONT_LOCK; + } + } +} + /** * onenand_print_device_info - Print device ID * @param device device ID * * Print device ID */ -static void onenand_print_device_info(int device) +static void onenand_print_device_info(int device, int version) { int vcc, demuxed, ddp, density; @@ -1583,6 +1688,7 @@ static void onenand_print_device_info(int device) (16 << density), vcc ? "2.65/3.3" : "1.8", device); + printk(KERN_DEBUG "OneNAND version = 0x%04x\n", version); } static const struct onenand_manufacturers onenand_manuf_ids[] = { @@ -1625,8 +1731,7 @@ static int onenand_check_maf(int manuf) static int onenand_probe(struct mtd_info *mtd) { struct onenand_chip *this = mtd->priv; - int bram_maf_id, bram_dev_id, maf_id, dev_id; - int version_id; + int bram_maf_id, bram_dev_id, maf_id, dev_id, ver_id; int density; int syscfg; @@ -1657,14 +1762,16 @@ static int onenand_probe(struct mtd_info *mtd) /* Read manufacturer and device IDs from Register */ maf_id = this->read_word(this->base + ONENAND_REG_MANUFACTURER_ID); dev_id = this->read_word(this->base + ONENAND_REG_DEVICE_ID); + ver_id= this->read_word(this->base + ONENAND_REG_VERSION_ID); /* Check OneNAND device */ if (maf_id != bram_maf_id || dev_id != bram_dev_id) return -ENXIO; /* Flash device information */ - onenand_print_device_info(dev_id); + onenand_print_device_info(dev_id, ver_id); this->device_id = dev_id; + this->version_id = ver_id; density = dev_id >> ONENAND_DEVICE_DENSITY_SHIFT; this->chipsize = (16 << density) << 20; @@ -1687,16 +1794,8 @@ static int onenand_probe(struct mtd_info *mtd) mtd->size = this->chipsize; - /* Version ID */ - version_id = this->read_word(this->base + ONENAND_REG_VERSION_ID); - printk(KERN_DEBUG "OneNAND version = 0x%04x\n", version_id); - - /* Lock scheme */ - if (density <= ONENAND_DEVICE_DENSITY_512Mb && - !(version_id >> ONENAND_VERSION_PROCESS_SHIFT)) { - printk(KERN_INFO "Lock scheme is Continues Lock\n"); - this->options |= ONENAND_CONT_LOCK; - } + /* Check OneNAND lock scheme */ + onenand_lock_scheme(mtd); return 0; } @@ -1832,7 +1931,7 @@ int onenand_scan(struct mtd_info *mtd, int maxchips) mtd->owner = THIS_MODULE; /* Unlock whole block */ - mtd->unlock(mtd, 0x0, this->chipsize); + onenand_unlock_all(mtd); return this->scan_bbt(mtd); } diff --git a/include/linux/mtd/onenand.h b/include/linux/mtd/onenand.h index 1f4972155249..6f045b586e76 100644 --- a/include/linux/mtd/onenand.h +++ b/include/linux/mtd/onenand.h @@ -1,7 +1,7 @@ /* * linux/include/linux/mtd/onenand.h * - * Copyright (C) 2005 Samsung Electronics + * Copyright (C) 2005-2006 Samsung Electronics * Kyungmin Park * * This program is free software; you can redistribute it and/or modify @@ -96,6 +96,7 @@ struct onenand_chip { void __iomem *base; unsigned int chipsize; unsigned int device_id; + unsigned int version_id; unsigned int density_mask; unsigned int options; @@ -149,7 +150,8 @@ struct onenand_chip { /* * Options bits */ -#define ONENAND_CONT_LOCK (0x0001) +#define ONENAND_HAS_CONT_LOCK (0x0001) +#define ONENAND_HAS_UNLOCK_ALL (0x0002) #define ONENAND_PAGEBUF_ALLOC (0x1000) /* diff --git a/include/linux/mtd/onenand_regs.h b/include/linux/mtd/onenand_regs.h index 4a72818d2545..9e409fe6ded6 100644 --- a/include/linux/mtd/onenand_regs.h +++ b/include/linux/mtd/onenand_regs.h @@ -3,7 +3,7 @@ * * OneNAND Register header file * - * Copyright (C) 2005 Samsung Electronics + * Copyright (C) 2005-2006 Samsung Electronics * * 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 @@ -72,6 +72,7 @@ #define ONENAND_DEVICE_VCC_MASK (0x3) #define ONENAND_DEVICE_DENSITY_512Mb (0x002) +#define ONENAND_DEVICE_DENSITY_1Gb (0x003) /* * Version ID Register F002h (R) @@ -110,6 +111,7 @@ #define ONENAND_CMD_UNLOCK (0x23) #define ONENAND_CMD_LOCK (0x2A) #define ONENAND_CMD_LOCK_TIGHT (0x2C) +#define ONENAND_CMD_UNLOCK_ALL (0x27) #define ONENAND_CMD_ERASE (0x94) #define ONENAND_CMD_RESET (0xF0) #define ONENAND_CMD_OTP_ACCESS (0x65) -- cgit v1.2.3