linux/drivers/staging/mt29f_spinand/mt29f_spinand.c

974 lines
23 KiB
C
Raw Normal View History

/*
* Copyright (c) 2003-2013 Broadcom Corporation
*
* Copyright (c) 2009-2010 Micron Technology, Inc.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#include <linux/module.h>
#include <linux/delay.h>
#include <linux/mtd/mtd.h>
#include <linux/mtd/partitions.h>
#include <linux/mtd/nand.h>
#include <linux/spi/spi.h>
#include "mt29f_spinand.h"
#define BUFSIZE (10 * 64 * 2048)
#define CACHE_BUF 2112
/*
* OOB area specification layout: Total 32 available free bytes.
*/
static inline struct spinand_state *mtd_to_state(struct mtd_info *mtd)
{
struct nand_chip *chip = mtd_to_nand(mtd);
struct spinand_info *info = nand_get_controller_data(chip);
struct spinand_state *state = info->priv;
return state;
}
#ifdef CONFIG_MTD_SPINAND_ONDIEECC
static int enable_hw_ecc;
static int enable_read_hw_ecc;
static int spinand_ooblayout_64_ecc(struct mtd_info *mtd, int section,
struct mtd_oob_region *oobregion)
{
if (section > 3)
return -ERANGE;
oobregion->offset = (section * 16) + 1;
oobregion->length = 6;
return 0;
}
static int spinand_ooblayout_64_free(struct mtd_info *mtd, int section,
struct mtd_oob_region *oobregion)
{
if (section > 3)
return -ERANGE;
oobregion->offset = (section * 16) + 8;
oobregion->length = 8;
return 0;
}
static const struct mtd_ooblayout_ops spinand_oob_64_ops = {
.ecc = spinand_ooblayout_64_ecc,
.free = spinand_ooblayout_64_free,
};
#endif
/**
* spinand_cmd - process a command to send to the SPI Nand
* Description:
* Set up the command buffer to send to the SPI controller.
* The command buffer has to initialized to 0.
*/
static int spinand_cmd(struct spi_device *spi, struct spinand_cmd *cmd)
{
struct spi_message message;
struct spi_transfer x[4];
u8 dummy = 0xff;
spi_message_init(&message);
memset(x, 0, sizeof(x));
x[0].len = 1;
x[0].tx_buf = &cmd->cmd;
spi_message_add_tail(&x[0], &message);
if (cmd->n_addr) {
x[1].len = cmd->n_addr;
x[1].tx_buf = cmd->addr;
spi_message_add_tail(&x[1], &message);
}
if (cmd->n_dummy) {
x[2].len = cmd->n_dummy;
x[2].tx_buf = &dummy;
spi_message_add_tail(&x[2], &message);
}
if (cmd->n_tx) {
x[3].len = cmd->n_tx;
x[3].tx_buf = cmd->tx_buf;
spi_message_add_tail(&x[3], &message);
}
if (cmd->n_rx) {
x[3].len = cmd->n_rx;
x[3].rx_buf = cmd->rx_buf;
spi_message_add_tail(&x[3], &message);
}
return spi_sync(spi, &message);
}
/**
* spinand_read_id - Read SPI Nand ID
* Description:
* read two ID bytes from the SPI Nand device
*/
static int spinand_read_id(struct spi_device *spi_nand, u8 *id)
{
int retval;
u8 nand_id[3];
struct spinand_cmd cmd = {0};
cmd.cmd = CMD_READ_ID;
cmd.n_rx = 3;
cmd.rx_buf = &nand_id[0];
retval = spinand_cmd(spi_nand, &cmd);
if (retval < 0) {
dev_err(&spi_nand->dev, "error %d reading id\n", retval);
return retval;
}
id[0] = nand_id[1];
id[1] = nand_id[2];
return retval;
}
/**
* spinand_read_status - send command 0xf to the SPI Nand status register
* Description:
* After read, write, or erase, the Nand device is expected to set the
* busy status.
* This function is to allow reading the status of the command: read,
* write, and erase.
* Once the status turns to be ready, the other status bits also are
* valid status bits.
*/
static int spinand_read_status(struct spi_device *spi_nand, u8 *status)
{
struct spinand_cmd cmd = {0};
int ret;
cmd.cmd = CMD_READ_REG;
cmd.n_addr = 1;
cmd.addr[0] = REG_STATUS;
cmd.n_rx = 1;
cmd.rx_buf = status;
ret = spinand_cmd(spi_nand, &cmd);
if (ret < 0)
dev_err(&spi_nand->dev, "err: %d read status register\n", ret);
return ret;
}
#define MAX_WAIT_JIFFIES (40 * HZ)
static int wait_till_ready(struct spi_device *spi_nand)
{
unsigned long deadline;
int retval;
u8 stat = 0;
deadline = jiffies + MAX_WAIT_JIFFIES;
do {
retval = spinand_read_status(spi_nand, &stat);
if (retval < 0)
return -1;
if (!(stat & 0x1))
break;
cond_resched();
} while (!time_after_eq(jiffies, deadline));
if ((stat & 0x1) == 0)
return 0;
return -1;
}
/**
* spinand_get_otp - send command 0xf to read the SPI Nand OTP register
* Description:
* There is one bit( bit 0x10 ) to set or to clear the internal ECC.
* Enable chip internal ECC, set the bit to 1
* Disable chip internal ECC, clear the bit to 0
*/
static int spinand_get_otp(struct spi_device *spi_nand, u8 *otp)
{
struct spinand_cmd cmd = {0};
int retval;
cmd.cmd = CMD_READ_REG;
cmd.n_addr = 1;
cmd.addr[0] = REG_OTP;
cmd.n_rx = 1;
cmd.rx_buf = otp;
retval = spinand_cmd(spi_nand, &cmd);
if (retval < 0)
dev_err(&spi_nand->dev, "error %d get otp\n", retval);
return retval;
}
/**
* spinand_set_otp - send command 0x1f to write the SPI Nand OTP register
* Description:
* There is one bit( bit 0x10 ) to set or to clear the internal ECC.
* Enable chip internal ECC, set the bit to 1
* Disable chip internal ECC, clear the bit to 0
*/
static int spinand_set_otp(struct spi_device *spi_nand, u8 *otp)
{
int retval;
struct spinand_cmd cmd = {0};
cmd.cmd = CMD_WRITE_REG;
cmd.n_addr = 1;
cmd.addr[0] = REG_OTP;
cmd.n_tx = 1;
cmd.tx_buf = otp;
retval = spinand_cmd(spi_nand, &cmd);
if (retval < 0)
dev_err(&spi_nand->dev, "error %d set otp\n", retval);
return retval;
}
#ifdef CONFIG_MTD_SPINAND_ONDIEECC
/**
* spinand_enable_ecc - send command 0x1f to write the SPI Nand OTP register
* Description:
* There is one bit( bit 0x10 ) to set or to clear the internal ECC.
* Enable chip internal ECC, set the bit to 1
* Disable chip internal ECC, clear the bit to 0
*/
static int spinand_enable_ecc(struct spi_device *spi_nand)
{
int retval;
u8 otp = 0;
retval = spinand_get_otp(spi_nand, &otp);
if (retval < 0)
return retval;
if ((otp & OTP_ECC_MASK) == OTP_ECC_MASK)
return 0;
otp |= OTP_ECC_MASK;
retval = spinand_set_otp(spi_nand, &otp);
if (retval < 0)
return retval;
return spinand_get_otp(spi_nand, &otp);
}
#endif
static int spinand_disable_ecc(struct spi_device *spi_nand)
{
int retval;
u8 otp = 0;
retval = spinand_get_otp(spi_nand, &otp);
if (retval < 0)
return retval;
if ((otp & OTP_ECC_MASK) == OTP_ECC_MASK) {
otp &= ~OTP_ECC_MASK;
retval = spinand_set_otp(spi_nand, &otp);
if (retval < 0)
return retval;
return spinand_get_otp(spi_nand, &otp);
}
return 0;
}
/**
* spinand_write_enable - send command 0x06 to enable write or erase the
* Nand cells
* Description:
* Before write and erase the Nand cells, the write enable has to be set.
* After the write or erase, the write enable bit is automatically
* cleared (status register bit 2)
* Set the bit 2 of the status register has the same effect
*/
static int spinand_write_enable(struct spi_device *spi_nand)
{
struct spinand_cmd cmd = {0};
cmd.cmd = CMD_WR_ENABLE;
return spinand_cmd(spi_nand, &cmd);
}
static int spinand_read_page_to_cache(struct spi_device *spi_nand, u16 page_id)
{
struct spinand_cmd cmd = {0};
u16 row;
row = page_id;
cmd.cmd = CMD_READ;
cmd.n_addr = 3;
cmd.addr[1] = (u8)((row & 0xff00) >> 8);
cmd.addr[2] = (u8)(row & 0x00ff);
return spinand_cmd(spi_nand, &cmd);
}
/**
* spinand_read_from_cache - send command 0x03 to read out the data from the
* cache register (2112 bytes max)
* Description:
* The read can specify 1 to 2112 bytes of data read at the corresponding
* locations.
* No tRd delay.
*/
static int spinand_read_from_cache(struct spi_device *spi_nand, u16 page_id,
u16 byte_id, u16 len, u8 *rbuf)
{
struct spinand_cmd cmd = {0};
u16 column;
column = byte_id;
cmd.cmd = CMD_READ_RDM;
cmd.n_addr = 3;
cmd.addr[0] = (u8)((column & 0xff00) >> 8);
cmd.addr[0] |= (u8)(((page_id >> 6) & 0x1) << 4);
cmd.addr[1] = (u8)(column & 0x00ff);
cmd.addr[2] = (u8)(0xff);
cmd.n_dummy = 0;
cmd.n_rx = len;
cmd.rx_buf = rbuf;
return spinand_cmd(spi_nand, &cmd);
}
/**
* spinand_read_page - read a page
* @page_id: the physical page number
* @offset: the location from 0 to 2111
* @len: number of bytes to read
* @rbuf: read buffer to hold @len bytes
*
* Description:
* The read includes two commands to the Nand - 0x13 and 0x03 commands
* Poll to read status to wait for tRD time.
*/
static int spinand_read_page(struct spi_device *spi_nand, u16 page_id,
u16 offset, u16 len, u8 *rbuf)
{
int ret;
u8 status = 0;
#ifdef CONFIG_MTD_SPINAND_ONDIEECC
if (enable_read_hw_ecc) {
if (spinand_enable_ecc(spi_nand) < 0)
dev_err(&spi_nand->dev, "enable HW ECC failed!");
}
#endif
ret = spinand_read_page_to_cache(spi_nand, page_id);
if (ret < 0)
return ret;
if (wait_till_ready(spi_nand))
dev_err(&spi_nand->dev, "WAIT timedout!!!\n");
while (1) {
ret = spinand_read_status(spi_nand, &status);
if (ret < 0) {
dev_err(&spi_nand->dev,
"err %d read status register\n", ret);
return ret;
}
if ((status & STATUS_OIP_MASK) == STATUS_READY) {
if ((status & STATUS_ECC_MASK) == STATUS_ECC_ERROR) {
dev_err(&spi_nand->dev, "ecc error, page=%d\n",
page_id);
return 0;
}
break;
}
}
ret = spinand_read_from_cache(spi_nand, page_id, offset, len, rbuf);
if (ret < 0) {
dev_err(&spi_nand->dev, "read from cache failed!!\n");
return ret;
}
#ifdef CONFIG_MTD_SPINAND_ONDIEECC
if (enable_read_hw_ecc) {
ret = spinand_disable_ecc(spi_nand);
if (ret < 0) {
dev_err(&spi_nand->dev, "disable ecc failed!!\n");
return ret;
}
enable_read_hw_ecc = 0;
}
#endif
return ret;
}
/**
* spinand_program_data_to_cache - write a page to cache
* @byte_id: the location to write to the cache
* @len: number of bytes to write
* @wbuf: write buffer holding @len bytes
*
* Description:
* The write command used here is 0x84--indicating that the cache is
* not cleared first.
* Since it is writing the data to cache, there is no tPROG time.
*/
static int spinand_program_data_to_cache(struct spi_device *spi_nand,
u16 page_id, u16 byte_id,
u16 len, u8 *wbuf)
{
struct spinand_cmd cmd = {0};
u16 column;
column = byte_id;
cmd.cmd = CMD_PROG_PAGE_CLRCACHE;
cmd.n_addr = 2;
cmd.addr[0] = (u8)((column & 0xff00) >> 8);
cmd.addr[0] |= (u8)(((page_id >> 6) & 0x1) << 4);
cmd.addr[1] = (u8)(column & 0x00ff);
cmd.n_tx = len;
cmd.tx_buf = wbuf;
return spinand_cmd(spi_nand, &cmd);
}
/**
* spinand_program_execute - write a page from cache to the Nand array
* @page_id: the physical page location to write the page.
*
* Description:
* The write command used here is 0x10--indicating the cache is writing to
* the Nand array.
* Need to wait for tPROG time to finish the transaction.
*/
static int spinand_program_execute(struct spi_device *spi_nand, u16 page_id)
{
struct spinand_cmd cmd = {0};
u16 row;
row = page_id;
cmd.cmd = CMD_PROG_PAGE_EXC;
cmd.n_addr = 3;
cmd.addr[1] = (u8)((row & 0xff00) >> 8);
cmd.addr[2] = (u8)(row & 0x00ff);
return spinand_cmd(spi_nand, &cmd);
}
/**
* spinand_program_page - write a page
* @page_id: the physical page location to write the page.
* @offset: the location from the cache starting from 0 to 2111
* @len: the number of bytes to write
* @buf: the buffer holding @len bytes
*
* Description:
* The commands used here are 0x06, 0x84, and 0x10--indicating that
* the write enable is first sent, the write cache command, and the
* write execute command.
* Poll to wait for the tPROG time to finish the transaction.
*/
static int spinand_program_page(struct spi_device *spi_nand,
u16 page_id, u16 offset, u16 len, u8 *buf)
{
int retval;
u8 status = 0;
u8 *wbuf;
#ifdef CONFIG_MTD_SPINAND_ONDIEECC
unsigned int i, j;
wbuf = devm_kzalloc(&spi_nand->dev, CACHE_BUF, GFP_KERNEL);
if (!wbuf)
return -ENOMEM;
enable_read_hw_ecc = 0;
spinand_read_page(spi_nand, page_id, 0, CACHE_BUF, wbuf);
for (i = offset, j = 0; i < len; i++, j++)
wbuf[i] &= buf[j];
if (enable_hw_ecc) {
retval = spinand_enable_ecc(spi_nand);
if (retval < 0) {
dev_err(&spi_nand->dev, "enable ecc failed!!\n");
return retval;
}
}
#else
wbuf = buf;
#endif
retval = spinand_write_enable(spi_nand);
if (retval < 0) {
dev_err(&spi_nand->dev, "write enable failed!!\n");
return retval;
}
if (wait_till_ready(spi_nand))
dev_err(&spi_nand->dev, "wait timedout!!!\n");
retval = spinand_program_data_to_cache(spi_nand, page_id,
offset, len, wbuf);
if (retval < 0)
return retval;
retval = spinand_program_execute(spi_nand, page_id);
if (retval < 0)
return retval;
while (1) {
retval = spinand_read_status(spi_nand, &status);
if (retval < 0) {
dev_err(&spi_nand->dev,
"error %d reading status register\n", retval);
return retval;
}
if ((status & STATUS_OIP_MASK) == STATUS_READY) {
if ((status & STATUS_P_FAIL_MASK) == STATUS_P_FAIL) {
dev_err(&spi_nand->dev,
"program error, page %d\n", page_id);
return -1;
}
break;
}
}
#ifdef CONFIG_MTD_SPINAND_ONDIEECC
if (enable_hw_ecc) {
retval = spinand_disable_ecc(spi_nand);
if (retval < 0) {
dev_err(&spi_nand->dev, "disable ecc failed!!\n");
return retval;
}
enable_hw_ecc = 0;
}
#endif
return 0;
}
/**
* spinand_erase_block_erase - erase a page
* @block_id: the physical block location to erase.
*
* Description:
* The command used here is 0xd8--indicating an erase command to erase
* one block--64 pages
* Need to wait for tERS.
*/
static int spinand_erase_block_erase(struct spi_device *spi_nand, u16 block_id)
{
struct spinand_cmd cmd = {0};
u16 row;
row = block_id;
cmd.cmd = CMD_ERASE_BLK;
cmd.n_addr = 3;
cmd.addr[1] = (u8)((row & 0xff00) >> 8);
cmd.addr[2] = (u8)(row & 0x00ff);
return spinand_cmd(spi_nand, &cmd);
}
/**
* spinand_erase_block - erase a page
* @block_id: the physical block location to erase.
*
* Description:
* The commands used here are 0x06 and 0xd8--indicating an erase
* command to erase one block--64 pages
* It will first to enable the write enable bit (0x06 command),
* and then send the 0xd8 erase command
* Poll to wait for the tERS time to complete the tranaction.
*/
static int spinand_erase_block(struct spi_device *spi_nand, u16 block_id)
{
int retval;
u8 status = 0;
retval = spinand_write_enable(spi_nand);
if (wait_till_ready(spi_nand))
dev_err(&spi_nand->dev, "wait timedout!!!\n");
retval = spinand_erase_block_erase(spi_nand, block_id);
while (1) {
retval = spinand_read_status(spi_nand, &status);
if (retval < 0) {
dev_err(&spi_nand->dev,
"error %d reading status register\n", retval);
return retval;
}
if ((status & STATUS_OIP_MASK) == STATUS_READY) {
if ((status & STATUS_E_FAIL_MASK) == STATUS_E_FAIL) {
dev_err(&spi_nand->dev,
"erase error, block %d\n", block_id);
return -1;
}
break;
}
}
return 0;
}
#ifdef CONFIG_MTD_SPINAND_ONDIEECC
static int spinand_write_page_hwecc(struct mtd_info *mtd,
struct nand_chip *chip,
MTD updates for 4.4-rc1: Core * WARN (in some cases) when a struct mtd_info is registered multiple times; in the past this was "supported", but it's still error prone for future development. There's only one ugly case of this left in the tree (that we're aware of) and the owners are aware of the problems there. * fix potential deadlock in the blkdev removal path NOTE: the (potential) deadlock was introduced in a for-stable patch. This one is also marked for -stable. * ioctl(BLKPG) compat_ioctl support; resolves issues with 32-bit user space vs. 64-bit kernel space * Set MTD parent device correctly throughout the tree, so the tree structure appears correctly in sysfs; many drivers were missing this (soft) requirement * Move device tree partitions (ofpart) into a dedicated 'partitions' subnode; this helps to disambiguate whether a node is a partition or some other auxiliary data * Improve error handling for partitioning failures NAND * General: Increase timeout period, for corner-case systems with less-than-accurate jiffies * Fix OF-based autoloading of several NAND drivers when built as modules * pxa3xx_nand: - Rework timing configuration to be more dynamic - Refactor PM support * brcmnand: prepare for NorthStar 2 support (ARM64, 16-bit NAND chips) * sunxi_nand: refactoring and a few bug fixes * vf610: new NAND driver * FSMC: add SW BCH support; support common NAND DT bindings * lpc32xx_slc: refactor and improve timing calculations logic * denali: support for rev 5.1 SPI NOR * Layering improvements * Added Winbond lock/unlock support * Added mtd_is_locked() (i.e., ioctl(MEMISLOCKED)) support * Increase full-chip-erase timeout linearly with flash size * fsl-quadspi: fix compile for non-ARM architectures * New flash support -----BEGIN PGP SIGNATURE----- Version: GnuPG v1 iQIcBAABAgAGBQJWPPj0AAoJEFySrpd9RFgtJEgP/RnfXRHBX51cUl4r8XrxiGtz zlH5zFOCYWEOtlGjoD25wp+A5RRjWi62At6KmLJZncf0clJ65fyKHjt/JEg6YuI6 DUTMepTwyC2Wh7Ux1ZEH3KOnl64xh5p+Wf7Tl4yUr0DCd26VEwE9o7tPRlahv9nx OhGCWS+uSsxW0Q2wDLCypFzXsnDBeoGxDO7VCIzle4d3aJ4PCcQIXINlr6ZYpocT VTTadPCMsmYq6AgV5W3KYGYLj62ITiN2YxdJRacg+QkKLfl21u2wVy9Ahk/oj5TG bV0DHiz6ky1F2K/bvJibcRFABiYup9UXIo1IzwLloSxEJ/GfennMC29xn9K/0gid e2kO/Ajh/bihgJXzoAoZD/40YJK40X5VW9rQZgo482sMBGLmJOzZiOHOIEXaVohs djQ7sbCwPmLwqp7C+6WTn8frp6ntIe9iXdmjDuR/WlPP0Sh5rI3cUeBQrJXEYxwc aYt1Zxkst6gEMPQJ/S2TiKwWm0BxVWEUEjKmt9FPWOaQnwmoeju0Y/6jIvs1TQKM vO8cmS17QyPUWT2kGIDmZ51KayY26uDC8/NA2t1HDYCiFbpDp61kgu2wyoBUTg7q YIAvjtnwOaG9qk0SLfZu4FEgNi4a/bC1bxGxChsi+S2krpNQAeMlPY394cf6OdsE j+CV/Ko0DguO26bO0MWr =UzSW -----END PGP SIGNATURE----- Merge tag 'for-linus-20151106' of git://git.infradead.org/linux-mtd Pull MTD updates from Brian Norris: "Core: - WARN (in some cases) when a struct mtd_info is registered multiple times; in the past this was "supported", but it's still error prone for future development. There's only one ugly case of this left in the tree (that we're aware of) and the owners are aware of the problems there. - fix potential deadlock in the blkdev removal path NOTE: the (potential) deadlock was introduced in a for-stable patch. This one is also marked for -stable. - ioctl(BLKPG) compat_ioctl support; resolves issues with 32-bit user space vs 64-bit kernel space - Set MTD parent device correctly throughout the tree, so the tree structure appears correctly in sysfs; many drivers were missing this (soft) requirement - Move device tree partitions (ofpart) into a dedicated 'partitions' subnode; this helps to disambiguate whether a node is a partition or some other auxiliary data - Improve error handling for partitioning failures NAND: - General: Increase timeout period, for corner-case systems with less-than-accurate jiffies - Fix OF-based autoloading of several NAND drivers when built as modules - pxa3xx_nand: - Rework timing configuration to be more dynamic - Refactor PM support - brcmnand: prepare for NorthStar 2 support (ARM64, 16-bit NAND chips) - sunxi_nand: refactoring and a few bug fixes - vf610: new NAND driver - FSMC: add SW BCH support; support common NAND DT bindings - lpc32xx_slc: refactor and improve timing calculations logic - denali: support for rev 5.1 SPI NOR: - Layering improvements - Added Winbond lock/unlock support - Added mtd_is_locked() (i.e., ioctl(MEMISLOCKED)) support - Increase full-chip-erase timeout linearly with flash size - fsl-quadspi: fix compile for non-ARM architectures - New flash support" * tag 'for-linus-20151106' of git://git.infradead.org/linux-mtd: (169 commits) mtd: don't WARN about overloaded users of mtd->reboot_notifier.notifier_call mtd: nand: sunxi: avoid retrieving data before ECC pass mtd: nand: sunxi: fix sunxi_nfc_hw_ecc_read/write_chunk() mtd: blkdevs: fix potential deadlock + lockdep warnings mtd: ofpart: move ofpart partitions to a dedicated dt node doc: dt: mtd: support partitions in a special 'partitions' subnode mtd: brcmnand: Force 8bit mode before doing nand_scan_ident() mtd: brcmnand: factor out CFG and CFG_EXT bitfields mtd: mtdpart: Do not fail mtd probe when parsing partitions fails mtd: fsl-quadspi: fix macro collision problems with READ/WRITE mtd: warn when registering the same master many times mtd: fixup corner case error handling in mtd_device_parse_register() mtd: tests: Replace timeval with ktime_t mtd: fsmc_nand: Add BCH4 SW ECC support for SPEAr600 mtd: nand: vf610_nfc: use nand_check_erased_ecc_chunk() helper mtd: nand: increase ready wait timeout and report timeouts mtd: docg3: off by one in doc_register_sysfs() mtd: pxa3xx_nand: clean up the pxa3xx timings mtd: pxa3xx_nand: rework flash detection and timing setup mtd: pxa3xx_nand: add helpers to setup the timings ...
2015-11-06 20:50:24 +01:00
const u8 *buf, int oob_required,
int page)
{
const u8 *p = buf;
int eccsize = chip->ecc.size;
int eccsteps = chip->ecc.steps;
enable_hw_ecc = 1;
chip->write_buf(mtd, p, eccsize * eccsteps);
return 0;
}
static int spinand_read_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip,
u8 *buf, int oob_required, int page)
{
int retval;
u8 status;
u8 *p = buf;
int eccsize = chip->ecc.size;
int eccsteps = chip->ecc.steps;
struct spinand_info *info = nand_get_controller_data(chip);
enable_read_hw_ecc = 1;
chip->read_buf(mtd, p, eccsize * eccsteps);
if (oob_required)
chip->read_buf(mtd, chip->oob_poi, mtd->oobsize);
while (1) {
retval = spinand_read_status(info->spi, &status);
if (retval < 0) {
dev_err(&mtd->dev,
"error %d reading status register\n", retval);
return retval;
}
if ((status & STATUS_OIP_MASK) == STATUS_READY) {
if ((status & STATUS_ECC_MASK) == STATUS_ECC_ERROR) {
pr_info("spinand: ECC error\n");
mtd->ecc_stats.failed++;
} else if ((status & STATUS_ECC_MASK) ==
STATUS_ECC_1BIT_CORRECTED)
mtd->ecc_stats.corrected++;
break;
}
}
return 0;
}
#endif
static void spinand_select_chip(struct mtd_info *mtd, int dev)
{
}
static u8 spinand_read_byte(struct mtd_info *mtd)
{
struct spinand_state *state = mtd_to_state(mtd);
u8 data;
data = state->buf[state->buf_ptr];
state->buf_ptr++;
return data;
}
static int spinand_wait(struct mtd_info *mtd, struct nand_chip *chip)
{
struct spinand_info *info = nand_get_controller_data(chip);
unsigned long timeo = jiffies;
int retval, state = chip->state;
u8 status;
if (state == FL_ERASING)
timeo += (HZ * 400) / 1000;
else
timeo += (HZ * 20) / 1000;
while (time_before(jiffies, timeo)) {
retval = spinand_read_status(info->spi, &status);
if (retval < 0) {
dev_err(&mtd->dev,
"error %d reading status register\n", retval);
return retval;
}
if ((status & STATUS_OIP_MASK) == STATUS_READY)
return 0;
cond_resched();
}
return 0;
}
static void spinand_write_buf(struct mtd_info *mtd, const u8 *buf, int len)
{
struct spinand_state *state = mtd_to_state(mtd);
memcpy(state->buf + state->buf_ptr, buf, len);
state->buf_ptr += len;
}
static void spinand_read_buf(struct mtd_info *mtd, u8 *buf, int len)
{
struct spinand_state *state = mtd_to_state(mtd);
memcpy(buf, state->buf + state->buf_ptr, len);
state->buf_ptr += len;
}
/*
* spinand_reset- send RESET command "0xff" to the Nand device.
*/
static void spinand_reset(struct spi_device *spi_nand)
{
struct spinand_cmd cmd = {0};
cmd.cmd = CMD_RESET;
if (spinand_cmd(spi_nand, &cmd) < 0)
pr_info("spinand reset failed!\n");
/* elapse 1ms before issuing any other command */
usleep_range(1000, 2000);
if (wait_till_ready(spi_nand))
dev_err(&spi_nand->dev, "wait timedout!\n");
}
static void spinand_cmdfunc(struct mtd_info *mtd, unsigned int command,
int column, int page)
{
struct nand_chip *chip = mtd_to_nand(mtd);
struct spinand_info *info = nand_get_controller_data(chip);
struct spinand_state *state = info->priv;
switch (command) {
/*
* READ0 - read in first 0x800 bytes
*/
case NAND_CMD_READ1:
case NAND_CMD_READ0:
state->buf_ptr = 0;
spinand_read_page(info->spi, page, 0x0, 0x840, state->buf);
break;
/* READOOB reads only the OOB because no ECC is performed. */
case NAND_CMD_READOOB:
state->buf_ptr = 0;
spinand_read_page(info->spi, page, 0x800, 0x40, state->buf);
break;
case NAND_CMD_RNDOUT:
state->buf_ptr = column;
break;
case NAND_CMD_READID:
state->buf_ptr = 0;
spinand_read_id(info->spi, state->buf);
break;
case NAND_CMD_PARAM:
state->buf_ptr = 0;
break;
/* ERASE1 stores the block and page address */
case NAND_CMD_ERASE1:
spinand_erase_block(info->spi, page);
break;
/* ERASE2 uses the block and page address from ERASE1 */
case NAND_CMD_ERASE2:
break;
/* SEQIN sets up the addr buffer and all registers except the length */
case NAND_CMD_SEQIN:
state->col = column;
state->row = page;
state->buf_ptr = 0;
break;
/* PAGEPROG reuses all of the setup from SEQIN and adds the length */
case NAND_CMD_PAGEPROG:
spinand_program_page(info->spi, state->row, state->col,
state->buf_ptr, state->buf);
break;
case NAND_CMD_STATUS:
spinand_get_otp(info->spi, state->buf);
if (!(state->buf[0] & 0x80))
state->buf[0] = 0x80;
state->buf_ptr = 0;
break;
/* RESET command */
case NAND_CMD_RESET:
if (wait_till_ready(info->spi))
dev_err(&info->spi->dev, "WAIT timedout!!!\n");
/* a minimum of 250us must elapse before issuing RESET cmd*/
usleep_range(250, 1000);
spinand_reset(info->spi);
break;
default:
dev_err(&mtd->dev, "Unknown CMD: 0x%x\n", command);
}
}
/**
* spinand_lock_block - send write register 0x1f command to the Nand device
*
* Description:
* After power up, all the Nand blocks are locked. This function allows
* one to unlock the blocks, and so it can be written or erased.
*/
static int spinand_lock_block(struct spi_device *spi_nand, u8 lock)
{
struct spinand_cmd cmd = {0};
int ret;
u8 otp = 0;
ret = spinand_get_otp(spi_nand, &otp);
cmd.cmd = CMD_WRITE_REG;
cmd.n_addr = 1;
cmd.addr[0] = REG_BLOCK_LOCK;
cmd.n_tx = 1;
cmd.tx_buf = &lock;
ret = spinand_cmd(spi_nand, &cmd);
if (ret < 0)
dev_err(&spi_nand->dev, "error %d lock block\n", ret);
return ret;
}
/**
* spinand_probe - [spinand Interface]
* @spi_nand: registered device driver.
*
* Description:
* Set up the device driver parameters to make the device available.
*/
static int spinand_probe(struct spi_device *spi_nand)
{
struct mtd_info *mtd;
struct nand_chip *chip;
struct spinand_info *info;
struct spinand_state *state;
info = devm_kzalloc(&spi_nand->dev, sizeof(struct spinand_info),
GFP_KERNEL);
if (!info)
return -ENOMEM;
info->spi = spi_nand;
spinand_lock_block(spi_nand, BL_ALL_UNLOCKED);
state = devm_kzalloc(&spi_nand->dev, sizeof(struct spinand_state),
GFP_KERNEL);
if (!state)
return -ENOMEM;
info->priv = state;
state->buf_ptr = 0;
state->buf = devm_kzalloc(&spi_nand->dev, BUFSIZE, GFP_KERNEL);
if (!state->buf)
return -ENOMEM;
chip = devm_kzalloc(&spi_nand->dev, sizeof(struct nand_chip),
GFP_KERNEL);
if (!chip)
return -ENOMEM;
#ifdef CONFIG_MTD_SPINAND_ONDIEECC
chip->ecc.mode = NAND_ECC_HW;
chip->ecc.size = 0x200;
chip->ecc.bytes = 0x6;
chip->ecc.steps = 0x4;
chip->ecc.strength = 1;
chip->ecc.total = chip->ecc.steps * chip->ecc.bytes;
chip->ecc.read_page = spinand_read_page_hwecc;
chip->ecc.write_page = spinand_write_page_hwecc;
#else
chip->ecc.mode = NAND_ECC_SOFT;
chip->ecc.algo = NAND_ECC_HAMMING;
if (spinand_disable_ecc(spi_nand) < 0)
dev_info(&spi_nand->dev, "%s: disable ecc failed!\n",
__func__);
#endif
nand_set_flash_node(chip, spi_nand->dev.of_node);
nand_set_controller_data(chip, info);
chip->read_buf = spinand_read_buf;
chip->write_buf = spinand_write_buf;
chip->read_byte = spinand_read_byte;
chip->cmdfunc = spinand_cmdfunc;
chip->waitfunc = spinand_wait;
chip->options |= NAND_CACHEPRG;
chip->select_chip = spinand_select_chip;
chip->onfi_set_features = nand_onfi_get_set_features_notsupp;
chip->onfi_get_features = nand_onfi_get_set_features_notsupp;
mtd = nand_to_mtd(chip);
dev_set_drvdata(&spi_nand->dev, mtd);
mtd->dev.parent = &spi_nand->dev;
mtd->oobsize = 64;
#ifdef CONFIG_MTD_SPINAND_ONDIEECC
mtd_set_ooblayout(mtd, &spinand_oob_64_ops);
#endif
if (nand_scan(mtd, 1))
return -ENXIO;
return mtd_device_register(mtd, NULL, 0);
}
/**
* spinand_remove - remove the device driver
* @spi: the spi device.
*
* Description:
* Remove the device driver parameters and free up allocated memories.
*/
static int spinand_remove(struct spi_device *spi)
{
mtd_device_unregister(dev_get_drvdata(&spi->dev));
return 0;
}
static const struct of_device_id spinand_dt[] = {
{ .compatible = "spinand,mt29f", },
{}
};
MODULE_DEVICE_TABLE(of, spinand_dt);
/*
* Device name structure description
*/
static struct spi_driver spinand_driver = {
.driver = {
.name = "mt29f",
.of_match_table = spinand_dt,
},
.probe = spinand_probe,
.remove = spinand_remove,
};
module_spi_driver(spinand_driver);
MODULE_DESCRIPTION("SPI NAND driver for Micron");
MODULE_AUTHOR("Henry Pan <hspan@micron.com>, Kamlakant Patel <kamlakant.patel@broadcom.com>");
MODULE_LICENSE("GPL v2");