MTD NAND: Beginning of software ECC logic
This commit is contained in:
parent
22d4eb9cca
commit
3faa880ef1
13 changed files with 806 additions and 116 deletions
|
|
@ -6081,4 +6081,6 @@
|
|||
NAND support (2013-11-17).
|
||||
* drivers/mtd/mtd_nandscheme.c: More NAND support (2013-11-17).
|
||||
* include/nuttx/mtd/nand_ecc.h: More NAND (2013-11-17).
|
||||
|
||||
* drivers/mtd/hamming.c and mtd_nandecc.c and
|
||||
include/nuttx/mtd/hamming.h: Beginning of NAND software ECC
|
||||
calculations. (2013-11-18).
|
||||
|
|
|
|||
|
|
@ -42,12 +42,29 @@
|
|||
|
||||
#include <nuttx/config.h>
|
||||
|
||||
#include <nuttx/mtd/nand_raw.h>
|
||||
|
||||
#include "chip.h"
|
||||
#include "chip/sam_hsmc.h"
|
||||
|
||||
/****************************************************************************
|
||||
* Pre-processor Definitions
|
||||
****************************************************************************/
|
||||
/* Hardware ECC types. These are extensions to the NANDECC_HWECC value
|
||||
* defined in include/nuttx/mtd/nand_raw.h.
|
||||
*
|
||||
* NANDECC_CHIPECC ECC is performed internal to chip
|
||||
* NANDECC_PMECC Programmable Multibit Error Correcting Code (PMECC)
|
||||
* NANDECC_HSIAO HSIAO ECC
|
||||
*/
|
||||
|
||||
#define NANDECC_CHIPECC (NANDECC_HWECC + 0)
|
||||
#define NANDECC_PMECC (NANDECC_HWECC + 1)
|
||||
#define NANDECC_HSIAO (NANDECC_HWECC + 2)
|
||||
|
||||
/****************************************************************************
|
||||
* Public Data
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef __ASSEMBLY__
|
||||
|
||||
|
|
|
|||
|
|
@ -87,12 +87,6 @@ config ARCH_NAND_HWECC
|
|||
|
||||
if MTD_NAND
|
||||
|
||||
config MTD_NAND_BLOCKCHECK
|
||||
bool "Block check"
|
||||
default y
|
||||
---help---
|
||||
Enable support for bad block checking.
|
||||
|
||||
config MTD_NAND_MAXNUMBLOCKS
|
||||
int "Max blocks"
|
||||
default 1024
|
||||
|
|
@ -123,6 +117,28 @@ config MTD_NAND_MAXSPAREECCBYTES
|
|||
---help---
|
||||
Maximum number of ECC bytes stored in the spare for one single page.
|
||||
|
||||
config MTD_NAND_BLOCKCHECK
|
||||
bool "Block check"
|
||||
default y
|
||||
---help---
|
||||
Enable support for ECC and bad block checking.
|
||||
|
||||
if MTD_NAND_BLOCKCHECK
|
||||
|
||||
config MTD_NAND_SWECC
|
||||
bool "Sofware ECC support"
|
||||
default n if ARCH_NAND_HWECC
|
||||
default y if !ARCH_NAND_HWECC
|
||||
---help---
|
||||
Build in logic to support software calculation of ECC.
|
||||
|
||||
config MTD_NAND_HWECC
|
||||
bool "Hardware ECC support"
|
||||
default n
|
||||
depends on ARCH_NAND_HWECC
|
||||
---help---
|
||||
Build in logic to support hardware calculation of ECC.
|
||||
|
||||
config MTD_NAND_MAXSPAREEXTRABYTES
|
||||
int "Max extra free bytes"
|
||||
default 206
|
||||
|
|
@ -132,7 +148,7 @@ config MTD_NAND_MAXSPAREEXTRABYTES
|
|||
config MTD_NAND_MAX_HWECCSIZE
|
||||
int "Max H/W ECC size"
|
||||
default 200
|
||||
depends on ARCH_NAND_HWECC
|
||||
depends on MTD_NAND_HWECC
|
||||
---help---
|
||||
Maximum HW ECC size
|
||||
|
||||
|
|
|
|||
|
|
@ -46,8 +46,10 @@ CSRCS += mtd_partition.c
|
|||
endif
|
||||
|
||||
ifeq ($(CONFIG_MTD_NAND),y)
|
||||
CSRCS += mtd_nand.c mtd_onfi.c mtd_nandscheme.c mtd_nandraw.c
|
||||
CSRCS += mtd_nandmodel.c mtd_modeltab.c
|
||||
CSRCS += mtd_nand.c mtd_onfi.c mtd_nandscheme.c mtd_nandmodel.c mtd_modeltab.c
|
||||
ifeq ($(CONFIG_MTD_NAND_BLOCKCHECK),y)
|
||||
CSRCS += mtd_nandecc.c hamming.c
|
||||
endif
|
||||
endif
|
||||
|
||||
ifeq ($(CONFIG_RAMMTD),y)
|
||||
|
|
|
|||
451
drivers/mtd/hamming.c
Normal file
451
drivers/mtd/hamming.c
Normal file
|
|
@ -0,0 +1,451 @@
|
|||
/****************************************************************************
|
||||
* drivers/mtd/hamming.c
|
||||
*
|
||||
* Copyright (C) 2013 Gregory Nutt. All rights reserved.
|
||||
* Author: Gregory Nutt <gnutt@nuttx.org>
|
||||
*
|
||||
* This logic was taken directly from Atmel sample code with only
|
||||
* modifications for better integration with NuttX. The Atmel sample
|
||||
* code has a BSD compatibile license that requires this copyright notice:
|
||||
*
|
||||
* Copyright (c) 2011, Atmel Corporation
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in
|
||||
* the documentation and/or other materials provided with the
|
||||
* distribution.
|
||||
* 3. Neither the names NuttX nor Atmel nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
|
||||
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
|
||||
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
|
||||
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Included Files
|
||||
****************************************************************************/
|
||||
|
||||
#include <nuttx/config.h>
|
||||
#include <nuttx/mtd/nand_config.h>
|
||||
|
||||
#include <stdint.h>
|
||||
#include <assert.h>
|
||||
#include <debug.h>
|
||||
|
||||
#include <nuttx/mtd/hamming.h>
|
||||
|
||||
/****************************************************************************
|
||||
* Private Functions
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Name: bitsinbyte
|
||||
*
|
||||
* Description:
|
||||
* Counts the number of bits set to '1' in the given byte.
|
||||
*
|
||||
* Input Parameters:
|
||||
* bytes - The byte to use.
|
||||
*
|
||||
* Returned Values:
|
||||
* Returns the number of bits set to '1' in the given byte.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
static unsigned int bitsinbyte(uint8_t byte)
|
||||
{
|
||||
unsigned int count = 0;
|
||||
|
||||
while (byte != 0)
|
||||
{
|
||||
if ((byte & 1) != 0)
|
||||
{
|
||||
count++;
|
||||
}
|
||||
byte >>= 1;
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: bitsincode256
|
||||
*
|
||||
* Description:
|
||||
* Counts the number of bits set to '1' in the given hamming code.
|
||||
*
|
||||
* Input Parameters:
|
||||
* code - Hamming code
|
||||
*
|
||||
* Returned Values:
|
||||
* Returns the number of bits set to '1' in the given hamming code.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
static uint8_t bitsincode256(FAR uint8_t *code)
|
||||
{
|
||||
return bitsinbyte(code[0]) + bitsinbyte(code[1]) + bitsinbyte(code[2]);
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: compute256
|
||||
*
|
||||
* Description:
|
||||
* Calculates the 22-bit hamming code for a 256-bytes block of data.
|
||||
*
|
||||
* Input Parameters:
|
||||
* data - Data buffer to calculate code
|
||||
* code - Pointer to a buffer where the code should be stored
|
||||
*
|
||||
* Returned Values:
|
||||
* None
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
static void compute256(FAR const uint8_t *data, FAR uint8_t *code)
|
||||
{
|
||||
uint8_t colsum = 0;
|
||||
uint8_t evenline = 0;
|
||||
uint8_t oddline = 0;
|
||||
uint8_t evencol = 0;
|
||||
uint8_t oddcol = 0;
|
||||
int i;
|
||||
|
||||
/* Xor all bytes together to get the column sum;
|
||||
* At the same time, calculate the even and odd line codes
|
||||
*/
|
||||
|
||||
for (i = 0; i < 256; i++)
|
||||
{
|
||||
colsum ^= data[i];
|
||||
|
||||
/* If the xor sum of the byte is 0, then this byte has no incidence on
|
||||
* the computed code; so check if the sum is 1.
|
||||
*/
|
||||
|
||||
if ((bitsinbyte(data[i]) & 1) == 1)
|
||||
{
|
||||
/* Parity groups are formed by forcing a particular index bit to 0
|
||||
* (even) or 1 (odd).
|
||||
* Example on one byte:
|
||||
*
|
||||
* bits (dec) 7 6 5 4 3 2 1 0
|
||||
* (bin) 111 110 101 100 011 010 001 000
|
||||
* '---'---'---'----------.
|
||||
* |
|
||||
* groups P4' ooooooooooooooo eeeeeeeeeeeeeee P4 |
|
||||
* P2' ooooooo eeeeeee ooooooo eeeeeee P2 |
|
||||
* P1' ooo eee ooo eee ooo eee ooo eee P1 |
|
||||
* |
|
||||
* We can see that: |
|
||||
* - P4 -> bit 2 of index is 0 --------------------'
|
||||
* - P4' -> bit 2 of index is 1.
|
||||
* - P2 -> bit 1 of index if 0.
|
||||
* - etc...
|
||||
* We deduce that a bit position has an impact on all even Px if
|
||||
* the log2(x)nth bit of its index is 0
|
||||
* ex: log2(4) = 2, bit2 of the index must be 0 (-> 0 1 2 3)
|
||||
* and on all odd Px' if the log2(x)nth bit of its index is 1
|
||||
* ex: log2(2) = 1, bit1 of the index must be 1 (-> 0 1 4 5)
|
||||
*
|
||||
* As such, we calculate all the possible Px and Px' values at the
|
||||
* same time in two variables, evenline and oddline, such as
|
||||
* evenline bits: P128 P64 P32 P16 P8 P4 P2 P1
|
||||
* oddline bits: P128' P64' P32' P16' P8' P4' P2' P1'
|
||||
*/
|
||||
|
||||
evenline ^= (255 - i);
|
||||
oddline ^= i;
|
||||
}
|
||||
}
|
||||
|
||||
/* At this point, we have the line parities, and the column sum. First, We
|
||||
* must caculate the parity group values on the column sum.
|
||||
*/
|
||||
|
||||
for (i = 0; i < 8; i++)
|
||||
{
|
||||
if (colsum & 1)
|
||||
{
|
||||
evencol ^= (7 - i);
|
||||
oddcol ^= i;
|
||||
}
|
||||
|
||||
colsum >>= 1;
|
||||
}
|
||||
|
||||
/* Now, we must interleave the parity values, to obtain the following layout:
|
||||
* Code[0] = Line1
|
||||
* Code[1] = Line2
|
||||
* Code[2] = Column
|
||||
* Line = Px' Px P(x-1)- P(x-1) ...
|
||||
* Column = P4' P4 P2' P2 P1' P1 PadBit PadBit
|
||||
*/
|
||||
|
||||
code[0] = 0;
|
||||
code[1] = 0;
|
||||
code[2] = 0;
|
||||
|
||||
for (i = 0; i < 4; i++)
|
||||
{
|
||||
code[0] <<= 2;
|
||||
code[1] <<= 2;
|
||||
code[2] <<= 2;
|
||||
|
||||
/* Line 1 */
|
||||
|
||||
if ((oddline & 0x80) != 0)
|
||||
{
|
||||
code[0] |= 2;
|
||||
}
|
||||
|
||||
if ((evenline & 0x80) != 0)
|
||||
{
|
||||
code[0] |= 1;
|
||||
}
|
||||
|
||||
/* Line 2 */
|
||||
|
||||
if ((oddline & 0x08) != 0)
|
||||
{
|
||||
code[1] |= 2;
|
||||
}
|
||||
|
||||
if ((evenline & 0x08) != 0)
|
||||
{
|
||||
code[1] |= 1;
|
||||
}
|
||||
|
||||
/* Column */
|
||||
|
||||
if ((oddcol & 0x04) != 0)
|
||||
{
|
||||
code[2] |= 2;
|
||||
}
|
||||
|
||||
if ((evencol & 0x04) != 0)
|
||||
{
|
||||
code[2] |= 1;
|
||||
}
|
||||
|
||||
oddline <<= 1;
|
||||
evenline <<= 1;
|
||||
oddcol <<= 1;
|
||||
evencol <<= 1;
|
||||
}
|
||||
|
||||
/* Invert codes (linux compatibility) */
|
||||
|
||||
code[0] = (~(uint32_t)code[0]);
|
||||
code[1] = (~(uint32_t)code[1]);
|
||||
code[2] = (~(uint32_t)code[2]);
|
||||
|
||||
fvdbg("Computed code = %02X %02X %02X\n", code[0], code[1], code[2]);
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: verify256
|
||||
*
|
||||
* Description:
|
||||
* Verifies and corrects a 256-bytes block of data using the given 22-bits
|
||||
* hamming code.
|
||||
*
|
||||
* Input Parameters:
|
||||
* data - Data buffer to check
|
||||
* original - Hamming code to use for verifying the data
|
||||
*
|
||||
* Returned Values:
|
||||
* Zero on success, otherwise returns a HAMMING_ERROR_ code.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
static int verify256(FAR uint8_t *data, FAR const uint8_t *original)
|
||||
{
|
||||
/* Calculate new code */
|
||||
|
||||
uint8_t computed[3];
|
||||
uint8_t correction[3];
|
||||
|
||||
compute256(data, computed);
|
||||
|
||||
/* Xor both codes together */
|
||||
|
||||
correction[0] = computed[0] ^ original[0];
|
||||
correction[1] = computed[1] ^ original[1];
|
||||
correction[2] = computed[2] ^ original[2];
|
||||
|
||||
fvdbg("Correction code: %02x %02x %02x\n",
|
||||
correction[0], correction[1], correction[2]);
|
||||
|
||||
/* If all bytes are 0, there is no error */
|
||||
|
||||
if ((correction[0] == 0) && (correction[1] == 0) && (correction[2] == 0))
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* If there is a single bit error, there are 11 bits set to 1 */
|
||||
|
||||
if (bitsincode256(correction) == 11)
|
||||
{
|
||||
uint8_t byte;
|
||||
uint8_t bit;
|
||||
|
||||
/* Get byte and bit indexes */
|
||||
|
||||
byte = correction[0] & 0x80;
|
||||
byte |= (correction[0] << 1) & 0x40;
|
||||
byte |= (correction[0] << 2) & 0x20;
|
||||
byte |= (correction[0] << 3) & 0x10;
|
||||
|
||||
byte |= (correction[1] >> 4) & 0x08;
|
||||
byte |= (correction[1] >> 3) & 0x04;
|
||||
byte |= (correction[1] >> 2) & 0x02;
|
||||
byte |= (correction[1] >> 1) & 0x01;
|
||||
|
||||
bit = (correction[2] >> 5) & 0x04;
|
||||
bit |= (correction[2] >> 4) & 0x02;
|
||||
bit |= (correction[2] >> 3) & 0x01;
|
||||
|
||||
/* Correct bit */
|
||||
|
||||
fdbg("Correcting byte %d at bit %d\n", byte, bit);
|
||||
data[byte] ^= (1 << bit);
|
||||
|
||||
return HAMMING_ERROR_SINGLEBIT;
|
||||
}
|
||||
|
||||
/* Check if ECC has been corrupted */
|
||||
|
||||
if (bitsincode256(correction) == 1)
|
||||
{
|
||||
return HAMMING_ERROR_ECC;
|
||||
}
|
||||
|
||||
/* Otherwise, this is a multi-bit error */
|
||||
|
||||
else
|
||||
{
|
||||
return HAMMING_ERROR_MULTIPLEBITS;
|
||||
}
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Public Functions
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Name: hamming_compute256x
|
||||
*
|
||||
* Description:
|
||||
* Computes 3-bytes hamming codes for a data block whose size is multiple
|
||||
* of 256 bytes. Each 256 bytes block gets its own code.
|
||||
*
|
||||
* Input Parameters:
|
||||
* data - Data to compute code for
|
||||
* size - Data size in bytes
|
||||
* code - Codes buffer
|
||||
*
|
||||
* Returned Values:
|
||||
* None
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
void hamming_compute256x(FAR const uint8_t *data, size_t size, uint8_t *code)
|
||||
{
|
||||
ssize_t remaining = (ssize_t)size;
|
||||
DEBUGASSERT((size & 0xff) == 0);
|
||||
|
||||
/* Loop, computing the Hamming code on each 256 byte chunk of data */
|
||||
|
||||
while (remaining > 0)
|
||||
{
|
||||
compute256(data, code);
|
||||
|
||||
/* Setup for the next 256 byte chunk */
|
||||
|
||||
data += 256;
|
||||
code += 3;
|
||||
remaining -= 256;
|
||||
}
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: hamming_verify256x
|
||||
*
|
||||
* Description:
|
||||
* Verifies 3-bytes hamming codes for a data block whose size is multiple
|
||||
* of 256 bytes. Each 256-bytes block is verified with its own code.
|
||||
*
|
||||
* Input Parameters:
|
||||
* data - Data buffer to verify
|
||||
* size - Size of the data in bytes
|
||||
* code - Original codes
|
||||
*
|
||||
* Returned Values:
|
||||
* Return 0 if the data is correct, HAMMING_ERROR_SINGLEBIT if one or more
|
||||
* block(s) have had a single bit corrected, or either HAMMING_ERROR_ECC
|
||||
* or HAMMING_ERROR_MULTIPLEBITS.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
int hamming_verify256x(uint8_t *data, size_t size, const uint8_t *code)
|
||||
{
|
||||
ssize_t remaining = (ssize_t)size;
|
||||
int result = HAMMING_SUCCESS;
|
||||
int ret;
|
||||
|
||||
DEBUGASSERT((size & 0xff) == 0);
|
||||
|
||||
/* Loop, verifying each 256 byte chunk of data */
|
||||
|
||||
while (remaining > 0)
|
||||
{
|
||||
result = verify256(data, code);
|
||||
if (result != HAMMING_SUCCESS)
|
||||
{
|
||||
/* Check for the case of a single bit error that was corrected */
|
||||
|
||||
if (result == HAMMING_ERROR_SINGLEBIT)
|
||||
{
|
||||
/* Report the error, but continue verifying */
|
||||
|
||||
ret = HAMMING_ERROR_SINGLEBIT;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* A bad error occurred, abort the verification and return the
|
||||
* error code
|
||||
*/
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
/* Setup for the next 256 byte chunk */
|
||||
|
||||
data += 256;
|
||||
code += 3;
|
||||
remaining -= 256;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
|
@ -88,7 +88,7 @@
|
|||
static int nand_lock(FAR struct nand_dev_s *nand);
|
||||
#define nand_unlock(n) sem_post(&(n)->exclsem)
|
||||
|
||||
/* Sparing logic */
|
||||
/* Bad block checking */
|
||||
|
||||
#ifdef CONFIG_MTD_NAND_BLOCKCHECK
|
||||
static int nand_checkblock(FAR struct nand_dev_s *nand, off_t block);
|
||||
|
|
@ -98,8 +98,15 @@ static int nand_devscan(FAR struct nand_dev_s *nand);
|
|||
# define nand_devscan(n)
|
||||
#endif
|
||||
|
||||
/* Misc. NAND helpers */
|
||||
|
||||
static uint32_t nand_chipid(struct nand_raw_s *raw);
|
||||
static int nand_eraseblock(FAR struct nand_dev_s *nand,
|
||||
off_t block, bool scrub);
|
||||
static int nand_readpage(FAR struct nand_dev_s *nand, off_t block,
|
||||
unsigned int page, FAR uint8_t *buf);
|
||||
static int nand_writepage(FAR struct nand_dev_s *nand, off_t block,
|
||||
unsigned int page, FAR const void *buf);
|
||||
|
||||
/* MTD driver methods */
|
||||
|
||||
|
|
@ -283,6 +290,44 @@ static int nand_devscan(FAR struct nand_dev_s *nand)
|
|||
}
|
||||
#endif /* CONFIG_MTD_NAND_BLOCKCHECK */
|
||||
|
||||
/****************************************************************************
|
||||
* Name: nand_chipid
|
||||
*
|
||||
* Description:
|
||||
* Reads and returns the identifiers of a NAND FLASH chip
|
||||
*
|
||||
* Input Parameters:
|
||||
* raw - Pointer to a struct nand_raw_s instance.
|
||||
*
|
||||
* Returned Value:
|
||||
* id1|(id2<<8)|(id3<<16)|(id4<<24)
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
static uint32_t nand_chipid(struct nand_raw_s *raw)
|
||||
{
|
||||
uint8_t id[5];
|
||||
|
||||
DEBUGASSERT(raw);
|
||||
|
||||
WRITE_COMMAND8(raw, COMMAND_READID);
|
||||
WRITE_ADDRESS8(raw, 0);
|
||||
|
||||
id[0] = READ_DATA8(raw);
|
||||
id[1] = READ_DATA8(raw);
|
||||
id[2] = READ_DATA8(raw);
|
||||
id[3] = READ_DATA8(raw);
|
||||
id[4] = READ_DATA8(raw);
|
||||
|
||||
fvdbg("Chip ID: %02x %02x %02x %02x %02x\n",
|
||||
id[0], id[1], id[2], id[3], id[4]);
|
||||
|
||||
return (uint32_t)id[0] |
|
||||
((uint32_t)id[1] << 8) |
|
||||
((uint32_t)id[2] << 16) |
|
||||
((uint32_t)id[3] << 24);
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: nand_eraseblock
|
||||
*
|
||||
|
|
@ -383,12 +428,27 @@ static int nand_readpage(FAR struct nand_dev_s *nand, off_t block,
|
|||
return -EAGAIN;
|
||||
}
|
||||
|
||||
/* Read data with ECC verification */
|
||||
#ifdef CONFIG_MTD_NAND_SWECC
|
||||
/* nandecc_readpage will handle the software ECC case */
|
||||
|
||||
return nandecc_readpage(nand, block, page, buf, NULL);
|
||||
#else
|
||||
return NAND_READPAGE(nand->raw, block, page, buf, NULL);
|
||||
DEBUGASSERT(nand && nand->raw);
|
||||
if (nand->raw->ecc == NANDECC_SWECC)
|
||||
{
|
||||
/* Read data with software ECC verification */
|
||||
|
||||
return nandecc_readpage(nand, block, page, buf, NULL);
|
||||
}
|
||||
|
||||
/* The lower half will handle the No ECC and all hardware assisted
|
||||
* ECC calculations.
|
||||
*/
|
||||
|
||||
else
|
||||
#endif
|
||||
#endif
|
||||
{
|
||||
return NAND_READPAGE(nand->raw, block, page, buf, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
|
|
@ -420,11 +480,28 @@ static int nand_writepage(FAR struct nand_dev_s *nand, off_t block,
|
|||
fdbg("ERROR: Block is BAD\n");
|
||||
return -EAGAIN;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_MTD_NAND_SWECC
|
||||
/* nandecc_writepage will handle the software ECC case */
|
||||
|
||||
DEBUGASSERT(nand && nand->raw);
|
||||
if (nand->raw->ecc == NANDECC_SWECC)
|
||||
{
|
||||
/* Write data with software ECC calculation */
|
||||
|
||||
return nandecc_writepage(nand, block, page, buf, NULL);
|
||||
}
|
||||
|
||||
/* The lower half will handle the No ECC and all hardware assisted
|
||||
* ECC calculations.
|
||||
*/
|
||||
|
||||
else
|
||||
#endif
|
||||
|
||||
/* Write data with ECC calculation */
|
||||
|
||||
return nandecc_writepage(nand, block, page, buf, NULL);
|
||||
#endif
|
||||
{
|
||||
return NAND_WRITEPAGE(nand->raw, block, page, buf, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
|
|
@ -614,7 +691,7 @@ static ssize_t nand_bwrite(struct mtd_dev_s *dev, off_t startpage,
|
|||
ret = nand_writepage(nand, block, page, buf);
|
||||
if (ret < 0)
|
||||
{
|
||||
fdbg("ERROR: nand_readpage failed block=%ld page=%d: %d\n",
|
||||
fdbg("ERROR: nand_writepage failed block=%ld page=%d: %d\n",
|
||||
(long)block, page, ret);
|
||||
goto errout_with_lock;
|
||||
}
|
||||
|
|
@ -656,8 +733,14 @@ errout_with_lock:
|
|||
static int nand_ioctl(struct mtd_dev_s *dev, int cmd, unsigned long arg)
|
||||
{
|
||||
FAR struct nand_dev_s *nand = (FAR struct nand_dev_s *)dev;
|
||||
FAR struct nand_raw_s *raw;
|
||||
FAR struct nand_model_s *model;
|
||||
int ret = -EINVAL; /* Assume good command with bad parameters */
|
||||
|
||||
DEBUGASSERT(nand && nand->raw);
|
||||
raw = nand->raw;
|
||||
model = &raw->model;
|
||||
|
||||
switch (cmd)
|
||||
{
|
||||
case MTDIOC_GEOMETRY:
|
||||
|
|
@ -666,17 +749,16 @@ static int nand_ioctl(struct mtd_dev_s *dev, int cmd, unsigned long arg)
|
|||
if (geo)
|
||||
{
|
||||
/* Populate the geometry structure with information needed to know
|
||||
* the capacity and how to access the device.
|
||||
* the capacity and how to access the device. Returns:
|
||||
*
|
||||
* NOTE: that the device is treated as though it where just an array
|
||||
* of fixed size blocks. That is most likely not true, but the client
|
||||
* will expect the device logic to do whatever is necessary to make it
|
||||
* appear so.
|
||||
* blocksize Size of one read/write block in bytes
|
||||
* erasesize Size of one erase block in bytes
|
||||
* neraseblocks The number of erase blocks in the device
|
||||
*/
|
||||
|
||||
geo->blocksize = 512; /* Size of one read/write block */
|
||||
geo->erasesize = 4096; /* Size of one erase block */
|
||||
geo->neraseblocks = 1024; /* Number of erase blocks */
|
||||
geo->blocksize = model->pagesize;
|
||||
geo->erasesize = nandmodel_getbyteblocksize(model);
|
||||
geo->neraseblocks = nandmodel_getdevblocks(model);
|
||||
ret = OK;
|
||||
}
|
||||
}
|
||||
|
|
@ -686,7 +768,7 @@ static int nand_ioctl(struct mtd_dev_s *dev, int cmd, unsigned long arg)
|
|||
{
|
||||
/* Erase the entire device */
|
||||
|
||||
ret = OK;
|
||||
ret = nand_erase(dev, 0, nandmodel_getdevblocks(model));
|
||||
}
|
||||
break;
|
||||
|
||||
|
|
|
|||
121
drivers/mtd/mtd_nandecc.c
Normal file
121
drivers/mtd/mtd_nandecc.c
Normal file
|
|
@ -0,0 +1,121 @@
|
|||
/****************************************************************************
|
||||
* drivers/mtd/mtd_nandecc.c
|
||||
*
|
||||
* Copyright (C) 2013 Gregory Nutt. All rights reserved.
|
||||
* Author: Gregory Nutt <gnutt@nuttx.org>
|
||||
*
|
||||
* This logic was based largely on Atmel sample code with modifications for
|
||||
* better integration with NuttX. The Atmel sample code has a BSD
|
||||
* compatibile license that requires this copyright notice:
|
||||
*
|
||||
* Copyright (c) 2011, 2012, Atmel Corporation
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in
|
||||
* the documentation and/or other materials provided with the
|
||||
* distribution.
|
||||
* 3. Neither the names NuttX nor Atmel nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
|
||||
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
|
||||
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
|
||||
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Included Files
|
||||
****************************************************************************/
|
||||
|
||||
#include <nuttx/config.h>
|
||||
#include <nuttx/mtd/nand_config.h>
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <stdint.h>
|
||||
#include <errno.h>
|
||||
#include <debug.h>
|
||||
|
||||
#include <nuttx/mtd/nand.h>
|
||||
#include <nuttx/mtd/nand_ecc.h>
|
||||
|
||||
/****************************************************************************
|
||||
* Pre-processor Definitions
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Public Functions
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Name: nandecc_readpage
|
||||
*
|
||||
* Description:
|
||||
* Reads the data and/or spare areas of a page of a NAND FLASH chip and
|
||||
* verifies that the data is valid using the ECC information contained in
|
||||
* the spare area. If a buffer pointer is NULL, then the corresponding area
|
||||
* is not saved.
|
||||
*
|
||||
* Input parameters:
|
||||
* nand - Upper-half, NAND FLASH interface
|
||||
* block - Number of the block where the page to read resides.
|
||||
* page - Number of the page to read inside the given block.
|
||||
* data - Buffer where the data area will be stored.
|
||||
* spare - Buffer where the spare area will be stored.
|
||||
*
|
||||
* Returned value.
|
||||
* OK is returned in success; a negated errno value is returned on failure.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
int nandecc_readpage(FAR struct nand_dev_s *nand, off_t block,
|
||||
unsigned int page, FAR void *data, FAR void *spare)
|
||||
{
|
||||
#warning Missing logic
|
||||
return -ENOSYS;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: nandecc_writepage
|
||||
*
|
||||
* Description:
|
||||
* Writes the data and/or spare area of a NAND FLASH page after
|
||||
* calculating an ECC for the data area and storing it in the spare. If no
|
||||
* data buffer is provided, the ECC is read from the existing page spare.
|
||||
* If no spare buffer is provided, the spare area is still written with the
|
||||
* ECC information calculated on the data buffer.
|
||||
*
|
||||
* Input parameters:
|
||||
* nand - Upper-half, NAND FLASH interface
|
||||
* block - Number of the block where the page to write resides.
|
||||
* page - Number of the page to write inside the given block.
|
||||
* data - Buffer containing the data to be writting
|
||||
* spare - Buffer containing the spare data to be written.
|
||||
*
|
||||
* Returned value.
|
||||
* OK is returned in success; a negated errno value is returned on failure.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
int nandecc_writepage(FAR struct nand_dev_s *nand, off_t block,
|
||||
unsigned int page, FAR const void *data,
|
||||
FAR void *spare)
|
||||
{
|
||||
#warning Missing logic
|
||||
return -ENOSYS;
|
||||
}
|
||||
|
|
@ -1,5 +1,5 @@
|
|||
/****************************************************************************
|
||||
* drivers/mtd/mtd_nand.c
|
||||
* drivers/mtd/mtd_nandmodel.c
|
||||
*
|
||||
* Copyright (C) 2013 Gregory Nutt. All rights reserved.
|
||||
* Author: Gregory Nutt <gnutt@nuttx.org>
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/****************************************************************************
|
||||
* include/nuttx/mtd/nand_scheme.c
|
||||
* include/nuttx/mtd/mtd_nandscheme.c
|
||||
*
|
||||
* Copyright (C) 2013 Gregory Nutt. All rights reserved.
|
||||
* Author: Gregory Nutt <gnutt@nuttx.org>
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/****************************************************************************
|
||||
* drivers/child/skeleton.c
|
||||
* drivers/mtd/mtd_partition.c
|
||||
*
|
||||
* Copyright (C) 2013 Gregory Nutt. All rights reserved.
|
||||
* Author: Gregory Nutt <gnutt@nuttx.org>
|
||||
|
|
|
|||
110
drivers/mtd/mtd_nandraw.c → include/nuttx/mtd/hamming.h
Executable file → Normal file
110
drivers/mtd/mtd_nandraw.c → include/nuttx/mtd/hamming.h
Executable file → Normal file
|
|
@ -1,14 +1,14 @@
|
|||
/****************************************************************************
|
||||
* drivers/mtd/mtd_nandraw.c
|
||||
* include/nuttx/mtd/hamming.h
|
||||
*
|
||||
* Copyright (C) 2013 Gregory Nutt. All rights reserved.
|
||||
* Author: Gregory Nutt <gnutt@nuttx.org>
|
||||
*
|
||||
* This logic was based largely on Atmel sample code with modifications for
|
||||
* better integration with NuttX. The Atmel sample code has a BSD
|
||||
* compatibile license that requires this copyright notice:
|
||||
* This logic was taken directly from Atmel sample code with only
|
||||
* modifications for better integration with NuttX. The Atmel sample
|
||||
* code has a BSD compatibile license that requires this copyright notice:
|
||||
*
|
||||
* Copyright (c) 2011, 2012, Atmel Corporation
|
||||
* Copyright (c) 2011, Atmel Corporation
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
|
|
@ -39,77 +39,67 @@
|
|||
*
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef __INCLUDE_NUTTX_HAMMING_H
|
||||
#define __INCLUDE_NUTTX_HAMMING_H
|
||||
|
||||
/****************************************************************************
|
||||
* Included Files
|
||||
****************************************************************************/
|
||||
|
||||
#include <nuttx/config.h>
|
||||
#include <nuttx/mtd/nand_config.h>
|
||||
|
||||
#include <stdint.h>
|
||||
#include <assert.h>
|
||||
#include <debug.h>
|
||||
#include <stdbool.h>
|
||||
#include <semaphore.h>
|
||||
|
||||
#include <nuttx/mtd/mtd.h>
|
||||
#include <nuttx/mtd/nand_raw.h>
|
||||
|
||||
/****************************************************************************
|
||||
* Pre-processor Definitions
|
||||
* Pre-Processor Definitions
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Private Types
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Private Function Prototypes
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Private Data
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Private Functions
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Public Functions
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Name: nand_chipid
|
||||
*
|
||||
* Description:
|
||||
* Reads and returns the identifiers of a NAND FLASH chip
|
||||
*
|
||||
* Input Parameters:
|
||||
* raw - Pointer to a struct nand_raw_s instance.
|
||||
*
|
||||
* Returned Value:
|
||||
* id1|(id2<<8)|(id3<<16)|(id4<<24)
|
||||
/* These are the possible errors when trying to verify a block of data
|
||||
* encoded using a Hamming code:
|
||||
*
|
||||
* HAMMING_SUCCESS - Block verified without errors
|
||||
* HAMMING_ERROR_SINGLEBIT - A single bit was incorrect but has been
|
||||
* recovered
|
||||
* HAMMING_ERROR_ECC - The original code has been corrupted
|
||||
* HAMMING_ERROR_MULTIPLEBITS - Multiple bits are incorrect in the data
|
||||
* and they cannot be corrected
|
||||
*/
|
||||
|
||||
#define HAMMING_SUCCESS 0
|
||||
#define HAMMING_ERROR_SINGLEBIT 1
|
||||
#define HAMMING_ERROR_ECC 2
|
||||
#define HAMMING_ERROR_MULTIPLEBITS 3
|
||||
|
||||
/****************************************************************************
|
||||
* Public Types
|
||||
****************************************************************************/
|
||||
|
||||
uint32_t nand_chipid(struct nand_raw_s *raw)
|
||||
/****************************************************************************
|
||||
* Public Data
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef __ASSEMBLY__
|
||||
|
||||
#ifdef __cplusplus
|
||||
#define EXTERN extern "C"
|
||||
extern "C"
|
||||
{
|
||||
uint8_t id[5];
|
||||
#else
|
||||
#define EXTERN extern
|
||||
#endif
|
||||
|
||||
DEBUGASSERT(raw);
|
||||
/****************************************************************************
|
||||
* Public Function Prototypes
|
||||
****************************************************************************/
|
||||
|
||||
WRITE_COMMAND8(raw, COMMAND_READID);
|
||||
WRITE_ADDRESS8(raw, 0);
|
||||
|
||||
id[0] = READ_DATA8(raw);
|
||||
id[1] = READ_DATA8(raw);
|
||||
id[2] = READ_DATA8(raw);
|
||||
id[3] = READ_DATA8(raw);
|
||||
id[4] = READ_DATA8(raw);
|
||||
|
||||
fvdbg("Chip ID: %02x %02x %02x %02x %02x\n",
|
||||
id[0], id[1], id[2], id[3], id[4]);
|
||||
|
||||
return (uint32_t)id[0] |
|
||||
((uint32_t)id[1] << 8) |
|
||||
((uint32_t)id[2] << 16) |
|
||||
((uint32_t)id[3] << 24);
|
||||
#undef EXTERN
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* __ASSEMBLY__ */
|
||||
#endif /* __INCLUDE_NUTTX_HAMMING_H */
|
||||
|
|
@ -81,8 +81,10 @@ extern "C"
|
|||
* Name: nandecc_readpage
|
||||
*
|
||||
* Description:
|
||||
* Reads the data and/or the spare areas of a page of a NAND FLASH into the
|
||||
* provided buffers.
|
||||
* Reads the data and/or spare areas of a page of a NAND FLASH chip and
|
||||
* verifies that the data is valid using the ECC information contained in
|
||||
* the spare area. If a buffer pointer is NULL, then the corresponding area
|
||||
* is not saved.
|
||||
*
|
||||
* Input parameters:
|
||||
* nand - Upper-half, NAND FLASH interface
|
||||
|
|
@ -103,14 +105,18 @@ int nandecc_readpage(FAR struct nand_dev_s *nand, off_t block,
|
|||
* Name: nandecc_writepage
|
||||
*
|
||||
* Description:
|
||||
* Writes the data and/or the spare area of a page on a NAND FLASH chip.
|
||||
* Writes the data and/or spare area of a NAND FLASH page after
|
||||
* calculating an ECC for the data area and storing it in the spare. If no
|
||||
* data buffer is provided, the ECC is read from the existing page spare.
|
||||
* If no spare buffer is provided, the spare area is still written with the
|
||||
* ECC information calculated on the data buffer.
|
||||
*
|
||||
* Input parameters:
|
||||
* nand - Upper-half, NAND FLASH interface
|
||||
* block - Number of the block where the page to write resides.
|
||||
* page - Number of the page to write inside the given block.
|
||||
* data - Buffer containing the data to be writting
|
||||
* spare - Buffer conatining the spare data to be written.
|
||||
* spare - Buffer containing the spare data to be written.
|
||||
*
|
||||
* Returned value.
|
||||
* OK is returned in success; a negated errno value is returned on failure.
|
||||
|
|
@ -118,8 +124,8 @@ int nandecc_readpage(FAR struct nand_dev_s *nand, off_t block,
|
|||
****************************************************************************/
|
||||
|
||||
int nandecc_writepage(FAR struct nand_dev_s *nand, off_t block,
|
||||
unsigned int page, FAR const void *data,
|
||||
FAR const void *spare);
|
||||
unsigned int page, FAR const void *data,
|
||||
FAR void *spare);
|
||||
|
||||
#undef EXTERN
|
||||
#ifdef __cplusplus
|
||||
|
|
|
|||
|
|
@ -81,6 +81,19 @@
|
|||
#define COMMAND_READ_A 0x00
|
||||
#define COMMAND_READ_C 0x50
|
||||
|
||||
/* Type of ECC to be performed (must be enabled in the configuration)
|
||||
* NANDECC_NONE No ECC, only raw NAND FLASH accesses
|
||||
* NANDECC_SWECC Software ECC. Handled by the common MTD logic.
|
||||
* NANDECC_HWECC Values >= 2 are various hardware ECC implementations
|
||||
* all handled by the lower-half, raw NAND FLASH driver.
|
||||
* These hardware ECC types may be extended beginning
|
||||
* with the value NANDECC_HWECC.
|
||||
*/
|
||||
|
||||
#define NANDECC_NONE 0
|
||||
#define NANDECC_SWECC 1
|
||||
#define NANDECC_HWECC 2
|
||||
|
||||
/* NAND access macros */
|
||||
|
||||
#define WRITE_COMMAND8(raw, command) \
|
||||
|
|
@ -151,7 +164,7 @@
|
|||
* block - Number of the block where the page to write resides.
|
||||
* page - Number of the page to write inside the given block.
|
||||
* data - Buffer containing the data to be writting
|
||||
* spare - Buffer conatining the spare data to be written.
|
||||
* spare - Buffer containing the spare data to be written.
|
||||
*
|
||||
* Returned value.
|
||||
* OK is returned in succes; a negated errno value is returned on failure.
|
||||
|
|
@ -171,13 +184,19 @@
|
|||
|
||||
struct nand_raw_s
|
||||
{
|
||||
/* NAND data */
|
||||
/* NAND data description */
|
||||
|
||||
struct nand_model_s model; /* The NAND model storage */
|
||||
uintptr_t cmdaddr; /* NAND command address base */
|
||||
uintptr_t addraddr; /* NAND address address base */
|
||||
uintptr_t dataaddr; /* NAND data address */
|
||||
|
||||
#ifdef CONFIG_MTD_NAND_BLOCKCHECK
|
||||
/* ECC */
|
||||
|
||||
uint8_t ecc; /* See enum nand_ecc_e */
|
||||
#endif
|
||||
|
||||
/* NAND operations */
|
||||
|
||||
CODE int (*eraseblock)(FAR struct nand_raw_s *raw, off_t block);
|
||||
|
|
@ -206,22 +225,6 @@ extern "C"
|
|||
* Public Function Prototypes
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Name: nand_chipid
|
||||
*
|
||||
* Description:
|
||||
* Reads and returns the identifiers of a NAND FLASH chip
|
||||
*
|
||||
* Input Parameters:
|
||||
* raw - Pointer to a struct nand_raw_s instance.
|
||||
*
|
||||
* Returned Value:
|
||||
* id1|(id2<<8)|(id3<<16)|(id4<<24)
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
uint32_t nand_chipid(FAR struct nand_raw_s *raw);
|
||||
|
||||
#undef EXTERN
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue