2007-10-12 08:04:54 +00: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.
|
|
|
|
* Basic support for AG-AND chips is provided.
|
|
|
|
*
|
|
|
|
* Additional technical information is available on
|
2008-08-11 08:59:28 +00:00
|
|
|
* http://www.linux-mtd.infradead.org/doc/nand.html
|
2007-10-12 08:04:54 +00:00
|
|
|
*
|
|
|
|
* Copyright (C) 2000 Steven J. Hill (sjhill@realitydiluted.com)
|
2008-08-11 08:59:28 +00:00
|
|
|
* 2002-2006 Thomas Gleixner (tglx@linutronix.de)
|
2007-10-12 08:04:54 +00:00
|
|
|
*
|
2008-08-11 08:59:28 +00:00
|
|
|
* Credits:
|
2007-10-12 08:04:54 +00:00
|
|
|
* David Woodhouse for adding multichip support
|
|
|
|
*
|
|
|
|
* Aleph One Ltd. and Toby Churchill Ltd. for supporting the
|
|
|
|
* rework for 2K page size chips
|
|
|
|
*
|
2008-08-11 08:59:28 +00:00
|
|
|
* TODO:
|
2007-10-12 08:04:54 +00:00
|
|
|
* Enable cached programming for 2k page size chips
|
|
|
|
* Check, if mtd->ecctype should be set to MTD_ECC_HW
|
|
|
|
* if we have HW ecc support.
|
|
|
|
* The AG-AND chips have nice features for speed improvement,
|
|
|
|
* which are not supported yet. Read / program 4 pages in one go.
|
2008-08-11 08:59:28 +00:00
|
|
|
* BBT table is not serialized, has to be fixed
|
2007-10-12 08:04:54 +00: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.
|
|
|
|
*
|
|
|
|
*/
|
2013-01-26 12:36:48 +00:00
|
|
|
|
|
|
|
#define pr_fmt(fmt) "nand: " fmt
|
|
|
|
|
2007-10-12 08:04:54 +00:00
|
|
|
#include <common.h>
|
2008-08-11 08:59:28 +00:00
|
|
|
#include <errno.h>
|
|
|
|
#include <clock.h>
|
2007-10-12 08:04:54 +00:00
|
|
|
#include <linux/mtd/mtd.h>
|
|
|
|
#include <linux/mtd/nand.h>
|
2008-08-11 08:59:28 +00:00
|
|
|
#include <linux/err.h>
|
2007-10-12 08:04:54 +00:00
|
|
|
#include <linux/mtd/nand_ecc.h>
|
2009-07-01 12:28:05 +00:00
|
|
|
#include <asm/byteorder.h>
|
2011-09-22 17:02:57 +00:00
|
|
|
#include <io.h>
|
2008-08-11 08:59:28 +00:00
|
|
|
#include <malloc.h>
|
|
|
|
#include <module.h>
|
2007-10-12 08:04:54 +00:00
|
|
|
|
2011-04-04 09:23:25 +00:00
|
|
|
#include "nand.h"
|
|
|
|
|
2009-12-15 10:32:02 +00:00
|
|
|
#ifndef DOXYGEN_SHOULD_SKIP_THIS
|
|
|
|
|
2007-10-12 08:04:54 +00:00
|
|
|
/* Define default oob placement schemes for large and small page devices */
|
2008-08-11 08:59:28 +00:00
|
|
|
static struct nand_ecclayout nand_oob_8 = {
|
2007-10-12 08:04:54 +00:00
|
|
|
.eccbytes = 3,
|
|
|
|
.eccpos = {0, 1, 2},
|
2008-08-11 08:59:28 +00:00
|
|
|
.oobfree = {
|
|
|
|
{.offset = 3,
|
|
|
|
.length = 2},
|
|
|
|
{.offset = 6,
|
|
|
|
.length = 2}}
|
2007-10-12 08:04:54 +00:00
|
|
|
};
|
|
|
|
|
2008-08-11 08:59:28 +00:00
|
|
|
static struct nand_ecclayout nand_oob_16 = {
|
2007-10-12 08:04:54 +00:00
|
|
|
.eccbytes = 6,
|
|
|
|
.eccpos = {0, 1, 2, 3, 6, 7},
|
2008-08-11 08:59:28 +00:00
|
|
|
.oobfree = {
|
|
|
|
{.offset = 8,
|
|
|
|
. length = 8}}
|
2007-10-12 08:04:54 +00:00
|
|
|
};
|
|
|
|
|
2008-08-11 08:59:28 +00:00
|
|
|
static struct nand_ecclayout nand_oob_64 = {
|
2007-10-12 08:04:54 +00:00
|
|
|
.eccbytes = 24,
|
|
|
|
.eccpos = {
|
2008-08-11 08:59:28 +00: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,
|
|
|
|
.length = 38}}
|
2007-10-12 08:04:54 +00:00
|
|
|
};
|
|
|
|
|
2008-08-11 08:59:28 +00:00
|
|
|
#define DEFINE_LED_TRIGGER(x)
|
|
|
|
#define DEFINE_LED_TRIGGER_GLOBAL(x)
|
|
|
|
#define led_trigger_register_simple(x, y) do {} while(0)
|
|
|
|
#define led_trigger_unregister_simple(x) do {} while(0)
|
|
|
|
#define led_trigger_event(x, y) do {} while(0)
|
2007-10-12 08:04:54 +00:00
|
|
|
|
|
|
|
/*
|
2008-08-11 08:59:28 +00:00
|
|
|
* For devices which display every fart in the system on a separate LED. Is
|
|
|
|
* compiled away when LED support is disabled.
|
2007-10-12 08:04:54 +00:00
|
|
|
*/
|
2008-08-11 08:59:28 +00:00
|
|
|
DEFINE_LED_TRIGGER(nand_led_trigger);
|
2007-10-12 08:04:54 +00:00
|
|
|
|
|
|
|
/**
|
2008-08-11 08:59:28 +00:00
|
|
|
* nand_read_byte - [DEFAULT] read one byte from the chip
|
|
|
|
* @mtd: MTD device structure
|
2007-10-12 08:04:54 +00:00
|
|
|
*
|
2008-08-11 08:59:28 +00:00
|
|
|
* Default read function for 8bit buswith
|
2007-10-12 08:04:54 +00:00
|
|
|
*/
|
2008-08-11 08:59:28 +00:00
|
|
|
static uint8_t nand_read_byte(struct mtd_info *mtd)
|
2007-10-12 08:04:54 +00:00
|
|
|
{
|
2008-08-11 08:59:28 +00:00
|
|
|
struct nand_chip *chip = mtd->priv;
|
|
|
|
return readb(chip->IO_ADDR_R);
|
2007-10-12 08:04:54 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* nand_read_byte16 - [DEFAULT] read one byte endianess aware from the chip
|
2008-08-11 08:59:28 +00:00
|
|
|
* @mtd: MTD device structure
|
2007-10-12 08:04:54 +00:00
|
|
|
*
|
|
|
|
* Default read function for 16bit buswith with
|
|
|
|
* endianess conversion
|
|
|
|
*/
|
2008-08-11 08:59:28 +00:00
|
|
|
static uint8_t nand_read_byte16(struct mtd_info *mtd)
|
2007-10-12 08:04:54 +00:00
|
|
|
{
|
2008-08-11 08:59:28 +00:00
|
|
|
struct nand_chip *chip = mtd->priv;
|
|
|
|
return (uint8_t) cpu_to_le16(readw(chip->IO_ADDR_R));
|
2007-10-12 08:04:54 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* nand_read_word - [DEFAULT] read one word from the chip
|
2008-08-11 08:59:28 +00:00
|
|
|
* @mtd: MTD device structure
|
2007-10-12 08:04:54 +00:00
|
|
|
*
|
|
|
|
* Default read function for 16bit buswith without
|
|
|
|
* endianess conversion
|
|
|
|
*/
|
2008-08-11 08:59:28 +00:00
|
|
|
static u16 nand_read_word(struct mtd_info *mtd)
|
2007-10-12 08:04:54 +00:00
|
|
|
{
|
2008-08-11 08:59:28 +00:00
|
|
|
struct nand_chip *chip = mtd->priv;
|
|
|
|
return readw(chip->IO_ADDR_R);
|
2007-10-12 08:04:54 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* nand_select_chip - [DEFAULT] control CE line
|
2008-08-11 08:59:28 +00:00
|
|
|
* @mtd: MTD device structure
|
|
|
|
* @chipnr: chipnumber to select, -1 for deselect
|
2007-10-12 08:04:54 +00:00
|
|
|
*
|
|
|
|
* Default select function for 1 chip devices.
|
|
|
|
*/
|
2008-08-11 08:59:28 +00:00
|
|
|
static void nand_select_chip(struct mtd_info *mtd, int chipnr)
|
2007-10-12 08:04:54 +00:00
|
|
|
{
|
2008-08-11 08:59:28 +00:00
|
|
|
struct nand_chip *chip = mtd->priv;
|
|
|
|
|
|
|
|
switch (chipnr) {
|
2007-10-12 08:04:54 +00:00
|
|
|
case -1:
|
2008-08-11 08:59:28 +00:00
|
|
|
chip->cmd_ctrl(mtd, NAND_CMD_NONE, 0 | NAND_CTRL_CHANGE);
|
2007-10-12 08:04:54 +00:00
|
|
|
break;
|
|
|
|
case 0:
|
|
|
|
break;
|
|
|
|
default:
|
2011-01-07 05:13:00 +00:00
|
|
|
printf("%s: illegal chip number %d\n", __func__, chipnr);
|
2007-10-12 08:04:54 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* nand_read_buf - [DEFAULT] read chip data into buffer
|
2008-08-11 08:59:28 +00:00
|
|
|
* @mtd: MTD device structure
|
|
|
|
* @buf: buffer to store date
|
|
|
|
* @len: number of bytes to read
|
2007-10-12 08:04:54 +00:00
|
|
|
*
|
|
|
|
* Default read function for 8bit buswith
|
|
|
|
*/
|
2008-08-11 08:59:28 +00:00
|
|
|
static void nand_read_buf(struct mtd_info *mtd, uint8_t *buf, int len)
|
2007-10-12 08:04:54 +00:00
|
|
|
{
|
|
|
|
int i;
|
2008-08-11 08:59:28 +00:00
|
|
|
struct nand_chip *chip = mtd->priv;
|
2007-10-12 08:04:54 +00:00
|
|
|
|
2008-08-11 08:59:28 +00:00
|
|
|
for (i = 0; i < len; i++)
|
|
|
|
buf[i] = readb(chip->IO_ADDR_R);
|
2007-10-12 08:04:54 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* nand_verify_buf - [DEFAULT] Verify chip data against buffer
|
2008-08-11 08:59:28 +00:00
|
|
|
* @mtd: MTD device structure
|
|
|
|
* @buf: buffer containing the data to compare
|
|
|
|
* @len: number of bytes to compare
|
2007-10-12 08:04:54 +00:00
|
|
|
*
|
|
|
|
* Default verify function for 8bit buswith
|
|
|
|
*/
|
2008-08-11 08:59:28 +00:00
|
|
|
static int nand_verify_buf(struct mtd_info *mtd, const uint8_t *buf, int len)
|
2007-10-12 08:04:54 +00:00
|
|
|
{
|
|
|
|
int i;
|
2008-08-11 08:59:28 +00:00
|
|
|
struct nand_chip *chip = mtd->priv;
|
2007-10-12 08:04:54 +00:00
|
|
|
|
2008-08-11 08:59:28 +00:00
|
|
|
for (i = 0; i < len; i++)
|
|
|
|
if (buf[i] != readb(chip->IO_ADDR_R))
|
2007-10-12 08:04:54 +00:00
|
|
|
return -EFAULT;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* nand_read_buf16 - [DEFAULT] read chip data into buffer
|
2008-08-11 08:59:28 +00:00
|
|
|
* @mtd: MTD device structure
|
|
|
|
* @buf: buffer to store date
|
|
|
|
* @len: number of bytes to read
|
2007-10-12 08:04:54 +00:00
|
|
|
*
|
|
|
|
* Default read function for 16bit buswith
|
|
|
|
*/
|
2008-08-11 08:59:28 +00:00
|
|
|
static void nand_read_buf16(struct mtd_info *mtd, uint8_t *buf, int len)
|
2007-10-12 08:04:54 +00:00
|
|
|
{
|
|
|
|
int i;
|
2008-08-11 08:59:28 +00:00
|
|
|
struct nand_chip *chip = mtd->priv;
|
2007-10-12 08:04:54 +00:00
|
|
|
u16 *p = (u16 *) buf;
|
|
|
|
len >>= 1;
|
|
|
|
|
2008-08-11 08:59:28 +00:00
|
|
|
for (i = 0; i < len; i++)
|
|
|
|
p[i] = readw(chip->IO_ADDR_R);
|
2007-10-12 08:04:54 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* nand_verify_buf16 - [DEFAULT] Verify chip data against buffer
|
2008-08-11 08:59:28 +00:00
|
|
|
* @mtd: MTD device structure
|
|
|
|
* @buf: buffer containing the data to compare
|
|
|
|
* @len: number of bytes to compare
|
2007-10-12 08:04:54 +00:00
|
|
|
*
|
|
|
|
* Default verify function for 16bit buswith
|
|
|
|
*/
|
2008-08-11 08:59:28 +00:00
|
|
|
static int nand_verify_buf16(struct mtd_info *mtd, const uint8_t *buf, int len)
|
2007-10-12 08:04:54 +00:00
|
|
|
{
|
|
|
|
int i;
|
2008-08-11 08:59:28 +00:00
|
|
|
struct nand_chip *chip = mtd->priv;
|
2007-10-12 08:04:54 +00:00
|
|
|
u16 *p = (u16 *) buf;
|
|
|
|
len >>= 1;
|
|
|
|
|
2008-08-11 08:59:28 +00:00
|
|
|
for (i = 0; i < len; i++)
|
|
|
|
if (p[i] != readw(chip->IO_ADDR_R))
|
2007-10-12 08:04:54 +00:00
|
|
|
return -EFAULT;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* nand_block_bad - [DEFAULT] Read bad block marker from the chip
|
2008-08-11 08:59:28 +00:00
|
|
|
* @mtd: MTD device structure
|
|
|
|
* @ofs: offset from device start
|
|
|
|
* @getchip: 0, if the chip is already selected
|
2007-10-12 08:04:54 +00:00
|
|
|
*
|
|
|
|
* Check, if the block is bad.
|
|
|
|
*/
|
2008-08-11 08:59:28 +00:00
|
|
|
static int nand_block_bad(struct mtd_info *mtd, loff_t ofs, int getchip)
|
2007-10-12 08:04:54 +00:00
|
|
|
{
|
|
|
|
int page, chipnr, res = 0;
|
2008-08-11 08:59:28 +00:00
|
|
|
struct nand_chip *chip = mtd->priv;
|
2007-10-12 08:04:54 +00:00
|
|
|
u16 bad;
|
|
|
|
|
2008-08-11 08:59:28 +00:00
|
|
|
page = (int)(ofs >> chip->page_shift) & chip->pagemask;
|
|
|
|
|
2007-10-12 08:04:54 +00:00
|
|
|
if (getchip) {
|
2008-08-11 08:59:28 +00:00
|
|
|
chipnr = (int)(ofs >> chip->chip_shift);
|
|
|
|
|
2007-10-12 08:04:54 +00:00
|
|
|
/* Select the NAND device */
|
2008-08-11 08:59:28 +00:00
|
|
|
chip->select_chip(mtd, chipnr);
|
|
|
|
}
|
2007-10-12 08:04:54 +00:00
|
|
|
|
2008-08-11 08:59:28 +00:00
|
|
|
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;
|
2007-10-12 08:04:54 +00:00
|
|
|
if ((bad & 0xFF) != 0xff)
|
|
|
|
res = 1;
|
|
|
|
} else {
|
2008-08-11 08:59:28 +00:00
|
|
|
chip->cmdfunc(mtd, NAND_CMD_READOOB, chip->badblockpos, page);
|
|
|
|
if (chip->read_byte(mtd) != 0xff)
|
2007-10-12 08:04:54 +00:00
|
|
|
res = 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* nand_block_checkbad - [GENERIC] Check if a block is marked bad
|
2008-08-11 08:59:28 +00: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
|
2007-10-12 08:04:54 +00:00
|
|
|
*
|
|
|
|
* Check, if the block is bad. Either by reading the bad block table or
|
|
|
|
* calling of the scan function.
|
|
|
|
*/
|
2011-04-04 09:24:14 +00:00
|
|
|
int nand_block_checkbad(struct mtd_info *mtd, loff_t ofs, int getchip,
|
2008-08-11 08:59:28 +00:00
|
|
|
int allowbbt)
|
2007-10-12 08:04:54 +00:00
|
|
|
{
|
2008-08-11 08:59:28 +00:00
|
|
|
struct nand_chip *chip = mtd->priv;
|
|
|
|
|
2011-04-04 12:16:42 +00:00
|
|
|
#ifdef CONFIG_NAND_BBT
|
2008-08-11 08:59:28 +00:00
|
|
|
if (!chip->bbt)
|
|
|
|
return chip->block_bad(mtd, ofs, getchip);
|
2007-10-12 08:04:54 +00:00
|
|
|
/* Return info from the table */
|
2008-08-11 08:59:28 +00:00
|
|
|
return nand_isbad_bbt(mtd, ofs, allowbbt);
|
2011-04-04 12:16:42 +00:00
|
|
|
#else
|
|
|
|
return chip->block_bad(mtd, ofs, getchip);
|
|
|
|
#endif
|
2008-08-11 08:59:28 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Wait for the ready pin, after a command
|
|
|
|
* The timeout is catched later.
|
|
|
|
*/
|
|
|
|
void nand_wait_ready(struct mtd_info *mtd)
|
|
|
|
{
|
|
|
|
struct nand_chip *chip = mtd->priv;
|
|
|
|
uint64_t start = get_time_ns();
|
|
|
|
|
|
|
|
led_trigger_event(nand_led_trigger, LED_FULL);
|
|
|
|
/* wait until command is processed or timeout occures */
|
|
|
|
do {
|
|
|
|
if (chip->dev_ready(mtd))
|
|
|
|
break;
|
|
|
|
} while (!is_timeout(start, SECOND * 2));
|
|
|
|
led_trigger_event(nand_led_trigger, LED_OFF);
|
2007-10-12 08:04:54 +00:00
|
|
|
}
|
2008-08-11 08:59:28 +00:00
|
|
|
EXPORT_SYMBOL(nand_wait_ready);
|
2007-10-12 08:04:54 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* nand_command - [DEFAULT] Send command to NAND device
|
2008-08-11 08:59:28 +00: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
|
2007-10-12 08:04:54 +00:00
|
|
|
*
|
|
|
|
* Send command to NAND device. This function is used for small page
|
|
|
|
* devices (256/512 Bytes per page)
|
|
|
|
*/
|
2008-08-11 08:59:28 +00:00
|
|
|
static void nand_command(struct mtd_info *mtd, unsigned int command,
|
|
|
|
int column, int page_addr)
|
2007-10-12 08:04:54 +00:00
|
|
|
{
|
2008-08-11 08:59:28 +00:00
|
|
|
register struct nand_chip *chip = mtd->priv;
|
|
|
|
int ctrl = NAND_CTRL_CLE | NAND_CTRL_CHANGE;
|
|
|
|
|
2007-10-12 08:04:54 +00:00
|
|
|
/*
|
|
|
|
* Write out the command to the device.
|
|
|
|
*/
|
|
|
|
if (command == NAND_CMD_SEQIN) {
|
|
|
|
int readcmd;
|
|
|
|
|
2008-08-11 08:59:28 +00:00
|
|
|
if (column >= mtd->writesize) {
|
2007-10-12 08:04:54 +00:00
|
|
|
/* OOB area */
|
2008-08-11 08:59:28 +00:00
|
|
|
column -= mtd->writesize;
|
2007-10-12 08:04:54 +00:00
|
|
|
readcmd = NAND_CMD_READOOB;
|
|
|
|
} else if (column < 256) {
|
|
|
|
/* First 256 bytes --> READ0 */
|
|
|
|
readcmd = NAND_CMD_READ0;
|
|
|
|
} else {
|
|
|
|
column -= 256;
|
|
|
|
readcmd = NAND_CMD_READ1;
|
|
|
|
}
|
2008-08-11 08:59:28 +00:00
|
|
|
chip->cmd_ctrl(mtd, readcmd, ctrl);
|
|
|
|
ctrl &= ~NAND_CTRL_CHANGE;
|
2007-10-12 08:04:54 +00:00
|
|
|
}
|
2008-08-11 08:59:28 +00:00
|
|
|
chip->cmd_ctrl(mtd, command, ctrl);
|
2007-10-12 08:04:54 +00:00
|
|
|
|
2008-08-11 08:59:28 +00:00
|
|
|
/*
|
|
|
|
* Address cycle, when necessary
|
|
|
|
*/
|
|
|
|
ctrl = NAND_CTRL_ALE | NAND_CTRL_CHANGE;
|
|
|
|
/* Serially input address */
|
|
|
|
if (column != -1) {
|
|
|
|
/* Adjust columns for 16 bit buswidth */
|
|
|
|
if (chip->options & NAND_BUSWIDTH_16)
|
|
|
|
column >>= 1;
|
|
|
|
chip->cmd_ctrl(mtd, column, ctrl);
|
|
|
|
ctrl &= ~NAND_CTRL_CHANGE;
|
|
|
|
}
|
|
|
|
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);
|
2007-10-12 08:04:54 +00:00
|
|
|
}
|
2008-08-11 08:59:28 +00:00
|
|
|
chip->cmd_ctrl(mtd, NAND_CMD_NONE, NAND_NCE | NAND_CTRL_CHANGE);
|
2007-10-12 08:04:54 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* program and erase have their own busy handlers
|
|
|
|
* status and sequential in needs no delay
|
2008-08-11 08:59:28 +00:00
|
|
|
*/
|
2007-10-12 08:04:54 +00:00
|
|
|
switch (command) {
|
|
|
|
|
|
|
|
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:
|
2008-08-11 08:59:28 +00:00
|
|
|
if (chip->dev_ready)
|
2007-10-12 08:04:54 +00:00
|
|
|
break;
|
2008-08-11 08:59:28 +00: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);
|
|
|
|
while (!(chip->read_byte(mtd) & NAND_STATUS_READY)) ;
|
2007-10-12 08:04:54 +00:00
|
|
|
return;
|
|
|
|
|
2008-08-11 08:59:28 +00:00
|
|
|
/* This applies to read commands */
|
2007-10-12 08:04:54 +00:00
|
|
|
default:
|
|
|
|
/*
|
|
|
|
* If we don't have access to the busy pin, we apply the given
|
|
|
|
* command delay
|
2008-08-11 08:59:28 +00:00
|
|
|
*/
|
|
|
|
if (!chip->dev_ready) {
|
|
|
|
udelay(chip->chip_delay);
|
2007-10-12 08:04:54 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
/* Apply this short delay always to ensure that we do wait tWB in
|
|
|
|
* any case on any machine. */
|
2008-08-11 08:59:28 +00:00
|
|
|
ndelay(100);
|
|
|
|
|
|
|
|
nand_wait_ready(mtd);
|
2007-10-12 08:04:54 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* nand_command_lp - [DEFAULT] Send command to NAND large page device
|
2008-08-11 08:59:28 +00: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
|
2007-10-12 08:04:54 +00:00
|
|
|
*
|
2008-08-11 08:59:28 +00:00
|
|
|
* Send command to NAND device. This is the version for the new large page
|
|
|
|
* devices We dont have the separate regions as we have in the small page
|
|
|
|
* devices. We must emulate NAND_CMD_READOOB to keep the code compatible.
|
2007-10-12 08:04:54 +00:00
|
|
|
*/
|
2008-08-11 08:59:28 +00:00
|
|
|
static void nand_command_lp(struct mtd_info *mtd, unsigned int command,
|
|
|
|
int column, int page_addr)
|
2007-10-12 08:04:54 +00:00
|
|
|
{
|
2008-08-11 08:59:28 +00:00
|
|
|
register struct nand_chip *chip = mtd->priv;
|
|
|
|
|
2007-10-12 08:04:54 +00:00
|
|
|
/* Emulate NAND_CMD_READOOB */
|
|
|
|
if (command == NAND_CMD_READOOB) {
|
2008-08-11 08:59:28 +00:00
|
|
|
column += mtd->writesize;
|
2007-10-12 08:04:54 +00:00
|
|
|
command = NAND_CMD_READ0;
|
|
|
|
}
|
|
|
|
|
2008-08-11 08:59:28 +00:00
|
|
|
/* Command latch cycle */
|
|
|
|
chip->cmd_ctrl(mtd, command & 0xff,
|
|
|
|
NAND_NCE | NAND_CLE | NAND_CTRL_CHANGE);
|
2007-10-12 08:04:54 +00:00
|
|
|
|
|
|
|
if (column != -1 || page_addr != -1) {
|
2008-08-11 08:59:28 +00:00
|
|
|
int ctrl = NAND_CTRL_CHANGE | NAND_NCE | NAND_ALE;
|
2007-10-12 08:04:54 +00:00
|
|
|
|
|
|
|
/* Serially input address */
|
|
|
|
if (column != -1) {
|
|
|
|
/* Adjust columns for 16 bit buswidth */
|
2008-08-11 08:59:28 +00:00
|
|
|
if (chip->options & NAND_BUSWIDTH_16)
|
2007-10-12 08:04:54 +00:00
|
|
|
column >>= 1;
|
2008-08-11 08:59:28 +00:00
|
|
|
chip->cmd_ctrl(mtd, column, ctrl);
|
|
|
|
ctrl &= ~NAND_CTRL_CHANGE;
|
|
|
|
chip->cmd_ctrl(mtd, column >> 8, ctrl);
|
2007-10-12 08:04:54 +00:00
|
|
|
}
|
|
|
|
if (page_addr != -1) {
|
2008-08-11 08:59:28 +00:00
|
|
|
chip->cmd_ctrl(mtd, page_addr, ctrl);
|
|
|
|
chip->cmd_ctrl(mtd, page_addr >> 8,
|
|
|
|
NAND_NCE | NAND_ALE);
|
2007-10-12 08:04:54 +00:00
|
|
|
/* One more address cycle for devices > 128MiB */
|
2008-08-11 08:59:28 +00:00
|
|
|
if (chip->chipsize > (128 << 20))
|
|
|
|
chip->cmd_ctrl(mtd, page_addr >> 16,
|
|
|
|
NAND_NCE | NAND_ALE);
|
2007-10-12 08:04:54 +00:00
|
|
|
}
|
|
|
|
}
|
2008-08-11 08:59:28 +00:00
|
|
|
chip->cmd_ctrl(mtd, NAND_CMD_NONE, NAND_NCE | NAND_CTRL_CHANGE);
|
2007-10-12 08:04:54 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* program and erase have their own busy handlers
|
2008-08-11 08:59:28 +00:00
|
|
|
* status, sequential in, and deplete1 need no delay
|
|
|
|
*/
|
2007-10-12 08:04:54 +00:00
|
|
|
switch (command) {
|
|
|
|
|
|
|
|
case NAND_CMD_CACHEDPROG:
|
|
|
|
case NAND_CMD_PAGEPROG:
|
|
|
|
case NAND_CMD_ERASE1:
|
|
|
|
case NAND_CMD_ERASE2:
|
|
|
|
case NAND_CMD_SEQIN:
|
2008-08-11 08:59:28 +00:00
|
|
|
case NAND_CMD_RNDIN:
|
2007-10-12 08:04:54 +00:00
|
|
|
case NAND_CMD_STATUS:
|
2008-08-11 08:59:28 +00:00
|
|
|
case NAND_CMD_DEPLETE1:
|
2007-10-12 08:04:54 +00:00
|
|
|
return;
|
|
|
|
|
2008-08-11 08:59:28 +00:00
|
|
|
/*
|
|
|
|
* read error status commands require only a short delay
|
|
|
|
*/
|
|
|
|
case NAND_CMD_STATUS_ERROR:
|
|
|
|
case NAND_CMD_STATUS_ERROR0:
|
|
|
|
case NAND_CMD_STATUS_ERROR1:
|
|
|
|
case NAND_CMD_STATUS_ERROR2:
|
|
|
|
case NAND_CMD_STATUS_ERROR3:
|
|
|
|
udelay(chip->chip_delay);
|
|
|
|
return;
|
2007-10-12 08:04:54 +00:00
|
|
|
|
|
|
|
case NAND_CMD_RESET:
|
2008-08-11 08:59:28 +00:00
|
|
|
if (chip->dev_ready)
|
2007-10-12 08:04:54 +00:00
|
|
|
break;
|
2008-08-11 08:59:28 +00: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);
|
|
|
|
while (!(chip->read_byte(mtd) & NAND_STATUS_READY)) ;
|
|
|
|
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);
|
2007-10-12 08:04:54 +00:00
|
|
|
return;
|
|
|
|
|
|
|
|
case NAND_CMD_READ0:
|
2008-08-11 08:59:28 +00: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 */
|
2007-10-12 08:04:54 +00:00
|
|
|
default:
|
|
|
|
/*
|
|
|
|
* If we don't have access to the busy pin, we apply the given
|
|
|
|
* command delay
|
2008-08-11 08:59:28 +00:00
|
|
|
*/
|
|
|
|
if (!chip->dev_ready) {
|
|
|
|
udelay(chip->chip_delay);
|
2007-10-12 08:04:54 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Apply this short delay always to ensure that we do wait tWB in
|
|
|
|
* any case on any machine. */
|
2008-08-11 08:59:28 +00:00
|
|
|
ndelay(100);
|
|
|
|
|
|
|
|
nand_wait_ready(mtd);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* nand_wait - [DEFAULT] wait until the command is done
|
|
|
|
* @mtd: MTD device structure
|
|
|
|
* @chip: NAND chip structure
|
|
|
|
*
|
|
|
|
* 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
|
|
|
|
*/
|
|
|
|
static int nand_wait(struct mtd_info *mtd, struct nand_chip *chip)
|
2007-10-12 08:04:54 +00:00
|
|
|
{
|
2008-08-11 08:59:28 +00:00
|
|
|
|
|
|
|
uint64_t start = get_time_ns();
|
|
|
|
uint64_t timeo;
|
|
|
|
int status, state = chip->state;
|
2007-10-12 08:04:54 +00:00
|
|
|
|
|
|
|
if (state == FL_ERASING)
|
2008-08-11 08:59:28 +00:00
|
|
|
timeo = 400 * MSECOND;
|
2007-10-12 08:04:54 +00:00
|
|
|
else
|
2007-10-15 15:16:25 +00:00
|
|
|
timeo = 20 * MSECOND;
|
2007-10-12 08:04:54 +00:00
|
|
|
|
2008-08-11 08:59:28 +00:00
|
|
|
led_trigger_event(nand_led_trigger, LED_FULL);
|
2007-10-12 08:04:54 +00:00
|
|
|
|
2008-08-11 08:59:28 +00:00
|
|
|
/* Apply this short delay always to ensure that we do wait tWB in
|
|
|
|
* any case on any machine. */
|
|
|
|
ndelay(100);
|
2007-10-12 08:04:54 +00:00
|
|
|
|
2008-08-11 08:59:28 +00:00
|
|
|
if ((state == FL_ERASING) && (chip->options & NAND_IS_AND))
|
|
|
|
chip->cmdfunc(mtd, NAND_CMD_STATUS_MULTI, -1, -1);
|
|
|
|
else
|
|
|
|
chip->cmdfunc(mtd, NAND_CMD_STATUS, -1, -1);
|
2007-10-12 08:04:54 +00:00
|
|
|
|
2008-08-11 08:59:28 +00:00
|
|
|
while (!is_timeout(start, timeo)) {
|
|
|
|
if (chip->dev_ready) {
|
|
|
|
if (chip->dev_ready(mtd))
|
2007-10-12 08:04:54 +00:00
|
|
|
break;
|
|
|
|
} else {
|
2008-08-11 08:59:28 +00:00
|
|
|
if (chip->read_byte(mtd) & NAND_STATUS_READY)
|
2007-10-12 08:04:54 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2008-08-11 08:59:28 +00:00
|
|
|
led_trigger_event(nand_led_trigger, LED_OFF);
|
2007-10-12 08:04:54 +00:00
|
|
|
|
2008-08-11 08:59:28 +00:00
|
|
|
status = (int)chip->read_byte(mtd);
|
|
|
|
return status;
|
2007-10-12 08:04:54 +00:00
|
|
|
}
|
2007-10-19 23:13:46 +00:00
|
|
|
|
2008-08-11 08:59:28 +00: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
|
|
|
|
*/
|
|
|
|
static int nand_read_page_raw(struct mtd_info *mtd, struct nand_chip *chip,
|
|
|
|
uint8_t *buf)
|
|
|
|
{
|
|
|
|
chip->read_buf(mtd, buf, mtd->writesize);
|
|
|
|
chip->read_buf(mtd, chip->oob_poi, mtd->oobsize);
|
|
|
|
return 0;
|
|
|
|
}
|
2007-10-12 08:04:54 +00:00
|
|
|
|
2008-08-11 08:59:28 +00:00
|
|
|
/**
|
|
|
|
* nand_transfer_oob - [Internal] Transfer oob to client buffer
|
|
|
|
* @chip: nand chip structure
|
|
|
|
* @oob: oob destination address
|
|
|
|
* @ops: oob ops structure
|
|
|
|
* @len: size of oob to transfer
|
|
|
|
*/
|
2011-04-07 15:59:52 +00:00
|
|
|
#ifdef CONFIG_NAND_READ_OOB
|
2008-08-11 08:59:28 +00:00
|
|
|
static uint8_t *nand_transfer_oob(struct nand_chip *chip, uint8_t *oob,
|
|
|
|
struct mtd_oob_ops *ops, size_t len)
|
|
|
|
{
|
|
|
|
switch(ops->mode) {
|
|
|
|
|
|
|
|
case MTD_OOB_PLACE:
|
|
|
|
case MTD_OOB_RAW:
|
|
|
|
memcpy(oob, chip->oob_poi + ops->ooboffs, len);
|
|
|
|
return oob + len;
|
|
|
|
|
|
|
|
case MTD_OOB_AUTO: {
|
|
|
|
struct nand_oobfree *free = chip->ecc.layout->oobfree;
|
|
|
|
uint32_t boffs = 0, roffs = ops->ooboffs;
|
|
|
|
size_t bytes = 0;
|
|
|
|
|
|
|
|
for(; free->length && len; free++, len -= bytes) {
|
|
|
|
/* Read request not from offset 0 ? */
|
|
|
|
if (unlikely(roffs)) {
|
|
|
|
if (roffs >= free->length) {
|
|
|
|
roffs -= free->length;
|
|
|
|
continue;
|
2007-10-12 08:04:54 +00:00
|
|
|
}
|
2008-08-11 08:59:28 +00:00
|
|
|
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;
|
2007-10-12 08:04:54 +00:00
|
|
|
}
|
2008-08-11 08:59:28 +00:00
|
|
|
memcpy(oob, chip->oob_poi + boffs, bytes);
|
|
|
|
oob += bytes;
|
2007-10-12 08:04:54 +00:00
|
|
|
}
|
2008-08-11 08:59:28 +00:00
|
|
|
return oob;
|
|
|
|
}
|
|
|
|
default:
|
|
|
|
BUG();
|
|
|
|
}
|
|
|
|
return NULL;
|
|
|
|
}
|
2011-04-07 15:59:52 +00:00
|
|
|
#endif
|
2007-10-12 08:04:54 +00:00
|
|
|
|
2008-08-11 08:59:28 +00:00
|
|
|
/**
|
|
|
|
* nand_do_read_ops - [Internal] Read data with ECC
|
|
|
|
*
|
|
|
|
* @mtd: MTD device structure
|
|
|
|
* @from: offset to read from
|
|
|
|
* @ops: oob ops structure
|
|
|
|
*
|
|
|
|
* Internal function. Called with chip held.
|
|
|
|
*/
|
|
|
|
static int nand_do_read_ops(struct mtd_info *mtd, loff_t from,
|
|
|
|
struct mtd_oob_ops *ops)
|
|
|
|
{
|
|
|
|
int chipnr, page, realpage, col, bytes, aligned;
|
|
|
|
struct nand_chip *chip = mtd->priv;
|
|
|
|
struct mtd_ecc_stats stats;
|
|
|
|
int blkcheck = (1 << (chip->phys_erase_shift - chip->page_shift)) - 1;
|
|
|
|
int sndcmd = 1;
|
|
|
|
int ret = 0;
|
|
|
|
uint32_t readlen = ops->len;
|
|
|
|
uint32_t oobreadlen = ops->ooblen;
|
|
|
|
uint8_t *bufpoi, *oob, *buf;
|
2007-10-12 08:04:54 +00:00
|
|
|
|
2008-08-11 08:59:28 +00:00
|
|
|
stats = mtd->ecc_stats;
|
2007-10-12 08:04:54 +00:00
|
|
|
|
2008-08-11 08:59:28 +00:00
|
|
|
chipnr = (int)(from >> chip->chip_shift);
|
|
|
|
chip->select_chip(mtd, chipnr);
|
2007-10-12 08:04:54 +00:00
|
|
|
|
2008-08-11 08:59:28 +00:00
|
|
|
realpage = (int)(from >> chip->page_shift);
|
|
|
|
page = realpage & chip->pagemask;
|
2007-10-12 08:04:54 +00:00
|
|
|
|
2008-08-11 08:59:28 +00:00
|
|
|
col = (int)(from & (mtd->writesize - 1));
|
2007-10-12 08:04:54 +00:00
|
|
|
|
2008-08-11 08:59:28 +00:00
|
|
|
buf = ops->datbuf;
|
|
|
|
oob = ops->oobbuf;
|
|
|
|
|
|
|
|
while(1) {
|
|
|
|
bytes = min(mtd->writesize - col, readlen);
|
|
|
|
aligned = (bytes == mtd->writesize);
|
2007-10-12 08:04:54 +00:00
|
|
|
|
2008-08-11 08:59:28 +00:00
|
|
|
/* Is the current page in the buffer ? */
|
|
|
|
if (realpage != chip->pagebuf || oob) {
|
|
|
|
bufpoi = aligned ? buf : chip->buffers->databuf;
|
|
|
|
|
|
|
|
if (likely(sndcmd)) {
|
|
|
|
chip->cmdfunc(mtd, NAND_CMD_READ0, 0x00, page);
|
|
|
|
sndcmd = 0;
|
2007-10-12 08:04:54 +00:00
|
|
|
}
|
|
|
|
|
2008-08-11 08:59:28 +00:00
|
|
|
/* Now read the page into the buffer */
|
|
|
|
if (unlikely(ops->mode == MTD_OOB_RAW))
|
|
|
|
ret = chip->ecc.read_page_raw(mtd, chip, bufpoi);
|
|
|
|
else
|
|
|
|
ret = chip->ecc.read_page(mtd, chip, bufpoi);
|
|
|
|
if (ret < 0)
|
2007-10-12 08:04:54 +00:00
|
|
|
break;
|
2008-08-11 08:59:28 +00:00
|
|
|
|
|
|
|
/* Transfer not aligned data */
|
|
|
|
if (!aligned) {
|
|
|
|
chip->pagebuf = realpage;
|
|
|
|
memcpy(buf, chip->buffers->databuf + col, bytes);
|
|
|
|
}
|
|
|
|
|
|
|
|
buf += bytes;
|
|
|
|
|
2011-04-07 15:59:52 +00:00
|
|
|
#ifdef CONFIG_NAND_READ_OOB
|
2008-08-11 08:59:28 +00:00
|
|
|
if (unlikely(oob)) {
|
|
|
|
/* Raw mode does data:oob:data:oob */
|
|
|
|
if (ops->mode != MTD_OOB_RAW) {
|
|
|
|
int toread = min(oobreadlen,
|
|
|
|
chip->ecc.layout->oobavail);
|
|
|
|
if (toread) {
|
|
|
|
oob = nand_transfer_oob(chip,
|
|
|
|
oob, ops, toread);
|
|
|
|
oobreadlen -= toread;
|
|
|
|
}
|
|
|
|
} else
|
|
|
|
buf = nand_transfer_oob(chip,
|
|
|
|
buf, ops, mtd->oobsize);
|
|
|
|
}
|
2011-04-07 15:59:52 +00:00
|
|
|
#endif
|
2008-08-11 08:59:28 +00:00
|
|
|
if (!(chip->options & NAND_NO_READRDY)) {
|
|
|
|
/*
|
|
|
|
* Apply delay or wait for ready/busy pin. Do
|
|
|
|
* this before the AUTOINCR check, so no
|
|
|
|
* problems arise if a chip which does auto
|
|
|
|
* increment is marked as NOAUTOINCR by the
|
|
|
|
* board driver.
|
|
|
|
*/
|
|
|
|
if (!chip->dev_ready)
|
|
|
|
udelay(chip->chip_delay);
|
|
|
|
else
|
|
|
|
nand_wait_ready(mtd);
|
2007-10-12 08:04:54 +00:00
|
|
|
}
|
2008-08-11 08:59:28 +00:00
|
|
|
} else {
|
|
|
|
memcpy(buf, chip->buffers->databuf + col, bytes);
|
|
|
|
buf += bytes;
|
2007-10-12 08:04:54 +00:00
|
|
|
}
|
|
|
|
|
2008-08-11 08:59:28 +00:00
|
|
|
readlen -= bytes;
|
|
|
|
|
|
|
|
if (!readlen)
|
2007-10-12 08:04:54 +00:00
|
|
|
break;
|
|
|
|
|
|
|
|
/* For subsequent reads align to page boundary. */
|
|
|
|
col = 0;
|
|
|
|
/* Increment page address */
|
|
|
|
realpage++;
|
|
|
|
|
2008-08-11 08:59:28 +00:00
|
|
|
page = realpage & chip->pagemask;
|
2007-10-12 08:04:54 +00:00
|
|
|
/* Check, if we cross a chip boundary */
|
|
|
|
if (!page) {
|
|
|
|
chipnr++;
|
2008-08-11 08:59:28 +00:00
|
|
|
chip->select_chip(mtd, -1);
|
|
|
|
chip->select_chip(mtd, chipnr);
|
2007-10-12 08:04:54 +00:00
|
|
|
}
|
2008-08-11 08:59:28 +00:00
|
|
|
|
2007-10-12 08:04:54 +00:00
|
|
|
/* Check, if the chip supports auto page increment
|
|
|
|
* or if we have hit a block boundary.
|
2008-08-11 08:59:28 +00:00
|
|
|
*/
|
|
|
|
if (!NAND_CANAUTOINCR(chip) || !(page & blkcheck))
|
2007-10-12 08:04:54 +00:00
|
|
|
sndcmd = 1;
|
|
|
|
}
|
|
|
|
|
2008-08-11 08:59:28 +00:00
|
|
|
ops->retlen = ops->len - (size_t) readlen;
|
|
|
|
if (oob)
|
|
|
|
ops->oobretlen = ops->ooblen - oobreadlen;
|
2007-10-12 08:04:54 +00:00
|
|
|
|
2008-08-11 08:59:28 +00:00
|
|
|
if (ret)
|
|
|
|
return ret;
|
|
|
|
|
|
|
|
if (mtd->ecc_stats.failed - stats.failed)
|
|
|
|
return -EBADMSG;
|
|
|
|
|
2009-09-08 08:34:14 +00:00
|
|
|
return 0;
|
2007-10-12 08:04:54 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2008-08-11 08:59:28 +00:00
|
|
|
* nand_read - [MTD Interface] MTD compability function for nand_do_read_ecc
|
|
|
|
* @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-12 08:04:54 +00:00
|
|
|
*
|
2008-08-11 08:59:28 +00:00
|
|
|
* Get hold of the chip and call nand_do_read
|
2007-10-12 08:04:54 +00:00
|
|
|
*/
|
2008-08-11 08:59:28 +00:00
|
|
|
static int nand_read(struct mtd_info *mtd, loff_t from, size_t len,
|
|
|
|
size_t *retlen, uint8_t *buf)
|
2007-10-12 08:04:54 +00:00
|
|
|
{
|
2008-08-11 08:59:28 +00:00
|
|
|
struct nand_chip *chip = mtd->priv;
|
|
|
|
int ret;
|
2007-10-12 08:04:54 +00:00
|
|
|
|
|
|
|
/* Do not allow reads past end of device */
|
2008-08-11 08:59:28 +00:00
|
|
|
if ((from + len) > mtd->size)
|
2007-10-12 08:04:54 +00:00
|
|
|
return -EINVAL;
|
2008-08-11 08:59:28 +00:00
|
|
|
if (!len)
|
|
|
|
return 0;
|
2007-10-12 08:04:54 +00:00
|
|
|
|
2008-08-11 08:59:28 +00:00
|
|
|
chip->ops.len = len;
|
|
|
|
chip->ops.datbuf = buf;
|
|
|
|
chip->ops.oobbuf = NULL;
|
2007-10-12 08:04:54 +00:00
|
|
|
|
2008-08-11 08:59:28 +00:00
|
|
|
ret = nand_do_read_ops(mtd, from, &chip->ops);
|
2007-10-12 08:04:54 +00:00
|
|
|
|
2008-08-11 08:59:28 +00:00
|
|
|
*retlen = chip->ops.retlen;
|
2007-10-12 08:04:54 +00:00
|
|
|
|
2008-08-11 08:59:28 +00:00
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* nand_read_oob_std - [REPLACABLE] the most common OOB data read function
|
|
|
|
* @mtd: mtd info structure
|
|
|
|
* @chip: nand chip info structure
|
|
|
|
* @page: page number to read
|
|
|
|
* @sndcmd: flag whether to issue read command or not
|
|
|
|
*/
|
2011-04-04 09:23:25 +00:00
|
|
|
int nand_read_oob_std(struct mtd_info *mtd, struct nand_chip *chip,
|
2008-08-11 08:59:28 +00:00
|
|
|
int page, int sndcmd)
|
|
|
|
{
|
|
|
|
if (sndcmd) {
|
|
|
|
chip->cmdfunc(mtd, NAND_CMD_READOOB, 0, page);
|
|
|
|
sndcmd = 0;
|
|
|
|
}
|
|
|
|
chip->read_buf(mtd, chip->oob_poi, mtd->oobsize);
|
|
|
|
return sndcmd;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* nand_do_read_oob - [Intern] NAND read out-of-band
|
|
|
|
* @mtd: MTD device structure
|
|
|
|
* @from: offset to read from
|
|
|
|
* @ops: oob operations description structure
|
2007-10-12 08:04:54 +00:00
|
|
|
*
|
2008-08-11 08:59:28 +00:00
|
|
|
* NAND read out-of-band data from the spare area
|
2007-10-12 08:04:54 +00:00
|
|
|
*/
|
2011-04-07 15:59:52 +00:00
|
|
|
#ifdef CONFIG_NAND_READ_OOB
|
2008-08-11 08:59:28 +00:00
|
|
|
static int nand_do_read_oob(struct mtd_info *mtd, loff_t from,
|
|
|
|
struct mtd_oob_ops *ops)
|
2007-10-12 08:04:54 +00:00
|
|
|
{
|
2008-08-11 08:59:28 +00:00
|
|
|
int page, realpage, chipnr, sndcmd = 1;
|
|
|
|
struct nand_chip *chip = mtd->priv;
|
|
|
|
int blkcheck = (1 << (chip->phys_erase_shift - chip->page_shift)) - 1;
|
|
|
|
int readlen = ops->ooblen;
|
|
|
|
int len;
|
|
|
|
uint8_t *buf = ops->oobbuf;
|
|
|
|
|
2009-04-24 19:42:37 +00:00
|
|
|
MTD_DEBUG(MTD_DEBUG_LEVEL3, "nand_read_oob: from = 0x%08Lx, len = %i\n",
|
2008-08-11 08:59:28 +00:00
|
|
|
(unsigned long long)from, readlen);
|
|
|
|
|
|
|
|
if (ops->mode == MTD_OOB_AUTO)
|
|
|
|
len = chip->ecc.layout->oobavail;
|
|
|
|
else
|
|
|
|
len = mtd->oobsize;
|
|
|
|
|
|
|
|
if (unlikely(ops->ooboffs >= len)) {
|
2009-04-24 19:42:37 +00:00
|
|
|
MTD_DEBUG(MTD_DEBUG_LEVEL0, "nand_read_oob: "
|
2008-08-11 08:59:28 +00:00
|
|
|
"Attempt to start read outside oob\n");
|
|
|
|
return -EINVAL;
|
|
|
|
}
|
2007-10-12 08:04:54 +00:00
|
|
|
|
|
|
|
/* Do not allow reads past end of device */
|
2008-08-11 08:59:28 +00:00
|
|
|
if (unlikely(from >= mtd->size ||
|
|
|
|
ops->ooboffs + readlen > ((mtd->size >> chip->page_shift) -
|
|
|
|
(from >> chip->page_shift)) * len)) {
|
2009-04-24 19:42:37 +00:00
|
|
|
MTD_DEBUG(MTD_DEBUG_LEVEL0, "nand_read_oob: "
|
2008-08-11 08:59:28 +00:00
|
|
|
"Attempt read beyond end of device\n");
|
2007-10-12 08:04:54 +00:00
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
|
2008-08-11 08:59:28 +00:00
|
|
|
chipnr = (int)(from >> chip->chip_shift);
|
|
|
|
chip->select_chip(mtd, chipnr);
|
2007-10-12 08:04:54 +00:00
|
|
|
|
2008-08-11 08:59:28 +00:00
|
|
|
/* Shift to get page */
|
|
|
|
realpage = (int)(from >> chip->page_shift);
|
|
|
|
page = realpage & chip->pagemask;
|
2007-10-12 08:04:54 +00:00
|
|
|
|
2008-08-11 08:59:28 +00:00
|
|
|
while(1) {
|
|
|
|
sndcmd = chip->ecc.read_oob(mtd, chip, page, sndcmd);
|
2007-10-12 08:04:54 +00:00
|
|
|
|
2008-08-11 08:59:28 +00:00
|
|
|
len = min(len, readlen);
|
|
|
|
buf = nand_transfer_oob(chip, buf, ops, len);
|
2007-10-12 08:04:54 +00:00
|
|
|
|
2008-08-11 08:59:28 +00:00
|
|
|
if (!(chip->options & NAND_NO_READRDY)) {
|
|
|
|
/*
|
|
|
|
* Apply delay or wait for ready/busy pin. Do this
|
|
|
|
* before the AUTOINCR check, so no problems arise if a
|
|
|
|
* chip which does auto increment is marked as
|
|
|
|
* NOAUTOINCR by the board driver.
|
|
|
|
*/
|
|
|
|
if (!chip->dev_ready)
|
|
|
|
udelay(chip->chip_delay);
|
|
|
|
else
|
|
|
|
nand_wait_ready(mtd);
|
|
|
|
}
|
2007-10-12 08:04:54 +00:00
|
|
|
|
2008-08-11 08:59:28 +00:00
|
|
|
readlen -= len;
|
|
|
|
if (!readlen)
|
|
|
|
break;
|
|
|
|
|
|
|
|
/* Increment page address */
|
|
|
|
realpage++;
|
2007-10-12 08:04:54 +00:00
|
|
|
|
2008-08-11 08:59:28 +00: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);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Check, if the chip supports auto page increment
|
|
|
|
* or if we have hit a block boundary.
|
|
|
|
*/
|
|
|
|
if (!NAND_CANAUTOINCR(chip) || !(page & blkcheck))
|
2007-10-12 08:04:54 +00:00
|
|
|
sndcmd = 1;
|
|
|
|
}
|
|
|
|
|
2008-08-11 08:59:28 +00:00
|
|
|
ops->oobretlen = ops->ooblen;
|
2007-10-12 08:04:54 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2008-08-11 08:59:28 +00:00
|
|
|
* nand_read_oob - [MTD Interface] NAND read data and/or out-of-band
|
|
|
|
* @mtd: MTD device structure
|
|
|
|
* @from: offset to read from
|
|
|
|
* @ops: oob operation description structure
|
2007-10-12 08:04:54 +00:00
|
|
|
*
|
2008-08-11 08:59:28 +00:00
|
|
|
* NAND read data and/or out-of-band data
|
|
|
|
*/
|
|
|
|
static int nand_read_oob(struct mtd_info *mtd, loff_t from,
|
|
|
|
struct mtd_oob_ops *ops)
|
2007-10-12 08:04:54 +00:00
|
|
|
{
|
2008-08-11 08:59:28 +00:00
|
|
|
int ret = -ENOSYS;
|
2007-10-12 08:04:54 +00:00
|
|
|
|
2008-08-11 08:59:28 +00:00
|
|
|
ops->retlen = 0;
|
2007-10-12 08:04:54 +00:00
|
|
|
|
2008-08-11 08:59:28 +00:00
|
|
|
/* Do not allow reads past end of device */
|
|
|
|
if (ops->datbuf && (from + ops->len) > mtd->size) {
|
2009-04-24 19:42:37 +00:00
|
|
|
MTD_DEBUG(MTD_DEBUG_LEVEL0, "nand_read_oob: "
|
2008-08-11 08:59:28 +00:00
|
|
|
"Attempt read beyond end of device\n");
|
|
|
|
return -EINVAL;
|
2007-10-12 08:04:54 +00:00
|
|
|
}
|
|
|
|
|
2008-08-11 08:59:28 +00:00
|
|
|
switch(ops->mode) {
|
|
|
|
case MTD_OOB_PLACE:
|
|
|
|
case MTD_OOB_AUTO:
|
|
|
|
case MTD_OOB_RAW:
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
goto out;
|
2007-10-12 08:04:54 +00:00
|
|
|
}
|
2008-08-11 08:59:28 +00:00
|
|
|
|
|
|
|
if (!ops->datbuf)
|
|
|
|
ret = nand_do_read_oob(mtd, from, ops);
|
|
|
|
else
|
|
|
|
ret = nand_do_read_ops(mtd, from, ops);
|
|
|
|
|
|
|
|
out:
|
|
|
|
return ret;
|
2007-10-12 08:04:54 +00:00
|
|
|
}
|
2011-04-07 15:59:52 +00:00
|
|
|
#endif
|
2007-10-12 08:04:54 +00:00
|
|
|
|
|
|
|
/**
|
2008-08-11 08:59:28 +00:00
|
|
|
* nand_block_isbad - [MTD Interface] Check if block at offset is bad
|
|
|
|
* @mtd: MTD device structure
|
|
|
|
* @offs: offset relative to mtd start
|
2007-10-12 08:04:54 +00:00
|
|
|
*/
|
2011-04-04 09:24:14 +00:00
|
|
|
int nand_block_isbad(struct mtd_info *mtd, loff_t offs)
|
2007-10-12 08:04:54 +00:00
|
|
|
{
|
|
|
|
/* Check for invalid offset */
|
2008-08-11 08:59:28 +00:00
|
|
|
if (offs > mtd->size)
|
2007-10-12 08:04:54 +00:00
|
|
|
return -EINVAL;
|
|
|
|
|
2008-08-11 08:59:28 +00:00
|
|
|
return nand_block_checkbad(mtd, offs, 1, 0);
|
2007-10-12 08:04:54 +00:00
|
|
|
}
|
|
|
|
|
2008-08-11 08:59:28 +00:00
|
|
|
/*
|
|
|
|
* Set default functions
|
|
|
|
*/
|
|
|
|
static void nand_set_defaults(struct nand_chip *chip, int busw)
|
|
|
|
{
|
2007-10-12 08:04:54 +00:00
|
|
|
/* check for proper chip_delay setup, set 20us if not */
|
2008-08-11 08:59:28 +00:00
|
|
|
if (!chip->chip_delay)
|
|
|
|
chip->chip_delay = 20;
|
2007-10-12 08:04:54 +00:00
|
|
|
|
|
|
|
/* check, if a user supplied command function given */
|
2008-08-11 08:59:28 +00:00
|
|
|
if (chip->cmdfunc == NULL)
|
|
|
|
chip->cmdfunc = nand_command;
|
2007-10-12 08:04:54 +00:00
|
|
|
|
|
|
|
/* check, if a user supplied wait function given */
|
2008-08-11 08:59:28 +00:00
|
|
|
if (chip->waitfunc == NULL)
|
|
|
|
chip->waitfunc = nand_wait;
|
|
|
|
|
|
|
|
if (!chip->select_chip)
|
|
|
|
chip->select_chip = nand_select_chip;
|
2012-08-02 10:01:05 +00:00
|
|
|
if (!chip->read_byte || chip->read_byte == nand_read_byte)
|
2008-08-11 08:59:28 +00: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;
|
2011-12-21 21:30:40 +00:00
|
|
|
#ifdef CONFIG_MTD_WRITE
|
2008-08-11 08:59:28 +00:00
|
|
|
if (!chip->block_markbad)
|
|
|
|
chip->block_markbad = nand_default_block_markbad;
|
2012-08-02 10:01:05 +00:00
|
|
|
if (!chip->write_buf || chip->write_buf == nand_write_buf)
|
2008-08-11 08:59:28 +00:00
|
|
|
chip->write_buf = busw ? nand_write_buf16 : nand_write_buf;
|
2011-04-04 09:24:47 +00:00
|
|
|
#endif
|
2012-08-02 10:01:05 +00:00
|
|
|
if (!chip->read_buf || chip->read_buf == nand_read_buf)
|
2008-08-11 08:59:28 +00:00
|
|
|
chip->read_buf = busw ? nand_read_buf16 : nand_read_buf;
|
2012-08-02 10:01:05 +00:00
|
|
|
if (!chip->verify_buf || chip->verify_buf == nand_verify_buf)
|
2008-08-11 08:59:28 +00:00
|
|
|
chip->verify_buf = busw ? nand_verify_buf16 : nand_verify_buf;
|
2011-04-04 12:16:42 +00:00
|
|
|
#ifdef CONFIG_NAND_BBT
|
2008-08-11 08:59:28 +00:00
|
|
|
if (!chip->scan_bbt)
|
|
|
|
chip->scan_bbt = nand_default_bbt;
|
2011-04-04 12:16:42 +00:00
|
|
|
#endif
|
2008-08-11 08:59:28 +00:00
|
|
|
if (!chip->controller) {
|
|
|
|
chip->controller = &chip->hwcontrol;
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2012-07-05 10:22:46 +00:00
|
|
|
/*
|
|
|
|
* sanitize ONFI strings so we can safely print them
|
|
|
|
*/
|
|
|
|
static void sanitize_string(char *s, size_t len)
|
|
|
|
{
|
|
|
|
ssize_t i;
|
|
|
|
|
|
|
|
/* null terminate */
|
|
|
|
s[len - 1] = 0;
|
|
|
|
|
|
|
|
/* remove non printable chars */
|
|
|
|
for (i = 0; i < len - 1; i++) {
|
|
|
|
if (s[i] < ' ' || s[i] > 127)
|
|
|
|
s[i] = '?';
|
|
|
|
}
|
|
|
|
|
|
|
|
/* remove trailing spaces */
|
|
|
|
strim(s);
|
|
|
|
}
|
|
|
|
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Check if the NAND chip is ONFI compliant, returns 1 if it is, 0 otherwise
|
|
|
|
*/
|
|
|
|
static int nand_flash_detect_onfi(struct mtd_info *mtd, struct nand_chip *chip,
|
|
|
|
int *busw)
|
|
|
|
{
|
|
|
|
struct nand_onfi_params *p = &chip->onfi_params;
|
|
|
|
int i;
|
|
|
|
int val;
|
|
|
|
|
|
|
|
/* try ONFI for unknow chip or LP */
|
|
|
|
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++) {
|
|
|
|
chip->read_buf(mtd, (uint8_t *)p, sizeof(*p));
|
|
|
|
if (onfi_crc16(ONFI_CRC_BASE, (uint8_t *)p, 254) ==
|
|
|
|
le16_to_cpu(p->crc)) {
|
2013-01-26 12:36:48 +00:00
|
|
|
pr_info("ONFI param page %d valid\n", i);
|
2012-07-05 10:22:46 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-05-15 07:43:29 +00:00
|
|
|
if (i == 3)
|
2012-07-05 10:22:46 +00:00
|
|
|
return 0;
|
|
|
|
|
|
|
|
/* check version */
|
|
|
|
val = le16_to_cpu(p->revision);
|
|
|
|
if (val & (1 << 5))
|
|
|
|
chip->onfi_version = 23;
|
|
|
|
else if (val & (1 << 4))
|
|
|
|
chip->onfi_version = 22;
|
|
|
|
else if (val & (1 << 3))
|
|
|
|
chip->onfi_version = 21;
|
|
|
|
else if (val & (1 << 2))
|
|
|
|
chip->onfi_version = 20;
|
|
|
|
else if (val & (1 << 1))
|
|
|
|
chip->onfi_version = 10;
|
|
|
|
else
|
|
|
|
chip->onfi_version = 0;
|
|
|
|
|
|
|
|
if (!chip->onfi_version) {
|
2013-01-26 12:36:48 +00:00
|
|
|
pr_info("unsupported ONFI version: %d\n", val);
|
2012-07-05 10:22:46 +00:00
|
|
|
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);
|
|
|
|
mtd->erasesize = le32_to_cpu(p->pages_per_block) * mtd->writesize;
|
|
|
|
mtd->oobsize = le16_to_cpu(p->spare_bytes_per_page);
|
2013-06-24 12:08:42 +00:00
|
|
|
chip->chipsize = le32_to_cpu(p->blocks_per_lun);
|
|
|
|
chip->chipsize *= (uint64_t)mtd->erasesize * p->lun_count;
|
2012-07-05 10:22:46 +00:00
|
|
|
*busw = 0;
|
|
|
|
if (le16_to_cpu(p->features) & 1)
|
|
|
|
*busw = NAND_BUSWIDTH_16;
|
|
|
|
|
|
|
|
chip->options &= ~NAND_CHIPOPTIONS_MSK;
|
|
|
|
chip->options |= NAND_NO_READRDY & NAND_CHIPOPTIONS_MSK;
|
|
|
|
|
2013-07-09 15:36:32 +00:00
|
|
|
pr_info("ONFI flash detected ...\n");
|
2013-05-15 07:43:29 +00:00
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* 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
|
|
|
|
* period of 3). This is a helper function for nand_id_len(). Returns non-zero
|
|
|
|
* 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;
|
2012-07-05 10:22:46 +00:00
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2013-05-15 07:43:29 +00:00
|
|
|
/*
|
|
|
|
* 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;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* 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 */
|
|
|
|
chip->cellinfo = id_data[2];
|
|
|
|
/* 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 &&
|
|
|
|
(chip->cellinfo & NAND_CI_CELLTYPE_MSK) &&
|
|
|
|
id_data[5] != 0x00) {
|
|
|
|
/* 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:
|
|
|
|
default: /* Other cases are "reserved" (unknown) */
|
|
|
|
mtd->oobsize = 640;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
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 &&
|
|
|
|
(chip->cellinfo & NAND_CI_CELLTYPE_MSK)) {
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* 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,
|
|
|
|
struct nand_flash_dev *type, u8 id_data[8],
|
|
|
|
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;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* 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);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* 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.
|
|
|
|
*/
|
|
|
|
if ((chip->cellinfo & NAND_CI_CELLTYPE_MSK) &&
|
|
|
|
(maf_id == NAND_MFR_SAMSUNG ||
|
|
|
|
maf_id == NAND_MFR_HYNIX))
|
|
|
|
chip->bbt_options |= NAND_BBT_SCANLASTPAGE;
|
|
|
|
else if ((!(chip->cellinfo & NAND_CI_CELLTYPE_MSK) &&
|
|
|
|
(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;
|
|
|
|
}
|
|
|
|
|
2008-08-11 08:59:28 +00:00
|
|
|
/*
|
|
|
|
* Get the flash and manufacturer id and lookup if the type is supported
|
|
|
|
*/
|
|
|
|
static struct nand_flash_dev *nand_get_flash_type(struct mtd_info *mtd,
|
|
|
|
struct nand_chip *chip,
|
|
|
|
int busw, int *maf_id)
|
|
|
|
{
|
|
|
|
struct nand_flash_dev *type = NULL;
|
|
|
|
int i, dev_id, maf_idx;
|
2013-05-15 07:43:29 +00:00
|
|
|
u8 id_data[8];
|
2007-10-12 08:04:54 +00:00
|
|
|
|
|
|
|
/* Select the device */
|
2008-08-11 08:59:28 +00:00
|
|
|
chip->select_chip(mtd, 0);
|
2007-10-12 08:04:54 +00:00
|
|
|
|
2010-11-10 14:19:05 +00:00
|
|
|
/*
|
|
|
|
* Reset the chip, required by some chips (e.g. Micron MT29FxGxxxxx)
|
|
|
|
* after power-up
|
|
|
|
*/
|
|
|
|
chip->cmdfunc(mtd, NAND_CMD_RESET, -1, -1);
|
|
|
|
|
2007-10-12 08:04:54 +00:00
|
|
|
/* Send the command for reading device ID */
|
2008-08-11 08:59:28 +00:00
|
|
|
chip->cmdfunc(mtd, NAND_CMD_READID, 0x00, -1);
|
2007-10-12 08:04:54 +00:00
|
|
|
|
|
|
|
/* Read manufacturer and device IDs */
|
2008-08-11 08:59:28 +00:00
|
|
|
*maf_id = chip->read_byte(mtd);
|
|
|
|
dev_id = chip->read_byte(mtd);
|
2007-10-12 08:04:54 +00:00
|
|
|
|
2008-08-11 08:59:28 +00:00
|
|
|
/* Try again to make sure, as some systems the bus-hold or other
|
|
|
|
* 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.
|
|
|
|
*/
|
2007-10-12 08:04:54 +00:00
|
|
|
|
2008-08-11 08:59:28 +00:00
|
|
|
chip->cmdfunc(mtd, NAND_CMD_READID, 0x00, -1);
|
2007-10-12 08:04:54 +00:00
|
|
|
|
2013-05-15 07:43:29 +00:00
|
|
|
/* Read entire ID string */
|
|
|
|
for (i = 0; i < 8; i++)
|
|
|
|
id_data[i] = chip->read_byte(mtd);
|
2007-10-12 08:04:54 +00:00
|
|
|
|
2012-09-15 11:45:06 +00:00
|
|
|
if (id_data[0] != *maf_id || id_data[1] != dev_id) {
|
2013-01-26 12:36:48 +00:00
|
|
|
pr_err("%s: second ID read did not match "
|
2008-08-11 08:59:28 +00:00
|
|
|
"%02x,%02x against %02x,%02x\n", __func__,
|
2012-09-15 11:45:06 +00:00
|
|
|
*maf_id, dev_id, id_data[0], id_data[1]);
|
2008-08-11 08:59:28 +00:00
|
|
|
return ERR_PTR(-ENODEV);
|
|
|
|
}
|
2007-10-12 08:04:54 +00:00
|
|
|
|
nand_base: detect more ONFI flash
if the flash has a known type, the ONFI detection won't occur
and thus we may not detect the right parameters.
By testing both namd and pagesize, as done in the kernel, we
can detect ONFI flash with know IDs.
As an example on an i.MX53 board :
- without the patch :
NAND device: Manufacturer ID: 0x2c, Chip ID: 0xd3
(Micron NAND 1GiB 3,3V 8-bit), page size: 4096, OOB size: 128
- with the patch :
ONFI flash detected ... ONFI param page 0 valid
NAND device: Manufacturer ID: 0x2c, Chip ID: 0xd3
(Micron MT29F8G08ABACAWP), page size: 4096, OOB size: 224
in the first case the OOB size is wrong.
Signed-off-by: Eric Bénard <eric@eukrea.com>
Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
2013-04-10 16:04:52 +00:00
|
|
|
if (!type)
|
|
|
|
type = nand_flash_ids;
|
|
|
|
|
|
|
|
for (; type->name != NULL; type++)
|
|
|
|
if (dev_id == type->id)
|
2008-08-11 08:59:28 +00:00
|
|
|
break;
|
2007-10-12 08:04:54 +00:00
|
|
|
|
2012-07-05 10:22:46 +00:00
|
|
|
chip->onfi_version = 0;
|
nand_base: detect more ONFI flash
if the flash has a known type, the ONFI detection won't occur
and thus we may not detect the right parameters.
By testing both namd and pagesize, as done in the kernel, we
can detect ONFI flash with know IDs.
As an example on an i.MX53 board :
- without the patch :
NAND device: Manufacturer ID: 0x2c, Chip ID: 0xd3
(Micron NAND 1GiB 3,3V 8-bit), page size: 4096, OOB size: 128
- with the patch :
ONFI flash detected ... ONFI param page 0 valid
NAND device: Manufacturer ID: 0x2c, Chip ID: 0xd3
(Micron MT29F8G08ABACAWP), page size: 4096, OOB size: 224
in the first case the OOB size is wrong.
Signed-off-by: Eric Bénard <eric@eukrea.com>
Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
2013-04-10 16:04:52 +00:00
|
|
|
if (!type->name || !type->pagesize) {
|
2012-07-05 10:22:46 +00:00
|
|
|
/* Check is chip is ONFI compliant */
|
2013-05-15 07:43:29 +00:00
|
|
|
if (nand_flash_detect_onfi(mtd, chip, &busw))
|
2012-07-05 10:22:46 +00:00
|
|
|
goto ident_done;
|
2011-11-28 11:46:56 +00:00
|
|
|
}
|
2008-08-11 08:59:28 +00:00
|
|
|
|
2013-05-15 07:43:29 +00:00
|
|
|
if (!type->name)
|
|
|
|
return ERR_PTR(-ENODEV);
|
2012-09-15 11:45:06 +00:00
|
|
|
|
2008-08-11 08:59:28 +00:00
|
|
|
if (!mtd->name)
|
|
|
|
mtd->name = type->name;
|
|
|
|
|
2013-05-15 07:43:29 +00:00
|
|
|
chip->chipsize = (uint64_t)type->chipsize << 20;
|
2008-08-11 08:59:28 +00:00
|
|
|
|
|
|
|
if (!type->pagesize) {
|
2013-05-15 07:43:29 +00:00
|
|
|
/* Decode parameters from extended ID */
|
|
|
|
nand_decode_ext_id(mtd, chip, id_data, &busw);
|
2008-08-11 08:59:28 +00:00
|
|
|
} else {
|
2013-05-15 07:43:29 +00:00
|
|
|
nand_decode_id(mtd, chip, type, id_data, &busw);
|
2007-10-12 08:04:54 +00:00
|
|
|
}
|
2013-05-15 07:43:29 +00:00
|
|
|
/* Get chip options */
|
|
|
|
chip->options |= type->options;
|
2007-10-12 08:04:54 +00:00
|
|
|
|
2013-05-15 07:43:29 +00:00
|
|
|
/*
|
|
|
|
* Check if chip is not a Samsung device. Do not clear the
|
|
|
|
* options for chips which do not have an extended id.
|
2012-07-05 10:22:46 +00:00
|
|
|
*/
|
|
|
|
if (*maf_id != NAND_MFR_SAMSUNG && !type->pagesize)
|
|
|
|
chip->options &= ~NAND_SAMSUNG_LP_OPTIONS;
|
|
|
|
ident_done:
|
|
|
|
/*
|
|
|
|
* Set chip as a default. Board drivers can override it, if necessary
|
|
|
|
*/
|
|
|
|
chip->options |= NAND_NO_AUTOINCR;
|
|
|
|
|
|
|
|
/* 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;
|
|
|
|
}
|
|
|
|
|
2012-08-02 10:01:05 +00:00
|
|
|
if (chip->options & NAND_BUSWIDTH_AUTO) {
|
|
|
|
chip->options |= busw;
|
|
|
|
nand_set_defaults(chip, busw);
|
|
|
|
if (chip->set_buswidth)
|
|
|
|
chip->set_buswidth(mtd, chip, busw);
|
2013-05-15 07:43:29 +00:00
|
|
|
} else if (busw != (chip->options & NAND_BUSWIDTH_16)) {
|
|
|
|
/*
|
|
|
|
* Check, if buswidth is correct. Hardware drivers should set
|
|
|
|
* chip correct !
|
|
|
|
*/
|
2013-01-26 12:36:48 +00:00
|
|
|
pr_info("NAND device: Manufacturer ID:"
|
2012-07-05 10:22:46 +00:00
|
|
|
" 0x%02x, Chip ID: 0x%02x (%s %s)\n", *maf_id,
|
|
|
|
dev_id, nand_manuf_ids[maf_idx].name, mtd->name);
|
2013-01-26 12:36:48 +00:00
|
|
|
pr_warning("NAND bus width %d instead %d bit\n",
|
2012-07-05 10:22:46 +00:00
|
|
|
(chip->options & NAND_BUSWIDTH_16) ? 16 : 8,
|
|
|
|
busw ? 16 : 8);
|
2008-08-11 08:59:28 +00:00
|
|
|
return ERR_PTR(-EINVAL);
|
2007-10-12 08:04:54 +00:00
|
|
|
}
|
|
|
|
|
2013-05-15 07:43:29 +00:00
|
|
|
nand_decode_bbm_options(mtd, chip, id_data);
|
|
|
|
|
2008-08-11 08:59:28 +00:00
|
|
|
/* Calculate the address shift from the page size */
|
|
|
|
chip->page_shift = ffs(mtd->writesize) - 1;
|
|
|
|
/* Convert chipsize to number of pages per chip -1. */
|
|
|
|
chip->pagemask = (chip->chipsize >> chip->page_shift) - 1;
|
2007-10-12 08:04:54 +00:00
|
|
|
|
2008-08-11 08:59:28 +00:00
|
|
|
chip->bbt_erase_shift = chip->phys_erase_shift =
|
|
|
|
ffs(mtd->erasesize) - 1;
|
2012-07-05 10:22:46 +00:00
|
|
|
if (chip->chipsize & 0xffffffff)
|
|
|
|
chip->chip_shift = ffs((unsigned)chip->chipsize) - 1;
|
|
|
|
else {
|
|
|
|
chip->chip_shift = ffs((unsigned)(chip->chipsize >> 32));
|
|
|
|
chip->chip_shift += 32 - 1;
|
|
|
|
}
|
2008-08-11 08:59:28 +00:00
|
|
|
|
|
|
|
/* Set the bad block position */
|
|
|
|
chip->badblockpos = mtd->writesize > 512 ?
|
|
|
|
NAND_LARGE_BADBLOCK_POS : NAND_SMALL_BADBLOCK_POS;
|
2007-10-12 08:04:54 +00:00
|
|
|
|
2011-12-21 21:30:40 +00:00
|
|
|
#ifdef CONFIG_MTD_WRITE
|
2008-08-11 08:59:28 +00:00
|
|
|
/* Check for AND chips with 4 page planes */
|
|
|
|
if (chip->options & NAND_4PAGE_ARRAY)
|
|
|
|
chip->erase_cmd = multi_erase_cmd;
|
|
|
|
else
|
|
|
|
chip->erase_cmd = single_erase_cmd;
|
2011-04-04 09:24:47 +00:00
|
|
|
#endif
|
2008-08-11 08:59:28 +00:00
|
|
|
/* Do not replace user supplied command function ! */
|
|
|
|
if (mtd->writesize > 512 && chip->cmdfunc == nand_command)
|
|
|
|
chip->cmdfunc = nand_command_lp;
|
|
|
|
|
2013-01-26 12:36:48 +00:00
|
|
|
pr_notice("Manufacturer ID: 0x%02x, Chip ID: 0x%02x (%s %s),"
|
2012-07-05 10:22:46 +00:00
|
|
|
" page size: %d, OOB size: %d\n",
|
|
|
|
*maf_id, dev_id, nand_manuf_ids[maf_idx].name,
|
|
|
|
chip->onfi_version ? chip->onfi_params.model : type->name,
|
|
|
|
mtd->writesize, mtd->oobsize);
|
2008-08-11 08:59:28 +00:00
|
|
|
|
|
|
|
return type;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* nand_scan_ident - [NAND Interface] Scan for the NAND device
|
|
|
|
* @mtd: MTD device structure
|
|
|
|
* @maxchips: Number of chips to scan for
|
|
|
|
*
|
|
|
|
* This is the first phase of the normal nand_scan() function. It
|
|
|
|
* reads the flash ID and sets up MTD fields accordingly.
|
|
|
|
*
|
|
|
|
* The mtd->owner field must be set to the module of the caller.
|
|
|
|
*/
|
|
|
|
int nand_scan_ident(struct mtd_info *mtd, int maxchips)
|
|
|
|
{
|
|
|
|
int i, busw, nand_maf_id;
|
|
|
|
struct nand_chip *chip = mtd->priv;
|
|
|
|
struct nand_flash_dev *type;
|
|
|
|
|
2012-08-02 10:01:05 +00:00
|
|
|
if (chip->options & NAND_BUSWIDTH_AUTO && !chip->set_buswidth) {
|
2013-01-26 12:36:48 +00:00
|
|
|
pr_err("buswidth detection but no buswidth callback\n");
|
2012-08-02 10:01:05 +00:00
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
|
2008-08-11 08:59:28 +00:00
|
|
|
/* Get buswidth to select the correct functions */
|
|
|
|
busw = chip->options & NAND_BUSWIDTH_16;
|
|
|
|
/* Set the default functions */
|
|
|
|
nand_set_defaults(chip, busw);
|
|
|
|
|
|
|
|
/* Read the flash type */
|
|
|
|
type = nand_get_flash_type(mtd, chip, busw, &nand_maf_id);
|
|
|
|
|
|
|
|
if (IS_ERR(type)) {
|
2013-01-26 12:36:48 +00:00
|
|
|
pr_warning("No NAND device found (%ld)!\n", PTR_ERR(type));
|
2008-08-11 08:59:28 +00:00
|
|
|
chip->select_chip(mtd, -1);
|
|
|
|
return PTR_ERR(type);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Check for a chip array */
|
|
|
|
for (i = 1; i < maxchips; i++) {
|
|
|
|
chip->select_chip(mtd, i);
|
|
|
|
/* Send the command for reading device ID */
|
|
|
|
chip->cmdfunc(mtd, NAND_CMD_READID, 0x00, -1);
|
2007-10-12 08:04:54 +00:00
|
|
|
/* Read manufacturer and device IDs */
|
2008-08-11 08:59:28 +00:00
|
|
|
if (nand_maf_id != chip->read_byte(mtd) ||
|
|
|
|
type->id != chip->read_byte(mtd))
|
2007-10-12 08:04:54 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
if (i > 1)
|
2013-01-26 12:36:48 +00:00
|
|
|
pr_info("%d NAND chips detected\n", i);
|
2007-10-12 08:04:54 +00:00
|
|
|
|
2008-08-11 08:59:28 +00:00
|
|
|
/* Store the number of chips and calc total size for mtd */
|
|
|
|
chip->numchips = i;
|
|
|
|
mtd->size = i * chip->chipsize;
|
2007-10-12 08:04:54 +00:00
|
|
|
|
2008-08-11 08:59:28 +00:00
|
|
|
return 0;
|
|
|
|
}
|
2007-10-12 08:04:54 +00:00
|
|
|
|
2011-04-04 09:19:18 +00:00
|
|
|
static void __maybe_unused nand_check_hwecc(struct mtd_info *mtd, struct nand_chip *chip)
|
|
|
|
{
|
|
|
|
if ((!chip->ecc.calculate || !chip->ecc.correct ||
|
|
|
|
!chip->ecc.hwctl) &&
|
|
|
|
(!chip->ecc.read_page || !chip->ecc.write_page)) {
|
2013-01-26 12:36:48 +00:00
|
|
|
pr_warning("No ECC functions supplied, "
|
2011-04-04 09:19:18 +00:00
|
|
|
"Hardware ECC not possible\n");
|
|
|
|
BUG();
|
|
|
|
}
|
|
|
|
|
|
|
|
if (mtd->writesize < chip->ecc.size) {
|
2013-01-26 12:36:48 +00:00
|
|
|
pr_warning("%d byte HW ECC not possible on "
|
2011-04-04 09:19:18 +00:00
|
|
|
"%d byte page size\n",
|
|
|
|
chip->ecc.size, mtd->writesize);
|
|
|
|
BUG();
|
|
|
|
}
|
|
|
|
}
|
2008-08-11 08:59:28 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* nand_scan_tail - [NAND Interface] Scan for the NAND device
|
|
|
|
* @mtd: MTD device structure
|
|
|
|
* @maxchips: Number of chips to scan for
|
|
|
|
*
|
|
|
|
* This is the second phase of the normal nand_scan() function. It
|
|
|
|
* fills out all the uninitialized function pointers with the defaults
|
|
|
|
* and scans for a bad block table if appropriate.
|
|
|
|
*/
|
|
|
|
int nand_scan_tail(struct mtd_info *mtd)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
struct nand_chip *chip = mtd->priv;
|
|
|
|
|
|
|
|
if (!(chip->options & NAND_OWN_BUFFERS))
|
|
|
|
chip->buffers = kmalloc(sizeof(*chip->buffers), GFP_KERNEL);
|
|
|
|
if (!chip->buffers)
|
|
|
|
return -ENOMEM;
|
|
|
|
|
|
|
|
/* Set the internal oob buffer location, just after the page data */
|
|
|
|
chip->oob_poi = chip->buffers->databuf + mtd->writesize;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* If no default placement scheme is given, select an appropriate one
|
|
|
|
*/
|
|
|
|
if (!chip->ecc.layout) {
|
|
|
|
switch (mtd->oobsize) {
|
2007-10-12 08:04:54 +00:00
|
|
|
case 8:
|
2008-08-11 08:59:28 +00:00
|
|
|
chip->ecc.layout = &nand_oob_8;
|
2007-10-12 08:04:54 +00:00
|
|
|
break;
|
|
|
|
case 16:
|
2008-08-11 08:59:28 +00:00
|
|
|
chip->ecc.layout = &nand_oob_16;
|
2007-10-12 08:04:54 +00:00
|
|
|
break;
|
|
|
|
case 64:
|
2008-08-11 08:59:28 +00:00
|
|
|
chip->ecc.layout = &nand_oob_64;
|
2007-10-12 08:04:54 +00:00
|
|
|
break;
|
|
|
|
default:
|
2013-01-26 12:36:48 +00:00
|
|
|
pr_warning("No oob scheme defined for "
|
2008-08-11 08:59:28 +00:00
|
|
|
"oobsize %d\n", mtd->oobsize);
|
|
|
|
BUG();
|
2007-10-12 08:04:54 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-12-21 21:30:40 +00:00
|
|
|
#ifdef CONFIG_MTD_WRITE
|
2008-08-11 08:59:28 +00:00
|
|
|
if (!chip->write_page)
|
|
|
|
chip->write_page = nand_write_page;
|
2011-04-04 09:24:47 +00:00
|
|
|
#endif
|
2007-10-12 08:04:54 +00:00
|
|
|
|
|
|
|
/*
|
2008-08-11 08:59:28 +00:00
|
|
|
* check ECC mode, default to software if 3byte/512byte hardware ECC is
|
|
|
|
* selected and we have 256 byte pagesize fallback to software ECC
|
|
|
|
*/
|
|
|
|
if (!chip->ecc.read_page_raw)
|
|
|
|
chip->ecc.read_page_raw = nand_read_page_raw;
|
2011-12-21 21:30:40 +00:00
|
|
|
#ifdef CONFIG_MTD_WRITE
|
2008-08-11 08:59:28 +00:00
|
|
|
if (!chip->ecc.write_page_raw)
|
|
|
|
chip->ecc.write_page_raw = nand_write_page_raw;
|
2011-04-04 09:24:47 +00:00
|
|
|
#endif
|
2008-08-11 08:59:28 +00:00
|
|
|
switch (chip->ecc.mode) {
|
2011-04-04 10:26:25 +00:00
|
|
|
#ifdef CONFIG_NAND_ECC_HW
|
2008-08-11 08:59:28 +00:00
|
|
|
case NAND_ECC_HW:
|
2011-04-04 09:19:18 +00:00
|
|
|
nand_check_hwecc(mtd, chip);
|
2011-04-04 09:23:25 +00:00
|
|
|
nand_init_ecc_hw(chip);
|
2011-04-04 09:19:18 +00:00
|
|
|
break;
|
2011-04-04 10:26:25 +00:00
|
|
|
#endif
|
|
|
|
#ifdef CONFIG_NAND_ECC_HW_SYNDROME
|
2008-08-11 08:59:28 +00:00
|
|
|
case NAND_ECC_HW_SYNDROME:
|
2011-04-04 09:19:18 +00:00
|
|
|
nand_check_hwecc(mtd, chip);
|
2011-04-04 09:23:52 +00:00
|
|
|
nand_init_ecc_hw_syndrome(chip);
|
2011-04-04 09:19:18 +00:00
|
|
|
break;
|
2011-04-04 10:26:25 +00:00
|
|
|
#endif
|
|
|
|
#ifdef CONFIG_NAND_ECC_SOFT
|
2008-08-11 08:59:28 +00:00
|
|
|
case NAND_ECC_SOFT:
|
2011-04-04 09:23:36 +00:00
|
|
|
nand_init_ecc_soft(chip);
|
2007-10-12 08:04:54 +00:00
|
|
|
break;
|
2011-04-04 10:26:25 +00:00
|
|
|
#endif
|
|
|
|
#ifdef CONFIG_NAND_ECC_NONE
|
2007-10-12 08:04:54 +00:00
|
|
|
case NAND_ECC_NONE:
|
2013-01-26 12:36:48 +00:00
|
|
|
pr_warning("NAND_ECC_NONE selected by board driver. "
|
2008-08-11 08:59:28 +00:00
|
|
|
"This is not recommended !!\n");
|
|
|
|
chip->ecc.read_page = nand_read_page_raw;
|
2011-12-21 21:30:40 +00:00
|
|
|
#ifdef CONFIG_MTD_WRITE
|
2008-08-11 08:59:28 +00:00
|
|
|
chip->ecc.write_page = nand_write_page_raw;
|
|
|
|
chip->ecc.write_oob = nand_write_oob_std;
|
2011-04-04 09:24:47 +00:00
|
|
|
#endif
|
|
|
|
chip->ecc.read_oob = nand_read_oob_std;
|
2008-08-11 08:59:28 +00:00
|
|
|
chip->ecc.size = mtd->writesize;
|
|
|
|
chip->ecc.bytes = 0;
|
2007-10-12 08:04:54 +00:00
|
|
|
break;
|
2011-04-04 10:26:25 +00:00
|
|
|
#endif
|
2007-10-12 08:04:54 +00:00
|
|
|
default:
|
2013-01-26 12:36:48 +00:00
|
|
|
pr_warning("Invalid NAND_ECC_MODE %d\n",
|
2008-08-11 08:59:28 +00:00
|
|
|
chip->ecc.mode);
|
|
|
|
BUG();
|
2007-10-12 08:04:54 +00:00
|
|
|
}
|
|
|
|
|
2008-08-11 08:59:28 +00:00
|
|
|
/*
|
|
|
|
* The number of bytes available for a client to place data into
|
|
|
|
* the out of band area
|
|
|
|
*/
|
|
|
|
chip->ecc.layout->oobavail = 0;
|
|
|
|
for (i = 0; chip->ecc.layout->oobfree[i].length; i++)
|
|
|
|
chip->ecc.layout->oobavail +=
|
|
|
|
chip->ecc.layout->oobfree[i].length;
|
|
|
|
mtd->oobavail = chip->ecc.layout->oobavail;
|
2007-10-12 08:04:54 +00:00
|
|
|
|
2008-08-11 08:59:28 +00:00
|
|
|
/*
|
|
|
|
* Set the number of read / write steps for one page depending on ECC
|
|
|
|
* mode
|
|
|
|
*/
|
|
|
|
chip->ecc.steps = mtd->writesize / chip->ecc.size;
|
|
|
|
if(chip->ecc.steps * chip->ecc.size != mtd->writesize) {
|
2013-01-26 12:36:48 +00:00
|
|
|
pr_warning("Invalid ecc parameters\n");
|
2008-08-11 08:59:28 +00:00
|
|
|
BUG();
|
|
|
|
}
|
|
|
|
chip->ecc.total = chip->ecc.steps * chip->ecc.bytes;
|
2007-10-12 08:04:54 +00:00
|
|
|
|
2008-08-11 08:59:28 +00:00
|
|
|
/*
|
|
|
|
* Allow subpage writes up to ecc.steps. Not possible for MLC
|
|
|
|
* FLASH.
|
|
|
|
*/
|
|
|
|
if (!(chip->options & NAND_NO_SUBPAGE_WRITE) &&
|
|
|
|
!(chip->cellinfo & NAND_CI_CELLTYPE_MSK)) {
|
|
|
|
switch(chip->ecc.steps) {
|
|
|
|
case 2:
|
|
|
|
mtd->subpage_sft = 1;
|
|
|
|
break;
|
|
|
|
case 4:
|
|
|
|
case 8:
|
|
|
|
mtd->subpage_sft = 2;
|
|
|
|
break;
|
|
|
|
}
|
2007-10-12 08:04:54 +00:00
|
|
|
}
|
2008-08-11 08:59:28 +00:00
|
|
|
chip->subpagesize = mtd->writesize >> mtd->subpage_sft;
|
2007-10-12 08:04:54 +00:00
|
|
|
|
2008-08-11 08:59:28 +00:00
|
|
|
/* Initialize state */
|
|
|
|
chip->state = FL_READY;
|
2007-10-12 08:04:54 +00:00
|
|
|
|
|
|
|
/* De-select the device */
|
2008-08-11 08:59:28 +00:00
|
|
|
chip->select_chip(mtd, -1);
|
2007-10-12 08:04:54 +00:00
|
|
|
|
|
|
|
/* Invalidate the pagebuffer reference */
|
2008-08-11 08:59:28 +00:00
|
|
|
chip->pagebuf = -1;
|
2007-10-12 08:04:54 +00:00
|
|
|
|
|
|
|
/* Fill in remaining MTD driver data */
|
2008-08-11 08:59:28 +00:00
|
|
|
mtd->type = MTD_NANDFLASH;
|
|
|
|
mtd->flags = MTD_CAP_NANDFLASH;
|
2011-12-21 21:30:40 +00:00
|
|
|
#ifdef CONFIG_MTD_WRITE
|
2008-08-11 08:59:28 +00:00
|
|
|
mtd->erase = nand_erase;
|
|
|
|
mtd->write = nand_write;
|
|
|
|
mtd->write_oob = nand_write_oob;
|
2011-04-04 09:24:47 +00:00
|
|
|
#endif
|
|
|
|
mtd->read = nand_read;
|
2011-04-07 15:59:52 +00:00
|
|
|
#ifdef CONFIG_NAND_READ_OOB
|
2011-04-04 09:24:47 +00:00
|
|
|
mtd->read_oob = nand_read_oob;
|
2011-04-07 15:59:52 +00:00
|
|
|
#endif
|
2008-08-11 08:59:28 +00:00
|
|
|
mtd->lock = NULL;
|
|
|
|
mtd->unlock = NULL;
|
|
|
|
mtd->block_isbad = nand_block_isbad;
|
2011-12-21 21:30:40 +00:00
|
|
|
#ifdef CONFIG_MTD_WRITE
|
2008-08-11 08:59:28 +00:00
|
|
|
mtd->block_markbad = nand_block_markbad;
|
2011-04-07 15:04:32 +00:00
|
|
|
#endif
|
2008-08-11 08:59:28 +00:00
|
|
|
/* propagate ecc.layout to mtd_info */
|
|
|
|
mtd->ecclayout = chip->ecc.layout;
|
|
|
|
|
|
|
|
/* Check, if we should skip the bad block table scan */
|
|
|
|
if (chip->options & NAND_SKIP_BBTSCAN)
|
|
|
|
return 0;
|
2011-04-04 12:16:42 +00:00
|
|
|
#ifdef CONFIG_NAND_BBT
|
2007-10-12 08:04:54 +00:00
|
|
|
/* Build bad block table */
|
2008-08-11 08:59:28 +00:00
|
|
|
return chip->scan_bbt(mtd);
|
2011-04-04 12:16:42 +00:00
|
|
|
#else
|
|
|
|
return 0;
|
|
|
|
#endif
|
2007-10-12 08:04:54 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2008-08-11 08:59:28 +00:00
|
|
|
* nand_scan - [NAND Interface] Scan for the NAND device
|
|
|
|
* @mtd: MTD device structure
|
|
|
|
* @maxchips: Number of chips to scan for
|
|
|
|
*
|
|
|
|
* This fills out all the uninitialized function pointers
|
|
|
|
* with the defaults.
|
|
|
|
* The flash ID is read and the mtd/chip structures are
|
|
|
|
* filled with the appropriate values.
|
|
|
|
* The mtd->owner field must be set to the module of the caller
|
|
|
|
*
|
2007-10-12 08:04:54 +00:00
|
|
|
*/
|
2008-08-11 08:59:28 +00:00
|
|
|
int nand_scan(struct mtd_info *mtd, int maxchips)
|
|
|
|
{
|
|
|
|
int ret;
|
|
|
|
|
|
|
|
ret = nand_scan_ident(mtd, maxchips);
|
|
|
|
if (!ret)
|
|
|
|
ret = nand_scan_tail(mtd);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* nand_release - [NAND Interface] Free resources held by the NAND device
|
|
|
|
* @mtd: MTD device structure
|
|
|
|
*/
|
|
|
|
void nand_release(struct mtd_info *mtd)
|
2007-10-12 08:04:54 +00:00
|
|
|
{
|
2008-08-11 08:59:28 +00:00
|
|
|
struct nand_chip *chip = mtd->priv;
|
2007-10-12 08:04:54 +00:00
|
|
|
|
|
|
|
/* Deregister the device */
|
2008-08-11 08:59:28 +00:00
|
|
|
del_mtd_device(mtd);
|
|
|
|
|
|
|
|
/* Free bad block table memory */
|
|
|
|
kfree(chip->bbt);
|
|
|
|
if (!(chip->options & NAND_OWN_BUFFERS))
|
|
|
|
kfree(chip->buffers);
|
2007-10-12 08:04:54 +00:00
|
|
|
}
|
|
|
|
|
2008-08-11 08:59:28 +00:00
|
|
|
EXPORT_SYMBOL(nand_scan);
|
|
|
|
EXPORT_SYMBOL(nand_scan_ident);
|
|
|
|
EXPORT_SYMBOL(nand_scan_tail);
|
|
|
|
EXPORT_SYMBOL(nand_release);
|
|
|
|
|
2013-04-06 10:19:56 +00:00
|
|
|
static int mtd_set_erasebad(struct param_d *param, void *priv)
|
2013-02-27 10:01:17 +00:00
|
|
|
{
|
2013-04-06 10:19:56 +00:00
|
|
|
struct mtd_info *mtd = priv;
|
2013-02-27 10:01:17 +00:00
|
|
|
|
2013-04-06 10:19:56 +00:00
|
|
|
if (!mtd->p_allow_erasebad) {
|
|
|
|
mtd->allow_erasebad = false;
|
|
|
|
return 0;
|
|
|
|
}
|
2013-02-27 10:01:17 +00:00
|
|
|
|
2013-04-06 10:19:56 +00:00
|
|
|
if (!mtd->allow_erasebad)
|
|
|
|
dev_warn(&mtd->class_dev,
|
|
|
|
"Allowing to erase bad blocks. This may be dangerous!\n");
|
2013-02-27 10:01:17 +00:00
|
|
|
|
2013-04-06 10:19:56 +00:00
|
|
|
mtd->allow_erasebad = true;
|
2013-02-27 10:01:17 +00:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2013-02-27 14:24:50 +00:00
|
|
|
static const char *mtd_get_bbt_type(struct device_d *dev, struct param_d *p)
|
|
|
|
{
|
|
|
|
struct mtd_info *mtd = container_of(dev, struct mtd_info, class_dev);
|
|
|
|
struct nand_chip *chip = mtd->priv;
|
|
|
|
const char *str;
|
|
|
|
|
|
|
|
if (!chip->bbt)
|
|
|
|
str = "none";
|
|
|
|
else if ((chip->bbt_td && chip->bbt_td->pages[0] != -1) ||
|
|
|
|
(chip->bbt_md && chip->bbt_md->pages[0] != -1))
|
|
|
|
str = "flashbased";
|
|
|
|
else
|
|
|
|
str = "memorybased";
|
|
|
|
|
|
|
|
return str;
|
|
|
|
}
|
|
|
|
|
2013-02-27 13:25:30 +00:00
|
|
|
int add_mtd_nand_device(struct mtd_info *mtd, char *devname)
|
|
|
|
{
|
|
|
|
int ret;
|
|
|
|
|
|
|
|
ret = add_mtd_device(mtd, devname);
|
|
|
|
if (ret)
|
|
|
|
return ret;
|
|
|
|
|
2013-02-27 10:01:17 +00:00
|
|
|
if (IS_ENABLED(CONFIG_NAND_ALLOW_ERASE_BAD))
|
2013-04-06 10:19:56 +00:00
|
|
|
dev_add_param_bool(&mtd->class_dev, "erasebad", mtd_set_erasebad,
|
|
|
|
NULL, &mtd->p_allow_erasebad, mtd);
|
2013-02-27 10:01:17 +00:00
|
|
|
|
2013-02-27 14:24:50 +00:00
|
|
|
dev_add_param(&mtd->class_dev, "bbt", NULL, mtd_get_bbt_type, 0);
|
|
|
|
|
2013-02-27 13:25:30 +00:00
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2009-12-15 10:32:02 +00:00
|
|
|
#endif /* DOXYGEN_SHOULD_SKIP_THIS */
|