2005-08-17 19:55:25 +09:00
|
|
|
/*
|
|
|
|
* drivers/mtd/nand.c
|
|
|
|
*
|
|
|
|
* Overview:
|
|
|
|
* This is the generic MTD driver for NAND flash devices. It should be
|
|
|
|
* capable of working with almost all NAND chips currently available.
|
2005-09-15 06:53:32 +09:00
|
|
|
*
|
2005-08-17 19:55:25 +09:00
|
|
|
* Additional technical information is available on
|
2008-10-25 06:20:43 +09:00
|
|
|
* http://www.linux-mtd.infradead.org/doc/nand.html
|
2005-09-15 06:53:32 +09:00
|
|
|
*
|
2005-08-17 19:55:25 +09:00
|
|
|
* Copyright (C) 2000 Steven J. Hill (sjhill@realitydiluted.com)
|
2007-10-31 21:53:06 +09:00
|
|
|
* 2002-2006 Thomas Gleixner (tglx@linutronix.de)
|
2005-08-17 19:55:25 +09:00
|
|
|
*
|
2007-10-31 21:53:06 +09:00
|
|
|
* Credits:
|
2005-09-15 06:53:32 +09:00
|
|
|
* David Woodhouse for adding multichip support
|
|
|
|
*
|
2005-08-17 19:55:25 +09:00
|
|
|
* Aleph One Ltd. and Toby Churchill Ltd. for supporting the
|
|
|
|
* rework for 2K page size chips
|
|
|
|
*
|
2007-10-31 21:53:06 +09:00
|
|
|
* TODO:
|
2005-08-17 19:55:25 +09:00
|
|
|
* Enable cached programming for 2k page size chips
|
|
|
|
* Check, if mtd->ecctype should be set to MTD_ECC_HW
|
2013-01-14 12:46:50 +09:00
|
|
|
* if we have HW ECC support.
|
2008-10-25 06:20:43 +09:00
|
|
|
* BBT table is not serialized, has to be fixed
|
2005-08-17 19:55:25 +09:00
|
|
|
*
|
|
|
|
* 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.
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
|
2014-06-24 17:10:04 +09:00
|
|
|
#ifndef __UBOOT__
|
|
|
|
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
|
2007-10-31 21:53:06 +09:00
|
|
|
|
2014-06-24 17:10:04 +09:00
|
|
|
#include <linux/module.h>
|
|
|
|
#include <linux/delay.h>
|
|
|
|
#include <linux/errno.h>
|
|
|
|
#include <linux/err.h>
|
|
|
|
#include <linux/sched.h>
|
|
|
|
#include <linux/slab.h>
|
|
|
|
#include <linux/types.h>
|
|
|
|
#include <linux/mtd/mtd.h>
|
|
|
|
#include <linux/mtd/nand.h>
|
|
|
|
#include <linux/mtd/nand_ecc.h>
|
|
|
|
#include <linux/mtd/nand_bch.h>
|
|
|
|
#include <linux/interrupt.h>
|
|
|
|
#include <linux/bitops.h>
|
|
|
|
#include <linux/leds.h>
|
|
|
|
#include <linux/io.h>
|
|
|
|
#include <linux/mtd/partitions.h>
|
|
|
|
#else
|
|
|
|
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
|
|
|
|
#include <common.h>
|
2005-08-17 19:55:25 +09:00
|
|
|
#include <malloc.h>
|
|
|
|
#include <watchdog.h>
|
2007-10-31 21:53:06 +09:00
|
|
|
#include <linux/err.h>
|
2012-04-09 22:39:55 +09:00
|
|
|
#include <linux/compat.h>
|
2005-08-17 19:55:25 +09:00
|
|
|
#include <linux/mtd/mtd.h>
|
|
|
|
#include <linux/mtd/nand.h>
|
|
|
|
#include <linux/mtd/nand_ecc.h>
|
2011-10-12 16:31:59 +09:00
|
|
|
#include <linux/mtd/nand_bch.h>
|
2009-04-24 22:58:33 +09:00
|
|
|
#ifdef CONFIG_MTD_PARTITIONS
|
|
|
|
#include <linux/mtd/partitions.h>
|
|
|
|
#endif
|
2005-08-17 19:55:25 +09:00
|
|
|
#include <asm/io.h>
|
|
|
|
#include <asm/errno.h>
|
|
|
|
|
2009-02-05 04:47:22 +09:00
|
|
|
/*
|
|
|
|
* CONFIG_SYS_NAND_RESET_CNT is used as a timeout mechanism when resetting
|
|
|
|
* a flash. NAND flash is initialized prior to interrupts so standard timers
|
|
|
|
* can't be used. CONFIG_SYS_NAND_RESET_CNT should be set to a value
|
|
|
|
* which is greater than (max NAND reset time / NAND status read time).
|
|
|
|
* A conservative default of 200000 (500 us / 25 ns) is used as a default.
|
|
|
|
*/
|
|
|
|
#ifndef CONFIG_SYS_NAND_RESET_CNT
|
|
|
|
#define CONFIG_SYS_NAND_RESET_CNT 200000
|
|
|
|
#endif
|
|
|
|
|
2014-06-24 17:10:04 +09:00
|
|
|
static bool is_module_text_address(unsigned long addr) {return 0;}
|
|
|
|
#endif
|
|
|
|
|
2005-08-17 19:55:25 +09:00
|
|
|
/* Define default oob placement schemes for large and small page devices */
|
2007-10-31 21:53:06 +09:00
|
|
|
static struct nand_ecclayout nand_oob_8 = {
|
2005-08-17 19:55:25 +09:00
|
|
|
.eccbytes = 3,
|
|
|
|
.eccpos = {0, 1, 2},
|
2007-10-31 21:53:06 +09:00
|
|
|
.oobfree = {
|
|
|
|
{.offset = 3,
|
|
|
|
.length = 2},
|
|
|
|
{.offset = 6,
|
2011-10-12 16:32:01 +09:00
|
|
|
.length = 2} }
|
2005-08-17 19:55:25 +09:00
|
|
|
};
|
|
|
|
|
2007-10-31 21:53:06 +09:00
|
|
|
static struct nand_ecclayout nand_oob_16 = {
|
2005-08-17 19:55:25 +09:00
|
|
|
.eccbytes = 6,
|
|
|
|
.eccpos = {0, 1, 2, 3, 6, 7},
|
2007-10-31 21:53:06 +09:00
|
|
|
.oobfree = {
|
|
|
|
{.offset = 8,
|
2011-10-12 16:32:01 +09:00
|
|
|
. length = 8} }
|
2005-08-17 19:55:25 +09:00
|
|
|
};
|
|
|
|
|
2007-10-31 21:53:06 +09:00
|
|
|
static struct nand_ecclayout nand_oob_64 = {
|
2005-08-17 19:55:25 +09:00
|
|
|
.eccbytes = 24,
|
|
|
|
.eccpos = {
|
2007-10-31 21:53:06 +09:00
|
|
|
40, 41, 42, 43, 44, 45, 46, 47,
|
|
|
|
48, 49, 50, 51, 52, 53, 54, 55,
|
|
|
|
56, 57, 58, 59, 60, 61, 62, 63},
|
|
|
|
.oobfree = {
|
|
|
|
{.offset = 2,
|
2011-10-12 16:32:01 +09:00
|
|
|
.length = 38} }
|
2005-08-17 19:55:25 +09:00
|
|
|
};
|
|
|
|
|
2007-10-31 21:53:06 +09:00
|
|
|
static struct nand_ecclayout nand_oob_128 = {
|
2008-06-06 22:42:43 +09:00
|
|
|
.eccbytes = 48,
|
|
|
|
.eccpos = {
|
2011-10-12 16:32:01 +09:00
|
|
|
80, 81, 82, 83, 84, 85, 86, 87,
|
|
|
|
88, 89, 90, 91, 92, 93, 94, 95,
|
|
|
|
96, 97, 98, 99, 100, 101, 102, 103,
|
2007-10-31 21:53:06 +09:00
|
|
|
104, 105, 106, 107, 108, 109, 110, 111,
|
|
|
|
112, 113, 114, 115, 116, 117, 118, 119,
|
|
|
|
120, 121, 122, 123, 124, 125, 126, 127},
|
|
|
|
.oobfree = {
|
|
|
|
{.offset = 2,
|
2011-10-12 16:32:01 +09:00
|
|
|
.length = 78} }
|
2005-08-17 19:55:25 +09:00
|
|
|
};
|
|
|
|
|
2014-06-24 17:10:04 +09:00
|
|
|
static int nand_get_device(struct mtd_info *mtd, int new_state);
|
2007-10-31 21:53:06 +09:00
|
|
|
|
|
|
|
static int nand_do_write_oob(struct mtd_info *mtd, loff_t to,
|
|
|
|
struct mtd_oob_ops *ops);
|
|
|
|
|
2014-06-24 17:10:04 +09:00
|
|
|
/*
|
|
|
|
* For devices which display every fart in the system on a separate LED. Is
|
|
|
|
* compiled away when LED support is disabled.
|
|
|
|
*/
|
|
|
|
DEFINE_LED_TRIGGER(nand_led_trigger);
|
2008-06-06 22:42:43 +09:00
|
|
|
|
2011-10-12 16:32:02 +09:00
|
|
|
static int check_offs_len(struct mtd_info *mtd,
|
|
|
|
loff_t ofs, uint64_t len)
|
|
|
|
{
|
|
|
|
struct nand_chip *chip = mtd->priv;
|
|
|
|
int ret = 0;
|
|
|
|
|
|
|
|
/* Start address must align on block boundary */
|
2014-06-24 17:10:04 +09:00
|
|
|
if (ofs & ((1ULL << chip->phys_erase_shift) - 1)) {
|
|
|
|
pr_debug("%s: unaligned address\n", __func__);
|
2011-10-12 16:32:02 +09:00
|
|
|
ret = -EINVAL;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Length must align on block boundary */
|
2014-06-24 17:10:04 +09:00
|
|
|
if (len & ((1ULL << chip->phys_erase_shift) - 1)) {
|
|
|
|
pr_debug("%s: length not block aligned\n", __func__);
|
2011-10-12 16:32:02 +09:00
|
|
|
ret = -EINVAL;
|
|
|
|
}
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2005-08-17 19:55:25 +09:00
|
|
|
/**
|
|
|
|
* nand_release_device - [GENERIC] release chip
|
2013-01-14 12:46:50 +09:00
|
|
|
* @mtd: MTD device structure
|
2005-09-15 06:53:32 +09:00
|
|
|
*
|
2014-06-24 17:10:04 +09:00
|
|
|
* Release chip lock and wake up anyone waiting on the device.
|
2005-08-17 19:55:25 +09:00
|
|
|
*/
|
2011-10-12 16:32:01 +09:00
|
|
|
static void nand_release_device(struct mtd_info *mtd)
|
2005-11-02 22:29:12 +09:00
|
|
|
{
|
2011-10-12 16:32:02 +09:00
|
|
|
struct nand_chip *chip = mtd->priv;
|
|
|
|
|
2014-06-24 17:10:04 +09:00
|
|
|
#ifndef __UBOOT__
|
|
|
|
/* Release the controller and the chip */
|
|
|
|
spin_lock(&chip->controller->lock);
|
|
|
|
chip->controller->active = NULL;
|
|
|
|
chip->state = FL_READY;
|
|
|
|
wake_up(&chip->controller->wq);
|
|
|
|
spin_unlock(&chip->controller->lock);
|
|
|
|
#else
|
2011-10-12 16:32:02 +09:00
|
|
|
/* De-select the NAND device */
|
|
|
|
chip->select_chip(mtd, -1);
|
2014-06-24 17:10:04 +09:00
|
|
|
#endif
|
2005-11-02 22:29:12 +09:00
|
|
|
}
|
2005-08-17 19:55:25 +09:00
|
|
|
|
|
|
|
/**
|
|
|
|
* nand_read_byte - [DEFAULT] read one byte from the chip
|
2013-01-14 12:46:50 +09:00
|
|
|
* @mtd: MTD device structure
|
2005-08-17 19:55:25 +09:00
|
|
|
*
|
2014-06-24 17:10:04 +09:00
|
|
|
* Default read function for 8bit buswidth
|
2005-08-17 19:55:25 +09:00
|
|
|
*/
|
2014-06-24 17:10:04 +09:00
|
|
|
#ifndef __UBOOT__
|
|
|
|
static uint8_t nand_read_byte(struct mtd_info *mtd)
|
|
|
|
#else
|
2011-10-31 15:34:44 +09:00
|
|
|
uint8_t nand_read_byte(struct mtd_info *mtd)
|
2014-06-24 17:10:04 +09:00
|
|
|
#endif
|
2005-08-17 19:55:25 +09:00
|
|
|
{
|
2007-10-31 21:53:06 +09:00
|
|
|
struct nand_chip *chip = mtd->priv;
|
|
|
|
return readb(chip->IO_ADDR_R);
|
2005-08-17 19:55:25 +09:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2014-06-24 17:10:04 +09:00
|
|
|
* nand_read_byte16 - [DEFAULT] read one byte endianness aware from the chip
|
2013-01-14 12:46:50 +09:00
|
|
|
* nand_read_byte16 - [DEFAULT] read one byte endianness aware from the chip
|
|
|
|
* @mtd: MTD device structure
|
|
|
|
*
|
|
|
|
* Default read function for 16bit buswidth with endianness conversion.
|
2005-08-17 19:55:25 +09:00
|
|
|
*
|
|
|
|
*/
|
2007-10-31 21:53:06 +09:00
|
|
|
static uint8_t nand_read_byte16(struct mtd_info *mtd)
|
2005-08-17 19:55:25 +09:00
|
|
|
{
|
2007-10-31 21:53:06 +09:00
|
|
|
struct nand_chip *chip = mtd->priv;
|
|
|
|
return (uint8_t) cpu_to_le16(readw(chip->IO_ADDR_R));
|
2005-08-17 19:55:25 +09:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* nand_read_word - [DEFAULT] read one word from the chip
|
2013-01-14 12:46:50 +09:00
|
|
|
* @mtd: MTD device structure
|
2005-08-17 19:55:25 +09:00
|
|
|
*
|
2013-01-14 12:46:50 +09:00
|
|
|
* Default read function for 16bit buswidth without endianness conversion.
|
2005-08-17 19:55:25 +09:00
|
|
|
*/
|
|
|
|
static u16 nand_read_word(struct mtd_info *mtd)
|
|
|
|
{
|
2007-10-31 21:53:06 +09:00
|
|
|
struct nand_chip *chip = mtd->priv;
|
|
|
|
return readw(chip->IO_ADDR_R);
|
2005-08-17 19:55:25 +09:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* nand_select_chip - [DEFAULT] control CE line
|
2013-01-14 12:46:50 +09:00
|
|
|
* @mtd: MTD device structure
|
|
|
|
* @chipnr: chipnumber to select, -1 for deselect
|
2005-08-17 19:55:25 +09:00
|
|
|
*
|
|
|
|
* Default select function for 1 chip devices.
|
|
|
|
*/
|
2007-10-31 21:53:06 +09:00
|
|
|
static void nand_select_chip(struct mtd_info *mtd, int chipnr)
|
2005-08-17 19:55:25 +09:00
|
|
|
{
|
2007-10-31 21:53:06 +09:00
|
|
|
struct nand_chip *chip = mtd->priv;
|
|
|
|
|
|
|
|
switch (chipnr) {
|
2005-08-17 19:55:25 +09:00
|
|
|
case -1:
|
2007-10-31 21:53:06 +09:00
|
|
|
chip->cmd_ctrl(mtd, NAND_CMD_NONE, 0 | NAND_CTRL_CHANGE);
|
2005-08-17 19:55:25 +09:00
|
|
|
break;
|
|
|
|
case 0:
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
BUG();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-06-24 17:10:04 +09:00
|
|
|
/**
|
|
|
|
* nand_write_byte - [DEFAULT] write single byte to chip
|
|
|
|
* @mtd: MTD device structure
|
|
|
|
* @byte: value to write
|
|
|
|
*
|
|
|
|
* Default function to write a byte to I/O[7:0]
|
|
|
|
*/
|
|
|
|
static void nand_write_byte(struct mtd_info *mtd, uint8_t byte)
|
|
|
|
{
|
|
|
|
struct nand_chip *chip = mtd->priv;
|
|
|
|
|
|
|
|
chip->write_buf(mtd, &byte, 1);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* nand_write_byte16 - [DEFAULT] write single byte to a chip with width 16
|
|
|
|
* @mtd: MTD device structure
|
|
|
|
* @byte: value to write
|
|
|
|
*
|
|
|
|
* Default function to write a byte to I/O[7:0] on a 16-bit wide chip.
|
|
|
|
*/
|
|
|
|
static void nand_write_byte16(struct mtd_info *mtd, uint8_t byte)
|
|
|
|
{
|
|
|
|
struct nand_chip *chip = mtd->priv;
|
|
|
|
uint16_t word = byte;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* It's not entirely clear what should happen to I/O[15:8] when writing
|
|
|
|
* a byte. The ONFi spec (Revision 3.1; 2012-09-19, Section 2.16) reads:
|
|
|
|
*
|
|
|
|
* When the host supports a 16-bit bus width, only data is
|
|
|
|
* transferred at the 16-bit width. All address and command line
|
|
|
|
* transfers shall use only the lower 8-bits of the data bus. During
|
|
|
|
* command transfers, the host may place any value on the upper
|
|
|
|
* 8-bits of the data bus. During address transfers, the host shall
|
|
|
|
* set the upper 8-bits of the data bus to 00h.
|
|
|
|
*
|
|
|
|
* One user of the write_byte callback is nand_onfi_set_features. The
|
|
|
|
* four parameters are specified to be written to I/O[7:0], but this is
|
|
|
|
* neither an address nor a command transfer. Let's assume a 0 on the
|
|
|
|
* upper I/O lines is OK.
|
|
|
|
*/
|
|
|
|
chip->write_buf(mtd, (uint8_t *)&word, 2);
|
|
|
|
}
|
|
|
|
|
|
|
|
#if defined(__UBOOT__) && !defined(CONFIG_BLACKFIN)
|
|
|
|
static void iowrite8_rep(void *addr, const uint8_t *buf, int len)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
|
|
|
|
for (i = 0; i < len; i++)
|
|
|
|
writeb(buf[i], addr);
|
|
|
|
}
|
|
|
|
static void ioread8_rep(void *addr, uint8_t *buf, int len)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
|
|
|
|
for (i = 0; i < len; i++)
|
|
|
|
buf[i] = readb(addr);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void ioread16_rep(void *addr, void *buf, int len)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
u16 *p = (u16 *) buf;
|
2014-09-05 16:57:01 +09:00
|
|
|
|
2014-06-24 17:10:04 +09:00
|
|
|
for (i = 0; i < len; i++)
|
|
|
|
p[i] = readw(addr);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void iowrite16_rep(void *addr, void *buf, int len)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
u16 *p = (u16 *) buf;
|
|
|
|
|
|
|
|
for (i = 0; i < len; i++)
|
|
|
|
writew(p[i], addr);
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2005-08-17 19:55:25 +09:00
|
|
|
/**
|
|
|
|
* nand_write_buf - [DEFAULT] write buffer to chip
|
2013-01-14 12:46:50 +09:00
|
|
|
* @mtd: MTD device structure
|
|
|
|
* @buf: data buffer
|
|
|
|
* @len: number of bytes to write
|
2005-08-17 19:55:25 +09:00
|
|
|
*
|
2013-01-14 12:46:50 +09:00
|
|
|
* Default write function for 8bit buswidth.
|
2005-08-17 19:55:25 +09:00
|
|
|
*/
|
2014-06-24 17:10:04 +09:00
|
|
|
#ifndef __UBOOT__
|
|
|
|
static void nand_write_buf(struct mtd_info *mtd, const uint8_t *buf, int len)
|
|
|
|
#else
|
2011-10-31 15:34:44 +09:00
|
|
|
void nand_write_buf(struct mtd_info *mtd, const uint8_t *buf, int len)
|
2014-06-24 17:10:04 +09:00
|
|
|
#endif
|
2005-08-17 19:55:25 +09:00
|
|
|
{
|
2007-10-31 21:53:06 +09:00
|
|
|
struct nand_chip *chip = mtd->priv;
|
2005-08-17 19:55:25 +09:00
|
|
|
|
2014-06-24 17:10:04 +09:00
|
|
|
iowrite8_rep(chip->IO_ADDR_W, buf, len);
|
2005-08-17 19:55:25 +09:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2005-09-15 06:53:32 +09:00
|
|
|
* nand_read_buf - [DEFAULT] read chip data into buffer
|
2013-01-14 12:46:50 +09:00
|
|
|
* @mtd: MTD device structure
|
|
|
|
* @buf: buffer to store date
|
|
|
|
* @len: number of bytes to read
|
2005-08-17 19:55:25 +09:00
|
|
|
*
|
2013-01-14 12:46:50 +09:00
|
|
|
* Default read function for 8bit buswidth.
|
2005-08-17 19:55:25 +09:00
|
|
|
*/
|
2014-06-24 17:10:04 +09:00
|
|
|
#ifndef __UBOOT__
|
|
|
|
static void nand_read_buf(struct mtd_info *mtd, uint8_t *buf, int len)
|
|
|
|
#else
|
2011-09-15 04:30:16 +09:00
|
|
|
void nand_read_buf(struct mtd_info *mtd, uint8_t *buf, int len)
|
2014-06-24 17:10:04 +09:00
|
|
|
#endif
|
2005-08-17 19:55:25 +09:00
|
|
|
{
|
2007-10-31 21:53:06 +09:00
|
|
|
struct nand_chip *chip = mtd->priv;
|
2005-08-17 19:55:25 +09:00
|
|
|
|
2014-06-24 17:10:04 +09:00
|
|
|
ioread8_rep(chip->IO_ADDR_R, buf, len);
|
2005-08-17 19:55:25 +09:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2014-06-24 17:10:04 +09:00
|
|
|
* nand_write_buf16 - [DEFAULT] write buffer to chip
|
2013-01-14 12:46:50 +09:00
|
|
|
* @mtd: MTD device structure
|
2014-06-24 17:10:04 +09:00
|
|
|
* @buf: data buffer
|
|
|
|
* @len: number of bytes to write
|
2005-08-17 19:55:25 +09:00
|
|
|
*
|
2014-06-24 17:10:04 +09:00
|
|
|
* Default write function for 16bit buswidth.
|
2005-08-17 19:55:25 +09:00
|
|
|
*/
|
2014-06-24 17:10:04 +09:00
|
|
|
#ifndef __UBOOT__
|
|
|
|
static void nand_write_buf16(struct mtd_info *mtd, const uint8_t *buf, int len)
|
|
|
|
#else
|
|
|
|
void nand_write_buf16(struct mtd_info *mtd, const uint8_t *buf, int len)
|
|
|
|
#endif
|
2005-08-17 19:55:25 +09:00
|
|
|
{
|
2007-10-31 21:53:06 +09:00
|
|
|
struct nand_chip *chip = mtd->priv;
|
2005-08-17 19:55:25 +09:00
|
|
|
u16 *p = (u16 *) buf;
|
|
|
|
|
2014-06-24 17:10:04 +09:00
|
|
|
iowrite16_rep(chip->IO_ADDR_W, p, len >> 1);
|
2005-08-17 19:55:25 +09:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2014-06-24 17:10:04 +09:00
|
|
|
* nand_read_buf16 - [DEFAULT] read chip data into buffer
|
2013-01-14 12:46:50 +09:00
|
|
|
* @mtd: MTD device structure
|
2014-06-24 17:10:04 +09:00
|
|
|
* @buf: buffer to store date
|
|
|
|
* @len: number of bytes to read
|
2005-08-17 19:55:25 +09:00
|
|
|
*
|
2014-06-24 17:10:04 +09:00
|
|
|
* Default read function for 16bit buswidth.
|
2005-08-17 19:55:25 +09:00
|
|
|
*/
|
2014-06-24 17:10:04 +09:00
|
|
|
#ifndef __UBOOT__
|
|
|
|
static void nand_read_buf16(struct mtd_info *mtd, uint8_t *buf, int len)
|
|
|
|
#else
|
|
|
|
void nand_read_buf16(struct mtd_info *mtd, uint8_t *buf, int len)
|
|
|
|
#endif
|
2005-08-17 19:55:25 +09:00
|
|
|
{
|
2007-10-31 21:53:06 +09:00
|
|
|
struct nand_chip *chip = mtd->priv;
|
2005-08-17 19:55:25 +09:00
|
|
|
u16 *p = (u16 *) buf;
|
|
|
|
|
2014-06-24 17:10:04 +09:00
|
|
|
ioread16_rep(chip->IO_ADDR_R, p, len >> 1);
|
2005-08-17 19:55:25 +09:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* nand_block_bad - [DEFAULT] Read bad block marker from the chip
|
2013-01-14 12:46:50 +09:00
|
|
|
* @mtd: MTD device structure
|
|
|
|
* @ofs: offset from device start
|
|
|
|
* @getchip: 0, if the chip is already selected
|
2005-08-17 19:55:25 +09:00
|
|
|
*
|
2005-09-15 06:53:32 +09:00
|
|
|
* Check, if the block is bad.
|
2005-08-17 19:55:25 +09:00
|
|
|
*/
|
|
|
|
static int nand_block_bad(struct mtd_info *mtd, loff_t ofs, int getchip)
|
|
|
|
{
|
2013-01-14 12:46:50 +09:00
|
|
|
int page, chipnr, res = 0, i = 0;
|
2007-10-31 21:53:06 +09:00
|
|
|
struct nand_chip *chip = mtd->priv;
|
2005-08-17 19:55:25 +09:00
|
|
|
u16 bad;
|
|
|
|
|
2013-01-14 12:46:50 +09:00
|
|
|
if (chip->bbt_options & NAND_BBT_SCANLASTPAGE)
|
2011-10-12 16:32:02 +09:00
|
|
|
ofs += mtd->erasesize - mtd->writesize;
|
|
|
|
|
2007-10-31 21:53:06 +09:00
|
|
|
page = (int)(ofs >> chip->page_shift) & chip->pagemask;
|
2007-05-05 14:04:42 +09:00
|
|
|
|
2005-08-17 19:55:25 +09:00
|
|
|
if (getchip) {
|
2007-10-31 21:53:06 +09:00
|
|
|
chipnr = (int)(ofs >> chip->chip_shift);
|
2005-08-17 19:55:25 +09:00
|
|
|
|
2014-06-24 17:10:04 +09:00
|
|
|
nand_get_device(mtd, FL_READING);
|
2005-08-17 19:55:25 +09:00
|
|
|
|
|
|
|
/* Select the NAND device */
|
2007-10-31 21:53:06 +09:00
|
|
|
chip->select_chip(mtd, chipnr);
|
2007-05-05 14:04:42 +09:00
|
|
|
}
|
2005-08-17 19:55:25 +09:00
|
|
|
|
2013-01-14 12:46:50 +09:00
|
|
|
do {
|
|
|
|
if (chip->options & NAND_BUSWIDTH_16) {
|
|
|
|
chip->cmdfunc(mtd, NAND_CMD_READOOB,
|
|
|
|
chip->badblockpos & 0xFE, page);
|
|
|
|
bad = cpu_to_le16(chip->read_word(mtd));
|
|
|
|
if (chip->badblockpos & 0x1)
|
|
|
|
bad >>= 8;
|
|
|
|
else
|
|
|
|
bad &= 0xFF;
|
|
|
|
} else {
|
|
|
|
chip->cmdfunc(mtd, NAND_CMD_READOOB, chip->badblockpos,
|
|
|
|
page);
|
|
|
|
bad = chip->read_byte(mtd);
|
|
|
|
}
|
2005-09-15 06:53:32 +09:00
|
|
|
|
2013-01-14 12:46:50 +09:00
|
|
|
if (likely(chip->badblockbits == 8))
|
|
|
|
res = bad != 0xFF;
|
|
|
|
else
|
|
|
|
res = hweight8(bad) < chip->badblockbits;
|
|
|
|
ofs += mtd->writesize;
|
|
|
|
page = (int)(ofs >> chip->page_shift) & chip->pagemask;
|
|
|
|
i++;
|
|
|
|
} while (!res && i < 2 && (chip->bbt_options & NAND_BBT_SCAN2NDPAGE));
|
2011-10-12 16:32:02 +09:00
|
|
|
|
2014-06-24 17:10:04 +09:00
|
|
|
if (getchip) {
|
|
|
|
chip->select_chip(mtd, -1);
|
2005-08-17 19:55:25 +09:00
|
|
|
nand_release_device(mtd);
|
2014-06-24 17:10:04 +09:00
|
|
|
}
|
2005-09-15 06:53:32 +09:00
|
|
|
|
2005-08-17 19:55:25 +09:00
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2014-06-24 17:10:04 +09:00
|
|
|
* nand_default_block_markbad - [DEFAULT] mark a block bad via bad block marker
|
2013-01-14 12:46:50 +09:00
|
|
|
* @mtd: MTD device structure
|
|
|
|
* @ofs: offset from device start
|
2005-08-17 19:55:25 +09:00
|
|
|
*
|
2013-01-14 12:46:50 +09:00
|
|
|
* This is the default implementation, which can be overridden by a hardware
|
2014-06-24 17:10:04 +09:00
|
|
|
* specific driver. It provides the details for writing a bad block marker to a
|
|
|
|
* block.
|
|
|
|
*/
|
|
|
|
static int nand_default_block_markbad(struct mtd_info *mtd, loff_t ofs)
|
|
|
|
{
|
|
|
|
struct nand_chip *chip = mtd->priv;
|
|
|
|
struct mtd_oob_ops ops;
|
|
|
|
uint8_t buf[2] = { 0, 0 };
|
|
|
|
int ret = 0, res, i = 0;
|
|
|
|
|
|
|
|
ops.datbuf = NULL;
|
|
|
|
ops.oobbuf = buf;
|
|
|
|
ops.ooboffs = chip->badblockpos;
|
|
|
|
if (chip->options & NAND_BUSWIDTH_16) {
|
|
|
|
ops.ooboffs &= ~0x01;
|
|
|
|
ops.len = ops.ooblen = 2;
|
|
|
|
} else {
|
|
|
|
ops.len = ops.ooblen = 1;
|
|
|
|
}
|
|
|
|
ops.mode = MTD_OPS_PLACE_OOB;
|
|
|
|
|
|
|
|
/* Write to first/last page(s) if necessary */
|
|
|
|
if (chip->bbt_options & NAND_BBT_SCANLASTPAGE)
|
|
|
|
ofs += mtd->erasesize - mtd->writesize;
|
|
|
|
do {
|
|
|
|
res = nand_do_write_oob(mtd, ofs, &ops);
|
|
|
|
if (!ret)
|
|
|
|
ret = res;
|
|
|
|
|
|
|
|
i++;
|
|
|
|
ofs += mtd->writesize;
|
|
|
|
} while ((chip->bbt_options & NAND_BBT_SCAN2NDPAGE) && i < 2);
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* nand_block_markbad_lowlevel - mark a block bad
|
|
|
|
* @mtd: MTD device structure
|
|
|
|
* @ofs: offset from device start
|
|
|
|
*
|
|
|
|
* This function performs the generic NAND bad block marking steps (i.e., bad
|
|
|
|
* block table(s) and/or marker(s)). We only allow the hardware driver to
|
|
|
|
* specify how to write bad block markers to OOB (chip->block_markbad).
|
|
|
|
*
|
|
|
|
* We try operations in the following order:
|
2013-01-14 12:46:50 +09:00
|
|
|
* (1) erase the affected block, to allow OOB marker to be written cleanly
|
2014-06-24 17:10:04 +09:00
|
|
|
* (2) write bad block marker to OOB area of affected block (unless flag
|
|
|
|
* NAND_BBT_NO_OOB_BBM is present)
|
|
|
|
* (3) update the BBT
|
|
|
|
* Note that we retain the first error encountered in (2) or (3), finish the
|
2013-01-14 12:46:50 +09:00
|
|
|
* procedures, and dump the error in the end.
|
2005-08-17 19:55:25 +09:00
|
|
|
*/
|
2014-06-24 17:10:04 +09:00
|
|
|
static int nand_block_markbad_lowlevel(struct mtd_info *mtd, loff_t ofs)
|
2005-08-17 19:55:25 +09:00
|
|
|
{
|
2007-10-31 21:53:06 +09:00
|
|
|
struct nand_chip *chip = mtd->priv;
|
2014-06-24 17:10:04 +09:00
|
|
|
int res, ret = 0;
|
2011-10-12 16:32:02 +09:00
|
|
|
|
2014-06-24 17:10:04 +09:00
|
|
|
if (!(chip->bbt_options & NAND_BBT_NO_OOB_BBM)) {
|
2013-01-14 12:46:50 +09:00
|
|
|
struct erase_info einfo;
|
|
|
|
|
|
|
|
/* Attempt erase before marking OOB */
|
|
|
|
memset(&einfo, 0, sizeof(einfo));
|
|
|
|
einfo.mtd = mtd;
|
|
|
|
einfo.addr = ofs;
|
2014-06-24 17:10:04 +09:00
|
|
|
einfo.len = 1ULL << chip->phys_erase_shift;
|
2013-01-14 12:46:50 +09:00
|
|
|
nand_erase_nand(mtd, &einfo, 0);
|
2011-10-12 16:32:02 +09:00
|
|
|
|
2014-06-24 17:10:04 +09:00
|
|
|
/* Write bad block marker to OOB */
|
|
|
|
nand_get_device(mtd, FL_WRITING);
|
|
|
|
ret = chip->block_markbad(mtd, ofs);
|
2008-10-25 06:20:43 +09:00
|
|
|
nand_release_device(mtd);
|
2007-10-31 21:53:06 +09:00
|
|
|
}
|
2013-01-14 12:46:50 +09:00
|
|
|
|
2014-06-24 17:10:04 +09:00
|
|
|
/* Mark block bad in BBT */
|
|
|
|
if (chip->bbt) {
|
|
|
|
res = nand_markbad_bbt(mtd, ofs);
|
2013-01-14 12:46:50 +09:00
|
|
|
if (!ret)
|
|
|
|
ret = res;
|
|
|
|
}
|
|
|
|
|
2007-10-31 21:53:06 +09:00
|
|
|
if (!ret)
|
|
|
|
mtd->ecc_stats.badblocks++;
|
2008-10-25 06:20:43 +09:00
|
|
|
|
2007-10-31 21:53:06 +09:00
|
|
|
return ret;
|
2005-08-17 19:55:25 +09:00
|
|
|
}
|
|
|
|
|
2005-09-15 06:53:32 +09:00
|
|
|
/**
|
2005-08-17 19:55:25 +09:00
|
|
|
* nand_check_wp - [GENERIC] check if the chip is write protected
|
2013-01-14 12:46:50 +09:00
|
|
|
* @mtd: MTD device structure
|
2005-08-17 19:55:25 +09:00
|
|
|
*
|
2013-01-14 12:46:50 +09:00
|
|
|
* Check, if the device is write protected. The function expects, that the
|
|
|
|
* device is already selected.
|
2005-08-17 19:55:25 +09:00
|
|
|
*/
|
2007-10-31 21:53:06 +09:00
|
|
|
static int nand_check_wp(struct mtd_info *mtd)
|
2005-08-17 19:55:25 +09:00
|
|
|
{
|
2007-10-31 21:53:06 +09:00
|
|
|
struct nand_chip *chip = mtd->priv;
|
2011-10-12 16:32:02 +09:00
|
|
|
|
2013-01-14 12:46:50 +09:00
|
|
|
/* Broken xD cards report WP despite being writable */
|
2011-10-12 16:32:02 +09:00
|
|
|
if (chip->options & NAND_BROKEN_XD)
|
|
|
|
return 0;
|
|
|
|
|
2005-08-17 19:55:25 +09:00
|
|
|
/* Check the WP bit */
|
2007-10-31 21:53:06 +09:00
|
|
|
chip->cmdfunc(mtd, NAND_CMD_STATUS, -1, -1);
|
|
|
|
return (chip->read_byte(mtd) & NAND_STATUS_WP) ? 0 : 1;
|
2005-08-17 19:55:25 +09:00
|
|
|
}
|
2006-03-06 23:04:25 +09:00
|
|
|
|
2005-08-17 19:55:25 +09:00
|
|
|
/**
|
|
|
|
* nand_block_checkbad - [GENERIC] Check if a block is marked bad
|
2013-01-14 12:46:50 +09:00
|
|
|
* @mtd: MTD device structure
|
|
|
|
* @ofs: offset from device start
|
|
|
|
* @getchip: 0, if the chip is already selected
|
|
|
|
* @allowbbt: 1, if its allowed to access the bbt area
|
2005-08-17 19:55:25 +09:00
|
|
|
*
|
|
|
|
* Check, if the block is bad. Either by reading the bad block table or
|
|
|
|
* calling of the scan function.
|
|
|
|
*/
|
2007-10-31 21:53:06 +09:00
|
|
|
static int nand_block_checkbad(struct mtd_info *mtd, loff_t ofs, int getchip,
|
|
|
|
int allowbbt)
|
2005-08-17 19:55:25 +09:00
|
|
|
{
|
2007-10-31 21:53:06 +09:00
|
|
|
struct nand_chip *chip = mtd->priv;
|
2005-09-15 06:53:32 +09:00
|
|
|
|
2014-12-26 22:20:58 +09:00
|
|
|
if (!(chip->options & NAND_SKIP_BBTSCAN) &&
|
|
|
|
!(chip->options & NAND_BBT_SCANNED)) {
|
2014-10-22 20:40:44 +09:00
|
|
|
chip->options |= NAND_BBT_SCANNED;
|
2014-12-26 22:20:57 +09:00
|
|
|
chip->scan_bbt(mtd);
|
2014-10-22 20:40:44 +09:00
|
|
|
}
|
|
|
|
|
2007-10-31 21:53:06 +09:00
|
|
|
if (!chip->bbt)
|
|
|
|
return chip->block_bad(mtd, ofs, getchip);
|
2005-09-15 06:53:32 +09:00
|
|
|
|
2005-08-17 19:55:25 +09:00
|
|
|
/* Return info from the table */
|
2007-10-31 21:53:06 +09:00
|
|
|
return nand_isbad_bbt(mtd, ofs, allowbbt);
|
|
|
|
}
|
|
|
|
|
2014-06-24 17:10:04 +09:00
|
|
|
#ifndef __UBOOT__
|
|
|
|
/**
|
|
|
|
* panic_nand_wait_ready - [GENERIC] Wait for the ready pin after commands.
|
|
|
|
* @mtd: MTD device structure
|
|
|
|
* @timeo: Timeout
|
|
|
|
*
|
|
|
|
* Helper function for nand_wait_ready used when needing to wait in interrupt
|
|
|
|
* context.
|
|
|
|
*/
|
|
|
|
static void panic_nand_wait_ready(struct mtd_info *mtd, unsigned long timeo)
|
|
|
|
{
|
|
|
|
struct nand_chip *chip = mtd->priv;
|
|
|
|
int i;
|
|
|
|
|
|
|
|
/* Wait for the device to get ready */
|
|
|
|
for (i = 0; i < timeo; i++) {
|
|
|
|
if (chip->dev_ready(mtd))
|
|
|
|
break;
|
|
|
|
touch_softlockup_watchdog();
|
|
|
|
mdelay(1);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2013-01-14 12:46:50 +09:00
|
|
|
/* Wait for the ready pin, after a command. The timeout is caught later. */
|
2007-10-31 21:53:06 +09:00
|
|
|
void nand_wait_ready(struct mtd_info *mtd)
|
|
|
|
{
|
|
|
|
struct nand_chip *chip = mtd->priv;
|
2014-06-24 17:10:04 +09:00
|
|
|
#ifndef __UBOOT__
|
|
|
|
unsigned long timeo = jiffies + msecs_to_jiffies(20);
|
|
|
|
|
|
|
|
/* 400ms timeout */
|
|
|
|
if (in_interrupt() || oops_in_progress)
|
|
|
|
return panic_nand_wait_ready(mtd, 400);
|
|
|
|
|
|
|
|
led_trigger_event(nand_led_trigger, LED_FULL);
|
|
|
|
/* Wait until command is processed or timeout occurs */
|
|
|
|
do {
|
|
|
|
if (chip->dev_ready(mtd))
|
|
|
|
break;
|
|
|
|
touch_softlockup_watchdog();
|
|
|
|
} while (time_before(jiffies, timeo));
|
|
|
|
led_trigger_event(nand_led_trigger, LED_OFF);
|
|
|
|
#else
|
2008-10-16 22:01:15 +09:00
|
|
|
u32 timeo = (CONFIG_SYS_HZ * 20) / 1000;
|
2010-11-18 12:14:26 +09:00
|
|
|
u32 time_start;
|
2008-01-06 00:43:25 +09:00
|
|
|
|
2010-11-18 12:14:26 +09:00
|
|
|
time_start = get_timer(0);
|
2013-01-14 12:46:50 +09:00
|
|
|
/* Wait until command is processed or timeout occurs */
|
2010-11-18 12:14:26 +09:00
|
|
|
while (get_timer(time_start) < timeo) {
|
2008-01-06 00:43:25 +09:00
|
|
|
if (chip->dev_ready)
|
|
|
|
if (chip->dev_ready(mtd))
|
|
|
|
break;
|
|
|
|
}
|
2014-06-24 17:10:04 +09:00
|
|
|
#endif
|
2007-10-31 21:53:06 +09:00
|
|
|
}
|
2014-06-24 17:10:04 +09:00
|
|
|
EXPORT_SYMBOL_GPL(nand_wait_ready);
|
2005-08-17 19:55:25 +09:00
|
|
|
|
|
|
|
/**
|
|
|
|
* nand_command - [DEFAULT] Send command to NAND device
|
2013-01-14 12:46:50 +09:00
|
|
|
* @mtd: MTD device structure
|
|
|
|
* @command: the command to be sent
|
|
|
|
* @column: the column address for this command, -1 if none
|
|
|
|
* @page_addr: the page address for this command, -1 if none
|
2005-08-17 19:55:25 +09:00
|
|
|
*
|
2013-01-14 12:46:50 +09:00
|
|
|
* Send command to NAND device. This function is used for small page devices
|
2014-06-24 17:10:04 +09:00
|
|
|
* (512 Bytes per page).
|
2005-08-17 19:55:25 +09:00
|
|
|
*/
|
2007-10-31 21:53:06 +09:00
|
|
|
static void nand_command(struct mtd_info *mtd, unsigned int command,
|
|
|
|
int column, int page_addr)
|
2005-08-17 19:55:25 +09:00
|
|
|
{
|
2007-10-31 21:53:06 +09:00
|
|
|
register struct nand_chip *chip = mtd->priv;
|
|
|
|
int ctrl = NAND_CTRL_CLE | NAND_CTRL_CHANGE;
|
2009-02-05 04:47:22 +09:00
|
|
|
uint32_t rst_sts_cnt = CONFIG_SYS_NAND_RESET_CNT;
|
2005-08-17 19:55:25 +09:00
|
|
|
|
2013-01-14 12:46:50 +09:00
|
|
|
/* Write out the command to the device */
|
2005-08-17 19:55:25 +09:00
|
|
|
if (command == NAND_CMD_SEQIN) {
|
|
|
|
int readcmd;
|
|
|
|
|
2007-10-31 21:53:06 +09:00
|
|
|
if (column >= mtd->writesize) {
|
2005-08-17 19:55:25 +09:00
|
|
|
/* OOB area */
|
2007-10-31 21:53:06 +09:00
|
|
|
column -= mtd->writesize;
|
2005-08-17 19:55:25 +09:00
|
|
|
readcmd = NAND_CMD_READOOB;
|
|
|
|
} else if (column < 256) {
|
|
|
|
/* First 256 bytes --> READ0 */
|
|
|
|
readcmd = NAND_CMD_READ0;
|
|
|
|
} else {
|
|
|
|
column -= 256;
|
|
|
|
readcmd = NAND_CMD_READ1;
|
|
|
|
}
|
2007-10-31 21:53:06 +09:00
|
|
|
chip->cmd_ctrl(mtd, readcmd, ctrl);
|
|
|
|
ctrl &= ~NAND_CTRL_CHANGE;
|
2005-08-17 19:55:25 +09:00
|
|
|
}
|
2007-10-31 21:53:06 +09:00
|
|
|
chip->cmd_ctrl(mtd, command, ctrl);
|
2005-08-17 19:55:25 +09:00
|
|
|
|
2013-01-14 12:46:50 +09:00
|
|
|
/* Address cycle, when necessary */
|
2007-10-31 21:53:06 +09:00
|
|
|
ctrl = NAND_CTRL_ALE | NAND_CTRL_CHANGE;
|
|
|
|
/* Serially input address */
|
|
|
|
if (column != -1) {
|
|
|
|
/* Adjust columns for 16 bit buswidth */
|
2014-07-15 23:08:43 +09:00
|
|
|
if (chip->options & NAND_BUSWIDTH_16 &&
|
mtd: nand: force NAND_CMD_READID onto 8-bit bus
As per following Sections in ONFI Spec, NAND_CMD_READID should use only
lower 8-bit for transfering command, address and data even on x16 NAND device.
*Section: Target Initialization"
"The Read ID and Read Parameter Page commands only use the lower 8-bits of the
data bus. The host shall not issue commands that use a word data width on x16
devices until the host determines the device supports a 16-bit data bus width
in the parameter page."
*Section: Bus Width Requirements*
"When the host supports a 16-bit bus width, only data is transferred at the
16-bit width. All address and command line transfers shall use only the lower
8-bits of the data bus. During command transfers, the host may place any value
on the upper 8-bits of the data bus. During address transfers, the host shall
set the upper 8-bits of the data bus to 00h."
Thus porting following commit from linux-kernel to ensure that column address
is not altered to align to x16 bus when issuing NAND_CMD_READID command.
commit 3dad2344e92c6e1aeae42df1c4824f307c51bcc7
mtd: nand: force NAND_CMD_READID onto 8-bit bus
Author: Brian Norris <computersforpeace@gmail.com> (preserving authorship)
The NAND command helpers tend to automatically shift the column address
for x16 bus devices, since most commands expect a word address, not a
byte address. The Read ID command, however, expects an 8-bit address
(i.e., 0x00, 0x20, or 0x40 should not be translated to 0x00, 0x10, or
0x20).
This fixes the column address for a few drivers which imitate the
nand_base defaults.
Signed-off-by: Pekon Gupta <pekon@ti.com>
2014-05-06 04:16:17 +09:00
|
|
|
!nand_opcode_8bits(command))
|
2007-10-31 21:53:06 +09:00
|
|
|
column >>= 1;
|
|
|
|
chip->cmd_ctrl(mtd, column, ctrl);
|
|
|
|
ctrl &= ~NAND_CTRL_CHANGE;
|
2005-08-17 19:55:25 +09:00
|
|
|
}
|
2007-10-31 21:53:06 +09:00
|
|
|
if (page_addr != -1) {
|
|
|
|
chip->cmd_ctrl(mtd, page_addr, ctrl);
|
|
|
|
ctrl &= ~NAND_CTRL_CHANGE;
|
|
|
|
chip->cmd_ctrl(mtd, page_addr >> 8, ctrl);
|
|
|
|
/* One more address cycle for devices > 32MiB */
|
|
|
|
if (chip->chipsize > (32 << 20))
|
|
|
|
chip->cmd_ctrl(mtd, page_addr >> 16, ctrl);
|
|
|
|
}
|
|
|
|
chip->cmd_ctrl(mtd, NAND_CMD_NONE, NAND_NCE | NAND_CTRL_CHANGE);
|
2005-09-15 06:53:32 +09:00
|
|
|
|
|
|
|
/*
|
2013-01-14 12:46:50 +09:00
|
|
|
* Program and erase have their own busy handlers status and sequential
|
|
|
|
* in needs no delay
|
2007-10-31 21:53:06 +09:00
|
|
|
*/
|
2005-08-17 19:55:25 +09:00
|
|
|
switch (command) {
|
2005-09-15 06:53:32 +09:00
|
|
|
|
2005-08-17 19:55:25 +09:00
|
|
|
case NAND_CMD_PAGEPROG:
|
|
|
|
case NAND_CMD_ERASE1:
|
|
|
|
case NAND_CMD_ERASE2:
|
|
|
|
case NAND_CMD_SEQIN:
|
|
|
|
case NAND_CMD_STATUS:
|
|
|
|
return;
|
|
|
|
|
|
|
|
case NAND_CMD_RESET:
|
2007-10-31 21:53:06 +09:00
|
|
|
if (chip->dev_ready)
|
2005-08-17 19:55:25 +09:00
|
|
|
break;
|
2007-10-31 21:53:06 +09:00
|
|
|
udelay(chip->chip_delay);
|
|
|
|
chip->cmd_ctrl(mtd, NAND_CMD_STATUS,
|
|
|
|
NAND_CTRL_CLE | NAND_CTRL_CHANGE);
|
|
|
|
chip->cmd_ctrl(mtd,
|
|
|
|
NAND_CMD_NONE, NAND_NCE | NAND_CTRL_CHANGE);
|
2009-02-05 04:47:22 +09:00
|
|
|
while (!(chip->read_byte(mtd) & NAND_STATUS_READY) &&
|
|
|
|
(rst_sts_cnt--));
|
2005-08-17 19:55:25 +09:00
|
|
|
return;
|
|
|
|
|
2007-10-31 21:53:06 +09:00
|
|
|
/* This applies to read commands */
|
2005-08-17 19:55:25 +09:00
|
|
|
default:
|
2005-09-15 06:53:32 +09:00
|
|
|
/*
|
2005-08-17 19:55:25 +09:00
|
|
|
* If we don't have access to the busy pin, we apply the given
|
|
|
|
* command delay
|
2007-10-31 21:53:06 +09:00
|
|
|
*/
|
|
|
|
if (!chip->dev_ready) {
|
|
|
|
udelay(chip->chip_delay);
|
2005-08-17 19:55:25 +09:00
|
|
|
return;
|
2005-09-15 06:53:32 +09:00
|
|
|
}
|
2005-08-17 19:55:25 +09:00
|
|
|
}
|
2013-01-14 12:46:50 +09:00
|
|
|
/*
|
|
|
|
* Apply this short delay always to ensure that we do wait tWB in
|
|
|
|
* any case on any machine.
|
|
|
|
*/
|
2007-10-31 21:53:06 +09:00
|
|
|
ndelay(100);
|
|
|
|
|
|
|
|
nand_wait_ready(mtd);
|
2005-08-17 19:55:25 +09:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* nand_command_lp - [DEFAULT] Send command to NAND large page device
|
2013-01-14 12:46:50 +09:00
|
|
|
* @mtd: MTD device structure
|
|
|
|
* @command: the command to be sent
|
|
|
|
* @column: the column address for this command, -1 if none
|
|
|
|
* @page_addr: the page address for this command, -1 if none
|
2005-08-17 19:55:25 +09:00
|
|
|
*
|
2007-10-31 21:53:06 +09:00
|
|
|
* Send command to NAND device. This is the version for the new large page
|
2013-01-14 12:46:50 +09:00
|
|
|
* devices. We don't have the separate regions as we have in the small page
|
|
|
|
* devices. We must emulate NAND_CMD_READOOB to keep the code compatible.
|
2005-08-17 19:55:25 +09:00
|
|
|
*/
|
2007-10-31 21:53:06 +09:00
|
|
|
static void nand_command_lp(struct mtd_info *mtd, unsigned int command,
|
|
|
|
int column, int page_addr)
|
2005-08-17 19:55:25 +09:00
|
|
|
{
|
2007-10-31 21:53:06 +09:00
|
|
|
register struct nand_chip *chip = mtd->priv;
|
2009-02-05 04:47:22 +09:00
|
|
|
uint32_t rst_sts_cnt = CONFIG_SYS_NAND_RESET_CNT;
|
2005-08-17 19:55:25 +09:00
|
|
|
|
|
|
|
/* Emulate NAND_CMD_READOOB */
|
|
|
|
if (command == NAND_CMD_READOOB) {
|
2007-10-31 21:53:06 +09:00
|
|
|
column += mtd->writesize;
|
2005-08-17 19:55:25 +09:00
|
|
|
command = NAND_CMD_READ0;
|
|
|
|
}
|
2005-09-15 06:53:32 +09:00
|
|
|
|
2007-10-31 21:53:06 +09:00
|
|
|
/* Command latch cycle */
|
2014-06-24 17:10:04 +09:00
|
|
|
chip->cmd_ctrl(mtd, command, NAND_NCE | NAND_CLE | NAND_CTRL_CHANGE);
|
2005-08-17 19:55:25 +09:00
|
|
|
|
|
|
|
if (column != -1 || page_addr != -1) {
|
2007-10-31 21:53:06 +09:00
|
|
|
int ctrl = NAND_CTRL_CHANGE | NAND_NCE | NAND_ALE;
|
2005-08-17 19:55:25 +09:00
|
|
|
|
|
|
|
/* Serially input address */
|
|
|
|
if (column != -1) {
|
|
|
|
/* Adjust columns for 16 bit buswidth */
|
2014-07-15 23:08:43 +09:00
|
|
|
if (chip->options & NAND_BUSWIDTH_16 &&
|
mtd: nand: force NAND_CMD_READID onto 8-bit bus
As per following Sections in ONFI Spec, NAND_CMD_READID should use only
lower 8-bit for transfering command, address and data even on x16 NAND device.
*Section: Target Initialization"
"The Read ID and Read Parameter Page commands only use the lower 8-bits of the
data bus. The host shall not issue commands that use a word data width on x16
devices until the host determines the device supports a 16-bit data bus width
in the parameter page."
*Section: Bus Width Requirements*
"When the host supports a 16-bit bus width, only data is transferred at the
16-bit width. All address and command line transfers shall use only the lower
8-bits of the data bus. During command transfers, the host may place any value
on the upper 8-bits of the data bus. During address transfers, the host shall
set the upper 8-bits of the data bus to 00h."
Thus porting following commit from linux-kernel to ensure that column address
is not altered to align to x16 bus when issuing NAND_CMD_READID command.
commit 3dad2344e92c6e1aeae42df1c4824f307c51bcc7
mtd: nand: force NAND_CMD_READID onto 8-bit bus
Author: Brian Norris <computersforpeace@gmail.com> (preserving authorship)
The NAND command helpers tend to automatically shift the column address
for x16 bus devices, since most commands expect a word address, not a
byte address. The Read ID command, however, expects an 8-bit address
(i.e., 0x00, 0x20, or 0x40 should not be translated to 0x00, 0x10, or
0x20).
This fixes the column address for a few drivers which imitate the
nand_base defaults.
Signed-off-by: Pekon Gupta <pekon@ti.com>
2014-05-06 04:16:17 +09:00
|
|
|
!nand_opcode_8bits(command))
|
2005-08-17 19:55:25 +09:00
|
|
|
column >>= 1;
|
2007-10-31 21:53:06 +09:00
|
|
|
chip->cmd_ctrl(mtd, column, ctrl);
|
|
|
|
ctrl &= ~NAND_CTRL_CHANGE;
|
|
|
|
chip->cmd_ctrl(mtd, column >> 8, ctrl);
|
2005-09-15 06:53:32 +09:00
|
|
|
}
|
2005-08-17 19:55:25 +09:00
|
|
|
if (page_addr != -1) {
|
2007-10-31 21:53:06 +09:00
|
|
|
chip->cmd_ctrl(mtd, page_addr, ctrl);
|
|
|
|
chip->cmd_ctrl(mtd, page_addr >> 8,
|
|
|
|
NAND_NCE | NAND_ALE);
|
2005-08-17 19:55:25 +09:00
|
|
|
/* One more address cycle for devices > 128MiB */
|
2007-10-31 21:53:06 +09:00
|
|
|
if (chip->chipsize > (128 << 20))
|
|
|
|
chip->cmd_ctrl(mtd, page_addr >> 16,
|
|
|
|
NAND_NCE | NAND_ALE);
|
2005-08-17 19:55:25 +09:00
|
|
|
}
|
|
|
|
}
|
2007-10-31 21:53:06 +09:00
|
|
|
chip->cmd_ctrl(mtd, NAND_CMD_NONE, NAND_NCE | NAND_CTRL_CHANGE);
|
2005-09-15 06:53:32 +09:00
|
|
|
|
|
|
|
/*
|
2013-01-14 12:46:50 +09:00
|
|
|
* Program and erase have their own busy handlers status, sequential
|
|
|
|
* in, and deplete1 need no delay.
|
2007-10-31 21:53:06 +09:00
|
|
|
*/
|
2005-08-17 19:55:25 +09:00
|
|
|
switch (command) {
|
2005-09-15 06:53:32 +09:00
|
|
|
|
2005-08-17 19:55:25 +09:00
|
|
|
case NAND_CMD_CACHEDPROG:
|
|
|
|
case NAND_CMD_PAGEPROG:
|
|
|
|
case NAND_CMD_ERASE1:
|
|
|
|
case NAND_CMD_ERASE2:
|
|
|
|
case NAND_CMD_SEQIN:
|
2007-10-31 21:53:06 +09:00
|
|
|
case NAND_CMD_RNDIN:
|
2005-08-17 19:55:25 +09:00
|
|
|
case NAND_CMD_STATUS:
|
2007-10-31 21:53:06 +09:00
|
|
|
return;
|
2005-08-17 19:55:25 +09:00
|
|
|
|
|
|
|
case NAND_CMD_RESET:
|
2007-10-31 21:53:06 +09:00
|
|
|
if (chip->dev_ready)
|
2005-08-17 19:55:25 +09:00
|
|
|
break;
|
2007-10-31 21:53:06 +09:00
|
|
|
udelay(chip->chip_delay);
|
|
|
|
chip->cmd_ctrl(mtd, NAND_CMD_STATUS,
|
|
|
|
NAND_NCE | NAND_CLE | NAND_CTRL_CHANGE);
|
|
|
|
chip->cmd_ctrl(mtd, NAND_CMD_NONE,
|
|
|
|
NAND_NCE | NAND_CTRL_CHANGE);
|
2009-02-05 04:47:22 +09:00
|
|
|
while (!(chip->read_byte(mtd) & NAND_STATUS_READY) &&
|
|
|
|
(rst_sts_cnt--));
|
2007-10-31 21:53:06 +09:00
|
|
|
return;
|
|
|
|
|
|
|
|
case NAND_CMD_RNDOUT:
|
|
|
|
/* No ready / busy check necessary */
|
|
|
|
chip->cmd_ctrl(mtd, NAND_CMD_RNDOUTSTART,
|
|
|
|
NAND_NCE | NAND_CLE | NAND_CTRL_CHANGE);
|
|
|
|
chip->cmd_ctrl(mtd, NAND_CMD_NONE,
|
|
|
|
NAND_NCE | NAND_CTRL_CHANGE);
|
2005-08-17 19:55:25 +09:00
|
|
|
return;
|
|
|
|
|
|
|
|
case NAND_CMD_READ0:
|
2007-10-31 21:53:06 +09:00
|
|
|
chip->cmd_ctrl(mtd, NAND_CMD_READSTART,
|
|
|
|
NAND_NCE | NAND_CLE | NAND_CTRL_CHANGE);
|
|
|
|
chip->cmd_ctrl(mtd, NAND_CMD_NONE,
|
|
|
|
NAND_NCE | NAND_CTRL_CHANGE);
|
|
|
|
|
|
|
|
/* This applies to read commands */
|
2005-08-17 19:55:25 +09:00
|
|
|
default:
|
2005-09-15 06:53:32 +09:00
|
|
|
/*
|
2005-08-17 19:55:25 +09:00
|
|
|
* If we don't have access to the busy pin, we apply the given
|
2013-01-14 12:46:50 +09:00
|
|
|
* command delay.
|
2007-10-31 21:53:06 +09:00
|
|
|
*/
|
|
|
|
if (!chip->dev_ready) {
|
|
|
|
udelay(chip->chip_delay);
|
2005-08-17 19:55:25 +09:00
|
|
|
return;
|
2005-09-15 06:53:32 +09:00
|
|
|
}
|
2005-08-17 19:55:25 +09:00
|
|
|
}
|
2005-09-15 06:53:32 +09:00
|
|
|
|
2013-01-14 12:46:50 +09:00
|
|
|
/*
|
|
|
|
* Apply this short delay always to ensure that we do wait tWB in
|
|
|
|
* any case on any machine.
|
|
|
|
*/
|
2007-10-31 21:53:06 +09:00
|
|
|
ndelay(100);
|
|
|
|
|
|
|
|
nand_wait_ready(mtd);
|
2005-08-17 19:55:25 +09:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2014-06-24 17:10:04 +09:00
|
|
|
* panic_nand_get_device - [GENERIC] Get chip for selected access
|
2013-01-14 12:46:50 +09:00
|
|
|
* @chip: the nand chip descriptor
|
|
|
|
* @mtd: MTD device structure
|
|
|
|
* @new_state: the state which is requested
|
2005-08-17 19:55:25 +09:00
|
|
|
*
|
2014-06-24 17:10:04 +09:00
|
|
|
* Used when in panic, no locks are taken.
|
|
|
|
*/
|
|
|
|
static void panic_nand_get_device(struct nand_chip *chip,
|
|
|
|
struct mtd_info *mtd, int new_state)
|
|
|
|
{
|
|
|
|
/* Hardware controller shared among independent devices */
|
|
|
|
chip->controller->active = chip;
|
|
|
|
chip->state = new_state;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* nand_get_device - [GENERIC] Get chip for selected access
|
|
|
|
* @mtd: MTD device structure
|
|
|
|
* @new_state: the state which is requested
|
|
|
|
*
|
2005-08-17 19:55:25 +09:00
|
|
|
* Get the device and lock it for exclusive access
|
|
|
|
*/
|
2011-10-12 16:32:02 +09:00
|
|
|
static int
|
2014-06-24 17:10:04 +09:00
|
|
|
nand_get_device(struct mtd_info *mtd, int new_state)
|
2007-10-31 21:53:06 +09:00
|
|
|
{
|
2014-06-24 17:10:04 +09:00
|
|
|
struct nand_chip *chip = mtd->priv;
|
|
|
|
#ifndef __UBOOT__
|
|
|
|
spinlock_t *lock = &chip->controller->lock;
|
|
|
|
wait_queue_head_t *wq = &chip->controller->wq;
|
|
|
|
DECLARE_WAITQUEUE(wait, current);
|
|
|
|
retry:
|
|
|
|
spin_lock(lock);
|
|
|
|
|
|
|
|
/* Hardware controller shared among independent devices */
|
|
|
|
if (!chip->controller->active)
|
|
|
|
chip->controller->active = chip;
|
|
|
|
|
|
|
|
if (chip->controller->active == chip && chip->state == FL_READY) {
|
|
|
|
chip->state = new_state;
|
|
|
|
spin_unlock(lock);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
if (new_state == FL_PM_SUSPENDED) {
|
|
|
|
if (chip->controller->active->state == FL_PM_SUSPENDED) {
|
|
|
|
chip->state = FL_PM_SUSPENDED;
|
|
|
|
spin_unlock(lock);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
set_current_state(TASK_UNINTERRUPTIBLE);
|
|
|
|
add_wait_queue(wq, &wait);
|
|
|
|
spin_unlock(lock);
|
|
|
|
schedule();
|
|
|
|
remove_wait_queue(wq, &wait);
|
|
|
|
goto retry;
|
|
|
|
#else
|
2011-10-12 16:32:02 +09:00
|
|
|
chip->state = new_state;
|
2007-10-31 21:53:06 +09:00
|
|
|
return 0;
|
2014-06-24 17:10:04 +09:00
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* panic_nand_wait - [GENERIC] wait until the command is done
|
|
|
|
* @mtd: MTD device structure
|
|
|
|
* @chip: NAND chip structure
|
|
|
|
* @timeo: timeout
|
|
|
|
*
|
|
|
|
* Wait for command done. This is a helper function for nand_wait used when
|
|
|
|
* we are in interrupt context. May happen when in panic and trying to write
|
|
|
|
* an oops through mtdoops.
|
|
|
|
*/
|
|
|
|
static void panic_nand_wait(struct mtd_info *mtd, struct nand_chip *chip,
|
|
|
|
unsigned long timeo)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
for (i = 0; i < timeo; i++) {
|
|
|
|
if (chip->dev_ready) {
|
|
|
|
if (chip->dev_ready(mtd))
|
|
|
|
break;
|
|
|
|
} else {
|
|
|
|
if (chip->read_byte(mtd) & NAND_STATUS_READY)
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
mdelay(1);
|
|
|
|
}
|
2007-10-31 21:53:06 +09:00
|
|
|
}
|
2005-08-17 19:55:25 +09:00
|
|
|
|
|
|
|
/**
|
2013-01-14 12:46:50 +09:00
|
|
|
* nand_wait - [DEFAULT] wait until the command is done
|
|
|
|
* @mtd: MTD device structure
|
|
|
|
* @chip: NAND chip structure
|
2005-08-17 19:55:25 +09:00
|
|
|
*
|
2013-01-14 12:46:50 +09:00
|
|
|
* Wait for command done. This applies to erase and program only. Erase can
|
|
|
|
* take up to 400ms and program up to 20ms according to general NAND and
|
|
|
|
* SmartMedia specs.
|
2007-10-31 21:53:06 +09:00
|
|
|
*/
|
2011-10-12 16:32:02 +09:00
|
|
|
static int nand_wait(struct mtd_info *mtd, struct nand_chip *chip)
|
2005-08-17 19:55:25 +09:00
|
|
|
{
|
2005-11-02 22:29:12 +09:00
|
|
|
|
2014-06-24 17:10:04 +09:00
|
|
|
int status, state = chip->state;
|
|
|
|
unsigned long timeo = (state == FL_ERASING ? 400 : 20);
|
2005-11-02 22:29:12 +09:00
|
|
|
|
2014-06-24 17:10:04 +09:00
|
|
|
led_trigger_event(nand_led_trigger, LED_FULL);
|
2005-11-02 22:29:12 +09:00
|
|
|
|
2014-06-24 17:10:04 +09:00
|
|
|
/*
|
|
|
|
* Apply this short delay always to ensure that we do wait tWB in any
|
|
|
|
* case on any machine.
|
|
|
|
*/
|
|
|
|
ndelay(100);
|
2005-11-02 22:29:12 +09:00
|
|
|
|
2014-06-24 17:10:04 +09:00
|
|
|
chip->cmdfunc(mtd, NAND_CMD_STATUS, -1, -1);
|
2005-11-02 22:29:12 +09:00
|
|
|
|
2014-06-24 17:10:04 +09:00
|
|
|
#ifndef __UBOOT__
|
|
|
|
if (in_interrupt() || oops_in_progress)
|
|
|
|
panic_nand_wait(mtd, chip, timeo);
|
|
|
|
else {
|
|
|
|
timeo = jiffies + msecs_to_jiffies(timeo);
|
|
|
|
while (time_before(jiffies, timeo)) {
|
|
|
|
if (chip->dev_ready) {
|
|
|
|
if (chip->dev_ready(mtd))
|
|
|
|
break;
|
|
|
|
} else {
|
|
|
|
if (chip->read_byte(mtd) & NAND_STATUS_READY)
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
cond_resched();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#else
|
|
|
|
u32 timer = (CONFIG_SYS_HZ * timeo) / 1000;
|
|
|
|
u32 time_start;
|
|
|
|
|
|
|
|
time_start = get_timer(0);
|
|
|
|
while (get_timer(time_start) < timer) {
|
2011-10-12 16:32:02 +09:00
|
|
|
if (chip->dev_ready) {
|
|
|
|
if (chip->dev_ready(mtd))
|
2005-11-02 22:29:12 +09:00
|
|
|
break;
|
|
|
|
} else {
|
2011-10-12 16:32:02 +09:00
|
|
|
if (chip->read_byte(mtd) & NAND_STATUS_READY)
|
2005-11-02 22:29:12 +09:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2014-06-24 17:10:04 +09:00
|
|
|
#endif
|
|
|
|
led_trigger_event(nand_led_trigger, LED_OFF);
|
|
|
|
|
|
|
|
status = (int)chip->read_byte(mtd);
|
|
|
|
/* This can happen if in case of timeout or buggy dev_ready */
|
|
|
|
WARN_ON(!(status & NAND_STATUS_READY));
|
|
|
|
return status;
|
|
|
|
}
|
|
|
|
|
|
|
|
#ifndef __UBOOT__
|
|
|
|
/**
|
|
|
|
* __nand_unlock - [REPLACEABLE] unlocks specified locked blocks
|
|
|
|
* @mtd: mtd info
|
|
|
|
* @ofs: offset to start unlock from
|
|
|
|
* @len: length to unlock
|
|
|
|
* @invert: when = 0, unlock the range of blocks within the lower and
|
|
|
|
* upper boundary address
|
|
|
|
* when = 1, unlock the range of blocks outside the boundaries
|
|
|
|
* of the lower and upper boundary address
|
|
|
|
*
|
|
|
|
* Returs unlock status.
|
|
|
|
*/
|
|
|
|
static int __nand_unlock(struct mtd_info *mtd, loff_t ofs,
|
|
|
|
uint64_t len, int invert)
|
|
|
|
{
|
|
|
|
int ret = 0;
|
|
|
|
int status, page;
|
|
|
|
struct nand_chip *chip = mtd->priv;
|
|
|
|
|
|
|
|
/* Submit address of first page to unlock */
|
|
|
|
page = ofs >> chip->page_shift;
|
|
|
|
chip->cmdfunc(mtd, NAND_CMD_UNLOCK1, -1, page & chip->pagemask);
|
|
|
|
|
|
|
|
/* Submit address of last page to unlock */
|
|
|
|
page = (ofs + len) >> chip->page_shift;
|
|
|
|
chip->cmdfunc(mtd, NAND_CMD_UNLOCK2, -1,
|
|
|
|
(page | invert) & chip->pagemask);
|
|
|
|
|
|
|
|
/* Call wait ready function */
|
|
|
|
status = chip->waitfunc(mtd, chip);
|
|
|
|
/* See if device thinks it succeeded */
|
|
|
|
if (status & NAND_STATUS_FAIL) {
|
|
|
|
pr_debug("%s: error status = 0x%08x\n",
|
|
|
|
__func__, status);
|
|
|
|
ret = -EIO;
|
|
|
|
}
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* nand_unlock - [REPLACEABLE] unlocks specified locked blocks
|
|
|
|
* @mtd: mtd info
|
|
|
|
* @ofs: offset to start unlock from
|
|
|
|
* @len: length to unlock
|
|
|
|
*
|
|
|
|
* Returns unlock status.
|
|
|
|
*/
|
|
|
|
int nand_unlock(struct mtd_info *mtd, loff_t ofs, uint64_t len)
|
|
|
|
{
|
|
|
|
int ret = 0;
|
|
|
|
int chipnr;
|
|
|
|
struct nand_chip *chip = mtd->priv;
|
|
|
|
|
|
|
|
pr_debug("%s: start = 0x%012llx, len = %llu\n",
|
|
|
|
__func__, (unsigned long long)ofs, len);
|
|
|
|
|
|
|
|
if (check_offs_len(mtd, ofs, len))
|
|
|
|
ret = -EINVAL;
|
|
|
|
|
|
|
|
/* Align to last block address if size addresses end of the device */
|
|
|
|
if (ofs + len == mtd->size)
|
|
|
|
len -= mtd->erasesize;
|
|
|
|
|
|
|
|
nand_get_device(mtd, FL_UNLOCKING);
|
|
|
|
|
|
|
|
/* Shift to get chip number */
|
|
|
|
chipnr = ofs >> chip->chip_shift;
|
|
|
|
|
|
|
|
chip->select_chip(mtd, chipnr);
|
|
|
|
|
|
|
|
/* Check, if it is write protected */
|
|
|
|
if (nand_check_wp(mtd)) {
|
|
|
|
pr_debug("%s: device is write protected!\n",
|
|
|
|
__func__);
|
|
|
|
ret = -EIO;
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
|
|
|
|
ret = __nand_unlock(mtd, ofs, len, 0);
|
|
|
|
|
|
|
|
out:
|
|
|
|
chip->select_chip(mtd, -1);
|
|
|
|
nand_release_device(mtd);
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
EXPORT_SYMBOL(nand_unlock);
|
|
|
|
|
|
|
|
/**
|
|
|
|
* nand_lock - [REPLACEABLE] locks all blocks present in the device
|
|
|
|
* @mtd: mtd info
|
|
|
|
* @ofs: offset to start unlock from
|
|
|
|
* @len: length to unlock
|
|
|
|
*
|
|
|
|
* This feature is not supported in many NAND parts. 'Micron' NAND parts do
|
|
|
|
* have this feature, but it allows only to lock all blocks, not for specified
|
|
|
|
* range for block. Implementing 'lock' feature by making use of 'unlock', for
|
|
|
|
* now.
|
|
|
|
*
|
|
|
|
* Returns lock status.
|
|
|
|
*/
|
|
|
|
int nand_lock(struct mtd_info *mtd, loff_t ofs, uint64_t len)
|
|
|
|
{
|
|
|
|
int ret = 0;
|
|
|
|
int chipnr, status, page;
|
|
|
|
struct nand_chip *chip = mtd->priv;
|
|
|
|
|
|
|
|
pr_debug("%s: start = 0x%012llx, len = %llu\n",
|
|
|
|
__func__, (unsigned long long)ofs, len);
|
|
|
|
|
|
|
|
if (check_offs_len(mtd, ofs, len))
|
|
|
|
ret = -EINVAL;
|
|
|
|
|
|
|
|
nand_get_device(mtd, FL_LOCKING);
|
|
|
|
|
|
|
|
/* Shift to get chip number */
|
|
|
|
chipnr = ofs >> chip->chip_shift;
|
|
|
|
|
|
|
|
chip->select_chip(mtd, chipnr);
|
|
|
|
|
|
|
|
/* Check, if it is write protected */
|
|
|
|
if (nand_check_wp(mtd)) {
|
|
|
|
pr_debug("%s: device is write protected!\n",
|
|
|
|
__func__);
|
|
|
|
status = MTD_ERASE_FAILED;
|
|
|
|
ret = -EIO;
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Submit address of first page to lock */
|
|
|
|
page = ofs >> chip->page_shift;
|
|
|
|
chip->cmdfunc(mtd, NAND_CMD_LOCK, -1, page & chip->pagemask);
|
2006-02-24 17:37:22 +09:00
|
|
|
|
2014-06-24 17:10:04 +09:00
|
|
|
/* Call wait ready function */
|
|
|
|
status = chip->waitfunc(mtd, chip);
|
|
|
|
/* See if device thinks it succeeded */
|
|
|
|
if (status & NAND_STATUS_FAIL) {
|
|
|
|
pr_debug("%s: error status = 0x%08x\n",
|
|
|
|
__func__, status);
|
|
|
|
ret = -EIO;
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
|
|
|
|
ret = __nand_unlock(mtd, ofs, len, 0x1);
|
|
|
|
|
|
|
|
out:
|
|
|
|
chip->select_chip(mtd, -1);
|
|
|
|
nand_release_device(mtd);
|
|
|
|
|
|
|
|
return ret;
|
2005-08-17 19:55:25 +09:00
|
|
|
}
|
2014-06-24 17:10:04 +09:00
|
|
|
EXPORT_SYMBOL(nand_lock);
|
|
|
|
#endif
|
2005-08-17 19:55:25 +09:00
|
|
|
|
|
|
|
/**
|
2013-01-14 12:46:50 +09:00
|
|
|
* nand_read_page_raw - [INTERN] read raw page data without ecc
|
|
|
|
* @mtd: mtd info structure
|
|
|
|
* @chip: nand chip info structure
|
|
|
|
* @buf: buffer to store read data
|
|
|
|
* @oob_required: caller requires OOB data read to chip->oob_poi
|
|
|
|
* @page: page number to read
|
NAND: fix "raw" reads with ECC syndrome layouts
The syndrome based page read/write routines store ECC, and possibly other
"OOB" data, right after each chunk of ECC'd data. With ECC chunk size of
512 bytes and a large page (2KiB) NAND, the layout is:
data-0 OOB-0 data-1 OOB-1 data-2 OOB-2 data-3 OOB-3 OOB-leftover
Where OOBx is (prepad, ECC, postpad). However, the current "raw" routines
use a traditional layout -- data OOB, disregarding the prepad and postpad
values -- so when they're used with that type of ECC hardware, those calls
mix up the data and OOB. Which means, in particular, that bad block
tables won't be found on startup, with data corruption and related chaos
ensuing.
The current syndrome-based drivers in mainline all seem to use one chunk
per page; presumably they haven't noticed such bugs.
Fix this, by adding read/write page_raw_syndrome() routines as siblings of
the existing non-raw routines; "raw" just means to bypass the ECC
computations, not change data and OOB layout.
Signed-off-by: David Brownell <dbrownell@users.sourceforge.net>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: David Woodhouse <David.Woodhouse@intel.com>
2009-11-08 06:27:01 +09:00
|
|
|
*
|
2013-01-14 12:46:50 +09:00
|
|
|
* Not for syndrome calculating ECC controllers, which use a special oob layout.
|
2005-08-17 19:55:25 +09:00
|
|
|
*/
|
2007-10-31 21:53:06 +09:00
|
|
|
static int nand_read_page_raw(struct mtd_info *mtd, struct nand_chip *chip,
|
2013-01-14 12:46:50 +09:00
|
|
|
uint8_t *buf, int oob_required, int page)
|
2005-08-17 19:55:25 +09:00
|
|
|
{
|
2007-10-31 21:53:06 +09:00
|
|
|
chip->read_buf(mtd, buf, mtd->writesize);
|
2013-01-14 12:46:50 +09:00
|
|
|
if (oob_required)
|
|
|
|
chip->read_buf(mtd, chip->oob_poi, mtd->oobsize);
|
2007-10-31 21:53:06 +09:00
|
|
|
return 0;
|
|
|
|
}
|
2005-09-15 06:53:32 +09:00
|
|
|
|
NAND: fix "raw" reads with ECC syndrome layouts
The syndrome based page read/write routines store ECC, and possibly other
"OOB" data, right after each chunk of ECC'd data. With ECC chunk size of
512 bytes and a large page (2KiB) NAND, the layout is:
data-0 OOB-0 data-1 OOB-1 data-2 OOB-2 data-3 OOB-3 OOB-leftover
Where OOBx is (prepad, ECC, postpad). However, the current "raw" routines
use a traditional layout -- data OOB, disregarding the prepad and postpad
values -- so when they're used with that type of ECC hardware, those calls
mix up the data and OOB. Which means, in particular, that bad block
tables won't be found on startup, with data corruption and related chaos
ensuing.
The current syndrome-based drivers in mainline all seem to use one chunk
per page; presumably they haven't noticed such bugs.
Fix this, by adding read/write page_raw_syndrome() routines as siblings of
the existing non-raw routines; "raw" just means to bypass the ECC
computations, not change data and OOB layout.
Signed-off-by: David Brownell <dbrownell@users.sourceforge.net>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: David Woodhouse <David.Woodhouse@intel.com>
2009-11-08 06:27:01 +09:00
|
|
|
/**
|
2013-01-14 12:46:50 +09:00
|
|
|
* nand_read_page_raw_syndrome - [INTERN] read raw page data without ecc
|
|
|
|
* @mtd: mtd info structure
|
|
|
|
* @chip: nand chip info structure
|
|
|
|
* @buf: buffer to store read data
|
|
|
|
* @oob_required: caller requires OOB data read to chip->oob_poi
|
|
|
|
* @page: page number to read
|
NAND: fix "raw" reads with ECC syndrome layouts
The syndrome based page read/write routines store ECC, and possibly other
"OOB" data, right after each chunk of ECC'd data. With ECC chunk size of
512 bytes and a large page (2KiB) NAND, the layout is:
data-0 OOB-0 data-1 OOB-1 data-2 OOB-2 data-3 OOB-3 OOB-leftover
Where OOBx is (prepad, ECC, postpad). However, the current "raw" routines
use a traditional layout -- data OOB, disregarding the prepad and postpad
values -- so when they're used with that type of ECC hardware, those calls
mix up the data and OOB. Which means, in particular, that bad block
tables won't be found on startup, with data corruption and related chaos
ensuing.
The current syndrome-based drivers in mainline all seem to use one chunk
per page; presumably they haven't noticed such bugs.
Fix this, by adding read/write page_raw_syndrome() routines as siblings of
the existing non-raw routines; "raw" just means to bypass the ECC
computations, not change data and OOB layout.
Signed-off-by: David Brownell <dbrownell@users.sourceforge.net>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: David Woodhouse <David.Woodhouse@intel.com>
2009-11-08 06:27:01 +09:00
|
|
|
*
|
|
|
|
* We need a special oob layout and handling even when OOB isn't used.
|
|
|
|
*/
|
2011-10-12 16:32:01 +09:00
|
|
|
static int nand_read_page_raw_syndrome(struct mtd_info *mtd,
|
2013-01-14 12:46:50 +09:00
|
|
|
struct nand_chip *chip, uint8_t *buf,
|
|
|
|
int oob_required, int page)
|
NAND: fix "raw" reads with ECC syndrome layouts
The syndrome based page read/write routines store ECC, and possibly other
"OOB" data, right after each chunk of ECC'd data. With ECC chunk size of
512 bytes and a large page (2KiB) NAND, the layout is:
data-0 OOB-0 data-1 OOB-1 data-2 OOB-2 data-3 OOB-3 OOB-leftover
Where OOBx is (prepad, ECC, postpad). However, the current "raw" routines
use a traditional layout -- data OOB, disregarding the prepad and postpad
values -- so when they're used with that type of ECC hardware, those calls
mix up the data and OOB. Which means, in particular, that bad block
tables won't be found on startup, with data corruption and related chaos
ensuing.
The current syndrome-based drivers in mainline all seem to use one chunk
per page; presumably they haven't noticed such bugs.
Fix this, by adding read/write page_raw_syndrome() routines as siblings of
the existing non-raw routines; "raw" just means to bypass the ECC
computations, not change data and OOB layout.
Signed-off-by: David Brownell <dbrownell@users.sourceforge.net>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: David Woodhouse <David.Woodhouse@intel.com>
2009-11-08 06:27:01 +09:00
|
|
|
{
|
|
|
|
int eccsize = chip->ecc.size;
|
|
|
|
int eccbytes = chip->ecc.bytes;
|
|
|
|
uint8_t *oob = chip->oob_poi;
|
|
|
|
int steps, size;
|
|
|
|
|
|
|
|
for (steps = chip->ecc.steps; steps > 0; steps--) {
|
|
|
|
chip->read_buf(mtd, buf, eccsize);
|
|
|
|
buf += eccsize;
|
|
|
|
|
|
|
|
if (chip->ecc.prepad) {
|
|
|
|
chip->read_buf(mtd, oob, chip->ecc.prepad);
|
|
|
|
oob += chip->ecc.prepad;
|
|
|
|
}
|
|
|
|
|
|
|
|
chip->read_buf(mtd, oob, eccbytes);
|
|
|
|
oob += eccbytes;
|
|
|
|
|
|
|
|
if (chip->ecc.postpad) {
|
|
|
|
chip->read_buf(mtd, oob, chip->ecc.postpad);
|
|
|
|
oob += chip->ecc.postpad;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
size = mtd->oobsize - (oob - chip->oob_poi);
|
|
|
|
if (size)
|
|
|
|
chip->read_buf(mtd, oob, size);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2007-10-31 21:53:06 +09:00
|
|
|
/**
|
2013-01-14 12:46:50 +09:00
|
|
|
* nand_read_page_swecc - [REPLACEABLE] software ECC based page read function
|
|
|
|
* @mtd: mtd info structure
|
|
|
|
* @chip: nand chip info structure
|
|
|
|
* @buf: buffer to store read data
|
|
|
|
* @oob_required: caller requires OOB data read to chip->oob_poi
|
|
|
|
* @page: page number to read
|
2007-10-31 21:53:06 +09:00
|
|
|
*/
|
|
|
|
static int nand_read_page_swecc(struct mtd_info *mtd, struct nand_chip *chip,
|
2013-01-14 12:46:50 +09:00
|
|
|
uint8_t *buf, int oob_required, int page)
|
2007-10-31 21:53:06 +09:00
|
|
|
{
|
|
|
|
int i, eccsize = chip->ecc.size;
|
|
|
|
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;
|
|
|
|
uint32_t *eccpos = chip->ecc.layout->eccpos;
|
2014-06-24 17:10:04 +09:00
|
|
|
unsigned int max_bitflips = 0;
|
2005-09-15 06:53:32 +09:00
|
|
|
|
2013-01-14 12:46:50 +09:00
|
|
|
chip->ecc.read_page_raw(mtd, chip, buf, 1, page);
|
2005-08-17 19:55:25 +09:00
|
|
|
|
2007-10-31 21:53:06 +09:00
|
|
|
for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize)
|
|
|
|
chip->ecc.calculate(mtd, p, &ecc_calc[i]);
|
2005-09-15 06:53:32 +09:00
|
|
|
|
2007-10-31 21:53:06 +09:00
|
|
|
for (i = 0; i < chip->ecc.total; i++)
|
|
|
|
ecc_code[i] = chip->oob_poi[eccpos[i]];
|
2005-09-15 06:53:32 +09:00
|
|
|
|
2007-10-31 21:53:06 +09:00
|
|
|
eccsteps = chip->ecc.steps;
|
|
|
|
p = buf;
|
|
|
|
|
|
|
|
for (i = 0 ; eccsteps; eccsteps--, i += eccbytes, p += eccsize) {
|
|
|
|
int stat;
|
|
|
|
|
|
|
|
stat = chip->ecc.correct(mtd, p, &ecc_code[i], &ecc_calc[i]);
|
2014-06-24 17:10:04 +09:00
|
|
|
if (stat < 0) {
|
2008-10-25 06:20:43 +09:00
|
|
|
mtd->ecc_stats.failed++;
|
2014-06-24 17:10:04 +09:00
|
|
|
} else {
|
2008-10-25 06:20:43 +09:00
|
|
|
mtd->ecc_stats.corrected += stat;
|
2014-06-24 17:10:04 +09:00
|
|
|
max_bitflips = max_t(unsigned int, max_bitflips, stat);
|
|
|
|
}
|
2008-10-25 06:20:43 +09:00
|
|
|
}
|
2014-06-24 17:10:04 +09:00
|
|
|
return max_bitflips;
|
2008-10-25 06:20:43 +09:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2014-06-24 17:10:04 +09:00
|
|
|
* nand_read_subpage - [REPLACEABLE] ECC based sub-page read function
|
2013-01-14 12:46:50 +09:00
|
|
|
* @mtd: mtd info structure
|
|
|
|
* @chip: nand chip info structure
|
|
|
|
* @data_offs: offset of requested data within the page
|
|
|
|
* @readlen: data length
|
|
|
|
* @bufpoi: buffer to store read data
|
2014-07-15 23:08:43 +09:00
|
|
|
* @page: page number to read
|
2008-10-25 06:20:43 +09:00
|
|
|
*/
|
2011-10-12 16:32:01 +09:00
|
|
|
static int nand_read_subpage(struct mtd_info *mtd, struct nand_chip *chip,
|
2014-07-15 23:08:43 +09:00
|
|
|
uint32_t data_offs, uint32_t readlen, uint8_t *bufpoi,
|
|
|
|
int page)
|
2008-10-25 06:20:43 +09:00
|
|
|
{
|
|
|
|
int start_step, end_step, num_steps;
|
|
|
|
uint32_t *eccpos = chip->ecc.layout->eccpos;
|
|
|
|
uint8_t *p;
|
|
|
|
int data_col_addr, i, gaps = 0;
|
|
|
|
int datafrag_len, eccfrag_len, aligned_len, aligned_pos;
|
|
|
|
int busw = (chip->options & NAND_BUSWIDTH_16) ? 2 : 1;
|
2014-07-15 23:08:43 +09:00
|
|
|
int index;
|
2014-06-24 17:10:04 +09:00
|
|
|
unsigned int max_bitflips = 0;
|
2008-10-25 06:20:43 +09:00
|
|
|
|
2013-01-14 12:46:50 +09:00
|
|
|
/* Column address within the page aligned to ECC size (256bytes) */
|
2008-10-25 06:20:43 +09:00
|
|
|
start_step = data_offs / chip->ecc.size;
|
|
|
|
end_step = (data_offs + readlen - 1) / chip->ecc.size;
|
|
|
|
num_steps = end_step - start_step + 1;
|
2014-07-15 23:08:43 +09:00
|
|
|
index = start_step * chip->ecc.bytes;
|
2008-10-25 06:20:43 +09:00
|
|
|
|
2013-01-14 12:46:50 +09:00
|
|
|
/* Data size aligned to ECC ecc.size */
|
2008-10-25 06:20:43 +09:00
|
|
|
datafrag_len = num_steps * chip->ecc.size;
|
|
|
|
eccfrag_len = num_steps * chip->ecc.bytes;
|
|
|
|
|
|
|
|
data_col_addr = start_step * chip->ecc.size;
|
|
|
|
/* If we read not a page aligned data */
|
|
|
|
if (data_col_addr != 0)
|
|
|
|
chip->cmdfunc(mtd, NAND_CMD_RNDOUT, data_col_addr, -1);
|
|
|
|
|
|
|
|
p = bufpoi + data_col_addr;
|
|
|
|
chip->read_buf(mtd, p, datafrag_len);
|
|
|
|
|
2013-01-14 12:46:50 +09:00
|
|
|
/* Calculate ECC */
|
2008-10-25 06:20:43 +09:00
|
|
|
for (i = 0; i < eccfrag_len ; i += chip->ecc.bytes, p += chip->ecc.size)
|
|
|
|
chip->ecc.calculate(mtd, p, &chip->buffers->ecccalc[i]);
|
|
|
|
|
2013-01-14 12:46:50 +09:00
|
|
|
/*
|
|
|
|
* The performance is faster if we position offsets according to
|
|
|
|
* ecc.pos. Let's make sure that there are no gaps in ECC positions.
|
|
|
|
*/
|
2008-10-25 06:20:43 +09:00
|
|
|
for (i = 0; i < eccfrag_len - 1; i++) {
|
|
|
|
if (eccpos[i + start_step * chip->ecc.bytes] + 1 !=
|
|
|
|
eccpos[i + start_step * chip->ecc.bytes + 1]) {
|
|
|
|
gaps = 1;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (gaps) {
|
|
|
|
chip->cmdfunc(mtd, NAND_CMD_RNDOUT, mtd->writesize, -1);
|
|
|
|
chip->read_buf(mtd, chip->oob_poi, mtd->oobsize);
|
|
|
|
} else {
|
2013-01-14 12:46:50 +09:00
|
|
|
/*
|
|
|
|
* Send the command to read the particular ECC bytes take care
|
|
|
|
* about buswidth alignment in read_buf.
|
|
|
|
*/
|
2011-10-12 16:32:02 +09:00
|
|
|
aligned_pos = eccpos[index] & ~(busw - 1);
|
2008-10-25 06:20:43 +09:00
|
|
|
aligned_len = eccfrag_len;
|
2011-10-12 16:32:02 +09:00
|
|
|
if (eccpos[index] & (busw - 1))
|
2008-10-25 06:20:43 +09:00
|
|
|
aligned_len++;
|
2011-10-12 16:32:02 +09:00
|
|
|
if (eccpos[index + (num_steps * chip->ecc.bytes)] & (busw - 1))
|
2008-10-25 06:20:43 +09:00
|
|
|
aligned_len++;
|
|
|
|
|
2011-10-12 16:32:02 +09:00
|
|
|
chip->cmdfunc(mtd, NAND_CMD_RNDOUT,
|
|
|
|
mtd->writesize + aligned_pos, -1);
|
2008-10-25 06:20:43 +09:00
|
|
|
chip->read_buf(mtd, &chip->oob_poi[aligned_pos], aligned_len);
|
|
|
|
}
|
|
|
|
|
|
|
|
for (i = 0; i < eccfrag_len; i++)
|
2011-10-12 16:32:02 +09:00
|
|
|
chip->buffers->ecccode[i] = chip->oob_poi[eccpos[i + index]];
|
2008-10-25 06:20:43 +09:00
|
|
|
|
|
|
|
p = bufpoi + data_col_addr;
|
|
|
|
for (i = 0; i < eccfrag_len ; i += chip->ecc.bytes, p += chip->ecc.size) {
|
|
|
|
int stat;
|
|
|
|
|
2011-10-12 16:32:02 +09:00
|
|
|
stat = chip->ecc.correct(mtd, p,
|
|
|
|
&chip->buffers->ecccode[i], &chip->buffers->ecccalc[i]);
|
2014-06-24 17:10:04 +09:00
|
|
|
if (stat < 0) {
|
2007-10-31 21:53:06 +09:00
|
|
|
mtd->ecc_stats.failed++;
|
2014-06-24 17:10:04 +09:00
|
|
|
} else {
|
2007-10-31 21:53:06 +09:00
|
|
|
mtd->ecc_stats.corrected += stat;
|
2014-06-24 17:10:04 +09:00
|
|
|
max_bitflips = max_t(unsigned int, max_bitflips, stat);
|
|
|
|
}
|
2005-08-17 19:55:25 +09:00
|
|
|
}
|
2014-06-24 17:10:04 +09:00
|
|
|
return max_bitflips;
|
2005-08-17 19:55:25 +09:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2013-01-14 12:46:50 +09:00
|
|
|
* nand_read_page_hwecc - [REPLACEABLE] hardware ECC based page read function
|
|
|
|
* @mtd: mtd info structure
|
|
|
|
* @chip: nand chip info structure
|
|
|
|
* @buf: buffer to store read data
|
|
|
|
* @oob_required: caller requires OOB data read to chip->oob_poi
|
|
|
|
* @page: page number to read
|
2005-08-17 19:55:25 +09:00
|
|
|
*
|
2013-01-14 12:46:50 +09:00
|
|
|
* Not for syndrome calculating ECC controllers which need a special oob layout.
|
2005-08-17 19:55:25 +09:00
|
|
|
*/
|
2007-10-31 21:53:06 +09:00
|
|
|
static int nand_read_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip,
|
2013-01-14 12:46:50 +09:00
|
|
|
uint8_t *buf, int oob_required, int page)
|
2007-10-31 21:53:06 +09:00
|
|
|
{
|
|
|
|
int i, eccsize = chip->ecc.size;
|
|
|
|
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;
|
|
|
|
uint32_t *eccpos = chip->ecc.layout->eccpos;
|
2014-06-24 17:10:04 +09:00
|
|
|
unsigned int max_bitflips = 0;
|
2007-10-31 21:53:06 +09:00
|
|
|
|
|
|
|
for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize) {
|
|
|
|
chip->ecc.hwctl(mtd, NAND_ECC_READ);
|
|
|
|
chip->read_buf(mtd, p, eccsize);
|
|
|
|
chip->ecc.calculate(mtd, p, &ecc_calc[i]);
|
|
|
|
}
|
|
|
|
chip->read_buf(mtd, chip->oob_poi, mtd->oobsize);
|
2005-08-17 19:55:25 +09:00
|
|
|
|
2007-10-31 21:53:06 +09:00
|
|
|
for (i = 0; i < chip->ecc.total; i++)
|
|
|
|
ecc_code[i] = chip->oob_poi[eccpos[i]];
|
2005-08-17 19:55:25 +09:00
|
|
|
|
2007-10-31 21:53:06 +09:00
|
|
|
eccsteps = chip->ecc.steps;
|
|
|
|
p = buf;
|
2005-09-15 06:53:32 +09:00
|
|
|
|
2007-10-31 21:53:06 +09:00
|
|
|
for (i = 0 ; eccsteps; eccsteps--, i += eccbytes, p += eccsize) {
|
|
|
|
int stat;
|
2005-09-15 06:53:32 +09:00
|
|
|
|
2007-10-31 21:53:06 +09:00
|
|
|
stat = chip->ecc.correct(mtd, p, &ecc_code[i], &ecc_calc[i]);
|
2014-06-24 17:10:04 +09:00
|
|
|
if (stat < 0) {
|
2007-10-31 21:53:06 +09:00
|
|
|
mtd->ecc_stats.failed++;
|
2014-06-24 17:10:04 +09:00
|
|
|
} else {
|
2007-10-31 21:53:06 +09:00
|
|
|
mtd->ecc_stats.corrected += stat;
|
2014-06-24 17:10:04 +09:00
|
|
|
max_bitflips = max_t(unsigned int, max_bitflips, stat);
|
|
|
|
}
|
2005-08-17 19:55:25 +09:00
|
|
|
}
|
2014-06-24 17:10:04 +09:00
|
|
|
return max_bitflips;
|
2005-08-17 19:55:25 +09:00
|
|
|
}
|
|
|
|
|
2009-08-11 02:27:56 +09:00
|
|
|
/**
|
2013-01-14 12:46:50 +09:00
|
|
|
* nand_read_page_hwecc_oob_first - [REPLACEABLE] hw ecc, read oob first
|
|
|
|
* @mtd: mtd info structure
|
|
|
|
* @chip: nand chip info structure
|
|
|
|
* @buf: buffer to store read data
|
|
|
|
* @oob_required: caller requires OOB data read to chip->oob_poi
|
|
|
|
* @page: page number to read
|
2009-08-11 02:27:56 +09:00
|
|
|
*
|
2013-01-14 12:46:50 +09:00
|
|
|
* Hardware ECC for large page chips, require OOB to be read first. For this
|
|
|
|
* ECC mode, the write_page method is re-used from ECC_HW. These methods
|
|
|
|
* read/write ECC from the OOB area, unlike the ECC_HW_SYNDROME support with
|
|
|
|
* multiple ECC steps, follows the "infix ECC" scheme and reads/writes ECC from
|
|
|
|
* the data area, by overwriting the NAND manufacturer bad block markings.
|
2009-08-11 02:27:56 +09:00
|
|
|
*/
|
|
|
|
static int nand_read_page_hwecc_oob_first(struct mtd_info *mtd,
|
2013-01-14 12:46:50 +09:00
|
|
|
struct nand_chip *chip, uint8_t *buf, int oob_required, int page)
|
2009-08-11 02:27:56 +09:00
|
|
|
{
|
|
|
|
int i, eccsize = chip->ecc.size;
|
|
|
|
int eccbytes = chip->ecc.bytes;
|
|
|
|
int eccsteps = chip->ecc.steps;
|
|
|
|
uint8_t *p = buf;
|
|
|
|
uint8_t *ecc_code = chip->buffers->ecccode;
|
|
|
|
uint32_t *eccpos = chip->ecc.layout->eccpos;
|
|
|
|
uint8_t *ecc_calc = chip->buffers->ecccalc;
|
2014-06-24 17:10:04 +09:00
|
|
|
unsigned int max_bitflips = 0;
|
2009-08-11 02:27:56 +09:00
|
|
|
|
|
|
|
/* Read the OOB area first */
|
|
|
|
chip->cmdfunc(mtd, NAND_CMD_READOOB, 0, page);
|
|
|
|
chip->read_buf(mtd, chip->oob_poi, mtd->oobsize);
|
|
|
|
chip->cmdfunc(mtd, NAND_CMD_READ0, 0, page);
|
|
|
|
|
|
|
|
for (i = 0; i < chip->ecc.total; i++)
|
|
|
|
ecc_code[i] = chip->oob_poi[eccpos[i]];
|
|
|
|
|
|
|
|
for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize) {
|
|
|
|
int stat;
|
|
|
|
|
|
|
|
chip->ecc.hwctl(mtd, NAND_ECC_READ);
|
|
|
|
chip->read_buf(mtd, p, eccsize);
|
|
|
|
chip->ecc.calculate(mtd, p, &ecc_calc[i]);
|
|
|
|
|
|
|
|
stat = chip->ecc.correct(mtd, p, &ecc_code[i], NULL);
|
2014-06-24 17:10:04 +09:00
|
|
|
if (stat < 0) {
|
2009-08-11 02:27:56 +09:00
|
|
|
mtd->ecc_stats.failed++;
|
2014-06-24 17:10:04 +09:00
|
|
|
} else {
|
2009-08-11 02:27:56 +09:00
|
|
|
mtd->ecc_stats.corrected += stat;
|
2014-06-24 17:10:04 +09:00
|
|
|
max_bitflips = max_t(unsigned int, max_bitflips, stat);
|
|
|
|
}
|
2009-08-11 02:27:56 +09:00
|
|
|
}
|
2014-06-24 17:10:04 +09:00
|
|
|
return max_bitflips;
|
2009-08-11 02:27:56 +09:00
|
|
|
}
|
|
|
|
|
2005-08-17 19:55:25 +09:00
|
|
|
/**
|
2013-01-14 12:46:50 +09:00
|
|
|
* nand_read_page_syndrome - [REPLACEABLE] hardware ECC syndrome based page read
|
|
|
|
* @mtd: mtd info structure
|
|
|
|
* @chip: nand chip info structure
|
|
|
|
* @buf: buffer to store read data
|
|
|
|
* @oob_required: caller requires OOB data read to chip->oob_poi
|
|
|
|
* @page: page number to read
|
2005-08-17 19:55:25 +09:00
|
|
|
*
|
2013-01-14 12:46:50 +09:00
|
|
|
* The hw generator calculates the error syndrome automatically. Therefore we
|
|
|
|
* need a special oob layout and handling.
|
2007-10-31 21:53:06 +09:00
|
|
|
*/
|
|
|
|
static int nand_read_page_syndrome(struct mtd_info *mtd, struct nand_chip *chip,
|
2013-01-14 12:46:50 +09:00
|
|
|
uint8_t *buf, int oob_required, int page)
|
2005-08-17 19:55:25 +09:00
|
|
|
{
|
2007-10-31 21:53:06 +09:00
|
|
|
int i, eccsize = chip->ecc.size;
|
|
|
|
int eccbytes = chip->ecc.bytes;
|
|
|
|
int eccsteps = chip->ecc.steps;
|
|
|
|
uint8_t *p = buf;
|
|
|
|
uint8_t *oob = chip->oob_poi;
|
2014-06-24 17:10:04 +09:00
|
|
|
unsigned int max_bitflips = 0;
|
2007-10-31 21:53:06 +09:00
|
|
|
|
|
|
|
for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize) {
|
|
|
|
int stat;
|
|
|
|
|
|
|
|
chip->ecc.hwctl(mtd, NAND_ECC_READ);
|
|
|
|
chip->read_buf(mtd, p, eccsize);
|
|
|
|
|
|
|
|
if (chip->ecc.prepad) {
|
|
|
|
chip->read_buf(mtd, oob, chip->ecc.prepad);
|
|
|
|
oob += chip->ecc.prepad;
|
|
|
|
}
|
|
|
|
|
|
|
|
chip->ecc.hwctl(mtd, NAND_ECC_READSYN);
|
|
|
|
chip->read_buf(mtd, oob, eccbytes);
|
|
|
|
stat = chip->ecc.correct(mtd, p, oob, NULL);
|
|
|
|
|
2014-06-24 17:10:04 +09:00
|
|
|
if (stat < 0) {
|
2007-10-31 21:53:06 +09:00
|
|
|
mtd->ecc_stats.failed++;
|
2014-06-24 17:10:04 +09:00
|
|
|
} else {
|
2007-10-31 21:53:06 +09:00
|
|
|
mtd->ecc_stats.corrected += stat;
|
2014-06-24 17:10:04 +09:00
|
|
|
max_bitflips = max_t(unsigned int, max_bitflips, stat);
|
|
|
|
}
|
2007-10-31 21:53:06 +09:00
|
|
|
|
|
|
|
oob += eccbytes;
|
|
|
|
|
|
|
|
if (chip->ecc.postpad) {
|
|
|
|
chip->read_buf(mtd, oob, chip->ecc.postpad);
|
|
|
|
oob += chip->ecc.postpad;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Calculate remaining oob bytes */
|
|
|
|
i = mtd->oobsize - (oob - chip->oob_poi);
|
|
|
|
if (i)
|
|
|
|
chip->read_buf(mtd, oob, i);
|
|
|
|
|
2014-06-24 17:10:04 +09:00
|
|
|
return max_bitflips;
|
2005-09-15 06:53:32 +09:00
|
|
|
}
|
2005-08-17 19:55:25 +09:00
|
|
|
|
2007-10-31 21:53:06 +09:00
|
|
|
/**
|
2013-01-14 12:46:50 +09:00
|
|
|
* nand_transfer_oob - [INTERN] Transfer oob to client buffer
|
|
|
|
* @chip: nand chip structure
|
|
|
|
* @oob: oob destination address
|
|
|
|
* @ops: oob ops structure
|
|
|
|
* @len: size of oob to transfer
|
2007-10-31 21:53:06 +09:00
|
|
|
*/
|
|
|
|
static uint8_t *nand_transfer_oob(struct nand_chip *chip, uint8_t *oob,
|
|
|
|
struct mtd_oob_ops *ops, size_t len)
|
|
|
|
{
|
2011-10-12 16:32:01 +09:00
|
|
|
switch (ops->mode) {
|
2007-10-31 21:53:06 +09:00
|
|
|
|
2013-01-14 12:46:50 +09:00
|
|
|
case MTD_OPS_PLACE_OOB:
|
|
|
|
case MTD_OPS_RAW:
|
2007-10-31 21:53:06 +09:00
|
|
|
memcpy(oob, chip->oob_poi + ops->ooboffs, len);
|
|
|
|
return oob + len;
|
|
|
|
|
2013-01-14 12:46:50 +09:00
|
|
|
case MTD_OPS_AUTO_OOB: {
|
2007-10-31 21:53:06 +09:00
|
|
|
struct nand_oobfree *free = chip->ecc.layout->oobfree;
|
|
|
|
uint32_t boffs = 0, roffs = ops->ooboffs;
|
|
|
|
size_t bytes = 0;
|
|
|
|
|
2011-10-12 16:32:01 +09:00
|
|
|
for (; free->length && len; free++, len -= bytes) {
|
2013-01-14 12:46:50 +09:00
|
|
|
/* Read request not from offset 0? */
|
2007-10-31 21:53:06 +09:00
|
|
|
if (unlikely(roffs)) {
|
|
|
|
if (roffs >= free->length) {
|
|
|
|
roffs -= free->length;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
boffs = free->offset + roffs;
|
|
|
|
bytes = min_t(size_t, len,
|
|
|
|
(free->length - roffs));
|
|
|
|
roffs = 0;
|
|
|
|
} else {
|
|
|
|
bytes = min_t(size_t, len, free->length);
|
|
|
|
boffs = free->offset;
|
|
|
|
}
|
|
|
|
memcpy(oob, chip->oob_poi + boffs, bytes);
|
|
|
|
oob += bytes;
|
|
|
|
}
|
|
|
|
return oob;
|
|
|
|
}
|
|
|
|
default:
|
|
|
|
BUG();
|
|
|
|
}
|
|
|
|
return NULL;
|
|
|
|
}
|
2005-08-17 19:55:25 +09:00
|
|
|
|
2014-06-24 17:10:04 +09:00
|
|
|
/**
|
|
|
|
* nand_setup_read_retry - [INTERN] Set the READ RETRY mode
|
|
|
|
* @mtd: MTD device structure
|
|
|
|
* @retry_mode: the retry mode to use
|
|
|
|
*
|
|
|
|
* Some vendors supply a special command to shift the Vt threshold, to be used
|
|
|
|
* when there are too many bitflips in a page (i.e., ECC error). After setting
|
|
|
|
* a new threshold, the host should retry reading the page.
|
|
|
|
*/
|
|
|
|
static int nand_setup_read_retry(struct mtd_info *mtd, int retry_mode)
|
|
|
|
{
|
|
|
|
struct nand_chip *chip = mtd->priv;
|
|
|
|
|
|
|
|
pr_debug("setting READ RETRY mode %d\n", retry_mode);
|
|
|
|
|
|
|
|
if (retry_mode >= chip->read_retries)
|
|
|
|
return -EINVAL;
|
|
|
|
|
|
|
|
if (!chip->setup_read_retry)
|
|
|
|
return -EOPNOTSUPP;
|
|
|
|
|
|
|
|
return chip->setup_read_retry(mtd, retry_mode);
|
|
|
|
}
|
|
|
|
|
2005-08-17 19:55:25 +09:00
|
|
|
/**
|
2013-01-14 12:46:50 +09:00
|
|
|
* nand_do_read_ops - [INTERN] Read data with ECC
|
|
|
|
* @mtd: MTD device structure
|
|
|
|
* @from: offset to read from
|
|
|
|
* @ops: oob ops structure
|
2005-08-17 19:55:25 +09:00
|
|
|
*
|
2007-10-31 21:53:06 +09:00
|
|
|
* Internal function. Called with chip held.
|
2005-08-17 19:55:25 +09:00
|
|
|
*/
|
2007-10-31 21:53:06 +09:00
|
|
|
static int nand_do_read_ops(struct mtd_info *mtd, loff_t from,
|
|
|
|
struct mtd_oob_ops *ops)
|
2005-08-17 19:55:25 +09:00
|
|
|
{
|
2013-01-14 12:46:50 +09:00
|
|
|
int chipnr, page, realpage, col, bytes, aligned, oob_required;
|
2007-10-31 21:53:06 +09:00
|
|
|
struct nand_chip *chip = mtd->priv;
|
|
|
|
int ret = 0;
|
|
|
|
uint32_t readlen = ops->len;
|
|
|
|
uint32_t oobreadlen = ops->ooblen;
|
2013-01-14 12:46:50 +09:00
|
|
|
uint32_t max_oobsize = ops->mode == MTD_OPS_AUTO_OOB ?
|
2011-10-12 16:32:02 +09:00
|
|
|
mtd->oobavail : mtd->oobsize;
|
|
|
|
|
2007-10-31 21:53:06 +09:00
|
|
|
uint8_t *bufpoi, *oob, *buf;
|
mtd: driver _read() returns max_bitflips; mtd_read() returns -EUCLEAN
Linux modified the MTD driver interface in commit edbc4540 (with the
same name as this commit). The effect is that calls to mtd_read will
not return -EUCLEAN if the number of ECC-corrected bit errors is below
a certain threshold, which defaults to the strength of the ECC. This
allows -EUCLEAN to stop indicating "some bits were corrected" and begin
indicating "a large number of bits were corrected, the data held in
this region of flash may be lost soon". UBI makes use of this and when
-EUCLEAN is returned from mtd_read it will move data to another block
of flash. Without adopting this interface change UBI on U-boot attempts
to move data between blocks every time a single bit is corrected using
the ECC, which is a very common occurance on some devices.
For some devices where bit errors are common enough, UBI can get stuck
constantly moving data around because each block it attempts to use has
a single bit error. This condition is hit when wear_leveling_worker
attempts to move data from one PEB to another in response to an
-EUCLEAN/UBI_IO_BITFLIPS error. When this happens ubi_eba_copy_leb is
called to perform the data copy, and after the data is written it is
read back to check its validity. If that read returns UBI_IO_BITFLIPS
(in response to an MTD -EUCLEAN) then ubi_eba_copy_leb returns 1 to
wear_leveling worker, which then proceeds to schedule the destination
PEB for erasure. This leads to erase_worker running on the PEB, and
following a successful erase wear_leveling_worker is called which
begins this whole cycle all over again. The end result is that (without
UBI debug output enabled) the boot appears to simply hang whilst in
reality U-boot busily works away at destroying a block of the NAND
flash. Debug output from this situation:
UBI DBG: ensure_wear_leveling: schedule scrubbing
UBI DBG: wear_leveling_worker: scrub PEB 1027 to PEB 4083
UBI DBG: ubi_io_read_vid_hdr: read VID header from PEB 1027
UBI DBG: ubi_io_read: read 4096 bytes from PEB 1027:4096
UBI DBG: ubi_eba_copy_leb: copy LEB 0:0, PEB 1027 to PEB 4083
UBI DBG: ubi_eba_copy_leb: read 1040384 bytes of data
UBI DBG: ubi_io_read: read 1040384 bytes from PEB 1027:8192
UBI: fixable bit-flip detected at PEB 1027
UBI DBG: ubi_io_write_vid_hdr: write VID header to PEB 4083
UBI DBG: ubi_io_write: write 4096 bytes to PEB 4083:4096
UBI DBG: ubi_io_read_vid_hdr: read VID header from PEB 4083
UBI DBG: ubi_io_read: read 4096 bytes from PEB 4083:4096
UBI DBG: ubi_io_write: write 4096 bytes to PEB 4083:8192
UBI DBG: ubi_io_read: read 4096 bytes from PEB 4083:8192
UBI: fixable bit-flip detected at PEB 4083
UBI DBG: schedule_erase: schedule erasure of PEB 4083, EC 55, torture 0
UBI DBG: erase_worker: erase PEB 4083 EC 55
UBI DBG: sync_erase: erase PEB 4083, old EC 55
UBI DBG: do_sync_erase: erase PEB 4083
UBI DBG: sync_erase: erased PEB 4083, new EC 56
UBI DBG: ubi_io_write_ec_hdr: write EC header to PEB 4083
UBI DBG: ubi_io_write: write 4096 bytes to PEB 4083:0
UBI DBG: ensure_wear_leveling: schedule scrubbing
UBI DBG: wear_leveling_worker: scrub PEB 1027 to PEB 4083
...
This patch adopts the interface change as in Linux commit edbc4540 in
order to avoid such situations. Given that none of the drivers under
drivers/mtd return -EUCLEAN, this should only affect those using
software ECC. I have tested that it works on a board which is
currently out of tree, but which I hope to be able to begin
upstreaming soon.
Signed-off-by: Paul Burton <paul.burton@imgtec.com>
Acked-by: Stefan Roese <sr@denx.de>
2013-09-04 23:16:56 +09:00
|
|
|
unsigned int max_bitflips = 0;
|
2014-06-24 17:10:04 +09:00
|
|
|
int retry_mode = 0;
|
|
|
|
bool ecc_fail = false;
|
2005-08-17 19:55:25 +09:00
|
|
|
|
2007-10-31 21:53:06 +09:00
|
|
|
chipnr = (int)(from >> chip->chip_shift);
|
|
|
|
chip->select_chip(mtd, chipnr);
|
2005-08-17 19:55:25 +09:00
|
|
|
|
2007-10-31 21:53:06 +09:00
|
|
|
realpage = (int)(from >> chip->page_shift);
|
|
|
|
page = realpage & chip->pagemask;
|
2005-08-17 19:55:25 +09:00
|
|
|
|
2007-10-31 21:53:06 +09:00
|
|
|
col = (int)(from & (mtd->writesize - 1));
|
2005-08-17 19:55:25 +09:00
|
|
|
|
2007-10-31 21:53:06 +09:00
|
|
|
buf = ops->datbuf;
|
|
|
|
oob = ops->oobbuf;
|
2013-01-14 12:46:50 +09:00
|
|
|
oob_required = oob ? 1 : 0;
|
2005-09-15 06:53:32 +09:00
|
|
|
|
2011-10-12 16:32:01 +09:00
|
|
|
while (1) {
|
2014-06-24 17:10:04 +09:00
|
|
|
unsigned int ecc_failures = mtd->ecc_stats.failed;
|
2011-02-03 09:15:57 +09:00
|
|
|
|
2014-06-24 17:10:04 +09:00
|
|
|
WATCHDOG_RESET();
|
2007-10-31 21:53:06 +09:00
|
|
|
bytes = min(mtd->writesize - col, readlen);
|
|
|
|
aligned = (bytes == mtd->writesize);
|
2005-09-15 06:53:32 +09:00
|
|
|
|
2013-01-14 12:46:50 +09:00
|
|
|
/* Is the current page in the buffer? */
|
2007-10-31 21:53:06 +09:00
|
|
|
if (realpage != chip->pagebuf || oob) {
|
|
|
|
bufpoi = aligned ? buf : chip->buffers->databuf;
|
2005-08-17 19:55:25 +09:00
|
|
|
|
2014-06-24 17:10:04 +09:00
|
|
|
read_retry:
|
2013-01-14 12:46:50 +09:00
|
|
|
chip->cmdfunc(mtd, NAND_CMD_READ0, 0x00, page);
|
2005-08-17 19:55:25 +09:00
|
|
|
|
mtd: driver _read() returns max_bitflips; mtd_read() returns -EUCLEAN
Linux modified the MTD driver interface in commit edbc4540 (with the
same name as this commit). The effect is that calls to mtd_read will
not return -EUCLEAN if the number of ECC-corrected bit errors is below
a certain threshold, which defaults to the strength of the ECC. This
allows -EUCLEAN to stop indicating "some bits were corrected" and begin
indicating "a large number of bits were corrected, the data held in
this region of flash may be lost soon". UBI makes use of this and when
-EUCLEAN is returned from mtd_read it will move data to another block
of flash. Without adopting this interface change UBI on U-boot attempts
to move data between blocks every time a single bit is corrected using
the ECC, which is a very common occurance on some devices.
For some devices where bit errors are common enough, UBI can get stuck
constantly moving data around because each block it attempts to use has
a single bit error. This condition is hit when wear_leveling_worker
attempts to move data from one PEB to another in response to an
-EUCLEAN/UBI_IO_BITFLIPS error. When this happens ubi_eba_copy_leb is
called to perform the data copy, and after the data is written it is
read back to check its validity. If that read returns UBI_IO_BITFLIPS
(in response to an MTD -EUCLEAN) then ubi_eba_copy_leb returns 1 to
wear_leveling worker, which then proceeds to schedule the destination
PEB for erasure. This leads to erase_worker running on the PEB, and
following a successful erase wear_leveling_worker is called which
begins this whole cycle all over again. The end result is that (without
UBI debug output enabled) the boot appears to simply hang whilst in
reality U-boot busily works away at destroying a block of the NAND
flash. Debug output from this situation:
UBI DBG: ensure_wear_leveling: schedule scrubbing
UBI DBG: wear_leveling_worker: scrub PEB 1027 to PEB 4083
UBI DBG: ubi_io_read_vid_hdr: read VID header from PEB 1027
UBI DBG: ubi_io_read: read 4096 bytes from PEB 1027:4096
UBI DBG: ubi_eba_copy_leb: copy LEB 0:0, PEB 1027 to PEB 4083
UBI DBG: ubi_eba_copy_leb: read 1040384 bytes of data
UBI DBG: ubi_io_read: read 1040384 bytes from PEB 1027:8192
UBI: fixable bit-flip detected at PEB 1027
UBI DBG: ubi_io_write_vid_hdr: write VID header to PEB 4083
UBI DBG: ubi_io_write: write 4096 bytes to PEB 4083:4096
UBI DBG: ubi_io_read_vid_hdr: read VID header from PEB 4083
UBI DBG: ubi_io_read: read 4096 bytes from PEB 4083:4096
UBI DBG: ubi_io_write: write 4096 bytes to PEB 4083:8192
UBI DBG: ubi_io_read: read 4096 bytes from PEB 4083:8192
UBI: fixable bit-flip detected at PEB 4083
UBI DBG: schedule_erase: schedule erasure of PEB 4083, EC 55, torture 0
UBI DBG: erase_worker: erase PEB 4083 EC 55
UBI DBG: sync_erase: erase PEB 4083, old EC 55
UBI DBG: do_sync_erase: erase PEB 4083
UBI DBG: sync_erase: erased PEB 4083, new EC 56
UBI DBG: ubi_io_write_ec_hdr: write EC header to PEB 4083
UBI DBG: ubi_io_write: write 4096 bytes to PEB 4083:0
UBI DBG: ensure_wear_leveling: schedule scrubbing
UBI DBG: wear_leveling_worker: scrub PEB 1027 to PEB 4083
...
This patch adopts the interface change as in Linux commit edbc4540 in
order to avoid such situations. Given that none of the drivers under
drivers/mtd return -EUCLEAN, this should only affect those using
software ECC. I have tested that it works on a board which is
currently out of tree, but which I hope to be able to begin
upstreaming soon.
Signed-off-by: Paul Burton <paul.burton@imgtec.com>
Acked-by: Stefan Roese <sr@denx.de>
2013-09-04 23:16:56 +09:00
|
|
|
/*
|
|
|
|
* Now read the page into the buffer. Absent an error,
|
|
|
|
* the read methods return max bitflips per ecc step.
|
|
|
|
*/
|
2013-01-14 12:46:50 +09:00
|
|
|
if (unlikely(ops->mode == MTD_OPS_RAW))
|
|
|
|
ret = chip->ecc.read_page_raw(mtd, chip, bufpoi,
|
|
|
|
oob_required,
|
|
|
|
page);
|
2012-11-05 15:46:31 +09:00
|
|
|
else if (!aligned && NAND_HAS_SUBPAGE_READ(chip) &&
|
2014-06-24 17:10:04 +09:00
|
|
|
!oob)
|
2011-10-12 16:32:01 +09:00
|
|
|
ret = chip->ecc.read_subpage(mtd, chip,
|
2014-07-15 23:08:43 +09:00
|
|
|
col, bytes, bufpoi,
|
|
|
|
page);
|
2007-10-31 21:53:06 +09:00
|
|
|
else
|
2009-08-11 02:27:46 +09:00
|
|
|
ret = chip->ecc.read_page(mtd, chip, bufpoi,
|
2013-01-14 12:46:50 +09:00
|
|
|
oob_required, page);
|
|
|
|
if (ret < 0) {
|
|
|
|
if (!aligned)
|
|
|
|
/* Invalidate page cache */
|
|
|
|
chip->pagebuf = -1;
|
2007-10-31 21:53:06 +09:00
|
|
|
break;
|
2013-01-14 12:46:50 +09:00
|
|
|
}
|
2005-08-17 19:55:25 +09:00
|
|
|
|
mtd: driver _read() returns max_bitflips; mtd_read() returns -EUCLEAN
Linux modified the MTD driver interface in commit edbc4540 (with the
same name as this commit). The effect is that calls to mtd_read will
not return -EUCLEAN if the number of ECC-corrected bit errors is below
a certain threshold, which defaults to the strength of the ECC. This
allows -EUCLEAN to stop indicating "some bits were corrected" and begin
indicating "a large number of bits were corrected, the data held in
this region of flash may be lost soon". UBI makes use of this and when
-EUCLEAN is returned from mtd_read it will move data to another block
of flash. Without adopting this interface change UBI on U-boot attempts
to move data between blocks every time a single bit is corrected using
the ECC, which is a very common occurance on some devices.
For some devices where bit errors are common enough, UBI can get stuck
constantly moving data around because each block it attempts to use has
a single bit error. This condition is hit when wear_leveling_worker
attempts to move data from one PEB to another in response to an
-EUCLEAN/UBI_IO_BITFLIPS error. When this happens ubi_eba_copy_leb is
called to perform the data copy, and after the data is written it is
read back to check its validity. If that read returns UBI_IO_BITFLIPS
(in response to an MTD -EUCLEAN) then ubi_eba_copy_leb returns 1 to
wear_leveling worker, which then proceeds to schedule the destination
PEB for erasure. This leads to erase_worker running on the PEB, and
following a successful erase wear_leveling_worker is called which
begins this whole cycle all over again. The end result is that (without
UBI debug output enabled) the boot appears to simply hang whilst in
reality U-boot busily works away at destroying a block of the NAND
flash. Debug output from this situation:
UBI DBG: ensure_wear_leveling: schedule scrubbing
UBI DBG: wear_leveling_worker: scrub PEB 1027 to PEB 4083
UBI DBG: ubi_io_read_vid_hdr: read VID header from PEB 1027
UBI DBG: ubi_io_read: read 4096 bytes from PEB 1027:4096
UBI DBG: ubi_eba_copy_leb: copy LEB 0:0, PEB 1027 to PEB 4083
UBI DBG: ubi_eba_copy_leb: read 1040384 bytes of data
UBI DBG: ubi_io_read: read 1040384 bytes from PEB 1027:8192
UBI: fixable bit-flip detected at PEB 1027
UBI DBG: ubi_io_write_vid_hdr: write VID header to PEB 4083
UBI DBG: ubi_io_write: write 4096 bytes to PEB 4083:4096
UBI DBG: ubi_io_read_vid_hdr: read VID header from PEB 4083
UBI DBG: ubi_io_read: read 4096 bytes from PEB 4083:4096
UBI DBG: ubi_io_write: write 4096 bytes to PEB 4083:8192
UBI DBG: ubi_io_read: read 4096 bytes from PEB 4083:8192
UBI: fixable bit-flip detected at PEB 4083
UBI DBG: schedule_erase: schedule erasure of PEB 4083, EC 55, torture 0
UBI DBG: erase_worker: erase PEB 4083 EC 55
UBI DBG: sync_erase: erase PEB 4083, old EC 55
UBI DBG: do_sync_erase: erase PEB 4083
UBI DBG: sync_erase: erased PEB 4083, new EC 56
UBI DBG: ubi_io_write_ec_hdr: write EC header to PEB 4083
UBI DBG: ubi_io_write: write 4096 bytes to PEB 4083:0
UBI DBG: ensure_wear_leveling: schedule scrubbing
UBI DBG: wear_leveling_worker: scrub PEB 1027 to PEB 4083
...
This patch adopts the interface change as in Linux commit edbc4540 in
order to avoid such situations. Given that none of the drivers under
drivers/mtd return -EUCLEAN, this should only affect those using
software ECC. I have tested that it works on a board which is
currently out of tree, but which I hope to be able to begin
upstreaming soon.
Signed-off-by: Paul Burton <paul.burton@imgtec.com>
Acked-by: Stefan Roese <sr@denx.de>
2013-09-04 23:16:56 +09:00
|
|
|
max_bitflips = max_t(unsigned int, max_bitflips, ret);
|
|
|
|
|
2007-10-31 21:53:06 +09:00
|
|
|
/* Transfer not aligned data */
|
|
|
|
if (!aligned) {
|
2012-11-05 15:46:31 +09:00
|
|
|
if (!NAND_HAS_SUBPAGE_READ(chip) && !oob &&
|
2014-06-24 17:10:04 +09:00
|
|
|
!(mtd->ecc_stats.failed - ecc_failures) &&
|
mtd: driver _read() returns max_bitflips; mtd_read() returns -EUCLEAN
Linux modified the MTD driver interface in commit edbc4540 (with the
same name as this commit). The effect is that calls to mtd_read will
not return -EUCLEAN if the number of ECC-corrected bit errors is below
a certain threshold, which defaults to the strength of the ECC. This
allows -EUCLEAN to stop indicating "some bits were corrected" and begin
indicating "a large number of bits were corrected, the data held in
this region of flash may be lost soon". UBI makes use of this and when
-EUCLEAN is returned from mtd_read it will move data to another block
of flash. Without adopting this interface change UBI on U-boot attempts
to move data between blocks every time a single bit is corrected using
the ECC, which is a very common occurance on some devices.
For some devices where bit errors are common enough, UBI can get stuck
constantly moving data around because each block it attempts to use has
a single bit error. This condition is hit when wear_leveling_worker
attempts to move data from one PEB to another in response to an
-EUCLEAN/UBI_IO_BITFLIPS error. When this happens ubi_eba_copy_leb is
called to perform the data copy, and after the data is written it is
read back to check its validity. If that read returns UBI_IO_BITFLIPS
(in response to an MTD -EUCLEAN) then ubi_eba_copy_leb returns 1 to
wear_leveling worker, which then proceeds to schedule the destination
PEB for erasure. This leads to erase_worker running on the PEB, and
following a successful erase wear_leveling_worker is called which
begins this whole cycle all over again. The end result is that (without
UBI debug output enabled) the boot appears to simply hang whilst in
reality U-boot busily works away at destroying a block of the NAND
flash. Debug output from this situation:
UBI DBG: ensure_wear_leveling: schedule scrubbing
UBI DBG: wear_leveling_worker: scrub PEB 1027 to PEB 4083
UBI DBG: ubi_io_read_vid_hdr: read VID header from PEB 1027
UBI DBG: ubi_io_read: read 4096 bytes from PEB 1027:4096
UBI DBG: ubi_eba_copy_leb: copy LEB 0:0, PEB 1027 to PEB 4083
UBI DBG: ubi_eba_copy_leb: read 1040384 bytes of data
UBI DBG: ubi_io_read: read 1040384 bytes from PEB 1027:8192
UBI: fixable bit-flip detected at PEB 1027
UBI DBG: ubi_io_write_vid_hdr: write VID header to PEB 4083
UBI DBG: ubi_io_write: write 4096 bytes to PEB 4083:4096
UBI DBG: ubi_io_read_vid_hdr: read VID header from PEB 4083
UBI DBG: ubi_io_read: read 4096 bytes from PEB 4083:4096
UBI DBG: ubi_io_write: write 4096 bytes to PEB 4083:8192
UBI DBG: ubi_io_read: read 4096 bytes from PEB 4083:8192
UBI: fixable bit-flip detected at PEB 4083
UBI DBG: schedule_erase: schedule erasure of PEB 4083, EC 55, torture 0
UBI DBG: erase_worker: erase PEB 4083 EC 55
UBI DBG: sync_erase: erase PEB 4083, old EC 55
UBI DBG: do_sync_erase: erase PEB 4083
UBI DBG: sync_erase: erased PEB 4083, new EC 56
UBI DBG: ubi_io_write_ec_hdr: write EC header to PEB 4083
UBI DBG: ubi_io_write: write 4096 bytes to PEB 4083:0
UBI DBG: ensure_wear_leveling: schedule scrubbing
UBI DBG: wear_leveling_worker: scrub PEB 1027 to PEB 4083
...
This patch adopts the interface change as in Linux commit edbc4540 in
order to avoid such situations. Given that none of the drivers under
drivers/mtd return -EUCLEAN, this should only affect those using
software ECC. I have tested that it works on a board which is
currently out of tree, but which I hope to be able to begin
upstreaming soon.
Signed-off-by: Paul Burton <paul.burton@imgtec.com>
Acked-by: Stefan Roese <sr@denx.de>
2013-09-04 23:16:56 +09:00
|
|
|
(ops->mode != MTD_OPS_RAW)) {
|
2008-10-25 06:20:43 +09:00
|
|
|
chip->pagebuf = realpage;
|
mtd: driver _read() returns max_bitflips; mtd_read() returns -EUCLEAN
Linux modified the MTD driver interface in commit edbc4540 (with the
same name as this commit). The effect is that calls to mtd_read will
not return -EUCLEAN if the number of ECC-corrected bit errors is below
a certain threshold, which defaults to the strength of the ECC. This
allows -EUCLEAN to stop indicating "some bits were corrected" and begin
indicating "a large number of bits were corrected, the data held in
this region of flash may be lost soon". UBI makes use of this and when
-EUCLEAN is returned from mtd_read it will move data to another block
of flash. Without adopting this interface change UBI on U-boot attempts
to move data between blocks every time a single bit is corrected using
the ECC, which is a very common occurance on some devices.
For some devices where bit errors are common enough, UBI can get stuck
constantly moving data around because each block it attempts to use has
a single bit error. This condition is hit when wear_leveling_worker
attempts to move data from one PEB to another in response to an
-EUCLEAN/UBI_IO_BITFLIPS error. When this happens ubi_eba_copy_leb is
called to perform the data copy, and after the data is written it is
read back to check its validity. If that read returns UBI_IO_BITFLIPS
(in response to an MTD -EUCLEAN) then ubi_eba_copy_leb returns 1 to
wear_leveling worker, which then proceeds to schedule the destination
PEB for erasure. This leads to erase_worker running on the PEB, and
following a successful erase wear_leveling_worker is called which
begins this whole cycle all over again. The end result is that (without
UBI debug output enabled) the boot appears to simply hang whilst in
reality U-boot busily works away at destroying a block of the NAND
flash. Debug output from this situation:
UBI DBG: ensure_wear_leveling: schedule scrubbing
UBI DBG: wear_leveling_worker: scrub PEB 1027 to PEB 4083
UBI DBG: ubi_io_read_vid_hdr: read VID header from PEB 1027
UBI DBG: ubi_io_read: read 4096 bytes from PEB 1027:4096
UBI DBG: ubi_eba_copy_leb: copy LEB 0:0, PEB 1027 to PEB 4083
UBI DBG: ubi_eba_copy_leb: read 1040384 bytes of data
UBI DBG: ubi_io_read: read 1040384 bytes from PEB 1027:8192
UBI: fixable bit-flip detected at PEB 1027
UBI DBG: ubi_io_write_vid_hdr: write VID header to PEB 4083
UBI DBG: ubi_io_write: write 4096 bytes to PEB 4083:4096
UBI DBG: ubi_io_read_vid_hdr: read VID header from PEB 4083
UBI DBG: ubi_io_read: read 4096 bytes from PEB 4083:4096
UBI DBG: ubi_io_write: write 4096 bytes to PEB 4083:8192
UBI DBG: ubi_io_read: read 4096 bytes from PEB 4083:8192
UBI: fixable bit-flip detected at PEB 4083
UBI DBG: schedule_erase: schedule erasure of PEB 4083, EC 55, torture 0
UBI DBG: erase_worker: erase PEB 4083 EC 55
UBI DBG: sync_erase: erase PEB 4083, old EC 55
UBI DBG: do_sync_erase: erase PEB 4083
UBI DBG: sync_erase: erased PEB 4083, new EC 56
UBI DBG: ubi_io_write_ec_hdr: write EC header to PEB 4083
UBI DBG: ubi_io_write: write 4096 bytes to PEB 4083:0
UBI DBG: ensure_wear_leveling: schedule scrubbing
UBI DBG: wear_leveling_worker: scrub PEB 1027 to PEB 4083
...
This patch adopts the interface change as in Linux commit edbc4540 in
order to avoid such situations. Given that none of the drivers under
drivers/mtd return -EUCLEAN, this should only affect those using
software ECC. I have tested that it works on a board which is
currently out of tree, but which I hope to be able to begin
upstreaming soon.
Signed-off-by: Paul Burton <paul.burton@imgtec.com>
Acked-by: Stefan Roese <sr@denx.de>
2013-09-04 23:16:56 +09:00
|
|
|
chip->pagebuf_bitflips = ret;
|
|
|
|
} else {
|
2013-01-14 12:46:50 +09:00
|
|
|
/* Invalidate page cache */
|
|
|
|
chip->pagebuf = -1;
|
mtd: driver _read() returns max_bitflips; mtd_read() returns -EUCLEAN
Linux modified the MTD driver interface in commit edbc4540 (with the
same name as this commit). The effect is that calls to mtd_read will
not return -EUCLEAN if the number of ECC-corrected bit errors is below
a certain threshold, which defaults to the strength of the ECC. This
allows -EUCLEAN to stop indicating "some bits were corrected" and begin
indicating "a large number of bits were corrected, the data held in
this region of flash may be lost soon". UBI makes use of this and when
-EUCLEAN is returned from mtd_read it will move data to another block
of flash. Without adopting this interface change UBI on U-boot attempts
to move data between blocks every time a single bit is corrected using
the ECC, which is a very common occurance on some devices.
For some devices where bit errors are common enough, UBI can get stuck
constantly moving data around because each block it attempts to use has
a single bit error. This condition is hit when wear_leveling_worker
attempts to move data from one PEB to another in response to an
-EUCLEAN/UBI_IO_BITFLIPS error. When this happens ubi_eba_copy_leb is
called to perform the data copy, and after the data is written it is
read back to check its validity. If that read returns UBI_IO_BITFLIPS
(in response to an MTD -EUCLEAN) then ubi_eba_copy_leb returns 1 to
wear_leveling worker, which then proceeds to schedule the destination
PEB for erasure. This leads to erase_worker running on the PEB, and
following a successful erase wear_leveling_worker is called which
begins this whole cycle all over again. The end result is that (without
UBI debug output enabled) the boot appears to simply hang whilst in
reality U-boot busily works away at destroying a block of the NAND
flash. Debug output from this situation:
UBI DBG: ensure_wear_leveling: schedule scrubbing
UBI DBG: wear_leveling_worker: scrub PEB 1027 to PEB 4083
UBI DBG: ubi_io_read_vid_hdr: read VID header from PEB 1027
UBI DBG: ubi_io_read: read 4096 bytes from PEB 1027:4096
UBI DBG: ubi_eba_copy_leb: copy LEB 0:0, PEB 1027 to PEB 4083
UBI DBG: ubi_eba_copy_leb: read 1040384 bytes of data
UBI DBG: ubi_io_read: read 1040384 bytes from PEB 1027:8192
UBI: fixable bit-flip detected at PEB 1027
UBI DBG: ubi_io_write_vid_hdr: write VID header to PEB 4083
UBI DBG: ubi_io_write: write 4096 bytes to PEB 4083:4096
UBI DBG: ubi_io_read_vid_hdr: read VID header from PEB 4083
UBI DBG: ubi_io_read: read 4096 bytes from PEB 4083:4096
UBI DBG: ubi_io_write: write 4096 bytes to PEB 4083:8192
UBI DBG: ubi_io_read: read 4096 bytes from PEB 4083:8192
UBI: fixable bit-flip detected at PEB 4083
UBI DBG: schedule_erase: schedule erasure of PEB 4083, EC 55, torture 0
UBI DBG: erase_worker: erase PEB 4083 EC 55
UBI DBG: sync_erase: erase PEB 4083, old EC 55
UBI DBG: do_sync_erase: erase PEB 4083
UBI DBG: sync_erase: erased PEB 4083, new EC 56
UBI DBG: ubi_io_write_ec_hdr: write EC header to PEB 4083
UBI DBG: ubi_io_write: write 4096 bytes to PEB 4083:0
UBI DBG: ensure_wear_leveling: schedule scrubbing
UBI DBG: wear_leveling_worker: scrub PEB 1027 to PEB 4083
...
This patch adopts the interface change as in Linux commit edbc4540 in
order to avoid such situations. Given that none of the drivers under
drivers/mtd return -EUCLEAN, this should only affect those using
software ECC. I have tested that it works on a board which is
currently out of tree, but which I hope to be able to begin
upstreaming soon.
Signed-off-by: Paul Burton <paul.burton@imgtec.com>
Acked-by: Stefan Roese <sr@denx.de>
2013-09-04 23:16:56 +09:00
|
|
|
}
|
2007-10-31 21:53:06 +09:00
|
|
|
memcpy(buf, chip->buffers->databuf + col, bytes);
|
|
|
|
}
|
2005-08-17 19:55:25 +09:00
|
|
|
|
2007-10-31 21:53:06 +09:00
|
|
|
if (unlikely(oob)) {
|
2011-10-12 16:32:02 +09:00
|
|
|
int toread = min(oobreadlen, max_oobsize);
|
|
|
|
|
|
|
|
if (toread) {
|
|
|
|
oob = nand_transfer_oob(chip,
|
|
|
|
oob, ops, toread);
|
|
|
|
oobreadlen -= toread;
|
|
|
|
}
|
2007-10-31 21:53:06 +09:00
|
|
|
}
|
2014-06-24 17:10:04 +09:00
|
|
|
|
|
|
|
if (chip->options & NAND_NEED_READRDY) {
|
|
|
|
/* Apply delay or wait for ready/busy pin */
|
|
|
|
if (!chip->dev_ready)
|
|
|
|
udelay(chip->chip_delay);
|
|
|
|
else
|
|
|
|
nand_wait_ready(mtd);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (mtd->ecc_stats.failed - ecc_failures) {
|
|
|
|
if (retry_mode + 1 < chip->read_retries) {
|
|
|
|
retry_mode++;
|
|
|
|
ret = nand_setup_read_retry(mtd,
|
|
|
|
retry_mode);
|
|
|
|
if (ret < 0)
|
|
|
|
break;
|
|
|
|
|
|
|
|
/* Reset failures; retry */
|
|
|
|
mtd->ecc_stats.failed = ecc_failures;
|
|
|
|
goto read_retry;
|
|
|
|
} else {
|
|
|
|
/* No more retry modes; real failure */
|
|
|
|
ecc_fail = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
buf += bytes;
|
2007-10-31 21:53:06 +09:00
|
|
|
} else {
|
|
|
|
memcpy(buf, chip->buffers->databuf + col, bytes);
|
|
|
|
buf += bytes;
|
mtd: driver _read() returns max_bitflips; mtd_read() returns -EUCLEAN
Linux modified the MTD driver interface in commit edbc4540 (with the
same name as this commit). The effect is that calls to mtd_read will
not return -EUCLEAN if the number of ECC-corrected bit errors is below
a certain threshold, which defaults to the strength of the ECC. This
allows -EUCLEAN to stop indicating "some bits were corrected" and begin
indicating "a large number of bits were corrected, the data held in
this region of flash may be lost soon". UBI makes use of this and when
-EUCLEAN is returned from mtd_read it will move data to another block
of flash. Without adopting this interface change UBI on U-boot attempts
to move data between blocks every time a single bit is corrected using
the ECC, which is a very common occurance on some devices.
For some devices where bit errors are common enough, UBI can get stuck
constantly moving data around because each block it attempts to use has
a single bit error. This condition is hit when wear_leveling_worker
attempts to move data from one PEB to another in response to an
-EUCLEAN/UBI_IO_BITFLIPS error. When this happens ubi_eba_copy_leb is
called to perform the data copy, and after the data is written it is
read back to check its validity. If that read returns UBI_IO_BITFLIPS
(in response to an MTD -EUCLEAN) then ubi_eba_copy_leb returns 1 to
wear_leveling worker, which then proceeds to schedule the destination
PEB for erasure. This leads to erase_worker running on the PEB, and
following a successful erase wear_leveling_worker is called which
begins this whole cycle all over again. The end result is that (without
UBI debug output enabled) the boot appears to simply hang whilst in
reality U-boot busily works away at destroying a block of the NAND
flash. Debug output from this situation:
UBI DBG: ensure_wear_leveling: schedule scrubbing
UBI DBG: wear_leveling_worker: scrub PEB 1027 to PEB 4083
UBI DBG: ubi_io_read_vid_hdr: read VID header from PEB 1027
UBI DBG: ubi_io_read: read 4096 bytes from PEB 1027:4096
UBI DBG: ubi_eba_copy_leb: copy LEB 0:0, PEB 1027 to PEB 4083
UBI DBG: ubi_eba_copy_leb: read 1040384 bytes of data
UBI DBG: ubi_io_read: read 1040384 bytes from PEB 1027:8192
UBI: fixable bit-flip detected at PEB 1027
UBI DBG: ubi_io_write_vid_hdr: write VID header to PEB 4083
UBI DBG: ubi_io_write: write 4096 bytes to PEB 4083:4096
UBI DBG: ubi_io_read_vid_hdr: read VID header from PEB 4083
UBI DBG: ubi_io_read: read 4096 bytes from PEB 4083:4096
UBI DBG: ubi_io_write: write 4096 bytes to PEB 4083:8192
UBI DBG: ubi_io_read: read 4096 bytes from PEB 4083:8192
UBI: fixable bit-flip detected at PEB 4083
UBI DBG: schedule_erase: schedule erasure of PEB 4083, EC 55, torture 0
UBI DBG: erase_worker: erase PEB 4083 EC 55
UBI DBG: sync_erase: erase PEB 4083, old EC 55
UBI DBG: do_sync_erase: erase PEB 4083
UBI DBG: sync_erase: erased PEB 4083, new EC 56
UBI DBG: ubi_io_write_ec_hdr: write EC header to PEB 4083
UBI DBG: ubi_io_write: write 4096 bytes to PEB 4083:0
UBI DBG: ensure_wear_leveling: schedule scrubbing
UBI DBG: wear_leveling_worker: scrub PEB 1027 to PEB 4083
...
This patch adopts the interface change as in Linux commit edbc4540 in
order to avoid such situations. Given that none of the drivers under
drivers/mtd return -EUCLEAN, this should only affect those using
software ECC. I have tested that it works on a board which is
currently out of tree, but which I hope to be able to begin
upstreaming soon.
Signed-off-by: Paul Burton <paul.burton@imgtec.com>
Acked-by: Stefan Roese <sr@denx.de>
2013-09-04 23:16:56 +09:00
|
|
|
max_bitflips = max_t(unsigned int, max_bitflips,
|
|
|
|
chip->pagebuf_bitflips);
|
2007-10-31 21:53:06 +09:00
|
|
|
}
|
2005-08-17 19:55:25 +09:00
|
|
|
|
2007-10-31 21:53:06 +09:00
|
|
|
readlen -= bytes;
|
2005-08-17 19:55:25 +09:00
|
|
|
|
2014-06-24 17:10:04 +09:00
|
|
|
/* Reset to retry mode 0 */
|
|
|
|
if (retry_mode) {
|
|
|
|
ret = nand_setup_read_retry(mtd, 0);
|
|
|
|
if (ret < 0)
|
|
|
|
break;
|
|
|
|
retry_mode = 0;
|
|
|
|
}
|
|
|
|
|
2007-10-31 21:53:06 +09:00
|
|
|
if (!readlen)
|
|
|
|
break;
|
2005-09-15 06:53:32 +09:00
|
|
|
|
2013-01-14 12:46:50 +09:00
|
|
|
/* For subsequent reads align to page boundary */
|
2007-10-31 21:53:06 +09:00
|
|
|
col = 0;
|
|
|
|
/* Increment page address */
|
|
|
|
realpage++;
|
2005-09-15 06:53:32 +09:00
|
|
|
|
2007-10-31 21:53:06 +09:00
|
|
|
page = realpage & chip->pagemask;
|
|
|
|
/* Check, if we cross a chip boundary */
|
|
|
|
if (!page) {
|
|
|
|
chipnr++;
|
|
|
|
chip->select_chip(mtd, -1);
|
|
|
|
chip->select_chip(mtd, chipnr);
|
2005-08-17 19:55:25 +09:00
|
|
|
}
|
2007-10-31 21:53:06 +09:00
|
|
|
}
|
2014-06-24 17:10:04 +09:00
|
|
|
chip->select_chip(mtd, -1);
|
2005-08-17 19:55:25 +09:00
|
|
|
|
2007-10-31 21:53:06 +09:00
|
|
|
ops->retlen = ops->len - (size_t) readlen;
|
|
|
|
if (oob)
|
|
|
|
ops->oobretlen = ops->ooblen - oobreadlen;
|
2005-08-17 19:55:25 +09:00
|
|
|
|
2014-06-24 17:10:04 +09:00
|
|
|
if (ret < 0)
|
2007-10-31 21:53:06 +09:00
|
|
|
return ret;
|
2005-09-15 06:53:32 +09:00
|
|
|
|
2014-06-24 17:10:04 +09:00
|
|
|
if (ecc_fail)
|
2007-10-31 21:53:06 +09:00
|
|
|
return -EBADMSG;
|
2005-09-15 06:53:32 +09:00
|
|
|
|
mtd: driver _read() returns max_bitflips; mtd_read() returns -EUCLEAN
Linux modified the MTD driver interface in commit edbc4540 (with the
same name as this commit). The effect is that calls to mtd_read will
not return -EUCLEAN if the number of ECC-corrected bit errors is below
a certain threshold, which defaults to the strength of the ECC. This
allows -EUCLEAN to stop indicating "some bits were corrected" and begin
indicating "a large number of bits were corrected, the data held in
this region of flash may be lost soon". UBI makes use of this and when
-EUCLEAN is returned from mtd_read it will move data to another block
of flash. Without adopting this interface change UBI on U-boot attempts
to move data between blocks every time a single bit is corrected using
the ECC, which is a very common occurance on some devices.
For some devices where bit errors are common enough, UBI can get stuck
constantly moving data around because each block it attempts to use has
a single bit error. This condition is hit when wear_leveling_worker
attempts to move data from one PEB to another in response to an
-EUCLEAN/UBI_IO_BITFLIPS error. When this happens ubi_eba_copy_leb is
called to perform the data copy, and after the data is written it is
read back to check its validity. If that read returns UBI_IO_BITFLIPS
(in response to an MTD -EUCLEAN) then ubi_eba_copy_leb returns 1 to
wear_leveling worker, which then proceeds to schedule the destination
PEB for erasure. This leads to erase_worker running on the PEB, and
following a successful erase wear_leveling_worker is called which
begins this whole cycle all over again. The end result is that (without
UBI debug output enabled) the boot appears to simply hang whilst in
reality U-boot busily works away at destroying a block of the NAND
flash. Debug output from this situation:
UBI DBG: ensure_wear_leveling: schedule scrubbing
UBI DBG: wear_leveling_worker: scrub PEB 1027 to PEB 4083
UBI DBG: ubi_io_read_vid_hdr: read VID header from PEB 1027
UBI DBG: ubi_io_read: read 4096 bytes from PEB 1027:4096
UBI DBG: ubi_eba_copy_leb: copy LEB 0:0, PEB 1027 to PEB 4083
UBI DBG: ubi_eba_copy_leb: read 1040384 bytes of data
UBI DBG: ubi_io_read: read 1040384 bytes from PEB 1027:8192
UBI: fixable bit-flip detected at PEB 1027
UBI DBG: ubi_io_write_vid_hdr: write VID header to PEB 4083
UBI DBG: ubi_io_write: write 4096 bytes to PEB 4083:4096
UBI DBG: ubi_io_read_vid_hdr: read VID header from PEB 4083
UBI DBG: ubi_io_read: read 4096 bytes from PEB 4083:4096
UBI DBG: ubi_io_write: write 4096 bytes to PEB 4083:8192
UBI DBG: ubi_io_read: read 4096 bytes from PEB 4083:8192
UBI: fixable bit-flip detected at PEB 4083
UBI DBG: schedule_erase: schedule erasure of PEB 4083, EC 55, torture 0
UBI DBG: erase_worker: erase PEB 4083 EC 55
UBI DBG: sync_erase: erase PEB 4083, old EC 55
UBI DBG: do_sync_erase: erase PEB 4083
UBI DBG: sync_erase: erased PEB 4083, new EC 56
UBI DBG: ubi_io_write_ec_hdr: write EC header to PEB 4083
UBI DBG: ubi_io_write: write 4096 bytes to PEB 4083:0
UBI DBG: ensure_wear_leveling: schedule scrubbing
UBI DBG: wear_leveling_worker: scrub PEB 1027 to PEB 4083
...
This patch adopts the interface change as in Linux commit edbc4540 in
order to avoid such situations. Given that none of the drivers under
drivers/mtd return -EUCLEAN, this should only affect those using
software ECC. I have tested that it works on a board which is
currently out of tree, but which I hope to be able to begin
upstreaming soon.
Signed-off-by: Paul Burton <paul.burton@imgtec.com>
Acked-by: Stefan Roese <sr@denx.de>
2013-09-04 23:16:56 +09:00
|
|
|
return max_bitflips;
|
2007-10-31 21:53:06 +09:00
|
|
|
}
|
2005-08-17 19:55:25 +09:00
|
|
|
|
2007-10-31 21:53:06 +09:00
|
|
|
/**
|
2011-10-12 16:32:01 +09:00
|
|
|
* nand_read - [MTD Interface] MTD compatibility function for nand_do_read_ecc
|
2013-01-14 12:46:50 +09:00
|
|
|
* @mtd: MTD device structure
|
|
|
|
* @from: offset to read from
|
|
|
|
* @len: number of bytes to read
|
|
|
|
* @retlen: pointer to variable to store the number of read bytes
|
|
|
|
* @buf: the databuffer to put data
|
2007-10-31 21:53:06 +09:00
|
|
|
*
|
2013-01-14 12:46:50 +09:00
|
|
|
* Get hold of the chip and call nand_do_read.
|
2007-10-31 21:53:06 +09:00
|
|
|
*/
|
|
|
|
static int nand_read(struct mtd_info *mtd, loff_t from, size_t len,
|
|
|
|
size_t *retlen, uint8_t *buf)
|
|
|
|
{
|
2013-01-14 12:46:50 +09:00
|
|
|
struct mtd_oob_ops ops;
|
2007-10-31 21:53:06 +09:00
|
|
|
int ret;
|
2005-08-17 19:55:25 +09:00
|
|
|
|
2014-06-24 17:10:04 +09:00
|
|
|
nand_get_device(mtd, FL_READING);
|
2013-01-14 12:46:50 +09:00
|
|
|
ops.len = len;
|
|
|
|
ops.datbuf = buf;
|
|
|
|
ops.oobbuf = NULL;
|
|
|
|
ops.mode = MTD_OPS_PLACE_OOB;
|
|
|
|
ret = nand_do_read_ops(mtd, from, &ops);
|
|
|
|
*retlen = ops.retlen;
|
2007-10-31 21:53:06 +09:00
|
|
|
nand_release_device(mtd);
|
|
|
|
return ret;
|
|
|
|
}
|
2005-08-17 19:55:25 +09:00
|
|
|
|
2007-10-31 21:53:06 +09:00
|
|
|
/**
|
2013-01-14 12:46:50 +09:00
|
|
|
* nand_read_oob_std - [REPLACEABLE] the most common OOB data read function
|
|
|
|
* @mtd: mtd info structure
|
|
|
|
* @chip: nand chip info structure
|
|
|
|
* @page: page number to read
|
2007-10-31 21:53:06 +09:00
|
|
|
*/
|
|
|
|
static int nand_read_oob_std(struct mtd_info *mtd, struct nand_chip *chip,
|
2013-01-14 12:46:50 +09:00
|
|
|
int page)
|
2007-10-31 21:53:06 +09:00
|
|
|
{
|
2013-01-14 12:46:50 +09:00
|
|
|
chip->cmdfunc(mtd, NAND_CMD_READOOB, 0, page);
|
2007-10-31 21:53:06 +09:00
|
|
|
chip->read_buf(mtd, chip->oob_poi, mtd->oobsize);
|
2013-01-14 12:46:50 +09:00
|
|
|
return 0;
|
2007-10-31 21:53:06 +09:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2013-01-14 12:46:50 +09:00
|
|
|
* nand_read_oob_syndrome - [REPLACEABLE] OOB data read function for HW ECC
|
2007-10-31 21:53:06 +09:00
|
|
|
* with syndromes
|
2013-01-14 12:46:50 +09:00
|
|
|
* @mtd: mtd info structure
|
|
|
|
* @chip: nand chip info structure
|
|
|
|
* @page: page number to read
|
2007-10-31 21:53:06 +09:00
|
|
|
*/
|
|
|
|
static int nand_read_oob_syndrome(struct mtd_info *mtd, struct nand_chip *chip,
|
2013-01-14 12:46:50 +09:00
|
|
|
int page)
|
2007-10-31 21:53:06 +09:00
|
|
|
{
|
|
|
|
uint8_t *buf = chip->oob_poi;
|
|
|
|
int length = mtd->oobsize;
|
|
|
|
int chunk = chip->ecc.bytes + chip->ecc.prepad + chip->ecc.postpad;
|
|
|
|
int eccsize = chip->ecc.size;
|
|
|
|
uint8_t *bufpoi = buf;
|
|
|
|
int i, toread, sndrnd = 0, pos;
|
|
|
|
|
|
|
|
chip->cmdfunc(mtd, NAND_CMD_READ0, chip->ecc.size, page);
|
|
|
|
for (i = 0; i < chip->ecc.steps; i++) {
|
|
|
|
if (sndrnd) {
|
|
|
|
pos = eccsize + i * (eccsize + chunk);
|
|
|
|
if (mtd->writesize > 512)
|
|
|
|
chip->cmdfunc(mtd, NAND_CMD_RNDOUT, pos, -1);
|
|
|
|
else
|
|
|
|
chip->cmdfunc(mtd, NAND_CMD_READ0, pos, page);
|
2005-09-15 06:53:32 +09:00
|
|
|
} else
|
2007-10-31 21:53:06 +09:00
|
|
|
sndrnd = 1;
|
|
|
|
toread = min_t(int, length, chunk);
|
|
|
|
chip->read_buf(mtd, bufpoi, toread);
|
|
|
|
bufpoi += toread;
|
|
|
|
length -= toread;
|
|
|
|
}
|
|
|
|
if (length > 0)
|
|
|
|
chip->read_buf(mtd, bufpoi, length);
|
2005-09-15 06:53:32 +09:00
|
|
|
|
2013-01-14 12:46:50 +09:00
|
|
|
return 0;
|
2007-10-31 21:53:06 +09:00
|
|
|
}
|
2005-08-17 19:55:25 +09:00
|
|
|
|
2007-10-31 21:53:06 +09:00
|
|
|
/**
|
2013-01-14 12:46:50 +09:00
|
|
|
* nand_write_oob_std - [REPLACEABLE] the most common OOB data write function
|
|
|
|
* @mtd: mtd info structure
|
|
|
|
* @chip: nand chip info structure
|
|
|
|
* @page: page number to write
|
2007-10-31 21:53:06 +09:00
|
|
|
*/
|
|
|
|
static int nand_write_oob_std(struct mtd_info *mtd, struct nand_chip *chip,
|
|
|
|
int page)
|
|
|
|
{
|
|
|
|
int status = 0;
|
|
|
|
const uint8_t *buf = chip->oob_poi;
|
|
|
|
int length = mtd->oobsize;
|
2005-08-17 19:55:25 +09:00
|
|
|
|
2007-10-31 21:53:06 +09:00
|
|
|
chip->cmdfunc(mtd, NAND_CMD_SEQIN, mtd->writesize, page);
|
|
|
|
chip->write_buf(mtd, buf, length);
|
|
|
|
/* Send command to program the OOB data */
|
|
|
|
chip->cmdfunc(mtd, NAND_CMD_PAGEPROG, -1, -1);
|
2005-08-17 19:55:25 +09:00
|
|
|
|
2007-10-31 21:53:06 +09:00
|
|
|
status = chip->waitfunc(mtd, chip);
|
|
|
|
|
|
|
|
return status & NAND_STATUS_FAIL ? -EIO : 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2013-01-14 12:46:50 +09:00
|
|
|
* nand_write_oob_syndrome - [REPLACEABLE] OOB data write function for HW ECC
|
|
|
|
* with syndrome - only for large page flash
|
|
|
|
* @mtd: mtd info structure
|
|
|
|
* @chip: nand chip info structure
|
|
|
|
* @page: page number to write
|
2007-10-31 21:53:06 +09:00
|
|
|
*/
|
|
|
|
static int nand_write_oob_syndrome(struct mtd_info *mtd,
|
|
|
|
struct nand_chip *chip, int page)
|
|
|
|
{
|
|
|
|
int chunk = chip->ecc.bytes + chip->ecc.prepad + chip->ecc.postpad;
|
|
|
|
int eccsize = chip->ecc.size, length = mtd->oobsize;
|
|
|
|
int i, len, pos, status = 0, sndcmd = 0, steps = chip->ecc.steps;
|
|
|
|
const uint8_t *bufpoi = chip->oob_poi;
|
2005-08-17 19:55:25 +09:00
|
|
|
|
|
|
|
/*
|
2007-10-31 21:53:06 +09:00
|
|
|
* data-ecc-data-ecc ... ecc-oob
|
|
|
|
* or
|
|
|
|
* data-pad-ecc-pad-data-pad .... ecc-pad-oob
|
2005-08-17 19:55:25 +09:00
|
|
|
*/
|
2007-10-31 21:53:06 +09:00
|
|
|
if (!chip->ecc.prepad && !chip->ecc.postpad) {
|
|
|
|
pos = steps * (eccsize + chunk);
|
|
|
|
steps = 0;
|
|
|
|
} else
|
|
|
|
pos = eccsize;
|
|
|
|
|
|
|
|
chip->cmdfunc(mtd, NAND_CMD_SEQIN, pos, page);
|
|
|
|
for (i = 0; i < steps; i++) {
|
|
|
|
if (sndcmd) {
|
|
|
|
if (mtd->writesize <= 512) {
|
|
|
|
uint32_t fill = 0xFFFFFFFF;
|
|
|
|
|
|
|
|
len = eccsize;
|
|
|
|
while (len > 0) {
|
|
|
|
int num = min_t(int, len, 4);
|
|
|
|
chip->write_buf(mtd, (uint8_t *)&fill,
|
|
|
|
num);
|
|
|
|
len -= num;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
pos = eccsize + i * (eccsize + chunk);
|
|
|
|
chip->cmdfunc(mtd, NAND_CMD_RNDIN, pos, -1);
|
|
|
|
}
|
|
|
|
} else
|
|
|
|
sndcmd = 1;
|
|
|
|
len = min_t(int, length, chunk);
|
|
|
|
chip->write_buf(mtd, bufpoi, len);
|
|
|
|
bufpoi += len;
|
|
|
|
length -= len;
|
|
|
|
}
|
|
|
|
if (length > 0)
|
|
|
|
chip->write_buf(mtd, bufpoi, length);
|
|
|
|
|
|
|
|
chip->cmdfunc(mtd, NAND_CMD_PAGEPROG, -1, -1);
|
|
|
|
status = chip->waitfunc(mtd, chip);
|
|
|
|
|
|
|
|
return status & NAND_STATUS_FAIL ? -EIO : 0;
|
2005-08-17 19:55:25 +09:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2013-01-14 12:46:50 +09:00
|
|
|
* nand_do_read_oob - [INTERN] NAND read out-of-band
|
|
|
|
* @mtd: MTD device structure
|
|
|
|
* @from: offset to read from
|
|
|
|
* @ops: oob operations description structure
|
2005-08-17 19:55:25 +09:00
|
|
|
*
|
2013-01-14 12:46:50 +09:00
|
|
|
* NAND read out-of-band data from the spare area.
|
2005-08-17 19:55:25 +09:00
|
|
|
*/
|
2007-10-31 21:53:06 +09:00
|
|
|
static int nand_do_read_oob(struct mtd_info *mtd, loff_t from,
|
|
|
|
struct mtd_oob_ops *ops)
|
2005-08-17 19:55:25 +09:00
|
|
|
{
|
2013-01-14 12:46:50 +09:00
|
|
|
int page, realpage, chipnr;
|
2007-10-31 21:53:06 +09:00
|
|
|
struct nand_chip *chip = mtd->priv;
|
2013-01-14 12:46:50 +09:00
|
|
|
struct mtd_ecc_stats stats;
|
2007-10-31 21:53:06 +09:00
|
|
|
int readlen = ops->ooblen;
|
|
|
|
int len;
|
|
|
|
uint8_t *buf = ops->oobbuf;
|
2013-01-14 12:46:50 +09:00
|
|
|
int ret = 0;
|
2007-10-31 21:53:06 +09:00
|
|
|
|
2014-06-24 17:10:04 +09:00
|
|
|
pr_debug("%s: from = 0x%08Lx, len = %i\n",
|
2011-10-12 16:32:01 +09:00
|
|
|
__func__, (unsigned long long)from, readlen);
|
2007-10-31 21:53:06 +09:00
|
|
|
|
2013-01-14 12:46:50 +09:00
|
|
|
stats = mtd->ecc_stats;
|
|
|
|
|
|
|
|
if (ops->mode == MTD_OPS_AUTO_OOB)
|
2007-10-31 21:53:06 +09:00
|
|
|
len = chip->ecc.layout->oobavail;
|
|
|
|
else
|
|
|
|
len = mtd->oobsize;
|
2005-08-17 19:55:25 +09:00
|
|
|
|
2007-10-31 21:53:06 +09:00
|
|
|
if (unlikely(ops->ooboffs >= len)) {
|
2014-06-24 17:10:04 +09:00
|
|
|
pr_debug("%s: attempt to start read outside oob\n",
|
|
|
|
__func__);
|
2007-10-31 21:53:06 +09:00
|
|
|
return -EINVAL;
|
|
|
|
}
|
2005-08-17 19:55:25 +09:00
|
|
|
|
|
|
|
/* Do not allow reads past end of device */
|
2007-10-31 21:53:06 +09:00
|
|
|
if (unlikely(from >= mtd->size ||
|
|
|
|
ops->ooboffs + readlen > ((mtd->size >> chip->page_shift) -
|
|
|
|
(from >> chip->page_shift)) * len)) {
|
2014-06-24 17:10:04 +09:00
|
|
|
pr_debug("%s: attempt to read beyond end of device\n",
|
|
|
|
__func__);
|
2005-08-17 19:55:25 +09:00
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
|
2007-10-31 21:53:06 +09:00
|
|
|
chipnr = (int)(from >> chip->chip_shift);
|
|
|
|
chip->select_chip(mtd, chipnr);
|
2005-08-17 19:55:25 +09:00
|
|
|
|
2007-10-31 21:53:06 +09:00
|
|
|
/* Shift to get page */
|
|
|
|
realpage = (int)(from >> chip->page_shift);
|
|
|
|
page = realpage & chip->pagemask;
|
2005-08-17 19:55:25 +09:00
|
|
|
|
2011-10-12 16:32:01 +09:00
|
|
|
while (1) {
|
2011-02-03 09:15:57 +09:00
|
|
|
WATCHDOG_RESET();
|
2014-06-24 17:10:04 +09:00
|
|
|
|
2013-01-14 12:46:50 +09:00
|
|
|
if (ops->mode == MTD_OPS_RAW)
|
|
|
|
ret = chip->ecc.read_oob_raw(mtd, chip, page);
|
|
|
|
else
|
|
|
|
ret = chip->ecc.read_oob(mtd, chip, page);
|
|
|
|
|
|
|
|
if (ret < 0)
|
|
|
|
break;
|
2005-09-15 06:53:32 +09:00
|
|
|
|
2007-10-31 21:53:06 +09:00
|
|
|
len = min(len, readlen);
|
|
|
|
buf = nand_transfer_oob(chip, buf, ops, len);
|
|
|
|
|
2014-06-24 17:10:04 +09:00
|
|
|
if (chip->options & NAND_NEED_READRDY) {
|
|
|
|
/* Apply delay or wait for ready/busy pin */
|
|
|
|
if (!chip->dev_ready)
|
|
|
|
udelay(chip->chip_delay);
|
|
|
|
else
|
|
|
|
nand_wait_ready(mtd);
|
|
|
|
}
|
|
|
|
|
2007-10-31 21:53:06 +09:00
|
|
|
readlen -= len;
|
|
|
|
if (!readlen)
|
|
|
|
break;
|
|
|
|
|
|
|
|
/* Increment page address */
|
|
|
|
realpage++;
|
|
|
|
|
|
|
|
page = realpage & chip->pagemask;
|
|
|
|
/* Check, if we cross a chip boundary */
|
|
|
|
if (!page) {
|
|
|
|
chipnr++;
|
|
|
|
chip->select_chip(mtd, -1);
|
|
|
|
chip->select_chip(mtd, chipnr);
|
|
|
|
}
|
|
|
|
}
|
2014-06-24 17:10:04 +09:00
|
|
|
chip->select_chip(mtd, -1);
|
2005-08-17 19:55:25 +09:00
|
|
|
|
2013-01-14 12:46:50 +09:00
|
|
|
ops->oobretlen = ops->ooblen - readlen;
|
|
|
|
|
|
|
|
if (ret < 0)
|
|
|
|
return ret;
|
|
|
|
|
|
|
|
if (mtd->ecc_stats.failed - stats.failed)
|
|
|
|
return -EBADMSG;
|
|
|
|
|
|
|
|
return mtd->ecc_stats.corrected - stats.corrected ? -EUCLEAN : 0;
|
2005-08-17 19:55:25 +09:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2007-10-31 21:53:06 +09:00
|
|
|
* nand_read_oob - [MTD Interface] NAND read data and/or out-of-band
|
2013-01-14 12:46:50 +09:00
|
|
|
* @mtd: MTD device structure
|
|
|
|
* @from: offset to read from
|
|
|
|
* @ops: oob operation description structure
|
2005-08-17 19:55:25 +09:00
|
|
|
*
|
2013-01-14 12:46:50 +09:00
|
|
|
* NAND read data and/or out-of-band data.
|
2005-08-17 19:55:25 +09:00
|
|
|
*/
|
2007-10-31 21:53:06 +09:00
|
|
|
static int nand_read_oob(struct mtd_info *mtd, loff_t from,
|
|
|
|
struct mtd_oob_ops *ops)
|
2005-08-17 19:55:25 +09:00
|
|
|
{
|
2007-10-31 21:53:06 +09:00
|
|
|
int ret = -ENOTSUPP;
|
|
|
|
|
|
|
|
ops->retlen = 0;
|
2005-08-17 19:55:25 +09:00
|
|
|
|
|
|
|
/* Do not allow reads past end of device */
|
2007-10-31 21:53:06 +09:00
|
|
|
if (ops->datbuf && (from + ops->len) > mtd->size) {
|
2014-06-24 17:10:04 +09:00
|
|
|
pr_debug("%s: attempt to read beyond end of device\n",
|
|
|
|
__func__);
|
2005-08-17 19:55:25 +09:00
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
|
2014-06-24 17:10:04 +09:00
|
|
|
nand_get_device(mtd, FL_READING);
|
2005-08-17 19:55:25 +09:00
|
|
|
|
2011-10-12 16:32:01 +09:00
|
|
|
switch (ops->mode) {
|
2013-01-14 12:46:50 +09:00
|
|
|
case MTD_OPS_PLACE_OOB:
|
|
|
|
case MTD_OPS_AUTO_OOB:
|
|
|
|
case MTD_OPS_RAW:
|
2007-10-31 21:53:06 +09:00
|
|
|
break;
|
2005-09-15 06:53:32 +09:00
|
|
|
|
2007-10-31 21:53:06 +09:00
|
|
|
default:
|
|
|
|
goto out;
|
|
|
|
}
|
2005-09-15 06:53:32 +09:00
|
|
|
|
2007-10-31 21:53:06 +09:00
|
|
|
if (!ops->datbuf)
|
|
|
|
ret = nand_do_read_oob(mtd, from, ops);
|
|
|
|
else
|
|
|
|
ret = nand_do_read_ops(mtd, from, ops);
|
2005-08-17 19:55:25 +09:00
|
|
|
|
2011-10-12 16:32:01 +09:00
|
|
|
out:
|
2007-10-31 21:53:06 +09:00
|
|
|
nand_release_device(mtd);
|
|
|
|
return ret;
|
|
|
|
}
|
2005-08-17 19:55:25 +09:00
|
|
|
|
2005-09-15 06:53:32 +09:00
|
|
|
|
2007-10-31 21:53:06 +09:00
|
|
|
/**
|
2013-01-14 12:46:50 +09:00
|
|
|
* nand_write_page_raw - [INTERN] raw page write function
|
|
|
|
* @mtd: mtd info structure
|
|
|
|
* @chip: nand chip info structure
|
|
|
|
* @buf: data buffer
|
|
|
|
* @oob_required: must write chip->oob_poi to OOB
|
NAND: fix "raw" reads with ECC syndrome layouts
The syndrome based page read/write routines store ECC, and possibly other
"OOB" data, right after each chunk of ECC'd data. With ECC chunk size of
512 bytes and a large page (2KiB) NAND, the layout is:
data-0 OOB-0 data-1 OOB-1 data-2 OOB-2 data-3 OOB-3 OOB-leftover
Where OOBx is (prepad, ECC, postpad). However, the current "raw" routines
use a traditional layout -- data OOB, disregarding the prepad and postpad
values -- so when they're used with that type of ECC hardware, those calls
mix up the data and OOB. Which means, in particular, that bad block
tables won't be found on startup, with data corruption and related chaos
ensuing.
The current syndrome-based drivers in mainline all seem to use one chunk
per page; presumably they haven't noticed such bugs.
Fix this, by adding read/write page_raw_syndrome() routines as siblings of
the existing non-raw routines; "raw" just means to bypass the ECC
computations, not change data and OOB layout.
Signed-off-by: David Brownell <dbrownell@users.sourceforge.net>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: David Woodhouse <David.Woodhouse@intel.com>
2009-11-08 06:27:01 +09:00
|
|
|
*
|
2013-01-14 12:46:50 +09:00
|
|
|
* Not for syndrome calculating ECC controllers, which use a special oob layout.
|
2007-10-31 21:53:06 +09:00
|
|
|
*/
|
2013-01-14 12:46:50 +09:00
|
|
|
static int nand_write_page_raw(struct mtd_info *mtd, struct nand_chip *chip,
|
|
|
|
const uint8_t *buf, int oob_required)
|
2007-10-31 21:53:06 +09:00
|
|
|
{
|
|
|
|
chip->write_buf(mtd, buf, mtd->writesize);
|
2013-01-14 12:46:50 +09:00
|
|
|
if (oob_required)
|
|
|
|
chip->write_buf(mtd, chip->oob_poi, mtd->oobsize);
|
|
|
|
|
|
|
|
return 0;
|
2007-10-31 21:53:06 +09:00
|
|
|
}
|
2005-09-15 06:53:32 +09:00
|
|
|
|
NAND: fix "raw" reads with ECC syndrome layouts
The syndrome based page read/write routines store ECC, and possibly other
"OOB" data, right after each chunk of ECC'd data. With ECC chunk size of
512 bytes and a large page (2KiB) NAND, the layout is:
data-0 OOB-0 data-1 OOB-1 data-2 OOB-2 data-3 OOB-3 OOB-leftover
Where OOBx is (prepad, ECC, postpad). However, the current "raw" routines
use a traditional layout -- data OOB, disregarding the prepad and postpad
values -- so when they're used with that type of ECC hardware, those calls
mix up the data and OOB. Which means, in particular, that bad block
tables won't be found on startup, with data corruption and related chaos
ensuing.
The current syndrome-based drivers in mainline all seem to use one chunk
per page; presumably they haven't noticed such bugs.
Fix this, by adding read/write page_raw_syndrome() routines as siblings of
the existing non-raw routines; "raw" just means to bypass the ECC
computations, not change data and OOB layout.
Signed-off-by: David Brownell <dbrownell@users.sourceforge.net>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: David Woodhouse <David.Woodhouse@intel.com>
2009-11-08 06:27:01 +09:00
|
|
|
/**
|
2013-01-14 12:46:50 +09:00
|
|
|
* nand_write_page_raw_syndrome - [INTERN] raw page write function
|
|
|
|
* @mtd: mtd info structure
|
|
|
|
* @chip: nand chip info structure
|
|
|
|
* @buf: data buffer
|
|
|
|
* @oob_required: must write chip->oob_poi to OOB
|
NAND: fix "raw" reads with ECC syndrome layouts
The syndrome based page read/write routines store ECC, and possibly other
"OOB" data, right after each chunk of ECC'd data. With ECC chunk size of
512 bytes and a large page (2KiB) NAND, the layout is:
data-0 OOB-0 data-1 OOB-1 data-2 OOB-2 data-3 OOB-3 OOB-leftover
Where OOBx is (prepad, ECC, postpad). However, the current "raw" routines
use a traditional layout -- data OOB, disregarding the prepad and postpad
values -- so when they're used with that type of ECC hardware, those calls
mix up the data and OOB. Which means, in particular, that bad block
tables won't be found on startup, with data corruption and related chaos
ensuing.
The current syndrome-based drivers in mainline all seem to use one chunk
per page; presumably they haven't noticed such bugs.
Fix this, by adding read/write page_raw_syndrome() routines as siblings of
the existing non-raw routines; "raw" just means to bypass the ECC
computations, not change data and OOB layout.
Signed-off-by: David Brownell <dbrownell@users.sourceforge.net>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: David Woodhouse <David.Woodhouse@intel.com>
2009-11-08 06:27:01 +09:00
|
|
|
*
|
|
|
|
* We need a special oob layout and handling even when ECC isn't checked.
|
|
|
|
*/
|
2013-01-14 12:46:50 +09:00
|
|
|
static int nand_write_page_raw_syndrome(struct mtd_info *mtd,
|
2011-10-12 16:32:01 +09:00
|
|
|
struct nand_chip *chip,
|
2013-01-14 12:46:50 +09:00
|
|
|
const uint8_t *buf, int oob_required)
|
NAND: fix "raw" reads with ECC syndrome layouts
The syndrome based page read/write routines store ECC, and possibly other
"OOB" data, right after each chunk of ECC'd data. With ECC chunk size of
512 bytes and a large page (2KiB) NAND, the layout is:
data-0 OOB-0 data-1 OOB-1 data-2 OOB-2 data-3 OOB-3 OOB-leftover
Where OOBx is (prepad, ECC, postpad). However, the current "raw" routines
use a traditional layout -- data OOB, disregarding the prepad and postpad
values -- so when they're used with that type of ECC hardware, those calls
mix up the data and OOB. Which means, in particular, that bad block
tables won't be found on startup, with data corruption and related chaos
ensuing.
The current syndrome-based drivers in mainline all seem to use one chunk
per page; presumably they haven't noticed such bugs.
Fix this, by adding read/write page_raw_syndrome() routines as siblings of
the existing non-raw routines; "raw" just means to bypass the ECC
computations, not change data and OOB layout.
Signed-off-by: David Brownell <dbrownell@users.sourceforge.net>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: David Woodhouse <David.Woodhouse@intel.com>
2009-11-08 06:27:01 +09:00
|
|
|
{
|
|
|
|
int eccsize = chip->ecc.size;
|
|
|
|
int eccbytes = chip->ecc.bytes;
|
|
|
|
uint8_t *oob = chip->oob_poi;
|
|
|
|
int steps, size;
|
|
|
|
|
|
|
|
for (steps = chip->ecc.steps; steps > 0; steps--) {
|
|
|
|
chip->write_buf(mtd, buf, eccsize);
|
|
|
|
buf += eccsize;
|
|
|
|
|
|
|
|
if (chip->ecc.prepad) {
|
|
|
|
chip->write_buf(mtd, oob, chip->ecc.prepad);
|
|
|
|
oob += chip->ecc.prepad;
|
|
|
|
}
|
|
|
|
|
2014-07-15 23:08:43 +09:00
|
|
|
chip->write_buf(mtd, oob, eccbytes);
|
NAND: fix "raw" reads with ECC syndrome layouts
The syndrome based page read/write routines store ECC, and possibly other
"OOB" data, right after each chunk of ECC'd data. With ECC chunk size of
512 bytes and a large page (2KiB) NAND, the layout is:
data-0 OOB-0 data-1 OOB-1 data-2 OOB-2 data-3 OOB-3 OOB-leftover
Where OOBx is (prepad, ECC, postpad). However, the current "raw" routines
use a traditional layout -- data OOB, disregarding the prepad and postpad
values -- so when they're used with that type of ECC hardware, those calls
mix up the data and OOB. Which means, in particular, that bad block
tables won't be found on startup, with data corruption and related chaos
ensuing.
The current syndrome-based drivers in mainline all seem to use one chunk
per page; presumably they haven't noticed such bugs.
Fix this, by adding read/write page_raw_syndrome() routines as siblings of
the existing non-raw routines; "raw" just means to bypass the ECC
computations, not change data and OOB layout.
Signed-off-by: David Brownell <dbrownell@users.sourceforge.net>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: David Woodhouse <David.Woodhouse@intel.com>
2009-11-08 06:27:01 +09:00
|
|
|
oob += eccbytes;
|
|
|
|
|
|
|
|
if (chip->ecc.postpad) {
|
|
|
|
chip->write_buf(mtd, oob, chip->ecc.postpad);
|
|
|
|
oob += chip->ecc.postpad;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
size = mtd->oobsize - (oob - chip->oob_poi);
|
|
|
|
if (size)
|
|
|
|
chip->write_buf(mtd, oob, size);
|
2013-01-14 12:46:50 +09:00
|
|
|
|
|
|
|
return 0;
|
NAND: fix "raw" reads with ECC syndrome layouts
The syndrome based page read/write routines store ECC, and possibly other
"OOB" data, right after each chunk of ECC'd data. With ECC chunk size of
512 bytes and a large page (2KiB) NAND, the layout is:
data-0 OOB-0 data-1 OOB-1 data-2 OOB-2 data-3 OOB-3 OOB-leftover
Where OOBx is (prepad, ECC, postpad). However, the current "raw" routines
use a traditional layout -- data OOB, disregarding the prepad and postpad
values -- so when they're used with that type of ECC hardware, those calls
mix up the data and OOB. Which means, in particular, that bad block
tables won't be found on startup, with data corruption and related chaos
ensuing.
The current syndrome-based drivers in mainline all seem to use one chunk
per page; presumably they haven't noticed such bugs.
Fix this, by adding read/write page_raw_syndrome() routines as siblings of
the existing non-raw routines; "raw" just means to bypass the ECC
computations, not change data and OOB layout.
Signed-off-by: David Brownell <dbrownell@users.sourceforge.net>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: David Woodhouse <David.Woodhouse@intel.com>
2009-11-08 06:27:01 +09:00
|
|
|
}
|
2007-10-31 21:53:06 +09:00
|
|
|
/**
|
2013-01-14 12:46:50 +09:00
|
|
|
* nand_write_page_swecc - [REPLACEABLE] software ECC based page write function
|
|
|
|
* @mtd: mtd info structure
|
|
|
|
* @chip: nand chip info structure
|
|
|
|
* @buf: data buffer
|
|
|
|
* @oob_required: must write chip->oob_poi to OOB
|
2007-10-31 21:53:06 +09:00
|
|
|
*/
|
2013-01-14 12:46:50 +09:00
|
|
|
static int nand_write_page_swecc(struct mtd_info *mtd, struct nand_chip *chip,
|
|
|
|
const uint8_t *buf, int oob_required)
|
2007-10-31 21:53:06 +09:00
|
|
|
{
|
|
|
|
int i, eccsize = chip->ecc.size;
|
|
|
|
int eccbytes = chip->ecc.bytes;
|
|
|
|
int eccsteps = chip->ecc.steps;
|
|
|
|
uint8_t *ecc_calc = chip->buffers->ecccalc;
|
|
|
|
const uint8_t *p = buf;
|
|
|
|
uint32_t *eccpos = chip->ecc.layout->eccpos;
|
2005-08-17 19:55:25 +09:00
|
|
|
|
2013-01-14 12:46:50 +09:00
|
|
|
/* Software ECC calculation */
|
2007-10-31 21:53:06 +09:00
|
|
|
for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize)
|
|
|
|
chip->ecc.calculate(mtd, p, &ecc_calc[i]);
|
|
|
|
|
|
|
|
for (i = 0; i < chip->ecc.total; i++)
|
|
|
|
chip->oob_poi[eccpos[i]] = ecc_calc[i];
|
|
|
|
|
2013-01-14 12:46:50 +09:00
|
|
|
return chip->ecc.write_page_raw(mtd, chip, buf, 1);
|
2005-08-17 19:55:25 +09:00
|
|
|
}
|
|
|
|
|
2007-10-31 21:53:06 +09:00
|
|
|
/**
|
2013-01-14 12:46:50 +09:00
|
|
|
* nand_write_page_hwecc - [REPLACEABLE] hardware ECC based page write function
|
|
|
|
* @mtd: mtd info structure
|
|
|
|
* @chip: nand chip info structure
|
|
|
|
* @buf: data buffer
|
|
|
|
* @oob_required: must write chip->oob_poi to OOB
|
2007-10-31 21:53:06 +09:00
|
|
|
*/
|
2013-01-14 12:46:50 +09:00
|
|
|
static int nand_write_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip,
|
|
|
|
const uint8_t *buf, int oob_required)
|
2007-10-31 21:53:06 +09:00
|
|
|
{
|
|
|
|
int i, eccsize = chip->ecc.size;
|
|
|
|
int eccbytes = chip->ecc.bytes;
|
|
|
|
int eccsteps = chip->ecc.steps;
|
|
|
|
uint8_t *ecc_calc = chip->buffers->ecccalc;
|
|
|
|
const uint8_t *p = buf;
|
|
|
|
uint32_t *eccpos = chip->ecc.layout->eccpos;
|
|
|
|
|
|
|
|
for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize) {
|
|
|
|
chip->ecc.hwctl(mtd, NAND_ECC_WRITE);
|
|
|
|
chip->write_buf(mtd, p, eccsize);
|
|
|
|
chip->ecc.calculate(mtd, p, &ecc_calc[i]);
|
|
|
|
}
|
|
|
|
|
|
|
|
for (i = 0; i < chip->ecc.total; i++)
|
|
|
|
chip->oob_poi[eccpos[i]] = ecc_calc[i];
|
|
|
|
|
|
|
|
chip->write_buf(mtd, chip->oob_poi, mtd->oobsize);
|
2013-01-14 12:46:50 +09:00
|
|
|
|
|
|
|
return 0;
|
2007-10-31 21:53:06 +09:00
|
|
|
}
|
2005-08-17 19:55:25 +09:00
|
|
|
|
2014-06-24 17:10:04 +09:00
|
|
|
|
|
|
|
/**
|
|
|
|
* nand_write_subpage_hwecc - [REPLACABLE] hardware ECC based subpage write
|
|
|
|
* @mtd: mtd info structure
|
|
|
|
* @chip: nand chip info structure
|
|
|
|
* @offset: column address of subpage within the page
|
|
|
|
* @data_len: data length
|
|
|
|
* @buf: data buffer
|
|
|
|
* @oob_required: must write chip->oob_poi to OOB
|
|
|
|
*/
|
|
|
|
static int nand_write_subpage_hwecc(struct mtd_info *mtd,
|
|
|
|
struct nand_chip *chip, uint32_t offset,
|
|
|
|
uint32_t data_len, const uint8_t *buf,
|
|
|
|
int oob_required)
|
|
|
|
{
|
|
|
|
uint8_t *oob_buf = chip->oob_poi;
|
|
|
|
uint8_t *ecc_calc = chip->buffers->ecccalc;
|
|
|
|
int ecc_size = chip->ecc.size;
|
|
|
|
int ecc_bytes = chip->ecc.bytes;
|
|
|
|
int ecc_steps = chip->ecc.steps;
|
|
|
|
uint32_t *eccpos = chip->ecc.layout->eccpos;
|
|
|
|
uint32_t start_step = offset / ecc_size;
|
|
|
|
uint32_t end_step = (offset + data_len - 1) / ecc_size;
|
|
|
|
int oob_bytes = mtd->oobsize / ecc_steps;
|
|
|
|
int step, i;
|
|
|
|
|
|
|
|
for (step = 0; step < ecc_steps; step++) {
|
|
|
|
/* configure controller for WRITE access */
|
|
|
|
chip->ecc.hwctl(mtd, NAND_ECC_WRITE);
|
|
|
|
|
|
|
|
/* write data (untouched subpages already masked by 0xFF) */
|
|
|
|
chip->write_buf(mtd, buf, ecc_size);
|
|
|
|
|
|
|
|
/* mask ECC of un-touched subpages by padding 0xFF */
|
|
|
|
if ((step < start_step) || (step > end_step))
|
|
|
|
memset(ecc_calc, 0xff, ecc_bytes);
|
|
|
|
else
|
|
|
|
chip->ecc.calculate(mtd, buf, ecc_calc);
|
|
|
|
|
|
|
|
/* mask OOB of un-touched subpages by padding 0xFF */
|
|
|
|
/* if oob_required, preserve OOB metadata of written subpage */
|
|
|
|
if (!oob_required || (step < start_step) || (step > end_step))
|
|
|
|
memset(oob_buf, 0xff, oob_bytes);
|
|
|
|
|
|
|
|
buf += ecc_size;
|
|
|
|
ecc_calc += ecc_bytes;
|
|
|
|
oob_buf += oob_bytes;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* copy calculated ECC for whole page to chip->buffer->oob */
|
|
|
|
/* this include masked-value(0xFF) for unwritten subpages */
|
|
|
|
ecc_calc = chip->buffers->ecccalc;
|
|
|
|
for (i = 0; i < chip->ecc.total; i++)
|
|
|
|
chip->oob_poi[eccpos[i]] = ecc_calc[i];
|
|
|
|
|
|
|
|
/* write OOB buffer to NAND device */
|
|
|
|
chip->write_buf(mtd, chip->oob_poi, mtd->oobsize);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2005-09-15 06:53:32 +09:00
|
|
|
/**
|
2013-01-14 12:46:50 +09:00
|
|
|
* nand_write_page_syndrome - [REPLACEABLE] hardware ECC syndrome based page write
|
|
|
|
* @mtd: mtd info structure
|
|
|
|
* @chip: nand chip info structure
|
|
|
|
* @buf: data buffer
|
|
|
|
* @oob_required: must write chip->oob_poi to OOB
|
2005-08-17 19:55:25 +09:00
|
|
|
*
|
2013-01-14 12:46:50 +09:00
|
|
|
* The hw generator calculates the error syndrome automatically. Therefore we
|
|
|
|
* need a special oob layout and handling.
|
2007-10-31 21:53:06 +09:00
|
|
|
*/
|
2013-01-14 12:46:50 +09:00
|
|
|
static int nand_write_page_syndrome(struct mtd_info *mtd,
|
|
|
|
struct nand_chip *chip,
|
|
|
|
const uint8_t *buf, int oob_required)
|
2005-08-17 19:55:25 +09:00
|
|
|
{
|
2007-10-31 21:53:06 +09:00
|
|
|
int i, eccsize = chip->ecc.size;
|
|
|
|
int eccbytes = chip->ecc.bytes;
|
|
|
|
int eccsteps = chip->ecc.steps;
|
|
|
|
const uint8_t *p = buf;
|
|
|
|
uint8_t *oob = chip->oob_poi;
|
2005-08-17 19:55:25 +09:00
|
|
|
|
2007-10-31 21:53:06 +09:00
|
|
|
for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize) {
|
2005-08-17 19:55:25 +09:00
|
|
|
|
2007-10-31 21:53:06 +09:00
|
|
|
chip->ecc.hwctl(mtd, NAND_ECC_WRITE);
|
|
|
|
chip->write_buf(mtd, p, eccsize);
|
2005-09-15 06:53:32 +09:00
|
|
|
|
2007-10-31 21:53:06 +09:00
|
|
|
if (chip->ecc.prepad) {
|
|
|
|
chip->write_buf(mtd, oob, chip->ecc.prepad);
|
|
|
|
oob += chip->ecc.prepad;
|
|
|
|
}
|
|
|
|
|
|
|
|
chip->ecc.calculate(mtd, p, oob);
|
|
|
|
chip->write_buf(mtd, oob, eccbytes);
|
|
|
|
oob += eccbytes;
|
|
|
|
|
|
|
|
if (chip->ecc.postpad) {
|
|
|
|
chip->write_buf(mtd, oob, chip->ecc.postpad);
|
|
|
|
oob += chip->ecc.postpad;
|
2005-08-17 19:55:25 +09:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2007-10-31 21:53:06 +09:00
|
|
|
/* Calculate remaining oob bytes */
|
|
|
|
i = mtd->oobsize - (oob - chip->oob_poi);
|
|
|
|
if (i)
|
|
|
|
chip->write_buf(mtd, oob, i);
|
2013-01-14 12:46:50 +09:00
|
|
|
|
|
|
|
return 0;
|
2007-10-31 21:53:06 +09:00
|
|
|
}
|
2005-08-17 19:55:25 +09:00
|
|
|
|
|
|
|
/**
|
2007-10-31 21:53:06 +09:00
|
|
|
* nand_write_page - [REPLACEABLE] write one page
|
2013-01-14 12:46:50 +09:00
|
|
|
* @mtd: MTD device structure
|
|
|
|
* @chip: NAND chip descriptor
|
2014-06-24 17:10:04 +09:00
|
|
|
* @offset: address offset within the page
|
|
|
|
* @data_len: length of actual data to be written
|
2013-01-14 12:46:50 +09:00
|
|
|
* @buf: the data to write
|
|
|
|
* @oob_required: must write chip->oob_poi to OOB
|
|
|
|
* @page: page number to write
|
|
|
|
* @cached: cached programming
|
|
|
|
* @raw: use _raw version of write_page
|
2007-10-31 21:53:06 +09:00
|
|
|
*/
|
|
|
|
static int nand_write_page(struct mtd_info *mtd, struct nand_chip *chip,
|
2014-06-24 17:10:04 +09:00
|
|
|
uint32_t offset, int data_len, const uint8_t *buf,
|
|
|
|
int oob_required, int page, int cached, int raw)
|
2005-08-17 19:55:25 +09:00
|
|
|
{
|
2014-06-24 17:10:04 +09:00
|
|
|
int status, subpage;
|
|
|
|
|
|
|
|
if (!(chip->options & NAND_NO_SUBPAGE_WRITE) &&
|
|
|
|
chip->ecc.write_subpage)
|
|
|
|
subpage = offset || (data_len < mtd->writesize);
|
|
|
|
else
|
|
|
|
subpage = 0;
|
2007-10-31 21:53:06 +09:00
|
|
|
|
|
|
|
chip->cmdfunc(mtd, NAND_CMD_SEQIN, 0x00, page);
|
|
|
|
|
|
|
|
if (unlikely(raw))
|
2014-06-24 17:10:04 +09:00
|
|
|
status = chip->ecc.write_page_raw(mtd, chip, buf,
|
|
|
|
oob_required);
|
|
|
|
else if (subpage)
|
|
|
|
status = chip->ecc.write_subpage(mtd, chip, offset, data_len,
|
|
|
|
buf, oob_required);
|
2007-10-31 21:53:06 +09:00
|
|
|
else
|
2013-01-14 12:46:50 +09:00
|
|
|
status = chip->ecc.write_page(mtd, chip, buf, oob_required);
|
|
|
|
|
|
|
|
if (status < 0)
|
|
|
|
return status;
|
2007-10-31 21:53:06 +09:00
|
|
|
|
|
|
|
/*
|
2013-01-14 12:46:50 +09:00
|
|
|
* Cached progamming disabled for now. Not sure if it's worth the
|
|
|
|
* trouble. The speed gain is not very impressive. (2.3->2.6Mib/s).
|
2007-10-31 21:53:06 +09:00
|
|
|
*/
|
|
|
|
cached = 0;
|
|
|
|
|
2014-06-24 17:10:04 +09:00
|
|
|
if (!cached || !NAND_HAS_CACHEPROG(chip)) {
|
2007-10-31 21:53:06 +09:00
|
|
|
|
|
|
|
chip->cmdfunc(mtd, NAND_CMD_PAGEPROG, -1, -1);
|
|
|
|
status = chip->waitfunc(mtd, chip);
|
|
|
|
/*
|
|
|
|
* See if operation failed and additional status checks are
|
2013-01-14 12:46:50 +09:00
|
|
|
* available.
|
2007-10-31 21:53:06 +09:00
|
|
|
*/
|
|
|
|
if ((status & NAND_STATUS_FAIL) && (chip->errstat))
|
|
|
|
status = chip->errstat(mtd, chip, FL_WRITING, status,
|
|
|
|
page);
|
|
|
|
|
|
|
|
if (status & NAND_STATUS_FAIL)
|
|
|
|
return -EIO;
|
|
|
|
} else {
|
|
|
|
chip->cmdfunc(mtd, NAND_CMD_CACHEDPROG, -1, -1);
|
|
|
|
status = chip->waitfunc(mtd, chip);
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2013-01-14 12:46:50 +09:00
|
|
|
* nand_fill_oob - [INTERN] Transfer client buffer to oob
|
|
|
|
* @mtd: MTD device structure
|
|
|
|
* @oob: oob data buffer
|
|
|
|
* @len: oob data write length
|
|
|
|
* @ops: oob ops structure
|
2007-10-31 21:53:06 +09:00
|
|
|
*/
|
2013-01-14 12:46:50 +09:00
|
|
|
static uint8_t *nand_fill_oob(struct mtd_info *mtd, uint8_t *oob, size_t len,
|
|
|
|
struct mtd_oob_ops *ops)
|
2007-10-31 21:53:06 +09:00
|
|
|
{
|
2013-01-14 12:46:50 +09:00
|
|
|
struct nand_chip *chip = mtd->priv;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Initialise to all 0xFF, to avoid the possibility of left over OOB
|
|
|
|
* data from a previous OOB read.
|
|
|
|
*/
|
|
|
|
memset(chip->oob_poi, 0xff, mtd->oobsize);
|
|
|
|
|
2011-10-12 16:32:01 +09:00
|
|
|
switch (ops->mode) {
|
2007-10-31 21:53:06 +09:00
|
|
|
|
2013-01-14 12:46:50 +09:00
|
|
|
case MTD_OPS_PLACE_OOB:
|
|
|
|
case MTD_OPS_RAW:
|
2007-10-31 21:53:06 +09:00
|
|
|
memcpy(chip->oob_poi + ops->ooboffs, oob, len);
|
|
|
|
return oob + len;
|
|
|
|
|
2013-01-14 12:46:50 +09:00
|
|
|
case MTD_OPS_AUTO_OOB: {
|
2007-10-31 21:53:06 +09:00
|
|
|
struct nand_oobfree *free = chip->ecc.layout->oobfree;
|
|
|
|
uint32_t boffs = 0, woffs = ops->ooboffs;
|
|
|
|
size_t bytes = 0;
|
|
|
|
|
2011-10-12 16:32:01 +09:00
|
|
|
for (; free->length && len; free++, len -= bytes) {
|
2013-01-14 12:46:50 +09:00
|
|
|
/* Write request not from offset 0? */
|
2007-10-31 21:53:06 +09:00
|
|
|
if (unlikely(woffs)) {
|
|
|
|
if (woffs >= free->length) {
|
|
|
|
woffs -= free->length;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
boffs = free->offset + woffs;
|
|
|
|
bytes = min_t(size_t, len,
|
|
|
|
(free->length - woffs));
|
|
|
|
woffs = 0;
|
|
|
|
} else {
|
|
|
|
bytes = min_t(size_t, len, free->length);
|
|
|
|
boffs = free->offset;
|
|
|
|
}
|
|
|
|
memcpy(chip->oob_poi + boffs, oob, bytes);
|
|
|
|
oob += bytes;
|
|
|
|
}
|
|
|
|
return oob;
|
|
|
|
}
|
|
|
|
default:
|
|
|
|
BUG();
|
|
|
|
}
|
|
|
|
return NULL;
|
2005-08-17 19:55:25 +09:00
|
|
|
}
|
2005-09-15 06:53:32 +09:00
|
|
|
|
2011-10-12 16:32:02 +09:00
|
|
|
#define NOTALIGNED(x) ((x & (chip->subpagesize - 1)) != 0)
|
2007-10-31 21:53:06 +09:00
|
|
|
|
2005-08-17 19:55:25 +09:00
|
|
|
/**
|
2013-01-14 12:46:50 +09:00
|
|
|
* nand_do_write_ops - [INTERN] NAND write with ECC
|
|
|
|
* @mtd: MTD device structure
|
|
|
|
* @to: offset to write to
|
|
|
|
* @ops: oob operations description structure
|
2005-08-17 19:55:25 +09:00
|
|
|
*
|
2013-01-14 12:46:50 +09:00
|
|
|
* NAND write with ECC.
|
2005-08-17 19:55:25 +09:00
|
|
|
*/
|
2007-10-31 21:53:06 +09:00
|
|
|
static int nand_do_write_ops(struct mtd_info *mtd, loff_t to,
|
|
|
|
struct mtd_oob_ops *ops)
|
2005-08-17 19:55:25 +09:00
|
|
|
{
|
2007-10-31 21:53:06 +09:00
|
|
|
int chipnr, realpage, page, blockmask, column;
|
|
|
|
struct nand_chip *chip = mtd->priv;
|
|
|
|
uint32_t writelen = ops->len;
|
2011-10-12 16:32:02 +09:00
|
|
|
|
|
|
|
uint32_t oobwritelen = ops->ooblen;
|
2013-01-14 12:46:50 +09:00
|
|
|
uint32_t oobmaxlen = ops->mode == MTD_OPS_AUTO_OOB ?
|
2011-10-12 16:32:02 +09:00
|
|
|
mtd->oobavail : mtd->oobsize;
|
|
|
|
|
2007-10-31 21:53:06 +09:00
|
|
|
uint8_t *oob = ops->oobbuf;
|
|
|
|
uint8_t *buf = ops->datbuf;
|
2014-06-24 17:10:04 +09:00
|
|
|
int ret;
|
2013-01-14 12:46:50 +09:00
|
|
|
int oob_required = oob ? 1 : 0;
|
2005-08-17 19:55:25 +09:00
|
|
|
|
2007-10-31 21:53:06 +09:00
|
|
|
ops->retlen = 0;
|
|
|
|
if (!writelen)
|
|
|
|
return 0;
|
2005-08-17 19:55:25 +09:00
|
|
|
|
2014-06-24 17:10:04 +09:00
|
|
|
#ifndef __UBOOT__
|
|
|
|
/* Reject writes, which are not page aligned */
|
|
|
|
if (NOTALIGNED(to) || NOTALIGNED(ops->len)) {
|
|
|
|
#else
|
|
|
|
/* Reject writes, which are not page aligned */
|
|
|
|
if (NOTALIGNED(to)) {
|
|
|
|
#endif
|
|
|
|
pr_notice("%s: attempt to write non page aligned data\n",
|
|
|
|
__func__);
|
2007-10-31 21:53:06 +09:00
|
|
|
return -EINVAL;
|
2014-06-24 17:10:04 +09:00
|
|
|
}
|
|
|
|
|
|
|
|
column = to & (mtd->writesize - 1);
|
2007-10-31 21:53:06 +09:00
|
|
|
|
|
|
|
chipnr = (int)(to >> chip->chip_shift);
|
|
|
|
chip->select_chip(mtd, chipnr);
|
2005-08-17 19:55:25 +09:00
|
|
|
|
|
|
|
/* Check, if it is write protected */
|
2007-09-25 08:41:43 +09:00
|
|
|
if (nand_check_wp(mtd)) {
|
2014-06-24 17:10:04 +09:00
|
|
|
ret = -EIO;
|
|
|
|
goto err_out;
|
2007-09-25 08:41:43 +09:00
|
|
|
}
|
2005-08-17 19:55:25 +09:00
|
|
|
|
2007-10-31 21:53:06 +09:00
|
|
|
realpage = (int)(to >> chip->page_shift);
|
|
|
|
page = realpage & chip->pagemask;
|
|
|
|
blockmask = (1 << (chip->phys_erase_shift - chip->page_shift)) - 1;
|
|
|
|
|
|
|
|
/* Invalidate the page cache, when we write to the cached page */
|
|
|
|
if (to <= (chip->pagebuf << chip->page_shift) &&
|
|
|
|
(chip->pagebuf << chip->page_shift) < (to + ops->len))
|
|
|
|
chip->pagebuf = -1;
|
|
|
|
|
2011-10-12 16:32:02 +09:00
|
|
|
/* Don't allow multipage oob writes with offset */
|
2014-06-24 17:10:04 +09:00
|
|
|
if (oob && ops->ooboffs && (ops->ooboffs + ops->ooblen > oobmaxlen)) {
|
|
|
|
ret = -EINVAL;
|
|
|
|
goto err_out;
|
|
|
|
}
|
2011-10-12 16:32:02 +09:00
|
|
|
|
2011-10-12 16:32:01 +09:00
|
|
|
while (1) {
|
2007-10-31 21:53:06 +09:00
|
|
|
int bytes = mtd->writesize;
|
|
|
|
int cached = writelen > bytes && page != blockmask;
|
|
|
|
uint8_t *wbuf = buf;
|
|
|
|
|
2014-06-24 17:10:04 +09:00
|
|
|
WATCHDOG_RESET();
|
2013-01-14 12:46:50 +09:00
|
|
|
/* Partial page write? */
|
2014-06-24 17:10:04 +09:00
|
|
|
if (unlikely(column || writelen < (mtd->writesize - 1))) {
|
2007-10-31 21:53:06 +09:00
|
|
|
cached = 0;
|
|
|
|
bytes = min_t(int, bytes - column, (int) writelen);
|
|
|
|
chip->pagebuf = -1;
|
|
|
|
memset(chip->buffers->databuf, 0xff, mtd->writesize);
|
|
|
|
memcpy(&chip->buffers->databuf[column], buf, bytes);
|
|
|
|
wbuf = chip->buffers->databuf;
|
|
|
|
}
|
2005-09-15 06:53:32 +09:00
|
|
|
|
2011-10-12 16:32:02 +09:00
|
|
|
if (unlikely(oob)) {
|
|
|
|
size_t len = min(oobwritelen, oobmaxlen);
|
2013-01-14 12:46:50 +09:00
|
|
|
oob = nand_fill_oob(mtd, oob, len, ops);
|
2011-10-12 16:32:02 +09:00
|
|
|
oobwritelen -= len;
|
2013-01-14 12:46:50 +09:00
|
|
|
} else {
|
|
|
|
/* We still need to erase leftover OOB data */
|
|
|
|
memset(chip->oob_poi, 0xff, mtd->oobsize);
|
2011-10-12 16:32:02 +09:00
|
|
|
}
|
2014-06-24 17:10:04 +09:00
|
|
|
ret = chip->write_page(mtd, chip, column, bytes, wbuf,
|
|
|
|
oob_required, page, cached,
|
|
|
|
(ops->mode == MTD_OPS_RAW));
|
2007-10-31 21:53:06 +09:00
|
|
|
if (ret)
|
|
|
|
break;
|
2005-09-15 06:53:32 +09:00
|
|
|
|
2007-10-31 21:53:06 +09:00
|
|
|
writelen -= bytes;
|
|
|
|
if (!writelen)
|
|
|
|
break;
|
|
|
|
|
2014-06-24 17:10:04 +09:00
|
|
|
column = 0;
|
|
|
|
buf += bytes;
|
|
|
|
realpage++;
|
|
|
|
|
|
|
|
page = realpage & chip->pagemask;
|
|
|
|
/* Check, if we cross a chip boundary */
|
|
|
|
if (!page) {
|
|
|
|
chipnr++;
|
|
|
|
chip->select_chip(mtd, -1);
|
|
|
|
chip->select_chip(mtd, chipnr);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
ops->retlen = ops->len - writelen;
|
|
|
|
if (unlikely(oob))
|
|
|
|
ops->oobretlen = ops->ooblen;
|
|
|
|
|
|
|
|
err_out:
|
|
|
|
chip->select_chip(mtd, -1);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* panic_nand_write - [MTD Interface] NAND write with ECC
|
|
|
|
* @mtd: MTD device structure
|
|
|
|
* @to: offset to write to
|
|
|
|
* @len: number of bytes to write
|
|
|
|
* @retlen: pointer to variable to store the number of written bytes
|
|
|
|
* @buf: the data to write
|
|
|
|
*
|
|
|
|
* NAND write with ECC. Used when performing writes in interrupt context, this
|
|
|
|
* may for example be called by mtdoops when writing an oops while in panic.
|
|
|
|
*/
|
|
|
|
static int panic_nand_write(struct mtd_info *mtd, loff_t to, size_t len,
|
|
|
|
size_t *retlen, const uint8_t *buf)
|
|
|
|
{
|
|
|
|
struct nand_chip *chip = mtd->priv;
|
|
|
|
struct mtd_oob_ops ops;
|
|
|
|
int ret;
|
|
|
|
|
|
|
|
/* Wait for the device to get ready */
|
|
|
|
panic_nand_wait(mtd, chip, 400);
|
|
|
|
|
|
|
|
/* Grab the device */
|
|
|
|
panic_nand_get_device(chip, mtd, FL_WRITING);
|
|
|
|
|
|
|
|
ops.len = len;
|
|
|
|
ops.datbuf = (uint8_t *)buf;
|
|
|
|
ops.oobbuf = NULL;
|
|
|
|
ops.mode = MTD_OPS_PLACE_OOB;
|
2007-10-31 21:53:06 +09:00
|
|
|
|
2014-06-24 17:10:04 +09:00
|
|
|
ret = nand_do_write_ops(mtd, to, &ops);
|
2005-08-17 19:55:25 +09:00
|
|
|
|
2014-06-24 17:10:04 +09:00
|
|
|
*retlen = ops.retlen;
|
2005-08-17 19:55:25 +09:00
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2007-10-31 21:53:06 +09:00
|
|
|
* nand_write - [MTD Interface] NAND write with ECC
|
2013-01-14 12:46:50 +09:00
|
|
|
* @mtd: MTD device structure
|
|
|
|
* @to: offset to write to
|
|
|
|
* @len: number of bytes to write
|
|
|
|
* @retlen: pointer to variable to store the number of written bytes
|
|
|
|
* @buf: the data to write
|
2005-08-17 19:55:25 +09:00
|
|
|
*
|
2013-01-14 12:46:50 +09:00
|
|
|
* NAND write with ECC.
|
2005-08-17 19:55:25 +09:00
|
|
|
*/
|
2007-10-31 21:53:06 +09:00
|
|
|
static int nand_write(struct mtd_info *mtd, loff_t to, size_t len,
|
|
|
|
size_t *retlen, const uint8_t *buf)
|
2005-08-17 19:55:25 +09:00
|
|
|
{
|
2013-01-14 12:46:50 +09:00
|
|
|
struct mtd_oob_ops ops;
|
2007-10-31 21:53:06 +09:00
|
|
|
int ret;
|
2005-08-17 19:55:25 +09:00
|
|
|
|
2014-06-24 17:10:04 +09:00
|
|
|
nand_get_device(mtd, FL_WRITING);
|
2013-01-14 12:46:50 +09:00
|
|
|
ops.len = len;
|
|
|
|
ops.datbuf = (uint8_t *)buf;
|
|
|
|
ops.oobbuf = NULL;
|
|
|
|
ops.mode = MTD_OPS_PLACE_OOB;
|
|
|
|
ret = nand_do_write_ops(mtd, to, &ops);
|
|
|
|
*retlen = ops.retlen;
|
2007-10-31 21:53:06 +09:00
|
|
|
nand_release_device(mtd);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* nand_do_write_oob - [MTD Interface] NAND write out-of-band
|
2013-01-14 12:46:50 +09:00
|
|
|
* @mtd: MTD device structure
|
|
|
|
* @to: offset to write to
|
|
|
|
* @ops: oob operation description structure
|
2007-10-31 21:53:06 +09:00
|
|
|
*
|
2013-01-14 12:46:50 +09:00
|
|
|
* NAND write out-of-band.
|
2007-10-31 21:53:06 +09:00
|
|
|
*/
|
|
|
|
static int nand_do_write_oob(struct mtd_info *mtd, loff_t to,
|
|
|
|
struct mtd_oob_ops *ops)
|
|
|
|
{
|
|
|
|
int chipnr, page, status, len;
|
|
|
|
struct nand_chip *chip = mtd->priv;
|
|
|
|
|
2014-06-24 17:10:04 +09:00
|
|
|
pr_debug("%s: to = 0x%08x, len = %i\n",
|
2011-10-12 16:32:01 +09:00
|
|
|
__func__, (unsigned int)to, (int)ops->ooblen);
|
2007-10-31 21:53:06 +09:00
|
|
|
|
2013-01-14 12:46:50 +09:00
|
|
|
if (ops->mode == MTD_OPS_AUTO_OOB)
|
2007-10-31 21:53:06 +09:00
|
|
|
len = chip->ecc.layout->oobavail;
|
|
|
|
else
|
|
|
|
len = mtd->oobsize;
|
2005-08-17 19:55:25 +09:00
|
|
|
|
|
|
|
/* Do not allow write past end of page */
|
2007-10-31 21:53:06 +09:00
|
|
|
if ((ops->ooboffs + ops->ooblen) > len) {
|
2014-06-24 17:10:04 +09:00
|
|
|
pr_debug("%s: attempt to write past end of page\n",
|
|
|
|
__func__);
|
2005-08-17 19:55:25 +09:00
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
|
2007-10-31 21:53:06 +09:00
|
|
|
if (unlikely(ops->ooboffs >= len)) {
|
2014-06-24 17:10:04 +09:00
|
|
|
pr_debug("%s: attempt to start write outside oob\n",
|
|
|
|
__func__);
|
2007-10-31 21:53:06 +09:00
|
|
|
return -EINVAL;
|
|
|
|
}
|
2005-08-17 19:55:25 +09:00
|
|
|
|
2011-10-12 16:32:01 +09:00
|
|
|
/* Do not allow write past end of device */
|
2007-10-31 21:53:06 +09:00
|
|
|
if (unlikely(to >= mtd->size ||
|
|
|
|
ops->ooboffs + ops->ooblen >
|
|
|
|
((mtd->size >> chip->page_shift) -
|
|
|
|
(to >> chip->page_shift)) * len)) {
|
2014-06-24 17:10:04 +09:00
|
|
|
pr_debug("%s: attempt to write beyond end of device\n",
|
|
|
|
__func__);
|
2007-10-31 21:53:06 +09:00
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
|
|
|
|
chipnr = (int)(to >> chip->chip_shift);
|
|
|
|
chip->select_chip(mtd, chipnr);
|
2005-08-17 19:55:25 +09:00
|
|
|
|
2007-10-31 21:53:06 +09:00
|
|
|
/* Shift to get page */
|
|
|
|
page = (int)(to >> chip->page_shift);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Reset the chip. Some chips (like the Toshiba TC5832DC found in one
|
|
|
|
* of my DiskOnChip 2000 test units) will clear the whole data page too
|
|
|
|
* if we don't do this. I have no clue why, but I seem to have 'fixed'
|
|
|
|
* it in the doc2000 driver in August 1999. dwmw2.
|
|
|
|
*/
|
|
|
|
chip->cmdfunc(mtd, NAND_CMD_RESET, -1, -1);
|
2005-08-17 19:55:25 +09:00
|
|
|
|
|
|
|
/* Check, if it is write protected */
|
2014-06-24 17:10:04 +09:00
|
|
|
if (nand_check_wp(mtd)) {
|
|
|
|
chip->select_chip(mtd, -1);
|
2007-10-31 21:53:06 +09:00
|
|
|
return -EROFS;
|
2014-06-24 17:10:04 +09:00
|
|
|
}
|
2005-09-15 06:53:32 +09:00
|
|
|
|
2005-08-17 19:55:25 +09:00
|
|
|
/* Invalidate the page cache, if we write to the cached page */
|
2007-10-31 21:53:06 +09:00
|
|
|
if (page == chip->pagebuf)
|
|
|
|
chip->pagebuf = -1;
|
2005-08-17 19:55:25 +09:00
|
|
|
|
2013-01-14 12:46:50 +09:00
|
|
|
nand_fill_oob(mtd, ops->oobbuf, ops->ooblen, ops);
|
|
|
|
|
|
|
|
if (ops->mode == MTD_OPS_RAW)
|
|
|
|
status = chip->ecc.write_oob_raw(mtd, chip, page & chip->pagemask);
|
|
|
|
else
|
|
|
|
status = chip->ecc.write_oob(mtd, chip, page & chip->pagemask);
|
2005-08-17 19:55:25 +09:00
|
|
|
|
2014-06-24 17:10:04 +09:00
|
|
|
chip->select_chip(mtd, -1);
|
|
|
|
|
2007-10-31 21:53:06 +09:00
|
|
|
if (status)
|
|
|
|
return status;
|
2005-08-17 19:55:25 +09:00
|
|
|
|
2007-10-31 21:53:06 +09:00
|
|
|
ops->oobretlen = ops->ooblen;
|
2005-08-17 19:55:25 +09:00
|
|
|
|
2007-10-31 21:53:06 +09:00
|
|
|
return 0;
|
2005-08-17 19:55:25 +09:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2007-10-31 21:53:06 +09:00
|
|
|
* nand_write_oob - [MTD Interface] NAND write data and/or out-of-band
|
2013-01-14 12:46:50 +09:00
|
|
|
* @mtd: MTD device structure
|
|
|
|
* @to: offset to write to
|
|
|
|
* @ops: oob operation description structure
|
2005-08-17 19:55:25 +09:00
|
|
|
*/
|
2007-10-31 21:53:06 +09:00
|
|
|
static int nand_write_oob(struct mtd_info *mtd, loff_t to,
|
|
|
|
struct mtd_oob_ops *ops)
|
2005-08-17 19:55:25 +09:00
|
|
|
{
|
2007-10-31 21:53:06 +09:00
|
|
|
int ret = -ENOTSUPP;
|
2005-08-17 19:55:25 +09:00
|
|
|
|
2007-10-31 21:53:06 +09:00
|
|
|
ops->retlen = 0;
|
2005-08-17 19:55:25 +09:00
|
|
|
|
2007-10-31 21:53:06 +09:00
|
|
|
/* Do not allow writes past end of device */
|
|
|
|
if (ops->datbuf && (to + ops->len) > mtd->size) {
|
2014-06-24 17:10:04 +09:00
|
|
|
pr_debug("%s: attempt to write beyond end of device\n",
|
|
|
|
__func__);
|
2005-08-17 19:55:25 +09:00
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
|
2014-06-24 17:10:04 +09:00
|
|
|
nand_get_device(mtd, FL_WRITING);
|
2005-08-17 19:55:25 +09:00
|
|
|
|
2011-10-12 16:32:01 +09:00
|
|
|
switch (ops->mode) {
|
2013-01-14 12:46:50 +09:00
|
|
|
case MTD_OPS_PLACE_OOB:
|
|
|
|
case MTD_OPS_AUTO_OOB:
|
|
|
|
case MTD_OPS_RAW:
|
2007-10-31 21:53:06 +09:00
|
|
|
break;
|
2005-08-17 19:55:25 +09:00
|
|
|
|
2007-10-31 21:53:06 +09:00
|
|
|
default:
|
2005-08-17 19:55:25 +09:00
|
|
|
goto out;
|
2005-09-15 06:53:32 +09:00
|
|
|
}
|
2005-08-17 19:55:25 +09:00
|
|
|
|
2007-10-31 21:53:06 +09:00
|
|
|
if (!ops->datbuf)
|
|
|
|
ret = nand_do_write_oob(mtd, to, ops);
|
|
|
|
else
|
|
|
|
ret = nand_do_write_ops(mtd, to, ops);
|
2005-08-17 19:55:25 +09:00
|
|
|
|
2011-10-12 16:32:01 +09:00
|
|
|
out:
|
2005-08-17 19:55:25 +09:00
|
|
|
nand_release_device(mtd);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2013-01-14 12:46:50 +09:00
|
|
|
* single_erase_cmd - [GENERIC] NAND standard block erase command function
|
|
|
|
* @mtd: MTD device structure
|
|
|
|
* @page: the page address of the block which will be erased
|
2005-08-17 19:55:25 +09:00
|
|
|
*
|
2013-01-14 12:46:50 +09:00
|
|
|
* Standard erase command for NAND chips.
|
2005-08-17 19:55:25 +09:00
|
|
|
*/
|
2007-10-31 21:53:06 +09:00
|
|
|
static void single_erase_cmd(struct mtd_info *mtd, int page)
|
2005-08-17 19:55:25 +09:00
|
|
|
{
|
2007-10-31 21:53:06 +09:00
|
|
|
struct nand_chip *chip = mtd->priv;
|
2005-08-17 19:55:25 +09:00
|
|
|
/* Send commands to erase a block */
|
2007-10-31 21:53:06 +09:00
|
|
|
chip->cmdfunc(mtd, NAND_CMD_ERASE1, -1, page);
|
|
|
|
chip->cmdfunc(mtd, NAND_CMD_ERASE2, -1, -1);
|
2005-08-17 19:55:25 +09:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* nand_erase - [MTD Interface] erase block(s)
|
2013-01-14 12:46:50 +09:00
|
|
|
* @mtd: MTD device structure
|
|
|
|
* @instr: erase instruction
|
2005-08-17 19:55:25 +09:00
|
|
|
*
|
2013-01-14 12:46:50 +09:00
|
|
|
* Erase one ore more blocks.
|
2005-08-17 19:55:25 +09:00
|
|
|
*/
|
2007-10-31 21:53:06 +09:00
|
|
|
static int nand_erase(struct mtd_info *mtd, struct erase_info *instr)
|
2005-08-17 19:55:25 +09:00
|
|
|
{
|
2007-10-31 21:53:06 +09:00
|
|
|
return nand_erase_nand(mtd, instr, 0);
|
2005-08-17 19:55:25 +09:00
|
|
|
}
|
2005-09-15 06:53:32 +09:00
|
|
|
|
2005-08-17 19:55:25 +09:00
|
|
|
/**
|
2013-01-14 12:46:50 +09:00
|
|
|
* nand_erase_nand - [INTERN] erase block(s)
|
|
|
|
* @mtd: MTD device structure
|
|
|
|
* @instr: erase instruction
|
|
|
|
* @allowbbt: allow erasing the bbt area
|
2005-08-17 19:55:25 +09:00
|
|
|
*
|
2013-01-14 12:46:50 +09:00
|
|
|
* Erase one ore more blocks.
|
2005-08-17 19:55:25 +09:00
|
|
|
*/
|
2007-10-31 21:53:06 +09:00
|
|
|
int nand_erase_nand(struct mtd_info *mtd, struct erase_info *instr,
|
|
|
|
int allowbbt)
|
2005-08-17 19:55:25 +09:00
|
|
|
{
|
2009-10-31 02:51:23 +09:00
|
|
|
int page, status, pages_per_block, ret, chipnr;
|
2007-10-31 21:53:06 +09:00
|
|
|
struct nand_chip *chip = mtd->priv;
|
2009-10-31 02:51:23 +09:00
|
|
|
loff_t len;
|
2005-08-17 19:55:25 +09:00
|
|
|
|
2014-06-24 17:10:04 +09:00
|
|
|
pr_debug("%s: start = 0x%012llx, len = %llu\n",
|
|
|
|
__func__, (unsigned long long)instr->addr,
|
|
|
|
(unsigned long long)instr->len);
|
2005-08-17 19:55:25 +09:00
|
|
|
|
2011-10-12 16:32:02 +09:00
|
|
|
if (check_offs_len(mtd, instr->addr, instr->len))
|
2005-08-17 19:55:25 +09:00
|
|
|
return -EINVAL;
|
|
|
|
|
|
|
|
/* Grab the lock and see if the device is available */
|
2014-06-24 17:10:04 +09:00
|
|
|
nand_get_device(mtd, FL_ERASING);
|
2005-08-17 19:55:25 +09:00
|
|
|
|
|
|
|
/* Shift to get first page */
|
2007-10-31 21:53:06 +09:00
|
|
|
page = (int)(instr->addr >> chip->page_shift);
|
|
|
|
chipnr = (int)(instr->addr >> chip->chip_shift);
|
2005-08-17 19:55:25 +09:00
|
|
|
|
|
|
|
/* Calculate pages in each block */
|
2007-10-31 21:53:06 +09:00
|
|
|
pages_per_block = 1 << (chip->phys_erase_shift - chip->page_shift);
|
2007-11-08 18:39:53 +09:00
|
|
|
|
2005-08-17 19:55:25 +09:00
|
|
|
/* Select the NAND device */
|
2007-10-31 21:53:06 +09:00
|
|
|
chip->select_chip(mtd, chipnr);
|
2005-08-17 19:55:25 +09:00
|
|
|
|
|
|
|
/* Check, if it is write protected */
|
|
|
|
if (nand_check_wp(mtd)) {
|
2014-06-24 17:10:04 +09:00
|
|
|
pr_debug("%s: device is write protected!\n",
|
|
|
|
__func__);
|
2005-08-17 19:55:25 +09:00
|
|
|
instr->state = MTD_ERASE_FAILED;
|
|
|
|
goto erase_exit;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Loop through the pages */
|
|
|
|
len = instr->len;
|
|
|
|
|
|
|
|
instr->state = MTD_ERASING;
|
|
|
|
|
|
|
|
while (len) {
|
2011-02-03 09:15:57 +09:00
|
|
|
WATCHDOG_RESET();
|
2014-06-24 17:10:04 +09:00
|
|
|
|
2013-01-14 12:46:50 +09:00
|
|
|
/* Check if we have a bad block, we do not erase bad blocks! */
|
2014-12-16 15:36:33 +09:00
|
|
|
if (!instr->scrub && nand_block_checkbad(mtd, ((loff_t) page) <<
|
2007-10-31 21:53:06 +09:00
|
|
|
chip->page_shift, 0, allowbbt)) {
|
2013-01-14 12:46:50 +09:00
|
|
|
pr_warn("%s: attempt to erase a bad block at page 0x%08x\n",
|
2014-06-24 17:10:04 +09:00
|
|
|
__func__, page);
|
2005-08-17 19:55:25 +09:00
|
|
|
instr->state = MTD_ERASE_FAILED;
|
|
|
|
goto erase_exit;
|
|
|
|
}
|
|
|
|
|
2007-10-31 21:53:06 +09:00
|
|
|
/*
|
|
|
|
* Invalidate the page cache, if we erase the block which
|
2013-01-14 12:46:50 +09:00
|
|
|
* contains the current cached page.
|
2007-10-31 21:53:06 +09:00
|
|
|
*/
|
|
|
|
if (page <= chip->pagebuf && chip->pagebuf <
|
|
|
|
(page + pages_per_block))
|
|
|
|
chip->pagebuf = -1;
|
|
|
|
|
|
|
|
chip->erase_cmd(mtd, page & chip->pagemask);
|
|
|
|
|
|
|
|
status = chip->waitfunc(mtd, chip);
|
2005-09-15 06:53:32 +09:00
|
|
|
|
2007-10-31 21:53:06 +09:00
|
|
|
/*
|
|
|
|
* See if operation failed and additional status checks are
|
|
|
|
* available
|
|
|
|
*/
|
|
|
|
if ((status & NAND_STATUS_FAIL) && (chip->errstat))
|
|
|
|
status = chip->errstat(mtd, chip, FL_ERASING,
|
|
|
|
status, page);
|
2005-08-17 19:55:25 +09:00
|
|
|
|
|
|
|
/* See if block erase succeeded */
|
2007-10-31 21:53:06 +09:00
|
|
|
if (status & NAND_STATUS_FAIL) {
|
2014-06-24 17:10:04 +09:00
|
|
|
pr_debug("%s: failed erase, page 0x%08x\n",
|
|
|
|
__func__, page);
|
2005-08-17 19:55:25 +09:00
|
|
|
instr->state = MTD_ERASE_FAILED;
|
2011-10-12 16:32:01 +09:00
|
|
|
instr->fail_addr =
|
|
|
|
((loff_t)page << chip->page_shift);
|
2005-08-17 19:55:25 +09:00
|
|
|
goto erase_exit;
|
|
|
|
}
|
2005-09-15 06:53:32 +09:00
|
|
|
|
2005-08-17 19:55:25 +09:00
|
|
|
/* Increment page address and decrement length */
|
2014-06-24 17:10:04 +09:00
|
|
|
len -= (1ULL << chip->phys_erase_shift);
|
2005-08-17 19:55:25 +09:00
|
|
|
page += pages_per_block;
|
|
|
|
|
|
|
|
/* Check, if we cross a chip boundary */
|
2007-10-31 21:53:06 +09:00
|
|
|
if (len && !(page & chip->pagemask)) {
|
2005-08-17 19:55:25 +09:00
|
|
|
chipnr++;
|
2007-10-31 21:53:06 +09:00
|
|
|
chip->select_chip(mtd, -1);
|
|
|
|
chip->select_chip(mtd, chipnr);
|
2005-08-17 19:55:25 +09:00
|
|
|
}
|
|
|
|
}
|
|
|
|
instr->state = MTD_ERASE_DONE;
|
|
|
|
|
2011-10-12 16:32:01 +09:00
|
|
|
erase_exit:
|
2005-08-17 19:55:25 +09:00
|
|
|
|
|
|
|
ret = instr->state == MTD_ERASE_DONE ? 0 : -EIO;
|
|
|
|
|
|
|
|
/* Deselect and wake up anyone waiting on the device */
|
2014-06-24 17:10:04 +09:00
|
|
|
chip->select_chip(mtd, -1);
|
2005-08-17 19:55:25 +09:00
|
|
|
nand_release_device(mtd);
|
|
|
|
|
2008-10-25 06:20:43 +09:00
|
|
|
/* Do call back function */
|
|
|
|
if (!ret)
|
|
|
|
mtd_erase_callback(instr);
|
|
|
|
|
2005-08-17 19:55:25 +09:00
|
|
|
/* Return more or less happy */
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* nand_sync - [MTD Interface] sync
|
2013-01-14 12:46:50 +09:00
|
|
|
* @mtd: MTD device structure
|
2005-08-17 19:55:25 +09:00
|
|
|
*
|
2013-01-14 12:46:50 +09:00
|
|
|
* Sync is actually a wait for chip ready function.
|
2005-08-17 19:55:25 +09:00
|
|
|
*/
|
2007-10-31 21:53:06 +09:00
|
|
|
static void nand_sync(struct mtd_info *mtd)
|
2005-08-17 19:55:25 +09:00
|
|
|
{
|
2014-06-24 17:10:04 +09:00
|
|
|
pr_debug("%s: called\n", __func__);
|
2005-08-17 19:55:25 +09:00
|
|
|
|
|
|
|
/* Grab the lock and see if the device is available */
|
2014-06-24 17:10:04 +09:00
|
|
|
nand_get_device(mtd, FL_SYNCING);
|
2005-08-17 19:55:25 +09:00
|
|
|
/* Release it and go back */
|
2007-10-31 21:53:06 +09:00
|
|
|
nand_release_device(mtd);
|
2005-08-17 19:55:25 +09:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2007-10-31 21:53:06 +09:00
|
|
|
* nand_block_isbad - [MTD Interface] Check if block at offset is bad
|
2013-01-14 12:46:50 +09:00
|
|
|
* @mtd: MTD device structure
|
|
|
|
* @offs: offset relative to mtd start
|
2005-08-17 19:55:25 +09:00
|
|
|
*/
|
2007-10-31 21:53:06 +09:00
|
|
|
static int nand_block_isbad(struct mtd_info *mtd, loff_t offs)
|
2005-08-17 19:55:25 +09:00
|
|
|
{
|
2007-10-31 21:53:06 +09:00
|
|
|
return nand_block_checkbad(mtd, offs, 1, 0);
|
2005-08-17 19:55:25 +09:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2007-10-31 21:53:06 +09:00
|
|
|
* nand_block_markbad - [MTD Interface] Mark block at the given offset as bad
|
2013-01-14 12:46:50 +09:00
|
|
|
* @mtd: MTD device structure
|
|
|
|
* @ofs: offset relative to mtd start
|
2005-08-17 19:55:25 +09:00
|
|
|
*/
|
2007-10-31 21:53:06 +09:00
|
|
|
static int nand_block_markbad(struct mtd_info *mtd, loff_t ofs)
|
2005-08-17 19:55:25 +09:00
|
|
|
{
|
|
|
|
int ret;
|
|
|
|
|
2011-10-12 16:32:02 +09:00
|
|
|
ret = nand_block_isbad(mtd, ofs);
|
|
|
|
if (ret) {
|
2013-01-14 12:46:50 +09:00
|
|
|
/* If it was bad already, return success and do nothing */
|
2005-08-17 19:55:25 +09:00
|
|
|
if (ret > 0)
|
|
|
|
return 0;
|
2005-09-15 06:53:32 +09:00
|
|
|
return ret;
|
|
|
|
}
|
2005-08-17 19:55:25 +09:00
|
|
|
|
2014-06-24 17:10:04 +09:00
|
|
|
return nand_block_markbad_lowlevel(mtd, ofs);
|
2005-08-17 19:55:25 +09:00
|
|
|
}
|
|
|
|
|
2014-06-24 17:10:04 +09:00
|
|
|
/**
|
2013-01-14 12:46:50 +09:00
|
|
|
* nand_onfi_set_features- [REPLACEABLE] set features for ONFI nand
|
|
|
|
* @mtd: MTD device structure
|
|
|
|
* @chip: nand chip info structure
|
|
|
|
* @addr: feature address.
|
|
|
|
* @subfeature_param: the subfeature parameters, a four bytes array.
|
2007-10-31 21:53:06 +09:00
|
|
|
*/
|
2013-01-14 12:46:50 +09:00
|
|
|
static int nand_onfi_set_features(struct mtd_info *mtd, struct nand_chip *chip,
|
|
|
|
int addr, uint8_t *subfeature_param)
|
|
|
|
{
|
|
|
|
int status;
|
2014-06-24 17:10:04 +09:00
|
|
|
int i;
|
2013-01-14 12:46:50 +09:00
|
|
|
|
2014-06-24 17:10:04 +09:00
|
|
|
#ifdef CONFIG_SYS_NAND_ONFI_DETECTION
|
|
|
|
if (!chip->onfi_version ||
|
|
|
|
!(le16_to_cpu(chip->onfi_params.opt_cmd)
|
|
|
|
& ONFI_OPT_CMD_SET_GET_FEATURES))
|
2013-01-14 12:46:50 +09:00
|
|
|
return -EINVAL;
|
2014-06-24 17:10:04 +09:00
|
|
|
#endif
|
2013-01-14 12:46:50 +09:00
|
|
|
|
|
|
|
chip->cmdfunc(mtd, NAND_CMD_SET_FEATURES, addr, -1);
|
2014-06-24 17:10:04 +09:00
|
|
|
for (i = 0; i < ONFI_SUBFEATURE_PARAM_LEN; ++i)
|
|
|
|
chip->write_byte(mtd, subfeature_param[i]);
|
|
|
|
|
2013-01-14 12:46:50 +09:00
|
|
|
status = chip->waitfunc(mtd, chip);
|
|
|
|
if (status & NAND_STATUS_FAIL)
|
|
|
|
return -EIO;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* nand_onfi_get_features- [REPLACEABLE] get features for ONFI nand
|
|
|
|
* @mtd: MTD device structure
|
|
|
|
* @chip: nand chip info structure
|
|
|
|
* @addr: feature address.
|
|
|
|
* @subfeature_param: the subfeature parameters, a four bytes array.
|
|
|
|
*/
|
|
|
|
static int nand_onfi_get_features(struct mtd_info *mtd, struct nand_chip *chip,
|
|
|
|
int addr, uint8_t *subfeature_param)
|
|
|
|
{
|
2014-06-24 17:10:04 +09:00
|
|
|
int i;
|
|
|
|
|
|
|
|
#ifdef CONFIG_SYS_NAND_ONFI_DETECTION
|
|
|
|
if (!chip->onfi_version ||
|
|
|
|
!(le16_to_cpu(chip->onfi_params.opt_cmd)
|
|
|
|
& ONFI_OPT_CMD_SET_GET_FEATURES))
|
2013-01-14 12:46:50 +09:00
|
|
|
return -EINVAL;
|
2014-06-24 17:10:04 +09:00
|
|
|
#endif
|
2013-01-14 12:46:50 +09:00
|
|
|
|
|
|
|
/* clear the sub feature parameters */
|
|
|
|
memset(subfeature_param, 0, ONFI_SUBFEATURE_PARAM_LEN);
|
|
|
|
|
|
|
|
chip->cmdfunc(mtd, NAND_CMD_GET_FEATURES, addr, -1);
|
2014-06-24 17:10:04 +09:00
|
|
|
for (i = 0; i < ONFI_SUBFEATURE_PARAM_LEN; ++i)
|
|
|
|
*subfeature_param++ = chip->read_byte(mtd);
|
2013-01-14 12:46:50 +09:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2014-06-24 17:10:04 +09:00
|
|
|
#ifndef __UBOOT__
|
|
|
|
/**
|
|
|
|
* nand_suspend - [MTD Interface] Suspend the NAND flash
|
|
|
|
* @mtd: MTD device structure
|
|
|
|
*/
|
|
|
|
static int nand_suspend(struct mtd_info *mtd)
|
|
|
|
{
|
|
|
|
return nand_get_device(mtd, FL_PM_SUSPENDED);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* nand_resume - [MTD Interface] Resume the NAND flash
|
|
|
|
* @mtd: MTD device structure
|
|
|
|
*/
|
|
|
|
static void nand_resume(struct mtd_info *mtd)
|
|
|
|
{
|
|
|
|
struct nand_chip *chip = mtd->priv;
|
|
|
|
|
|
|
|
if (chip->state == FL_PM_SUSPENDED)
|
|
|
|
nand_release_device(mtd);
|
|
|
|
else
|
|
|
|
pr_err("%s called for a chip which is not in suspended state\n",
|
|
|
|
__func__);
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2013-01-14 12:46:50 +09:00
|
|
|
/* Set default functions */
|
2007-10-31 21:53:06 +09:00
|
|
|
static void nand_set_defaults(struct nand_chip *chip, int busw)
|
|
|
|
{
|
2005-08-17 19:55:25 +09:00
|
|
|
/* check for proper chip_delay setup, set 20us if not */
|
2007-10-31 21:53:06 +09:00
|
|
|
if (!chip->chip_delay)
|
|
|
|
chip->chip_delay = 20;
|
2005-08-17 19:55:25 +09:00
|
|
|
|
|
|
|
/* check, if a user supplied command function given */
|
2007-10-31 21:53:06 +09:00
|
|
|
if (chip->cmdfunc == NULL)
|
|
|
|
chip->cmdfunc = nand_command;
|
2005-08-17 19:55:25 +09:00
|
|
|
|
|
|
|
/* check, if a user supplied wait function given */
|
2007-10-31 21:53:06 +09:00
|
|
|
if (chip->waitfunc == NULL)
|
|
|
|
chip->waitfunc = nand_wait;
|
|
|
|
|
|
|
|
if (!chip->select_chip)
|
|
|
|
chip->select_chip = nand_select_chip;
|
2014-06-24 17:10:04 +09:00
|
|
|
|
|
|
|
/* set for ONFI nand */
|
|
|
|
if (!chip->onfi_set_features)
|
|
|
|
chip->onfi_set_features = nand_onfi_set_features;
|
|
|
|
if (!chip->onfi_get_features)
|
|
|
|
chip->onfi_get_features = nand_onfi_get_features;
|
|
|
|
|
|
|
|
/* If called twice, pointers that depend on busw may need to be reset */
|
|
|
|
if (!chip->read_byte || chip->read_byte == nand_read_byte)
|
2007-10-31 21:53:06 +09:00
|
|
|
chip->read_byte = busw ? nand_read_byte16 : nand_read_byte;
|
|
|
|
if (!chip->read_word)
|
|
|
|
chip->read_word = nand_read_word;
|
|
|
|
if (!chip->block_bad)
|
|
|
|
chip->block_bad = nand_block_bad;
|
|
|
|
if (!chip->block_markbad)
|
|
|
|
chip->block_markbad = nand_default_block_markbad;
|
2014-06-24 17:10:04 +09:00
|
|
|
if (!chip->write_buf || chip->write_buf == nand_write_buf)
|
2007-10-31 21:53:06 +09:00
|
|
|
chip->write_buf = busw ? nand_write_buf16 : nand_write_buf;
|
2014-06-24 17:10:04 +09:00
|
|
|
if (!chip->write_byte || chip->write_byte == nand_write_byte)
|
|
|
|
chip->write_byte = busw ? nand_write_byte16 : nand_write_byte;
|
|
|
|
if (!chip->read_buf || chip->read_buf == nand_read_buf)
|
2007-10-31 21:53:06 +09:00
|
|
|
chip->read_buf = busw ? nand_read_buf16 : nand_read_buf;
|
|
|
|
if (!chip->scan_bbt)
|
|
|
|
chip->scan_bbt = nand_default_bbt;
|
2014-06-24 17:10:04 +09:00
|
|
|
|
|
|
|
if (!chip->controller) {
|
2007-10-31 21:53:06 +09:00
|
|
|
chip->controller = &chip->hwcontrol;
|
2014-06-24 17:10:04 +09:00
|
|
|
spin_lock_init(&chip->controller->lock);
|
|
|
|
init_waitqueue_head(&chip->controller->wq);
|
|
|
|
}
|
|
|
|
|
2007-10-31 21:53:06 +09:00
|
|
|
}
|
|
|
|
|
2013-01-14 12:46:50 +09:00
|
|
|
/* Sanitize ONFI strings so we can safely print them */
|
2014-06-24 17:10:04 +09:00
|
|
|
#ifndef __UBOOT__
|
|
|
|
static void sanitize_string(uint8_t *s, size_t len)
|
|
|
|
#else
|
2011-10-12 16:32:05 +09:00
|
|
|
static void sanitize_string(char *s, size_t len)
|
2014-06-24 17:10:04 +09:00
|
|
|
#endif
|
2011-10-12 16:32:05 +09:00
|
|
|
{
|
|
|
|
ssize_t i;
|
|
|
|
|
2013-01-14 12:46:50 +09:00
|
|
|
/* Null terminate */
|
2011-10-12 16:32:05 +09:00
|
|
|
s[len - 1] = 0;
|
|
|
|
|
2013-01-14 12:46:50 +09:00
|
|
|
/* Remove non printable chars */
|
2011-10-12 16:32:05 +09:00
|
|
|
for (i = 0; i < len - 1; i++) {
|
|
|
|
if (s[i] < ' ' || s[i] > 127)
|
|
|
|
s[i] = '?';
|
|
|
|
}
|
|
|
|
|
2013-01-14 12:46:50 +09:00
|
|
|
/* Remove trailing spaces */
|
2011-10-12 16:32:05 +09:00
|
|
|
strim(s);
|
|
|
|
}
|
|
|
|
|
2011-02-25 09:01:34 +09:00
|
|
|
static u16 onfi_crc16(u16 crc, u8 const *p, size_t len)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
while (len--) {
|
|
|
|
crc ^= *p++ << 8;
|
|
|
|
for (i = 0; i < 8; i++)
|
|
|
|
crc = (crc << 1) ^ ((crc & 0x8000) ? 0x8005 : 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
return crc;
|
|
|
|
}
|
|
|
|
|
2014-07-15 23:08:43 +09:00
|
|
|
#ifdef CONFIG_SYS_NAND_ONFI_DETECTION
|
2014-06-24 17:10:04 +09:00
|
|
|
/* Parse the Extended Parameter Page. */
|
|
|
|
static int nand_flash_detect_ext_param_page(struct mtd_info *mtd,
|
|
|
|
struct nand_chip *chip, struct nand_onfi_params *p)
|
|
|
|
{
|
|
|
|
struct onfi_ext_param_page *ep;
|
|
|
|
struct onfi_ext_section *s;
|
|
|
|
struct onfi_ext_ecc_info *ecc;
|
|
|
|
uint8_t *cursor;
|
|
|
|
int ret = -EINVAL;
|
|
|
|
int len;
|
|
|
|
int i;
|
|
|
|
|
|
|
|
len = le16_to_cpu(p->ext_param_page_length) * 16;
|
|
|
|
ep = kmalloc(len, GFP_KERNEL);
|
|
|
|
if (!ep)
|
|
|
|
return -ENOMEM;
|
|
|
|
|
|
|
|
/* Send our own NAND_CMD_PARAM. */
|
|
|
|
chip->cmdfunc(mtd, NAND_CMD_PARAM, 0, -1);
|
|
|
|
|
|
|
|
/* Use the Change Read Column command to skip the ONFI param pages. */
|
|
|
|
chip->cmdfunc(mtd, NAND_CMD_RNDOUT,
|
|
|
|
sizeof(*p) * p->num_of_param_pages , -1);
|
|
|
|
|
|
|
|
/* Read out the Extended Parameter Page. */
|
|
|
|
chip->read_buf(mtd, (uint8_t *)ep, len);
|
|
|
|
if ((onfi_crc16(ONFI_CRC_BASE, ((uint8_t *)ep) + 2, len - 2)
|
|
|
|
!= le16_to_cpu(ep->crc))) {
|
|
|
|
pr_debug("fail in the CRC.\n");
|
|
|
|
goto ext_out;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Check the signature.
|
|
|
|
* Do not strictly follow the ONFI spec, maybe changed in future.
|
|
|
|
*/
|
|
|
|
#ifndef __UBOOT__
|
|
|
|
if (strncmp(ep->sig, "EPPS", 4)) {
|
|
|
|
#else
|
|
|
|
if (strncmp((char *)ep->sig, "EPPS", 4)) {
|
|
|
|
#endif
|
|
|
|
pr_debug("The signature is invalid.\n");
|
|
|
|
goto ext_out;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* find the ECC section. */
|
|
|
|
cursor = (uint8_t *)(ep + 1);
|
|
|
|
for (i = 0; i < ONFI_EXT_SECTION_MAX; i++) {
|
|
|
|
s = ep->sections + i;
|
|
|
|
if (s->type == ONFI_SECTION_TYPE_2)
|
|
|
|
break;
|
|
|
|
cursor += s->length * 16;
|
|
|
|
}
|
|
|
|
if (i == ONFI_EXT_SECTION_MAX) {
|
|
|
|
pr_debug("We can not find the ECC section.\n");
|
|
|
|
goto ext_out;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* get the info we want. */
|
|
|
|
ecc = (struct onfi_ext_ecc_info *)cursor;
|
|
|
|
|
|
|
|
if (!ecc->codeword_size) {
|
|
|
|
pr_debug("Invalid codeword size\n");
|
|
|
|
goto ext_out;
|
|
|
|
}
|
|
|
|
|
|
|
|
chip->ecc_strength_ds = ecc->ecc_bits;
|
|
|
|
chip->ecc_step_ds = 1 << ecc->codeword_size;
|
|
|
|
ret = 0;
|
|
|
|
|
|
|
|
ext_out:
|
|
|
|
kfree(ep);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int nand_setup_read_retry_micron(struct mtd_info *mtd, int retry_mode)
|
|
|
|
{
|
|
|
|
struct nand_chip *chip = mtd->priv;
|
|
|
|
uint8_t feature[ONFI_SUBFEATURE_PARAM_LEN] = {retry_mode};
|
|
|
|
|
|
|
|
return chip->onfi_set_features(mtd, chip, ONFI_FEATURE_ADDR_READ_RETRY,
|
|
|
|
feature);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Configure chip properties from Micron vendor-specific ONFI table
|
|
|
|
*/
|
|
|
|
static void nand_onfi_detect_micron(struct nand_chip *chip,
|
|
|
|
struct nand_onfi_params *p)
|
|
|
|
{
|
|
|
|
struct nand_onfi_vendor_micron *micron = (void *)p->vendor;
|
|
|
|
|
|
|
|
if (le16_to_cpu(p->vendor_revision) < 1)
|
|
|
|
return;
|
|
|
|
|
|
|
|
chip->read_retries = micron->read_retry_options;
|
|
|
|
chip->setup_read_retry = nand_setup_read_retry_micron;
|
|
|
|
}
|
|
|
|
|
2011-02-25 09:01:34 +09:00
|
|
|
/*
|
2013-01-14 12:46:50 +09:00
|
|
|
* Check if the NAND chip is ONFI compliant, returns 1 if it is, 0 otherwise.
|
2011-02-25 09:01:34 +09:00
|
|
|
*/
|
2011-10-12 16:32:01 +09:00
|
|
|
static int nand_flash_detect_onfi(struct mtd_info *mtd, struct nand_chip *chip,
|
2011-02-25 09:01:34 +09:00
|
|
|
int *busw)
|
|
|
|
{
|
|
|
|
struct nand_onfi_params *p = &chip->onfi_params;
|
2014-05-06 04:16:16 +09:00
|
|
|
int i, j;
|
2011-02-25 09:01:34 +09:00
|
|
|
int val;
|
|
|
|
|
2013-01-14 12:46:50 +09:00
|
|
|
/* Try ONFI for unknown chip or LP */
|
2011-02-25 09:01:34 +09:00
|
|
|
chip->cmdfunc(mtd, NAND_CMD_READID, 0x20, -1);
|
|
|
|
if (chip->read_byte(mtd) != 'O' || chip->read_byte(mtd) != 'N' ||
|
|
|
|
chip->read_byte(mtd) != 'F' || chip->read_byte(mtd) != 'I')
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
chip->cmdfunc(mtd, NAND_CMD_PARAM, 0, -1);
|
|
|
|
for (i = 0; i < 3; i++) {
|
2014-05-06 04:16:16 +09:00
|
|
|
for (j = 0; j < sizeof(*p); j++)
|
|
|
|
((uint8_t *)p)[j] = chip->read_byte(mtd);
|
2011-02-25 09:01:34 +09:00
|
|
|
if (onfi_crc16(ONFI_CRC_BASE, (uint8_t *)p, 254) ==
|
2011-10-12 16:32:01 +09:00
|
|
|
le16_to_cpu(p->crc)) {
|
2011-02-25 09:01:34 +09:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-06-24 17:10:04 +09:00
|
|
|
if (i == 3) {
|
|
|
|
pr_err("Could not find valid ONFI parameter page; aborting\n");
|
2011-02-25 09:01:34 +09:00
|
|
|
return 0;
|
2014-06-24 17:10:04 +09:00
|
|
|
}
|
2011-02-25 09:01:34 +09:00
|
|
|
|
2013-01-14 12:46:50 +09:00
|
|
|
/* Check version */
|
2011-02-25 09:01:34 +09:00
|
|
|
val = le16_to_cpu(p->revision);
|
2011-04-04 01:23:56 +09:00
|
|
|
if (val & (1 << 5))
|
|
|
|
chip->onfi_version = 23;
|
|
|
|
else if (val & (1 << 4))
|
2011-02-25 09:01:34 +09:00
|
|
|
chip->onfi_version = 22;
|
|
|
|
else if (val & (1 << 3))
|
|
|
|
chip->onfi_version = 21;
|
|
|
|
else if (val & (1 << 2))
|
|
|
|
chip->onfi_version = 20;
|
2011-04-04 01:23:56 +09:00
|
|
|
else if (val & (1 << 1))
|
2011-02-25 09:01:34 +09:00
|
|
|
chip->onfi_version = 10;
|
2011-04-04 01:23:56 +09:00
|
|
|
|
|
|
|
if (!chip->onfi_version) {
|
2014-06-24 17:10:04 +09:00
|
|
|
pr_info("unsupported ONFI version: %d\n", val);
|
2011-04-04 01:23:56 +09:00
|
|
|
return 0;
|
|
|
|
}
|
2011-02-25 09:01:34 +09:00
|
|
|
|
2011-10-12 16:32:05 +09:00
|
|
|
sanitize_string(p->manufacturer, sizeof(p->manufacturer));
|
|
|
|
sanitize_string(p->model, sizeof(p->model));
|
2011-02-25 09:01:34 +09:00
|
|
|
if (!mtd->name)
|
|
|
|
mtd->name = p->model;
|
2014-06-24 17:10:04 +09:00
|
|
|
|
2011-02-25 09:01:34 +09:00
|
|
|
mtd->writesize = le32_to_cpu(p->byte_per_page);
|
2014-06-24 17:10:04 +09:00
|
|
|
|
|
|
|
/*
|
|
|
|
* pages_per_block and blocks_per_lun may not be a power-of-2 size
|
|
|
|
* (don't ask me who thought of this...). MTD assumes that these
|
|
|
|
* dimensions will be power-of-2, so just truncate the remaining area.
|
|
|
|
*/
|
|
|
|
mtd->erasesize = 1 << (fls(le32_to_cpu(p->pages_per_block)) - 1);
|
|
|
|
mtd->erasesize *= mtd->writesize;
|
|
|
|
|
2011-02-25 09:01:34 +09:00
|
|
|
mtd->oobsize = le16_to_cpu(p->spare_bytes_per_page);
|
2014-06-24 17:10:04 +09:00
|
|
|
|
|
|
|
/* See erasesize comment */
|
|
|
|
chip->chipsize = 1 << (fls(le32_to_cpu(p->blocks_per_lun)) - 1);
|
2012-03-19 23:35:25 +09:00
|
|
|
chip->chipsize *= (uint64_t)mtd->erasesize * p->lun_count;
|
2014-06-24 17:10:04 +09:00
|
|
|
chip->bits_per_cell = p->bits_per_cell;
|
|
|
|
|
|
|
|
if (onfi_feature(chip) & ONFI_FEATURE_16_BIT_BUS)
|
2011-02-25 09:01:34 +09:00
|
|
|
*busw = NAND_BUSWIDTH_16;
|
2014-06-24 17:10:04 +09:00
|
|
|
else
|
|
|
|
*busw = 0;
|
|
|
|
|
|
|
|
if (p->ecc_bits != 0xff) {
|
|
|
|
chip->ecc_strength_ds = p->ecc_bits;
|
|
|
|
chip->ecc_step_ds = 512;
|
|
|
|
} else if (chip->onfi_version >= 21 &&
|
|
|
|
(onfi_feature(chip) & ONFI_FEATURE_EXT_PARAM_PAGE)) {
|
|
|
|
|
|
|
|
/*
|
|
|
|
* The nand_flash_detect_ext_param_page() uses the
|
|
|
|
* Change Read Column command which maybe not supported
|
|
|
|
* by the chip->cmdfunc. So try to update the chip->cmdfunc
|
|
|
|
* now. We do not replace user supplied command function.
|
|
|
|
*/
|
|
|
|
if (mtd->writesize > 512 && chip->cmdfunc == nand_command)
|
|
|
|
chip->cmdfunc = nand_command_lp;
|
|
|
|
|
|
|
|
/* The Extended Parameter Page is supported since ONFI 2.1. */
|
|
|
|
if (nand_flash_detect_ext_param_page(mtd, chip, p))
|
|
|
|
pr_warn("Failed to detect ONFI extended param page\n");
|
|
|
|
} else {
|
|
|
|
pr_warn("Could not retrieve ONFI ECC requirements\n");
|
|
|
|
}
|
|
|
|
|
|
|
|
if (p->jedec_id == NAND_MFR_MICRON)
|
|
|
|
nand_onfi_detect_micron(chip, p);
|
2011-02-25 09:01:34 +09:00
|
|
|
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
#else
|
2014-06-24 17:10:04 +09:00
|
|
|
static int nand_flash_detect_onfi(struct mtd_info *mtd, struct nand_chip *chip,
|
2011-02-25 09:01:34 +09:00
|
|
|
int *busw)
|
|
|
|
{
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2014-07-15 23:08:43 +09:00
|
|
|
/*
|
|
|
|
* Check if the NAND chip is JEDEC compliant, returns 1 if it is, 0 otherwise.
|
|
|
|
*/
|
|
|
|
static int nand_flash_detect_jedec(struct mtd_info *mtd, struct nand_chip *chip,
|
|
|
|
int *busw)
|
|
|
|
{
|
|
|
|
struct nand_jedec_params *p = &chip->jedec_params;
|
|
|
|
struct jedec_ecc_info *ecc;
|
|
|
|
int val;
|
|
|
|
int i, j;
|
|
|
|
|
|
|
|
/* Try JEDEC for unknown chip or LP */
|
|
|
|
chip->cmdfunc(mtd, NAND_CMD_READID, 0x40, -1);
|
|
|
|
if (chip->read_byte(mtd) != 'J' || chip->read_byte(mtd) != 'E' ||
|
|
|
|
chip->read_byte(mtd) != 'D' || chip->read_byte(mtd) != 'E' ||
|
|
|
|
chip->read_byte(mtd) != 'C')
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
chip->cmdfunc(mtd, NAND_CMD_PARAM, 0x40, -1);
|
|
|
|
for (i = 0; i < 3; i++) {
|
|
|
|
for (j = 0; j < sizeof(*p); j++)
|
|
|
|
((uint8_t *)p)[j] = chip->read_byte(mtd);
|
|
|
|
|
|
|
|
if (onfi_crc16(ONFI_CRC_BASE, (uint8_t *)p, 510) ==
|
|
|
|
le16_to_cpu(p->crc))
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (i == 3) {
|
|
|
|
pr_err("Could not find valid JEDEC parameter page; aborting\n");
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Check version */
|
|
|
|
val = le16_to_cpu(p->revision);
|
|
|
|
if (val & (1 << 2))
|
|
|
|
chip->jedec_version = 10;
|
|
|
|
else if (val & (1 << 1))
|
|
|
|
chip->jedec_version = 1; /* vendor specific version */
|
|
|
|
|
|
|
|
if (!chip->jedec_version) {
|
|
|
|
pr_info("unsupported JEDEC version: %d\n", val);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
sanitize_string(p->manufacturer, sizeof(p->manufacturer));
|
|
|
|
sanitize_string(p->model, sizeof(p->model));
|
|
|
|
if (!mtd->name)
|
|
|
|
mtd->name = p->model;
|
|
|
|
|
|
|
|
mtd->writesize = le32_to_cpu(p->byte_per_page);
|
|
|
|
|
|
|
|
/* Please reference to the comment for nand_flash_detect_onfi. */
|
|
|
|
mtd->erasesize = 1 << (fls(le32_to_cpu(p->pages_per_block)) - 1);
|
|
|
|
mtd->erasesize *= mtd->writesize;
|
|
|
|
|
|
|
|
mtd->oobsize = le16_to_cpu(p->spare_bytes_per_page);
|
|
|
|
|
|
|
|
/* Please reference to the comment for nand_flash_detect_onfi. */
|
|
|
|
chip->chipsize = 1 << (fls(le32_to_cpu(p->blocks_per_lun)) - 1);
|
|
|
|
chip->chipsize *= (uint64_t)mtd->erasesize * p->lun_count;
|
|
|
|
chip->bits_per_cell = p->bits_per_cell;
|
|
|
|
|
|
|
|
if (jedec_feature(chip) & JEDEC_FEATURE_16_BIT_BUS)
|
|
|
|
*busw = NAND_BUSWIDTH_16;
|
|
|
|
else
|
|
|
|
*busw = 0;
|
|
|
|
|
|
|
|
/* ECC info */
|
|
|
|
ecc = &p->ecc_info[0];
|
|
|
|
|
|
|
|
if (ecc->codeword_size >= 9) {
|
|
|
|
chip->ecc_strength_ds = ecc->ecc_bits;
|
|
|
|
chip->ecc_step_ds = 1 << ecc->codeword_size;
|
|
|
|
} else {
|
|
|
|
pr_warn("Invalid codeword size\n");
|
|
|
|
}
|
|
|
|
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2007-10-31 21:53:06 +09:00
|
|
|
/*
|
2013-01-14 12:46:50 +09:00
|
|
|
* nand_id_has_period - Check if an ID string has a given wraparound period
|
|
|
|
* @id_data: the ID string
|
|
|
|
* @arrlen: the length of the @id_data array
|
|
|
|
* @period: the period of repitition
|
|
|
|
*
|
|
|
|
* Check if an ID string is repeated within a given sequence of bytes at
|
|
|
|
* specific repetition interval period (e.g., {0x20,0x01,0x7F,0x20} has a
|
2014-06-24 17:10:04 +09:00
|
|
|
* period of 3). This is a helper function for nand_id_len(). Returns non-zero
|
2013-01-14 12:46:50 +09:00
|
|
|
* if the repetition has a period of @period; otherwise, returns zero.
|
|
|
|
*/
|
|
|
|
static int nand_id_has_period(u8 *id_data, int arrlen, int period)
|
|
|
|
{
|
|
|
|
int i, j;
|
|
|
|
for (i = 0; i < period; i++)
|
|
|
|
for (j = i + period; j < arrlen; j += period)
|
|
|
|
if (id_data[i] != id_data[j])
|
|
|
|
return 0;
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* nand_id_len - Get the length of an ID string returned by CMD_READID
|
|
|
|
* @id_data: the ID string
|
|
|
|
* @arrlen: the length of the @id_data array
|
|
|
|
|
|
|
|
* Returns the length of the ID string, according to known wraparound/trailing
|
|
|
|
* zero patterns. If no pattern exists, returns the length of the array.
|
|
|
|
*/
|
|
|
|
static int nand_id_len(u8 *id_data, int arrlen)
|
|
|
|
{
|
|
|
|
int last_nonzero, period;
|
|
|
|
|
|
|
|
/* Find last non-zero byte */
|
|
|
|
for (last_nonzero = arrlen - 1; last_nonzero >= 0; last_nonzero--)
|
|
|
|
if (id_data[last_nonzero])
|
|
|
|
break;
|
|
|
|
|
|
|
|
/* All zeros */
|
|
|
|
if (last_nonzero < 0)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
/* Calculate wraparound period */
|
|
|
|
for (period = 1; period < arrlen; period++)
|
|
|
|
if (nand_id_has_period(id_data, arrlen, period))
|
|
|
|
break;
|
|
|
|
|
|
|
|
/* There's a repeated pattern */
|
|
|
|
if (period < arrlen)
|
|
|
|
return period;
|
|
|
|
|
|
|
|
/* There are trailing zeros */
|
|
|
|
if (last_nonzero < arrlen - 1)
|
|
|
|
return last_nonzero + 1;
|
|
|
|
|
|
|
|
/* No pattern detected */
|
|
|
|
return arrlen;
|
|
|
|
}
|
|
|
|
|
2014-06-24 17:10:04 +09:00
|
|
|
/* Extract the bits of per cell from the 3rd byte of the extended ID */
|
|
|
|
static int nand_get_bits_per_cell(u8 cellinfo)
|
|
|
|
{
|
|
|
|
int bits;
|
|
|
|
|
|
|
|
bits = cellinfo & NAND_CI_CELLTYPE_MSK;
|
|
|
|
bits >>= NAND_CI_CELLTYPE_SHIFT;
|
|
|
|
return bits + 1;
|
|
|
|
}
|
|
|
|
|
2013-01-14 12:46:50 +09:00
|
|
|
/*
|
|
|
|
* Many new NAND share similar device ID codes, which represent the size of the
|
|
|
|
* chip. The rest of the parameters must be decoded according to generic or
|
|
|
|
* manufacturer-specific "extended ID" decoding patterns.
|
|
|
|
*/
|
|
|
|
static void nand_decode_ext_id(struct mtd_info *mtd, struct nand_chip *chip,
|
|
|
|
u8 id_data[8], int *busw)
|
|
|
|
{
|
|
|
|
int extid, id_len;
|
|
|
|
/* The 3rd id byte holds MLC / multichip data */
|
2014-06-24 17:10:04 +09:00
|
|
|
chip->bits_per_cell = nand_get_bits_per_cell(id_data[2]);
|
2013-01-14 12:46:50 +09:00
|
|
|
/* The 4th id byte is the important one */
|
|
|
|
extid = id_data[3];
|
|
|
|
|
|
|
|
id_len = nand_id_len(id_data, 8);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Field definitions are in the following datasheets:
|
|
|
|
* Old style (4,5 byte ID): Samsung K9GAG08U0M (p.32)
|
|
|
|
* New Samsung (6 byte ID): Samsung K9GAG08U0F (p.44)
|
|
|
|
* Hynix MLC (6 byte ID): Hynix H27UBG8T2B (p.22)
|
|
|
|
*
|
|
|
|
* Check for ID length, non-zero 6th byte, cell type, and Hynix/Samsung
|
|
|
|
* ID to decide what to do.
|
|
|
|
*/
|
|
|
|
if (id_len == 6 && id_data[0] == NAND_MFR_SAMSUNG &&
|
2014-06-24 17:10:04 +09:00
|
|
|
!nand_is_slc(chip) && id_data[5] != 0x00) {
|
2013-01-14 12:46:50 +09:00
|
|
|
/* Calc pagesize */
|
|
|
|
mtd->writesize = 2048 << (extid & 0x03);
|
|
|
|
extid >>= 2;
|
|
|
|
/* Calc oobsize */
|
|
|
|
switch (((extid >> 2) & 0x04) | (extid & 0x03)) {
|
|
|
|
case 1:
|
|
|
|
mtd->oobsize = 128;
|
|
|
|
break;
|
|
|
|
case 2:
|
|
|
|
mtd->oobsize = 218;
|
|
|
|
break;
|
|
|
|
case 3:
|
|
|
|
mtd->oobsize = 400;
|
|
|
|
break;
|
|
|
|
case 4:
|
|
|
|
mtd->oobsize = 436;
|
|
|
|
break;
|
|
|
|
case 5:
|
|
|
|
mtd->oobsize = 512;
|
|
|
|
break;
|
|
|
|
case 6:
|
|
|
|
mtd->oobsize = 640;
|
|
|
|
break;
|
2014-06-24 17:10:04 +09:00
|
|
|
case 7:
|
|
|
|
default: /* Other cases are "reserved" (unknown) */
|
|
|
|
mtd->oobsize = 1024;
|
|
|
|
break;
|
2013-01-14 12:46:50 +09:00
|
|
|
}
|
|
|
|
extid >>= 2;
|
|
|
|
/* Calc blocksize */
|
|
|
|
mtd->erasesize = (128 * 1024) <<
|
|
|
|
(((extid >> 1) & 0x04) | (extid & 0x03));
|
|
|
|
*busw = 0;
|
|
|
|
} else if (id_len == 6 && id_data[0] == NAND_MFR_HYNIX &&
|
2014-06-24 17:10:04 +09:00
|
|
|
!nand_is_slc(chip)) {
|
2013-01-14 12:46:50 +09:00
|
|
|
unsigned int tmp;
|
|
|
|
|
|
|
|
/* Calc pagesize */
|
|
|
|
mtd->writesize = 2048 << (extid & 0x03);
|
|
|
|
extid >>= 2;
|
|
|
|
/* Calc oobsize */
|
|
|
|
switch (((extid >> 2) & 0x04) | (extid & 0x03)) {
|
|
|
|
case 0:
|
|
|
|
mtd->oobsize = 128;
|
|
|
|
break;
|
|
|
|
case 1:
|
|
|
|
mtd->oobsize = 224;
|
|
|
|
break;
|
|
|
|
case 2:
|
|
|
|
mtd->oobsize = 448;
|
|
|
|
break;
|
|
|
|
case 3:
|
|
|
|
mtd->oobsize = 64;
|
|
|
|
break;
|
|
|
|
case 4:
|
|
|
|
mtd->oobsize = 32;
|
|
|
|
break;
|
|
|
|
case 5:
|
|
|
|
mtd->oobsize = 16;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
mtd->oobsize = 640;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
extid >>= 2;
|
|
|
|
/* Calc blocksize */
|
|
|
|
tmp = ((extid >> 1) & 0x04) | (extid & 0x03);
|
|
|
|
if (tmp < 0x03)
|
|
|
|
mtd->erasesize = (128 * 1024) << tmp;
|
|
|
|
else if (tmp == 0x03)
|
|
|
|
mtd->erasesize = 768 * 1024;
|
|
|
|
else
|
|
|
|
mtd->erasesize = (64 * 1024) << tmp;
|
|
|
|
*busw = 0;
|
|
|
|
} else {
|
|
|
|
/* Calc pagesize */
|
|
|
|
mtd->writesize = 1024 << (extid & 0x03);
|
|
|
|
extid >>= 2;
|
|
|
|
/* Calc oobsize */
|
|
|
|
mtd->oobsize = (8 << (extid & 0x01)) *
|
|
|
|
(mtd->writesize >> 9);
|
|
|
|
extid >>= 2;
|
|
|
|
/* Calc blocksize. Blocksize is multiples of 64KiB */
|
|
|
|
mtd->erasesize = (64 * 1024) << (extid & 0x03);
|
|
|
|
extid >>= 2;
|
|
|
|
/* Get buswidth information */
|
|
|
|
*busw = (extid & 0x01) ? NAND_BUSWIDTH_16 : 0;
|
2014-06-24 17:10:04 +09:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Toshiba 24nm raw SLC (i.e., not BENAND) have 32B OOB per
|
|
|
|
* 512B page. For Toshiba SLC, we decode the 5th/6th byte as
|
|
|
|
* follows:
|
|
|
|
* - ID byte 6, bits[2:0]: 100b -> 43nm, 101b -> 32nm,
|
|
|
|
* 110b -> 24nm
|
|
|
|
* - ID byte 5, bit[7]: 1 -> BENAND, 0 -> raw SLC
|
|
|
|
*/
|
|
|
|
if (id_len >= 6 && id_data[0] == NAND_MFR_TOSHIBA &&
|
|
|
|
nand_is_slc(chip) &&
|
|
|
|
(id_data[5] & 0x7) == 0x6 /* 24nm */ &&
|
|
|
|
!(id_data[4] & 0x80) /* !BENAND */) {
|
|
|
|
mtd->oobsize = 32 * mtd->writesize >> 9;
|
|
|
|
}
|
|
|
|
|
2013-01-14 12:46:50 +09:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-06-24 17:10:04 +09:00
|
|
|
/*
|
2013-01-14 12:46:50 +09:00
|
|
|
* Old devices have chip data hardcoded in the device ID table. nand_decode_id
|
|
|
|
* decodes a matching ID table entry and assigns the MTD size parameters for
|
|
|
|
* the chip.
|
|
|
|
*/
|
|
|
|
static void nand_decode_id(struct mtd_info *mtd, struct nand_chip *chip,
|
2014-06-24 17:10:04 +09:00
|
|
|
struct nand_flash_dev *type, u8 id_data[8],
|
2013-01-14 12:46:50 +09:00
|
|
|
int *busw)
|
|
|
|
{
|
|
|
|
int maf_id = id_data[0];
|
|
|
|
|
|
|
|
mtd->erasesize = type->erasesize;
|
|
|
|
mtd->writesize = type->pagesize;
|
|
|
|
mtd->oobsize = mtd->writesize / 32;
|
|
|
|
*busw = type->options & NAND_BUSWIDTH_16;
|
|
|
|
|
2014-06-24 17:10:04 +09:00
|
|
|
/* All legacy ID NAND are small-page, SLC */
|
|
|
|
chip->bits_per_cell = 1;
|
|
|
|
|
2013-01-14 12:46:50 +09:00
|
|
|
/*
|
|
|
|
* Check for Spansion/AMD ID + repeating 5th, 6th byte since
|
|
|
|
* some Spansion chips have erasesize that conflicts with size
|
|
|
|
* listed in nand_ids table.
|
|
|
|
* Data sheet (5 byte ID): Spansion S30ML-P ORNAND (p.39)
|
|
|
|
*/
|
|
|
|
if (maf_id == NAND_MFR_AMD && id_data[4] != 0x00 && id_data[5] == 0x00
|
|
|
|
&& id_data[6] == 0x00 && id_data[7] == 0x00
|
|
|
|
&& mtd->writesize == 512) {
|
|
|
|
mtd->erasesize = 128 * 1024;
|
|
|
|
mtd->erasesize <<= ((id_data[3] & 0x03) << 1);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-06-24 17:10:04 +09:00
|
|
|
/*
|
2013-01-14 12:46:50 +09:00
|
|
|
* Set the bad block marker/indicator (BBM/BBI) patterns according to some
|
|
|
|
* heuristic patterns using various detected parameters (e.g., manufacturer,
|
|
|
|
* page size, cell-type information).
|
|
|
|
*/
|
|
|
|
static void nand_decode_bbm_options(struct mtd_info *mtd,
|
|
|
|
struct nand_chip *chip, u8 id_data[8])
|
|
|
|
{
|
|
|
|
int maf_id = id_data[0];
|
|
|
|
|
|
|
|
/* Set the bad block position */
|
|
|
|
if (mtd->writesize > 512 || (chip->options & NAND_BUSWIDTH_16))
|
|
|
|
chip->badblockpos = NAND_LARGE_BADBLOCK_POS;
|
|
|
|
else
|
|
|
|
chip->badblockpos = NAND_SMALL_BADBLOCK_POS;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Bad block marker is stored in the last page of each block on Samsung
|
|
|
|
* and Hynix MLC devices; stored in first two pages of each block on
|
|
|
|
* Micron devices with 2KiB pages and on SLC Samsung, Hynix, Toshiba,
|
|
|
|
* AMD/Spansion, and Macronix. All others scan only the first page.
|
|
|
|
*/
|
2014-06-24 17:10:04 +09:00
|
|
|
if (!nand_is_slc(chip) &&
|
2013-01-14 12:46:50 +09:00
|
|
|
(maf_id == NAND_MFR_SAMSUNG ||
|
|
|
|
maf_id == NAND_MFR_HYNIX))
|
|
|
|
chip->bbt_options |= NAND_BBT_SCANLASTPAGE;
|
2014-06-24 17:10:04 +09:00
|
|
|
else if ((nand_is_slc(chip) &&
|
2013-01-14 12:46:50 +09:00
|
|
|
(maf_id == NAND_MFR_SAMSUNG ||
|
|
|
|
maf_id == NAND_MFR_HYNIX ||
|
|
|
|
maf_id == NAND_MFR_TOSHIBA ||
|
|
|
|
maf_id == NAND_MFR_AMD ||
|
|
|
|
maf_id == NAND_MFR_MACRONIX)) ||
|
|
|
|
(mtd->writesize == 2048 &&
|
|
|
|
maf_id == NAND_MFR_MICRON))
|
|
|
|
chip->bbt_options |= NAND_BBT_SCAN2NDPAGE;
|
|
|
|
}
|
|
|
|
|
2014-06-24 17:10:04 +09:00
|
|
|
static inline bool is_full_id_nand(struct nand_flash_dev *type)
|
|
|
|
{
|
|
|
|
return type->id_len;
|
|
|
|
}
|
|
|
|
|
|
|
|
static bool find_full_id_nand(struct mtd_info *mtd, struct nand_chip *chip,
|
|
|
|
struct nand_flash_dev *type, u8 *id_data, int *busw)
|
|
|
|
{
|
|
|
|
#ifndef __UBOOT__
|
|
|
|
if (!strncmp(type->id, id_data, type->id_len)) {
|
|
|
|
#else
|
|
|
|
if (!strncmp((char *)type->id, (char *)id_data, type->id_len)) {
|
|
|
|
#endif
|
|
|
|
mtd->writesize = type->pagesize;
|
|
|
|
mtd->erasesize = type->erasesize;
|
|
|
|
mtd->oobsize = type->oobsize;
|
|
|
|
|
|
|
|
chip->bits_per_cell = nand_get_bits_per_cell(id_data[2]);
|
|
|
|
chip->chipsize = (uint64_t)type->chipsize << 20;
|
|
|
|
chip->options |= type->options;
|
|
|
|
chip->ecc_strength_ds = NAND_ECC_STRENGTH(type);
|
|
|
|
chip->ecc_step_ds = NAND_ECC_STEP(type);
|
|
|
|
|
|
|
|
*busw = type->options & NAND_BUSWIDTH_16;
|
|
|
|
|
|
|
|
if (!mtd->name)
|
|
|
|
mtd->name = type->name;
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2013-01-14 12:46:50 +09:00
|
|
|
/*
|
|
|
|
* Get the flash and manufacturer id and lookup if the type is supported.
|
2007-10-31 21:53:06 +09:00
|
|
|
*/
|
2014-06-24 17:10:04 +09:00
|
|
|
static struct nand_flash_dev *nand_get_flash_type(struct mtd_info *mtd,
|
2007-10-31 21:53:06 +09:00
|
|
|
struct nand_chip *chip,
|
2011-02-25 09:01:34 +09:00
|
|
|
int *maf_id, int *dev_id,
|
2014-06-24 17:10:04 +09:00
|
|
|
struct nand_flash_dev *type)
|
2007-10-31 21:53:06 +09:00
|
|
|
{
|
2014-07-15 23:08:43 +09:00
|
|
|
int busw;
|
2011-10-12 16:32:02 +09:00
|
|
|
int i, maf_idx;
|
|
|
|
u8 id_data[8];
|
2005-08-17 19:55:25 +09:00
|
|
|
|
|
|
|
/* Select the device */
|
2007-10-31 21:53:06 +09:00
|
|
|
chip->select_chip(mtd, 0);
|
2005-08-17 19:55:25 +09:00
|
|
|
|
2008-09-15 23:08:03 +09:00
|
|
|
/*
|
|
|
|
* Reset the chip, required by some chips (e.g. Micron MT29FxGxxxxx)
|
2013-01-14 12:46:50 +09:00
|
|
|
* after power-up.
|
2008-09-15 23:08:03 +09:00
|
|
|
*/
|
|
|
|
chip->cmdfunc(mtd, NAND_CMD_RESET, -1, -1);
|
|
|
|
|
2005-08-17 19:55:25 +09:00
|
|
|
/* Send the command for reading device ID */
|
2007-10-31 21:53:06 +09:00
|
|
|
chip->cmdfunc(mtd, NAND_CMD_READID, 0x00, -1);
|
2005-08-17 19:55:25 +09:00
|
|
|
|
|
|
|
/* Read manufacturer and device IDs */
|
2007-10-31 21:53:06 +09:00
|
|
|
*maf_id = chip->read_byte(mtd);
|
2011-02-25 09:01:34 +09:00
|
|
|
*dev_id = chip->read_byte(mtd);
|
2005-08-17 19:55:25 +09:00
|
|
|
|
2013-01-14 12:46:50 +09:00
|
|
|
/*
|
|
|
|
* Try again to make sure, as some systems the bus-hold or other
|
2008-10-25 06:20:43 +09:00
|
|
|
* interface concerns can cause random data which looks like a
|
|
|
|
* possibly credible NAND flash to appear. If the two results do
|
|
|
|
* not match, ignore the device completely.
|
|
|
|
*/
|
|
|
|
|
|
|
|
chip->cmdfunc(mtd, NAND_CMD_READID, 0x00, -1);
|
|
|
|
|
2013-01-14 12:46:50 +09:00
|
|
|
/* Read entire ID string */
|
|
|
|
for (i = 0; i < 8; i++)
|
2011-10-12 16:32:02 +09:00
|
|
|
id_data[i] = chip->read_byte(mtd);
|
2008-10-25 06:20:43 +09:00
|
|
|
|
2011-10-12 16:32:02 +09:00
|
|
|
if (id_data[0] != *maf_id || id_data[1] != *dev_id) {
|
2014-06-24 17:10:04 +09:00
|
|
|
pr_info("second ID read did not match %02x,%02x against %02x,%02x\n",
|
2013-01-14 12:46:50 +09:00
|
|
|
*maf_id, *dev_id, id_data[0], id_data[1]);
|
2008-10-25 06:20:43 +09:00
|
|
|
return ERR_PTR(-ENODEV);
|
|
|
|
}
|
|
|
|
|
2011-01-06 10:48:18 +09:00
|
|
|
if (!type)
|
|
|
|
type = nand_flash_ids;
|
|
|
|
|
2014-06-24 17:10:04 +09:00
|
|
|
for (; type->name != NULL; type++) {
|
|
|
|
if (is_full_id_nand(type)) {
|
|
|
|
if (find_full_id_nand(mtd, chip, type, id_data, &busw))
|
|
|
|
goto ident_done;
|
|
|
|
} else if (*dev_id == type->dev_id) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2005-09-15 06:53:32 +09:00
|
|
|
|
2011-10-12 16:32:02 +09:00
|
|
|
chip->onfi_version = 0;
|
|
|
|
if (!type->name || !type->pagesize) {
|
|
|
|
/* Check is chip is ONFI compliant */
|
2013-01-14 12:46:50 +09:00
|
|
|
if (nand_flash_detect_onfi(mtd, chip, &busw))
|
2011-10-12 16:32:02 +09:00
|
|
|
goto ident_done;
|
2014-07-15 23:08:43 +09:00
|
|
|
|
|
|
|
/* Check if the chip is JEDEC compliant */
|
|
|
|
if (nand_flash_detect_jedec(mtd, chip, &busw))
|
|
|
|
goto ident_done;
|
2010-06-13 03:59:25 +09:00
|
|
|
}
|
2007-10-31 21:53:06 +09:00
|
|
|
|
2011-10-12 16:32:02 +09:00
|
|
|
if (!type->name)
|
|
|
|
return ERR_PTR(-ENODEV);
|
|
|
|
|
2007-10-31 21:53:06 +09:00
|
|
|
if (!mtd->name)
|
|
|
|
mtd->name = type->name;
|
|
|
|
|
2009-10-31 02:51:23 +09:00
|
|
|
chip->chipsize = (uint64_t)type->chipsize << 20;
|
2007-10-31 21:53:06 +09:00
|
|
|
|
2011-10-12 16:32:02 +09:00
|
|
|
if (!type->pagesize && chip->init_size) {
|
2013-01-14 12:46:50 +09:00
|
|
|
/* Set the pagesize, oobsize, erasesize by the driver */
|
2011-10-12 16:32:02 +09:00
|
|
|
busw = chip->init_size(mtd, chip, id_data);
|
|
|
|
} else if (!type->pagesize) {
|
2013-01-14 12:46:50 +09:00
|
|
|
/* Decode parameters from extended ID */
|
|
|
|
nand_decode_ext_id(mtd, chip, id_data, &busw);
|
2011-10-12 16:32:02 +09:00
|
|
|
} else {
|
2013-01-14 12:46:50 +09:00
|
|
|
nand_decode_id(mtd, chip, type, id_data, &busw);
|
2011-10-12 16:32:02 +09:00
|
|
|
}
|
2014-06-24 17:10:04 +09:00
|
|
|
/* Get chip options */
|
2012-08-30 22:39:38 +09:00
|
|
|
chip->options |= type->options;
|
2011-02-25 09:01:34 +09:00
|
|
|
|
2013-01-14 12:46:50 +09:00
|
|
|
/*
|
|
|
|
* Check if chip is not a Samsung device. Do not clear the
|
|
|
|
* options for chips which do not have an extended id.
|
2011-10-12 16:32:02 +09:00
|
|
|
*/
|
|
|
|
if (*maf_id != NAND_MFR_SAMSUNG && !type->pagesize)
|
|
|
|
chip->options &= ~NAND_SAMSUNG_LP_OPTIONS;
|
|
|
|
ident_done:
|
|
|
|
|
2007-10-31 21:53:06 +09:00
|
|
|
/* Try to identify manufacturer */
|
|
|
|
for (maf_idx = 0; nand_manuf_ids[maf_idx].id != 0x0; maf_idx++) {
|
|
|
|
if (nand_manuf_ids[maf_idx].id == *maf_id)
|
|
|
|
break;
|
|
|
|
}
|
2005-08-17 19:55:25 +09:00
|
|
|
|
2014-06-24 17:10:04 +09:00
|
|
|
if (chip->options & NAND_BUSWIDTH_AUTO) {
|
|
|
|
WARN_ON(chip->options & NAND_BUSWIDTH_16);
|
|
|
|
chip->options |= busw;
|
|
|
|
nand_set_defaults(chip, busw);
|
|
|
|
} else if (busw != (chip->options & NAND_BUSWIDTH_16)) {
|
|
|
|
/*
|
|
|
|
* Check, if buswidth is correct. Hardware drivers should set
|
|
|
|
* chip correct!
|
|
|
|
*/
|
|
|
|
pr_info("device found, Manufacturer ID: 0x%02x, Chip ID: 0x%02x\n",
|
|
|
|
*maf_id, *dev_id);
|
|
|
|
pr_info("%s %s\n", nand_manuf_ids[maf_idx].name, mtd->name);
|
|
|
|
pr_warn("bus width %d instead %d bit\n",
|
2013-01-14 12:46:50 +09:00
|
|
|
(chip->options & NAND_BUSWIDTH_16) ? 16 : 8,
|
|
|
|
busw ? 16 : 8);
|
2007-10-31 21:53:06 +09:00
|
|
|
return ERR_PTR(-EINVAL);
|
|
|
|
}
|
2005-09-15 06:53:32 +09:00
|
|
|
|
2013-01-14 12:46:50 +09:00
|
|
|
nand_decode_bbm_options(mtd, chip, id_data);
|
|
|
|
|
2007-10-31 21:53:06 +09:00
|
|
|
/* Calculate the address shift from the page size */
|
|
|
|
chip->page_shift = ffs(mtd->writesize) - 1;
|
2013-01-14 12:46:50 +09:00
|
|
|
/* Convert chipsize to number of pages per chip -1 */
|
2007-10-31 21:53:06 +09:00
|
|
|
chip->pagemask = (chip->chipsize >> chip->page_shift) - 1;
|
2005-09-15 06:53:32 +09:00
|
|
|
|
2007-10-31 21:53:06 +09:00
|
|
|
chip->bbt_erase_shift = chip->phys_erase_shift =
|
|
|
|
ffs(mtd->erasesize) - 1;
|
2009-10-31 02:51:23 +09:00
|
|
|
if (chip->chipsize & 0xffffffff)
|
2009-11-08 04:24:06 +09:00
|
|
|
chip->chip_shift = ffs((unsigned)chip->chipsize) - 1;
|
2011-10-12 16:32:02 +09:00
|
|
|
else {
|
|
|
|
chip->chip_shift = ffs((unsigned)(chip->chipsize >> 32));
|
|
|
|
chip->chip_shift += 32 - 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
chip->badblockbits = 8;
|
2014-06-24 17:10:04 +09:00
|
|
|
chip->erase_cmd = single_erase_cmd;
|
2007-10-31 21:53:06 +09:00
|
|
|
|
2013-01-14 12:46:50 +09:00
|
|
|
/* Do not replace user supplied command function! */
|
2007-10-31 21:53:06 +09:00
|
|
|
if (mtd->writesize > 512 && chip->cmdfunc == nand_command)
|
|
|
|
chip->cmdfunc = nand_command_lp;
|
|
|
|
|
2014-06-24 17:10:04 +09:00
|
|
|
pr_info("device found, Manufacturer ID: 0x%02x, Chip ID: 0x%02x\n",
|
|
|
|
*maf_id, *dev_id);
|
2014-07-15 23:08:43 +09:00
|
|
|
|
2011-10-12 16:32:02 +09:00
|
|
|
#ifdef CONFIG_SYS_NAND_ONFI_DETECTION
|
2014-07-15 23:08:43 +09:00
|
|
|
if (chip->onfi_version)
|
|
|
|
pr_info("%s %s\n", nand_manuf_ids[maf_idx].name,
|
|
|
|
chip->onfi_params.model);
|
|
|
|
else if (chip->jedec_version)
|
|
|
|
pr_info("%s %s\n", nand_manuf_ids[maf_idx].name,
|
|
|
|
chip->jedec_params.model);
|
|
|
|
else
|
|
|
|
pr_info("%s %s\n", nand_manuf_ids[maf_idx].name,
|
|
|
|
type->name);
|
2014-06-24 17:10:04 +09:00
|
|
|
#else
|
2014-07-15 23:08:43 +09:00
|
|
|
if (chip->jedec_version)
|
|
|
|
pr_info("%s %s\n", nand_manuf_ids[maf_idx].name,
|
|
|
|
chip->jedec_params.model);
|
|
|
|
else
|
|
|
|
pr_info("%s %s\n", nand_manuf_ids[maf_idx].name,
|
|
|
|
type->name);
|
|
|
|
|
|
|
|
pr_info("%s %s\n", nand_manuf_ids[maf_idx].name,
|
|
|
|
type->name);
|
2011-10-12 16:32:02 +09:00
|
|
|
#endif
|
2014-07-15 23:08:43 +09:00
|
|
|
|
2014-06-24 17:10:04 +09:00
|
|
|
pr_info("%dMiB, %s, page size: %d, OOB size: %d\n",
|
|
|
|
(int)(chip->chipsize >> 20), nand_is_slc(chip) ? "SLC" : "MLC",
|
2013-01-14 12:46:50 +09:00
|
|
|
mtd->writesize, mtd->oobsize);
|
2007-10-31 21:53:06 +09:00
|
|
|
return type;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* nand_scan_ident - [NAND Interface] Scan for the NAND device
|
2013-01-14 12:46:50 +09:00
|
|
|
* @mtd: MTD device structure
|
|
|
|
* @maxchips: number of chips to scan for
|
|
|
|
* @table: alternative NAND ID table
|
2007-10-31 21:53:06 +09:00
|
|
|
*
|
2013-01-14 12:46:50 +09:00
|
|
|
* This is the first phase of the normal nand_scan() function. It reads the
|
|
|
|
* flash ID and sets up MTD fields accordingly.
|
2007-10-31 21:53:06 +09:00
|
|
|
*
|
|
|
|
* The mtd->owner field must be set to the module of the caller.
|
|
|
|
*/
|
2011-01-06 10:48:18 +09:00
|
|
|
int nand_scan_ident(struct mtd_info *mtd, int maxchips,
|
2014-06-24 17:10:04 +09:00
|
|
|
struct nand_flash_dev *table)
|
2007-10-31 21:53:06 +09:00
|
|
|
{
|
2014-07-15 23:08:43 +09:00
|
|
|
int i, nand_maf_id, nand_dev_id;
|
2007-10-31 21:53:06 +09:00
|
|
|
struct nand_chip *chip = mtd->priv;
|
2014-06-24 17:10:04 +09:00
|
|
|
struct nand_flash_dev *type;
|
2007-10-31 21:53:06 +09:00
|
|
|
|
|
|
|
/* Set the default functions */
|
2014-07-15 23:08:43 +09:00
|
|
|
nand_set_defaults(chip, chip->options & NAND_BUSWIDTH_16);
|
2007-10-31 21:53:06 +09:00
|
|
|
|
|
|
|
/* Read the flash type */
|
2014-07-15 23:08:43 +09:00
|
|
|
type = nand_get_flash_type(mtd, chip, &nand_maf_id,
|
|
|
|
&nand_dev_id, table);
|
2007-10-31 21:53:06 +09:00
|
|
|
|
|
|
|
if (IS_ERR(type)) {
|
2014-06-24 17:10:04 +09:00
|
|
|
if (!(chip->options & NAND_SCAN_SILENT_NODEV))
|
|
|
|
pr_warn("No NAND device found\n");
|
2007-10-31 21:53:06 +09:00
|
|
|
chip->select_chip(mtd, -1);
|
|
|
|
return PTR_ERR(type);
|
|
|
|
}
|
2005-08-17 19:55:25 +09:00
|
|
|
|
2014-06-24 17:10:04 +09:00
|
|
|
chip->select_chip(mtd, -1);
|
|
|
|
|
2007-10-31 21:53:06 +09:00
|
|
|
/* Check for a chip array */
|
|
|
|
for (i = 1; i < maxchips; i++) {
|
|
|
|
chip->select_chip(mtd, i);
|
2008-09-15 23:08:03 +09:00
|
|
|
/* See comment in nand_get_flash_type for reset */
|
|
|
|
chip->cmdfunc(mtd, NAND_CMD_RESET, -1, -1);
|
2007-10-31 21:53:06 +09:00
|
|
|
/* Send the command for reading device ID */
|
|
|
|
chip->cmdfunc(mtd, NAND_CMD_READID, 0x00, -1);
|
2005-08-17 19:55:25 +09:00
|
|
|
/* Read manufacturer and device IDs */
|
2007-10-31 21:53:06 +09:00
|
|
|
if (nand_maf_id != chip->read_byte(mtd) ||
|
2014-06-24 17:10:04 +09:00
|
|
|
nand_dev_id != chip->read_byte(mtd)) {
|
|
|
|
chip->select_chip(mtd, -1);
|
2005-08-17 19:55:25 +09:00
|
|
|
break;
|
2014-06-24 17:10:04 +09:00
|
|
|
}
|
|
|
|
chip->select_chip(mtd, -1);
|
2005-08-17 19:55:25 +09:00
|
|
|
}
|
2014-06-24 17:10:04 +09:00
|
|
|
|
2009-02-12 02:38:20 +09:00
|
|
|
#ifdef DEBUG
|
2005-08-17 19:55:25 +09:00
|
|
|
if (i > 1)
|
2014-06-24 17:10:04 +09:00
|
|
|
pr_info("%d chips detected\n", i);
|
2009-02-12 02:38:20 +09:00
|
|
|
#endif
|
2005-09-15 06:53:32 +09:00
|
|
|
|
2007-10-31 21:53:06 +09:00
|
|
|
/* Store the number of chips and calc total size for mtd */
|
|
|
|
chip->numchips = i;
|
|
|
|
mtd->size = i * chip->chipsize;
|
2005-09-15 06:53:32 +09:00
|
|
|
|
2007-10-31 21:53:06 +09:00
|
|
|
return 0;
|
|
|
|
}
|
2014-06-24 17:10:04 +09:00
|
|
|
EXPORT_SYMBOL(nand_scan_ident);
|
2005-08-17 19:55:25 +09:00
|
|
|
|
2007-10-31 21:53:06 +09:00
|
|
|
|
|
|
|
/**
|
|
|
|
* nand_scan_tail - [NAND Interface] Scan for the NAND device
|
2013-01-14 12:46:50 +09:00
|
|
|
* @mtd: MTD device structure
|
2007-10-31 21:53:06 +09:00
|
|
|
*
|
2013-01-14 12:46:50 +09:00
|
|
|
* 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.
|
2007-10-31 21:53:06 +09:00
|
|
|
*/
|
|
|
|
int nand_scan_tail(struct mtd_info *mtd)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
struct nand_chip *chip = mtd->priv;
|
2014-06-24 17:10:04 +09:00
|
|
|
struct nand_ecc_ctrl *ecc = &chip->ecc;
|
2014-07-15 23:08:43 +09:00
|
|
|
struct nand_buffers *nbuf;
|
2007-10-31 21:53:06 +09:00
|
|
|
|
2013-01-14 12:46:50 +09:00
|
|
|
/* New bad blocks should be marked in OOB, flash-based BBT, or both */
|
|
|
|
BUG_ON((chip->bbt_options & NAND_BBT_NO_OOB_BBM) &&
|
|
|
|
!(chip->bbt_options & NAND_BBT_USE_FLASH));
|
|
|
|
|
2014-07-15 23:08:43 +09:00
|
|
|
if (!(chip->options & NAND_OWN_BUFFERS)) {
|
|
|
|
#ifndef __UBOOT__
|
|
|
|
nbuf = kzalloc(sizeof(*nbuf) + mtd->writesize
|
|
|
|
+ mtd->oobsize * 3, GFP_KERNEL);
|
|
|
|
if (!nbuf)
|
|
|
|
return -ENOMEM;
|
|
|
|
nbuf->ecccalc = (uint8_t *)(nbuf + 1);
|
|
|
|
nbuf->ecccode = nbuf->ecccalc + mtd->oobsize;
|
|
|
|
nbuf->databuf = nbuf->ecccode + mtd->oobsize;
|
|
|
|
#else
|
|
|
|
nbuf = kzalloc(sizeof(struct nand_buffers), GFP_KERNEL);
|
|
|
|
#endif
|
|
|
|
|
|
|
|
chip->buffers = nbuf;
|
|
|
|
} else {
|
|
|
|
if (!chip->buffers)
|
|
|
|
return -ENOMEM;
|
|
|
|
}
|
2007-10-31 21:53:06 +09:00
|
|
|
|
|
|
|
/* Set the internal oob buffer location, just after the page data */
|
|
|
|
chip->oob_poi = chip->buffers->databuf + mtd->writesize;
|
|
|
|
|
|
|
|
/*
|
2013-01-14 12:46:50 +09:00
|
|
|
* If no default placement scheme is given, select an appropriate one.
|
2007-10-31 21:53:06 +09:00
|
|
|
*/
|
2014-06-24 17:10:04 +09:00
|
|
|
if (!ecc->layout && (ecc->mode != NAND_ECC_SOFT_BCH)) {
|
2005-09-15 06:53:32 +09:00
|
|
|
switch (mtd->oobsize) {
|
2005-08-17 19:55:25 +09:00
|
|
|
case 8:
|
2014-06-24 17:10:04 +09:00
|
|
|
ecc->layout = &nand_oob_8;
|
2005-08-17 19:55:25 +09:00
|
|
|
break;
|
|
|
|
case 16:
|
2014-06-24 17:10:04 +09:00
|
|
|
ecc->layout = &nand_oob_16;
|
2005-08-17 19:55:25 +09:00
|
|
|
break;
|
|
|
|
case 64:
|
2014-06-24 17:10:04 +09:00
|
|
|
ecc->layout = &nand_oob_64;
|
2005-08-17 19:55:25 +09:00
|
|
|
break;
|
2008-06-06 22:42:43 +09:00
|
|
|
case 128:
|
2014-06-24 17:10:04 +09:00
|
|
|
ecc->layout = &nand_oob_128;
|
2008-06-06 22:42:43 +09:00
|
|
|
break;
|
2005-08-17 19:55:25 +09:00
|
|
|
default:
|
2013-01-14 12:46:50 +09:00
|
|
|
pr_warn("No oob scheme defined for oobsize %d\n",
|
|
|
|
mtd->oobsize);
|
2014-06-24 17:10:04 +09:00
|
|
|
BUG();
|
2005-08-17 19:55:25 +09:00
|
|
|
}
|
|
|
|
}
|
2005-09-15 06:53:32 +09:00
|
|
|
|
2007-10-31 21:53:06 +09:00
|
|
|
if (!chip->write_page)
|
|
|
|
chip->write_page = nand_write_page;
|
2005-08-17 19:55:25 +09:00
|
|
|
|
2005-09-15 06:53:32 +09:00
|
|
|
/*
|
2013-01-14 12:46:50 +09:00
|
|
|
* Check ECC mode, default to software if 3byte/512byte hardware ECC is
|
2007-10-31 21:53:06 +09:00
|
|
|
* selected and we have 256 byte pagesize fallback to software ECC
|
|
|
|
*/
|
|
|
|
|
2014-06-24 17:10:04 +09:00
|
|
|
switch (ecc->mode) {
|
2009-08-11 02:27:56 +09:00
|
|
|
case NAND_ECC_HW_OOB_FIRST:
|
|
|
|
/* Similar to NAND_ECC_HW, but a separate read_page handle */
|
2014-06-24 17:10:04 +09:00
|
|
|
if (!ecc->calculate || !ecc->correct || !ecc->hwctl) {
|
2013-01-14 12:46:50 +09:00
|
|
|
pr_warn("No ECC functions supplied; "
|
|
|
|
"hardware ECC not possible\n");
|
2009-08-11 02:27:56 +09:00
|
|
|
BUG();
|
|
|
|
}
|
2014-06-24 17:10:04 +09:00
|
|
|
if (!ecc->read_page)
|
|
|
|
ecc->read_page = nand_read_page_hwecc_oob_first;
|
2009-08-11 02:27:56 +09:00
|
|
|
|
2007-10-31 21:53:06 +09:00
|
|
|
case NAND_ECC_HW:
|
2013-01-14 12:46:50 +09:00
|
|
|
/* Use standard hwecc read page function? */
|
2014-06-24 17:10:04 +09:00
|
|
|
if (!ecc->read_page)
|
|
|
|
ecc->read_page = nand_read_page_hwecc;
|
|
|
|
if (!ecc->write_page)
|
|
|
|
ecc->write_page = nand_write_page_hwecc;
|
|
|
|
if (!ecc->read_page_raw)
|
|
|
|
ecc->read_page_raw = nand_read_page_raw;
|
|
|
|
if (!ecc->write_page_raw)
|
|
|
|
ecc->write_page_raw = nand_write_page_raw;
|
|
|
|
if (!ecc->read_oob)
|
|
|
|
ecc->read_oob = nand_read_oob_std;
|
|
|
|
if (!ecc->write_oob)
|
|
|
|
ecc->write_oob = nand_write_oob_std;
|
|
|
|
if (!ecc->read_subpage)
|
|
|
|
ecc->read_subpage = nand_read_subpage;
|
|
|
|
if (!ecc->write_subpage)
|
|
|
|
ecc->write_subpage = nand_write_subpage_hwecc;
|
2007-10-31 21:53:06 +09:00
|
|
|
|
|
|
|
case NAND_ECC_HW_SYNDROME:
|
2014-06-24 17:10:04 +09:00
|
|
|
if ((!ecc->calculate || !ecc->correct || !ecc->hwctl) &&
|
|
|
|
(!ecc->read_page ||
|
|
|
|
ecc->read_page == nand_read_page_hwecc ||
|
|
|
|
!ecc->write_page ||
|
|
|
|
ecc->write_page == nand_write_page_hwecc)) {
|
2013-01-14 12:46:50 +09:00
|
|
|
pr_warn("No ECC functions supplied; "
|
|
|
|
"hardware ECC not possible\n");
|
2007-10-31 21:53:06 +09:00
|
|
|
BUG();
|
|
|
|
}
|
2013-01-14 12:46:50 +09:00
|
|
|
/* Use standard syndrome read/write page function? */
|
2014-06-24 17:10:04 +09:00
|
|
|
if (!ecc->read_page)
|
|
|
|
ecc->read_page = nand_read_page_syndrome;
|
|
|
|
if (!ecc->write_page)
|
|
|
|
ecc->write_page = nand_write_page_syndrome;
|
|
|
|
if (!ecc->read_page_raw)
|
|
|
|
ecc->read_page_raw = nand_read_page_raw_syndrome;
|
|
|
|
if (!ecc->write_page_raw)
|
|
|
|
ecc->write_page_raw = nand_write_page_raw_syndrome;
|
|
|
|
if (!ecc->read_oob)
|
|
|
|
ecc->read_oob = nand_read_oob_syndrome;
|
|
|
|
if (!ecc->write_oob)
|
|
|
|
ecc->write_oob = nand_write_oob_syndrome;
|
|
|
|
|
|
|
|
if (mtd->writesize >= ecc->size) {
|
|
|
|
if (!ecc->strength) {
|
2013-01-14 12:46:50 +09:00
|
|
|
pr_warn("Driver must set ecc.strength when using hardware ECC\n");
|
|
|
|
BUG();
|
|
|
|
}
|
2007-10-31 21:53:06 +09:00
|
|
|
break;
|
2013-01-14 12:46:50 +09:00
|
|
|
}
|
|
|
|
pr_warn("%d byte HW ECC not possible on "
|
|
|
|
"%d byte page size, fallback to SW ECC\n",
|
2014-06-24 17:10:04 +09:00
|
|
|
ecc->size, mtd->writesize);
|
|
|
|
ecc->mode = NAND_ECC_SOFT;
|
2005-09-15 06:53:32 +09:00
|
|
|
|
2007-10-31 21:53:06 +09:00
|
|
|
case NAND_ECC_SOFT:
|
2014-06-24 17:10:04 +09:00
|
|
|
ecc->calculate = nand_calculate_ecc;
|
|
|
|
ecc->correct = nand_correct_data;
|
|
|
|
ecc->read_page = nand_read_page_swecc;
|
|
|
|
ecc->read_subpage = nand_read_subpage;
|
|
|
|
ecc->write_page = nand_write_page_swecc;
|
|
|
|
ecc->read_page_raw = nand_read_page_raw;
|
|
|
|
ecc->write_page_raw = nand_write_page_raw;
|
|
|
|
ecc->read_oob = nand_read_oob_std;
|
|
|
|
ecc->write_oob = nand_write_oob_std;
|
|
|
|
if (!ecc->size)
|
|
|
|
ecc->size = 256;
|
|
|
|
ecc->bytes = 3;
|
|
|
|
ecc->strength = 1;
|
2005-08-17 19:55:25 +09:00
|
|
|
break;
|
2005-09-15 06:53:32 +09:00
|
|
|
|
2011-10-12 16:31:59 +09:00
|
|
|
case NAND_ECC_SOFT_BCH:
|
|
|
|
if (!mtd_nand_has_bch()) {
|
2014-07-15 23:08:43 +09:00
|
|
|
pr_warn("CONFIG_MTD_NAND_ECC_BCH not enabled\n");
|
2014-06-24 17:10:04 +09:00
|
|
|
BUG();
|
2011-10-12 16:31:59 +09:00
|
|
|
}
|
2014-06-24 17:10:04 +09:00
|
|
|
ecc->calculate = nand_bch_calculate_ecc;
|
|
|
|
ecc->correct = nand_bch_correct_data;
|
|
|
|
ecc->read_page = nand_read_page_swecc;
|
|
|
|
ecc->read_subpage = nand_read_subpage;
|
|
|
|
ecc->write_page = nand_write_page_swecc;
|
|
|
|
ecc->read_page_raw = nand_read_page_raw;
|
|
|
|
ecc->write_page_raw = nand_write_page_raw;
|
|
|
|
ecc->read_oob = nand_read_oob_std;
|
|
|
|
ecc->write_oob = nand_write_oob_std;
|
2011-10-12 16:31:59 +09:00
|
|
|
/*
|
|
|
|
* Board driver should supply ecc.size and ecc.bytes values to
|
|
|
|
* select how many bits are correctable; see nand_bch_init()
|
2013-01-14 12:46:50 +09:00
|
|
|
* for details. Otherwise, default to 4 bits for large page
|
|
|
|
* devices.
|
2011-10-12 16:31:59 +09:00
|
|
|
*/
|
2014-06-24 17:10:04 +09:00
|
|
|
if (!ecc->size && (mtd->oobsize >= 64)) {
|
|
|
|
ecc->size = 512;
|
|
|
|
ecc->bytes = 7;
|
2011-10-12 16:31:59 +09:00
|
|
|
}
|
2014-06-24 17:10:04 +09:00
|
|
|
ecc->priv = nand_bch_init(mtd, ecc->size, ecc->bytes,
|
|
|
|
&ecc->layout);
|
|
|
|
if (!ecc->priv) {
|
2013-01-14 12:46:50 +09:00
|
|
|
pr_warn("BCH ECC initialization failed!\n");
|
2014-06-24 17:10:04 +09:00
|
|
|
BUG();
|
|
|
|
}
|
|
|
|
ecc->strength = ecc->bytes * 8 / fls(8 * ecc->size);
|
2011-10-12 16:31:59 +09:00
|
|
|
break;
|
|
|
|
|
2005-09-15 06:53:32 +09:00
|
|
|
case NAND_ECC_NONE:
|
2013-01-14 12:46:50 +09:00
|
|
|
pr_warn("NAND_ECC_NONE selected by board driver. "
|
2014-06-24 17:10:04 +09:00
|
|
|
"This is not recommended!\n");
|
|
|
|
ecc->read_page = nand_read_page_raw;
|
|
|
|
ecc->write_page = nand_write_page_raw;
|
|
|
|
ecc->read_oob = nand_read_oob_std;
|
|
|
|
ecc->read_page_raw = nand_read_page_raw;
|
|
|
|
ecc->write_page_raw = nand_write_page_raw;
|
|
|
|
ecc->write_oob = nand_write_oob_std;
|
|
|
|
ecc->size = mtd->writesize;
|
|
|
|
ecc->bytes = 0;
|
|
|
|
ecc->strength = 0;
|
2005-08-17 19:55:25 +09:00
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
2014-06-24 17:10:04 +09:00
|
|
|
pr_warn("Invalid NAND_ECC_MODE %d\n", ecc->mode);
|
2007-10-31 21:53:06 +09:00
|
|
|
BUG();
|
2005-08-17 19:55:25 +09:00
|
|
|
}
|
2005-09-15 06:53:32 +09:00
|
|
|
|
2013-01-14 12:46:50 +09:00
|
|
|
/* For many systems, the standard OOB write also works for raw */
|
2014-06-24 17:10:04 +09:00
|
|
|
if (!ecc->read_oob_raw)
|
|
|
|
ecc->read_oob_raw = ecc->read_oob;
|
|
|
|
if (!ecc->write_oob_raw)
|
|
|
|
ecc->write_oob_raw = ecc->write_oob;
|
2013-01-14 12:46:50 +09:00
|
|
|
|
2007-10-31 21:53:06 +09:00
|
|
|
/*
|
|
|
|
* The number of bytes available for a client to place data into
|
2013-01-14 12:46:50 +09:00
|
|
|
* the out of band area.
|
2007-10-31 21:53:06 +09:00
|
|
|
*/
|
2014-06-24 17:10:04 +09:00
|
|
|
ecc->layout->oobavail = 0;
|
|
|
|
for (i = 0; ecc->layout->oobfree[i].length
|
|
|
|
&& i < ARRAY_SIZE(ecc->layout->oobfree); i++)
|
|
|
|
ecc->layout->oobavail += ecc->layout->oobfree[i].length;
|
|
|
|
mtd->oobavail = ecc->layout->oobavail;
|
2005-09-15 06:53:32 +09:00
|
|
|
|
2007-10-31 21:53:06 +09:00
|
|
|
/*
|
|
|
|
* Set the number of read / write steps for one page depending on ECC
|
2013-01-14 12:46:50 +09:00
|
|
|
* mode.
|
2007-10-31 21:53:06 +09:00
|
|
|
*/
|
2014-06-24 17:10:04 +09:00
|
|
|
ecc->steps = mtd->writesize / ecc->size;
|
|
|
|
if (ecc->steps * ecc->size != mtd->writesize) {
|
2013-01-14 12:46:50 +09:00
|
|
|
pr_warn("Invalid ECC parameters\n");
|
2007-10-31 21:53:06 +09:00
|
|
|
BUG();
|
|
|
|
}
|
2014-06-24 17:10:04 +09:00
|
|
|
ecc->total = ecc->steps * ecc->bytes;
|
2005-09-15 06:53:32 +09:00
|
|
|
|
2013-01-14 12:46:50 +09:00
|
|
|
/* Allow subpage writes up to ecc.steps. Not possible for MLC flash */
|
2014-06-24 17:10:04 +09:00
|
|
|
if (!(chip->options & NAND_NO_SUBPAGE_WRITE) && nand_is_slc(chip)) {
|
|
|
|
switch (ecc->steps) {
|
2007-10-31 21:53:06 +09:00
|
|
|
case 2:
|
|
|
|
mtd->subpage_sft = 1;
|
|
|
|
break;
|
|
|
|
case 4:
|
|
|
|
case 8:
|
2009-11-08 04:24:34 +09:00
|
|
|
case 16:
|
2007-10-31 21:53:06 +09:00
|
|
|
mtd->subpage_sft = 2;
|
|
|
|
break;
|
|
|
|
}
|
2005-08-17 19:55:25 +09:00
|
|
|
}
|
2007-10-31 21:53:06 +09:00
|
|
|
chip->subpagesize = mtd->writesize >> mtd->subpage_sft;
|
2005-08-17 19:55:25 +09:00
|
|
|
|
2007-10-31 21:53:06 +09:00
|
|
|
/* Initialize state */
|
|
|
|
chip->state = FL_READY;
|
2005-08-17 19:55:25 +09:00
|
|
|
|
|
|
|
/* Invalidate the pagebuffer reference */
|
2007-10-31 21:53:06 +09:00
|
|
|
chip->pagebuf = -1;
|
2005-08-17 19:55:25 +09:00
|
|
|
|
2012-11-05 15:46:31 +09:00
|
|
|
/* Large page NAND with SOFT_ECC should support subpage reads */
|
2014-06-24 17:10:04 +09:00
|
|
|
if ((ecc->mode == NAND_ECC_SOFT) && (chip->page_shift > 9))
|
2012-11-05 15:46:31 +09:00
|
|
|
chip->options |= NAND_SUBPAGE_READ;
|
|
|
|
|
2005-08-17 19:55:25 +09:00
|
|
|
/* Fill in remaining MTD driver data */
|
2014-06-24 17:10:04 +09:00
|
|
|
mtd->type = nand_is_slc(chip) ? MTD_NANDFLASH : MTD_MLCNANDFLASH;
|
2011-10-12 16:32:02 +09:00
|
|
|
mtd->flags = (chip->options & NAND_ROM) ? MTD_CAP_ROM :
|
|
|
|
MTD_CAP_NANDFLASH;
|
2013-01-14 12:46:50 +09:00
|
|
|
mtd->_erase = nand_erase;
|
2014-06-24 17:10:04 +09:00
|
|
|
#ifndef __UBOOT__
|
2013-01-14 12:46:50 +09:00
|
|
|
mtd->_point = NULL;
|
|
|
|
mtd->_unpoint = NULL;
|
2014-06-24 17:10:04 +09:00
|
|
|
#endif
|
2013-01-14 12:46:50 +09:00
|
|
|
mtd->_read = nand_read;
|
|
|
|
mtd->_write = nand_write;
|
2014-06-24 17:10:04 +09:00
|
|
|
mtd->_panic_write = panic_nand_write;
|
2013-01-14 12:46:50 +09:00
|
|
|
mtd->_read_oob = nand_read_oob;
|
|
|
|
mtd->_write_oob = nand_write_oob;
|
|
|
|
mtd->_sync = nand_sync;
|
|
|
|
mtd->_lock = NULL;
|
|
|
|
mtd->_unlock = NULL;
|
2014-06-24 17:10:04 +09:00
|
|
|
#ifndef __UBOOT__
|
|
|
|
mtd->_suspend = nand_suspend;
|
|
|
|
mtd->_resume = nand_resume;
|
|
|
|
#endif
|
2013-01-14 12:46:50 +09:00
|
|
|
mtd->_block_isbad = nand_block_isbad;
|
|
|
|
mtd->_block_markbad = nand_block_markbad;
|
2014-06-24 17:10:04 +09:00
|
|
|
mtd->writebufsize = mtd->writesize;
|
2013-01-14 12:46:50 +09:00
|
|
|
|
|
|
|
/* propagate ecc info to mtd_info */
|
2014-06-24 17:10:04 +09:00
|
|
|
mtd->ecclayout = ecc->layout;
|
|
|
|
mtd->ecc_strength = ecc->strength;
|
|
|
|
mtd->ecc_step_size = ecc->size;
|
2013-01-14 12:46:50 +09:00
|
|
|
/*
|
|
|
|
* Initialize bitflip_threshold to its default prior scan_bbt() call.
|
|
|
|
* scan_bbt() might invoke mtd_read(), thus bitflip_threshold must be
|
|
|
|
* properly set.
|
|
|
|
*/
|
|
|
|
if (!mtd->bitflip_threshold)
|
|
|
|
mtd->bitflip_threshold = mtd->ecc_strength;
|
2007-10-31 21:53:06 +09:00
|
|
|
|
2014-10-22 20:40:44 +09:00
|
|
|
return 0;
|
2007-10-31 21:53:06 +09:00
|
|
|
}
|
2014-06-24 17:10:04 +09:00
|
|
|
EXPORT_SYMBOL(nand_scan_tail);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* is_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() \
|
|
|
|
is_module_text_address((unsigned long)__builtin_return_address(0))
|
|
|
|
#endif
|
2007-10-31 21:53:06 +09:00
|
|
|
|
|
|
|
/**
|
|
|
|
* nand_scan - [NAND Interface] Scan for the NAND device
|
2013-01-14 12:46:50 +09:00
|
|
|
* @mtd: MTD device structure
|
|
|
|
* @maxchips: number of chips to scan for
|
2007-10-31 21:53:06 +09:00
|
|
|
*
|
2013-01-14 12:46:50 +09:00
|
|
|
* 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.
|
2007-10-31 21:53:06 +09:00
|
|
|
*/
|
|
|
|
int nand_scan(struct mtd_info *mtd, int maxchips)
|
|
|
|
{
|
|
|
|
int ret;
|
|
|
|
|
2014-06-24 17:10:04 +09:00
|
|
|
/* Many callers got this wrong, so check for it for a while... */
|
|
|
|
if (!mtd->owner && caller_is_module()) {
|
|
|
|
pr_crit("%s called with NULL mtd->owner!\n", __func__);
|
|
|
|
BUG();
|
|
|
|
}
|
|
|
|
|
2011-01-06 10:48:18 +09:00
|
|
|
ret = nand_scan_ident(mtd, maxchips, NULL);
|
2007-10-31 21:53:06 +09:00
|
|
|
if (!ret)
|
|
|
|
ret = nand_scan_tail(mtd);
|
|
|
|
return ret;
|
2005-08-17 19:55:25 +09:00
|
|
|
}
|
2014-06-24 17:10:04 +09:00
|
|
|
EXPORT_SYMBOL(nand_scan);
|
2005-08-17 19:55:25 +09:00
|
|
|
|
2014-06-24 17:10:04 +09:00
|
|
|
#ifndef __UBOOT__
|
2005-08-17 19:55:25 +09:00
|
|
|
/**
|
2005-09-15 06:53:32 +09:00
|
|
|
* nand_release - [NAND Interface] Free resources held by the NAND device
|
2013-01-14 12:46:50 +09:00
|
|
|
* @mtd: MTD device structure
|
|
|
|
*/
|
2007-10-31 21:53:06 +09:00
|
|
|
void nand_release(struct mtd_info *mtd)
|
2005-08-17 19:55:25 +09:00
|
|
|
{
|
2007-10-31 21:53:06 +09:00
|
|
|
struct nand_chip *chip = mtd->priv;
|
2005-08-17 19:55:25 +09:00
|
|
|
|
2011-10-12 16:31:59 +09:00
|
|
|
if (chip->ecc.mode == NAND_ECC_SOFT_BCH)
|
|
|
|
nand_bch_free((struct nand_bch_control *)chip->ecc.priv);
|
|
|
|
|
2014-06-24 17:10:04 +09:00
|
|
|
mtd_device_unregister(mtd);
|
2007-10-31 21:53:06 +09:00
|
|
|
|
|
|
|
/* Free bad block table memory */
|
|
|
|
kfree(chip->bbt);
|
|
|
|
if (!(chip->options & NAND_OWN_BUFFERS))
|
|
|
|
kfree(chip->buffers);
|
2011-10-12 16:32:02 +09:00
|
|
|
|
|
|
|
/* Free bad block descriptor memory */
|
|
|
|
if (chip->badblock_pattern && chip->badblock_pattern->options
|
|
|
|
& NAND_BBT_DYNAMICSTRUCT)
|
|
|
|
kfree(chip->badblock_pattern);
|
2007-10-31 21:53:06 +09:00
|
|
|
}
|
2014-06-24 17:10:04 +09:00
|
|
|
EXPORT_SYMBOL_GPL(nand_release);
|
|
|
|
|
|
|
|
static int __init nand_base_init(void)
|
|
|
|
{
|
|
|
|
led_trigger_register_simple("nand-disk", &nand_led_trigger);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void __exit nand_base_exit(void)
|
|
|
|
{
|
|
|
|
led_trigger_unregister_simple(nand_led_trigger);
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
module_init(nand_base_init);
|
|
|
|
module_exit(nand_base_exit);
|
|
|
|
|
|
|
|
MODULE_LICENSE("GPL");
|
|
|
|
MODULE_AUTHOR("Steven J. Hill <sjhill@realitydiluted.com>");
|
|
|
|
MODULE_AUTHOR("Thomas Gleixner <tglx@linutronix.de>");
|
|
|
|
MODULE_DESCRIPTION("Generic NAND flash driver code");
|