X-Git-Url: https://git.karo-electronics.de/?a=blobdiff_plain;f=drivers%2Fmtd%2Fnand%2Fnand_base.c;h=29090c6d48199894ee3f7425e1bdc931cda03605;hb=7dcdcbef5d2b60d1db68fd2c07351f7afd8ad376;hp=c8cbc00243fece8bd9da98ef160e76d89e57b8ea;hpb=d96299537e43681942ea272e00b0e529aa5b5fa4;p=karo-tx-linux.git diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c index c8cbc00243fe..29090c6d4819 100644 --- a/drivers/mtd/nand/nand_base.c +++ b/drivers/mtd/nand/nand_base.c @@ -415,7 +415,7 @@ static int nand_block_checkbad(struct mtd_info *mtd, loff_t ofs, int getchip, * Wait for the ready pin, after a command * The timeout is catched later. */ -static void nand_wait_ready(struct mtd_info *mtd) +void nand_wait_ready(struct mtd_info *mtd) { struct nand_chip *chip = mtd->priv; unsigned long timeo = jiffies + 2; @@ -429,6 +429,7 @@ static void nand_wait_ready(struct mtd_info *mtd) } while (time_before(jiffies, timeo)); led_trigger_event(nand_led_trigger, LED_OFF); } +EXPORT_SYMBOL_GPL(nand_wait_ready); /** * nand_command - [DEFAULT] Send command to NAND device @@ -754,7 +755,7 @@ static int nand_read_page_raw(struct mtd_info *mtd, struct nand_chip *chip, } /** - * nand_read_page_swecc - {REPLACABLE] software ecc based page read function + * nand_read_page_swecc - [REPLACABLE] software ecc based page read function * @mtd: mtd info structure * @chip: nand chip info structure * @buf: buffer to store read data @@ -766,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); @@ -794,7 +795,7 @@ static int nand_read_page_swecc(struct mtd_info *mtd, struct nand_chip *chip, } /** - * nand_read_page_hwecc - {REPLACABLE] hardware ecc based page read function + * nand_read_page_hwecc - [REPLACABLE] hardware ecc based page read function * @mtd: mtd info structure * @chip: nand chip info structure * @buf: buffer to store read data @@ -808,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) { @@ -838,7 +839,7 @@ static int nand_read_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip, } /** - * nand_read_page_syndrome - {REPLACABLE] hardware ecc syndrom based page read + * nand_read_page_syndrome - [REPLACABLE] hardware ecc syndrom based page read * @mtd: mtd info structure * @chip: nand chip info structure * @buf: buffer to store read data @@ -970,7 +971,6 @@ 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; buf = ops->datbuf; oob = ops->oobbuf; @@ -981,7 +981,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); @@ -989,14 +989,17 @@ 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; /* 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; @@ -1023,7 +1026,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; } @@ -1204,7 +1207,7 @@ static int nand_write_oob_syndrome(struct mtd_info *mtd, pos = steps * (eccsize + chunk); steps = 0; } else - pos = eccsize + chunk; + pos = eccsize; chip->cmdfunc(mtd, NAND_CMD_SEQIN, pos, page); for (i = 0; i < steps; i++) { @@ -1266,8 +1269,6 @@ 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; - while(1) { sndcmd = chip->ecc.read_oob(mtd, chip, page, sndcmd); buf = nand_transfer_oob(chip, buf, ops); @@ -1322,8 +1323,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; @@ -1341,12 +1340,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: @@ -1358,8 +1352,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; @@ -1380,7 +1372,7 @@ static void nand_write_page_raw(struct mtd_info *mtd, struct nand_chip *chip, } /** - * nand_write_page_swecc - {REPLACABLE] software ecc based page write function + * nand_write_page_swecc - [REPLACABLE] software ecc based page write function * @mtd: mtd info structure * @chip: nand chip info structure * @buf: data buffer @@ -1391,7 +1383,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; @@ -1406,7 +1398,7 @@ static void nand_write_page_swecc(struct mtd_info *mtd, struct nand_chip *chip, } /** - * nand_write_page_hwecc - {REPLACABLE] hardware ecc based page write function + * nand_write_page_hwecc - [REPLACABLE] hardware ecc based page write function * @mtd: mtd info structure * @chip: nand chip info structure * @buf: data buffer @@ -1417,7 +1409,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; @@ -1434,7 +1426,7 @@ static void nand_write_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip, } /** - * nand_write_page_syndrome - {REPLACABLE] hardware ecc syndrom based page write + * nand_write_page_syndrome - [REPLACABLE] hardware ecc syndrom based page write * @mtd: mtd info structure * @chip: nand chip info structure * @buf: data buffer @@ -1478,7 +1470,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 @@ -1486,13 +1478,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 @@ -1567,7 +1562,7 @@ static uint8_t *nand_fill_oob(struct nand_chip *chip, uint8_t *oob, bytes = min_t(size_t, len, free->length); boffs = free->offset; } - memcpy(chip->oob_poi + woffs, oob, bytes); + memcpy(chip->oob_poi + boffs, oob, bytes); oob += bytes; } return oob; @@ -1627,7 +1622,9 @@ 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; + /* If we're not given explicit OOB data, let it be 0xFF */ + if (likely(!oob)) + memset(chip->oob_poi, 0xff, mtd->oobsize); while(1) { int cached = writelen > bytes && page != blockmask; @@ -1635,7 +1632,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; @@ -1655,9 +1653,6 @@ static int nand_do_write_ops(struct mtd_info *mtd, loff_t to, } } - if (unlikely(oob)) - memset(chip->oob_poi, 0xff, mtd->oobsize); - ops->retlen = ops->len - writelen; return ret; } @@ -1745,7 +1740,6 @@ 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; memset(chip->oob_poi, 0xff, mtd->oobsize); nand_fill_oob(chip, ops->oobbuf, ops); status = chip->ecc.write_oob(mtd, chip, page & chip->pagemask); @@ -1768,8 +1762,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; @@ -1787,12 +1779,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: @@ -1804,8 +1791,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; @@ -2224,7 +2209,7 @@ static struct nand_flash_dev *nand_get_flash_type(struct mtd_info *mtd, } /* Try to identify manufacturer */ - for (maf_idx = 0; nand_manuf_ids[maf_idx].id != 0x0; maf_id++) { + for (maf_idx = 0; nand_manuf_ids[maf_idx].id != 0x0; maf_idx++) { if (nand_manuf_ids[maf_idx].id == *maf_id) break; } @@ -2288,40 +2273,22 @@ static struct nand_flash_dev *nand_get_flash_type(struct mtd_info *mtd, return type; } -/* module_text_address() isn't exported, and it's mostly a pointless - test if this is a module _anyway_ -- they'd have to try _really_ hard - to call us from in-kernel code if the core NAND support is modular. */ -#ifdef MODULE -#define caller_is_module() (1) -#else -#define caller_is_module() \ - module_text_address((unsigned long)__builtin_return_address(0)) -#endif - /** - * nand_scan - [NAND Interface] Scan for the NAND device - * @mtd: MTD device structure - * @maxchips: Number of chips to scan for + * nand_scan_ident - [NAND Interface] Scan for the NAND device + * @mtd: MTD device structure + * @maxchips: Number of chips to scan for * - * This fills out all the uninitialized function pointers - * with the defaults. - * The flash ID is read and the mtd/chip structures are - * filled with the appropriate values. - * The mtd->owner field must be set to the module of the caller + * This is the first phase of the normal nand_scan() function. It + * reads the flash ID and sets up MTD fields accordingly. * + * The mtd->owner field must be set to the module of the caller. */ -int nand_scan(struct mtd_info *mtd, int maxchips) +int nand_scan_ident(struct mtd_info *mtd, int maxchips) { int i, busw, nand_maf_id; struct nand_chip *chip = mtd->priv; struct nand_flash_dev *type; - /* Many callers got this wrong, so check for it for a while... */ - if (!mtd->owner && caller_is_module()) { - printk(KERN_CRIT "nand_scan() called with NULL mtd->owner!\n"); - BUG(); - } - /* Get buswidth to select the correct functions */ busw = chip->options & NAND_BUSWIDTH_16; /* Set the default functions */ @@ -2353,8 +2320,31 @@ int nand_scan(struct mtd_info *mtd, int maxchips) chip->numchips = i; mtd->size = i * chip->chipsize; - /* Preset the internal oob write buffer */ - memset(chip->buffers.oobwbuf, 0xff, mtd->oobsize); + return 0; +} + + +/** + * nand_scan_tail - [NAND Interface] Scan for the NAND device + * @mtd: MTD device structure + * @maxchips: Number of chips to scan for + * + * This is the second phase of the normal nand_scan() function. It + * fills out all the uninitialized function pointers with the defaults + * and scans for a bad block table if appropriate. + */ +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; + + /* Set the internal oob buffer location, just after the page data */ + chip->oob_poi = chip->buffers + mtd->writesize; /* * If no default placement scheme is given, select an appropriate one @@ -2377,10 +2367,18 @@ int nand_scan(struct mtd_info *mtd, int maxchips) } } + 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 ? */ @@ -2438,6 +2436,7 @@ int nand_scan(struct mtd_info *mtd, int maxchips) chip->ecc.size = mtd->writesize; chip->ecc.bytes = 0; break; + default: printk(KERN_WARNING "Invalid NAND_ECC_MODE %d\n", chip->ecc.mode); @@ -2503,6 +2502,44 @@ int nand_scan(struct mtd_info *mtd, int maxchips) return chip->scan_bbt(mtd); } +/* module_text_address() isn't exported, and it's mostly a pointless + test if this is a module _anyway_ -- they'd have to try _really_ hard + to call us from in-kernel code if the core NAND support is modular. */ +#ifdef MODULE +#define caller_is_module() (1) +#else +#define caller_is_module() \ + module_text_address((unsigned long)__builtin_return_address(0)) +#endif + +/** + * nand_scan - [NAND Interface] Scan for the NAND device + * @mtd: MTD device structure + * @maxchips: Number of chips to scan for + * + * This fills out all the uninitialized function pointers + * with the defaults. + * The flash ID is read and the mtd/chip structures are + * filled with the appropriate values. + * The mtd->owner field must be set to the module of the caller + * + */ +int nand_scan(struct mtd_info *mtd, int maxchips) +{ + int ret; + + /* Many callers got this wrong, so check for it for a while... */ + if (!mtd->owner && caller_is_module()) { + printk(KERN_CRIT "nand_scan() called with NULL mtd->owner!\n"); + BUG(); + } + + ret = nand_scan_ident(mtd, maxchips); + if (!ret) + ret = nand_scan_tail(mtd); + return ret; +} + /** * nand_release - [NAND Interface] Free resources held by the NAND device * @mtd: MTD device structure @@ -2520,9 +2557,13 @@ 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); +EXPORT_SYMBOL_GPL(nand_scan_ident); +EXPORT_SYMBOL_GPL(nand_scan_tail); EXPORT_SYMBOL_GPL(nand_release); static int __init nand_base_init(void)