mirror of
https://github.com/Fishwaldo/u-boot.git
synced 2025-03-18 21:21:37 +00:00
Merge git://git.denx.de/u-boot-nand-flash
This commit is contained in:
commit
980267a144
12 changed files with 218 additions and 172 deletions
|
@ -1,3 +1,5 @@
|
|||
CONFIG_ARM=y
|
||||
CONFIG_TARGET_COLIBRI_VF=y
|
||||
CONFIG_SYS_EXTRA_OPTIONS="IMX_CONFIG=board/toradex/colibri_vf/imximage.cfg,ENV_IS_IN_NAND,IMX_NAND"
|
||||
CONFIG_NAND_VF610_NFC=y
|
||||
CONFIG_SYS_NAND_VF610_NFC_60_ECC_BYTES=y
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
CONFIG_ARM=y
|
||||
CONFIG_TARGET_VF610TWR=y
|
||||
CONFIG_SYS_EXTRA_OPTIONS="IMX_CONFIG=board/freescale/vf610twr/imximage.cfg,ENV_IS_IN_MMC"
|
||||
CONFIG_NAND_VF610_NFC=y
|
||||
CONFIG_SYS_NAND_BUSWIDTH_16BIT=y
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
CONFIG_ARM=y
|
||||
CONFIG_TARGET_VF610TWR=y
|
||||
CONFIG_SYS_EXTRA_OPTIONS="IMX_CONFIG=board/freescale/vf610twr/imximage.cfg,ENV_IS_IN_NAND"
|
||||
CONFIG_NAND_VF610_NFC=y
|
||||
CONFIG_SYS_NAND_BUSWIDTH_16BIT=y
|
||||
|
|
|
@ -188,24 +188,6 @@ Configuration Options:
|
|||
This is used by SoC platforms which do not have built-in ELM
|
||||
hardware engine required for BCH ECC correction.
|
||||
|
||||
CONFIG_SYS_NAND_BUSWIDTH_16BIT
|
||||
Indicates that NAND device has 16-bit wide data-bus. In absence of this
|
||||
config, bus-width of NAND device is assumed to be either 8-bit and later
|
||||
determined by reading ONFI params.
|
||||
Above config is useful when NAND device's bus-width information cannot
|
||||
be determined from on-chip ONFI params, like in following scenarios:
|
||||
- SPL boot does not support reading of ONFI parameters. This is done to
|
||||
keep SPL code foot-print small.
|
||||
- In current U-Boot flow using nand_init(), driver initialization
|
||||
happens in board_nand_init() which is called before any device probe
|
||||
(nand_scan_ident + nand_scan_tail), thus device's ONFI parameters are
|
||||
not available while configuring controller. So a static CONFIG_NAND_xx
|
||||
is needed to know the device's bus-width in advance.
|
||||
Some drivers using above config are:
|
||||
drivers/mtd/nand/mxc_nand.c
|
||||
drivers/mtd/nand/ndfc.c
|
||||
drivers/mtd/nand/omap_gpmc.c
|
||||
|
||||
|
||||
Platform specific options
|
||||
=========================
|
||||
|
|
|
@ -32,6 +32,51 @@ config NAND_DENALI_SPARE_AREA_SKIP_BYTES
|
|||
of OOB area before last ECC sector data starts. This is potentially
|
||||
used to preserve the bad block marker in the OOB area.
|
||||
|
||||
config NAND_VF610_NFC
|
||||
bool "Support for Freescale NFC for VF610/MPC5125"
|
||||
select SYS_NAND_SELF_INIT
|
||||
help
|
||||
Enables support for NAND Flash Controller on some Freescale
|
||||
processors like the VF610, MPC5125, MCF54418 or Kinetis K70.
|
||||
The driver supports a maximum 2k page size. The driver
|
||||
currently does not support hardware ECC.
|
||||
|
||||
choice
|
||||
prompt "Hardware ECC strength"
|
||||
depends on NAND_VF610_NFC
|
||||
default SYS_NAND_VF610_NFC_45_ECC_BYTES
|
||||
help
|
||||
Select the ECC strength used in the hardware BCH ECC block.
|
||||
|
||||
config SYS_NAND_VF610_NFC_45_ECC_BYTES
|
||||
bool "24-error correction (45 ECC bytes)"
|
||||
|
||||
config SYS_NAND_VF610_NFC_60_ECC_BYTES
|
||||
bool "32-error correction (60 ECC bytes)"
|
||||
|
||||
endchoice
|
||||
|
||||
comment "Generic NAND options"
|
||||
|
||||
# Enhance depends when converting drivers to Kconfig which use this config
|
||||
# option (mxc_nand, ndfc, omap_gpmc).
|
||||
config SYS_NAND_BUSWIDTH_16BIT
|
||||
bool "Use 16-bit NAND interface"
|
||||
depends on NAND_VF610_NFC
|
||||
help
|
||||
Indicates that NAND device has 16-bit wide data-bus. In absence of this
|
||||
config, bus-width of NAND device is assumed to be either 8-bit and later
|
||||
determined by reading ONFI params.
|
||||
Above config is useful when NAND device's bus-width information cannot
|
||||
be determined from on-chip ONFI params, like in following scenarios:
|
||||
- SPL boot does not support reading of ONFI parameters. This is done to
|
||||
keep SPL code foot-print small.
|
||||
- In current U-Boot flow using nand_init(), driver initialization
|
||||
happens in board_nand_init() which is called before any device probe
|
||||
(nand_scan_ident + nand_scan_tail), thus device's ONFI parameters are
|
||||
not available while configuring controller. So a static CONFIG_NAND_xx
|
||||
is needed to know the device's bus-width in advance.
|
||||
|
||||
if SPL
|
||||
|
||||
config SPL_NAND_DENALI
|
||||
|
|
|
@ -679,6 +679,7 @@ static int fsl_elbc_chip_init(int devnum, u8 *addr)
|
|||
if (priv->bank >= MAX_BANKS) {
|
||||
printf("fsl_elbc_nand: address did not match any "
|
||||
"chip selects\n");
|
||||
kfree(priv);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
|
|
|
@ -36,7 +36,7 @@
|
|||
#define MXS_NAND_CHUNK_DATA_CHUNK_SIZE_SHIFT 0
|
||||
#endif
|
||||
#define MXS_NAND_METADATA_SIZE 10
|
||||
|
||||
#define MXS_NAND_BITS_PER_ECC_LEVEL 13
|
||||
#define MXS_NAND_COMMAND_BUFFER_SIZE 32
|
||||
|
||||
#define MXS_NAND_BCH_TIMEOUT 10000
|
||||
|
@ -135,7 +135,7 @@ static uint32_t mxs_nand_ecc_chunk_cnt(uint32_t page_data_size)
|
|||
|
||||
static uint32_t mxs_nand_ecc_size_in_bits(uint32_t ecc_strength)
|
||||
{
|
||||
return ecc_strength * 13;
|
||||
return ecc_strength * MXS_NAND_BITS_PER_ECC_LEVEL;
|
||||
}
|
||||
|
||||
static uint32_t mxs_nand_aux_status_offset(void)
|
||||
|
@ -146,26 +146,21 @@ static uint32_t mxs_nand_aux_status_offset(void)
|
|||
static inline uint32_t mxs_nand_get_ecc_strength(uint32_t page_data_size,
|
||||
uint32_t page_oob_size)
|
||||
{
|
||||
if (page_data_size == 2048) {
|
||||
if (page_oob_size == 64)
|
||||
return 8;
|
||||
int ecc_strength;
|
||||
|
||||
if (page_oob_size == 112)
|
||||
return 14;
|
||||
}
|
||||
/*
|
||||
* Determine the ECC layout with the formula:
|
||||
* ECC bits per chunk = (total page spare data bits) /
|
||||
* (bits per ECC level) / (chunks per page)
|
||||
* where:
|
||||
* total page spare data bits =
|
||||
* (page oob size - meta data size) * (bits per byte)
|
||||
*/
|
||||
ecc_strength = ((page_oob_size - MXS_NAND_METADATA_SIZE) * 8)
|
||||
/ (MXS_NAND_BITS_PER_ECC_LEVEL *
|
||||
mxs_nand_ecc_chunk_cnt(page_data_size));
|
||||
|
||||
if (page_data_size == 4096) {
|
||||
if (page_oob_size == 128)
|
||||
return 8;
|
||||
|
||||
if (page_oob_size == 218)
|
||||
return 16;
|
||||
|
||||
if (page_oob_size == 224)
|
||||
return 16;
|
||||
}
|
||||
|
||||
return 0;
|
||||
return round_down(ecc_strength, 2);
|
||||
}
|
||||
|
||||
static inline uint32_t mxs_nand_get_mark_offset(uint32_t page_data_size,
|
||||
|
|
|
@ -483,7 +483,7 @@ int nand_verify_page_oob(nand_info_t *nand, struct mtd_oob_ops *ops, loff_t ofs)
|
|||
|
||||
memcpy(&vops, ops, sizeof(vops));
|
||||
|
||||
vops.datbuf = malloc(verlen);
|
||||
vops.datbuf = memalign(ARCH_DMA_MINALIGN, verlen);
|
||||
|
||||
if (!vops.datbuf)
|
||||
return -ENOMEM;
|
||||
|
@ -520,7 +520,7 @@ int nand_verify(nand_info_t *nand, loff_t ofs, size_t len, u_char *buf)
|
|||
int rval = 0;
|
||||
size_t verofs;
|
||||
size_t verlen = nand->writesize;
|
||||
uint8_t *verbuf = malloc(verlen);
|
||||
uint8_t *verbuf = memalign(ARCH_DMA_MINALIGN, verlen);
|
||||
|
||||
if (!verbuf)
|
||||
return -ENOMEM;
|
||||
|
|
|
@ -62,6 +62,7 @@
|
|||
* Briefly these are bitmasks of controller cycles.
|
||||
*/
|
||||
#define READ_PAGE_CMD_CODE 0x7EE0
|
||||
#define READ_ONFI_PARAM_CMD_CODE 0x4860
|
||||
#define PROGRAM_PAGE_CMD_CODE 0x7FC0
|
||||
#define ERASE_CMD_CODE 0x4EC0
|
||||
#define READ_ID_CMD_CODE 0x4804
|
||||
|
@ -71,6 +72,7 @@
|
|||
/* NFC ECC mode define */
|
||||
#define ECC_BYPASS 0
|
||||
#define ECC_45_BYTE 6
|
||||
#define ECC_60_BYTE 7
|
||||
|
||||
/*** Register Mask and bit definitions */
|
||||
|
||||
|
@ -145,43 +147,21 @@ struct vf610_nfc {
|
|||
struct nand_chip chip;
|
||||
void __iomem *regs;
|
||||
uint column;
|
||||
int spareonly;
|
||||
int page_sz;
|
||||
int page;
|
||||
/* Status and ID are in alternate locations. */
|
||||
int alt_buf;
|
||||
#define ALT_BUF_ID 1
|
||||
#define ALT_BUF_STAT 2
|
||||
#define ALT_BUF_ONFI 3
|
||||
struct clk *clk;
|
||||
};
|
||||
|
||||
#define mtd_to_nfc(_mtd) \
|
||||
(struct vf610_nfc *)((struct nand_chip *)_mtd->priv)->priv
|
||||
|
||||
static u8 bbt_pattern[] = {'B', 'b', 't', '0' };
|
||||
static u8 mirror_pattern[] = {'1', 't', 'b', 'B' };
|
||||
#if defined(CONFIG_SYS_NAND_VF610_NFC_45_ECC_BYTES)
|
||||
#define ECC_HW_MODE ECC_45_BYTE
|
||||
|
||||
static struct nand_bbt_descr bbt_main_descr = {
|
||||
.options = NAND_BBT_LASTBLOCK | NAND_BBT_CREATE | NAND_BBT_WRITE |
|
||||
NAND_BBT_2BIT | NAND_BBT_VERSION,
|
||||
.offs = 11,
|
||||
.len = 4,
|
||||
.veroffs = 15,
|
||||
.maxblocks = 4,
|
||||
.pattern = bbt_pattern,
|
||||
};
|
||||
|
||||
static struct nand_bbt_descr bbt_mirror_descr = {
|
||||
.options = NAND_BBT_LASTBLOCK | NAND_BBT_CREATE | NAND_BBT_WRITE |
|
||||
NAND_BBT_2BIT | NAND_BBT_VERSION,
|
||||
.offs = 11,
|
||||
.len = 4,
|
||||
.veroffs = 15,
|
||||
.maxblocks = 4,
|
||||
.pattern = mirror_pattern,
|
||||
};
|
||||
|
||||
static struct nand_ecclayout vf610_nfc_ecc45 = {
|
||||
static struct nand_ecclayout vf610_nfc_ecc = {
|
||||
.eccbytes = 45,
|
||||
.eccpos = {19, 20, 21, 22, 23,
|
||||
24, 25, 26, 27, 28, 29, 30, 31,
|
||||
|
@ -193,6 +173,24 @@ static struct nand_ecclayout vf610_nfc_ecc45 = {
|
|||
{.offset = 8,
|
||||
.length = 11} }
|
||||
};
|
||||
#elif defined(CONFIG_SYS_NAND_VF610_NFC_60_ECC_BYTES)
|
||||
#define ECC_HW_MODE ECC_60_BYTE
|
||||
|
||||
static struct nand_ecclayout vf610_nfc_ecc = {
|
||||
.eccbytes = 60,
|
||||
.eccpos = { 4, 5, 6, 7, 8, 9, 10, 11,
|
||||
12, 13, 14, 15, 16, 17, 18, 19,
|
||||
20, 21, 22, 23, 24, 25, 26, 27,
|
||||
28, 29, 30, 31, 32, 33, 34, 35,
|
||||
36, 37, 38, 39, 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 = 2} }
|
||||
};
|
||||
#endif
|
||||
|
||||
static inline u32 vf610_nfc_read(struct mtd_info *mtd, uint reg)
|
||||
{
|
||||
|
@ -320,8 +318,8 @@ static void vf610_nfc_addr_cycle(struct mtd_info *mtd, int column, int page)
|
|||
{
|
||||
if (column != -1) {
|
||||
struct vf610_nfc *nfc = mtd_to_nfc(mtd);
|
||||
if (nfc->chip.options | NAND_BUSWIDTH_16)
|
||||
column = column/2;
|
||||
if (nfc->chip.options & NAND_BUSWIDTH_16)
|
||||
column = column / 2;
|
||||
vf610_nfc_set_field(mtd, NFC_COL_ADDR, COL_ADDR_MASK,
|
||||
COL_ADDR_SHIFT, column);
|
||||
}
|
||||
|
@ -330,6 +328,13 @@ static void vf610_nfc_addr_cycle(struct mtd_info *mtd, int column, int page)
|
|||
ROW_ADDR_SHIFT, page);
|
||||
}
|
||||
|
||||
static inline void vf610_nfc_ecc_mode(struct mtd_info *mtd, int ecc_mode)
|
||||
{
|
||||
vf610_nfc_set_field(mtd, NFC_FLASH_CONFIG,
|
||||
CONFIG_ECC_MODE_MASK,
|
||||
CONFIG_ECC_MODE_SHIFT, ecc_mode);
|
||||
}
|
||||
|
||||
static inline void vf610_nfc_transfer_size(void __iomem *regbase, int size)
|
||||
{
|
||||
__raw_writel(size, regbase + NFC_SECTOR_SIZE);
|
||||
|
@ -340,45 +345,64 @@ static void vf610_nfc_command(struct mtd_info *mtd, unsigned command,
|
|||
int column, int page)
|
||||
{
|
||||
struct vf610_nfc *nfc = mtd_to_nfc(mtd);
|
||||
int page_sz = nfc->chip.options & NAND_BUSWIDTH_16 ? 1 : 0;
|
||||
|
||||
nfc->column = max(column, 0);
|
||||
nfc->spareonly = 0;
|
||||
nfc->alt_buf = 0;
|
||||
nfc->column = max(column, 0);
|
||||
nfc->alt_buf = 0;
|
||||
|
||||
switch (command) {
|
||||
case NAND_CMD_SEQIN:
|
||||
/* Use valid column/page from preread... */
|
||||
vf610_nfc_addr_cycle(mtd, column, page);
|
||||
/*
|
||||
* SEQIN => data => PAGEPROG sequence is done by the controller
|
||||
* hence we do not need to issue the command here...
|
||||
*/
|
||||
return;
|
||||
case NAND_CMD_PAGEPROG:
|
||||
nfc->page = -1;
|
||||
vf610_nfc_transfer_size(nfc->regs, nfc->page_sz);
|
||||
page_sz += mtd->writesize + mtd->oobsize;
|
||||
vf610_nfc_transfer_size(nfc->regs, page_sz);
|
||||
vf610_nfc_send_commands(nfc->regs, NAND_CMD_SEQIN,
|
||||
command, PROGRAM_PAGE_CMD_CODE);
|
||||
vf610_nfc_addr_cycle(mtd, column, page);
|
||||
vf610_nfc_ecc_mode(mtd, ECC_HW_MODE);
|
||||
break;
|
||||
|
||||
case NAND_CMD_RESET:
|
||||
vf610_nfc_transfer_size(nfc->regs, 0);
|
||||
vf610_nfc_send_command(nfc->regs, command, RESET_CMD_CODE);
|
||||
break;
|
||||
/*
|
||||
* NFC does not support sub-page reads and writes,
|
||||
* so emulate them using full page transfers.
|
||||
*/
|
||||
|
||||
case NAND_CMD_READOOB:
|
||||
nfc->spareonly = 1;
|
||||
case NAND_CMD_SEQIN: /* Pre-read for partial writes. */
|
||||
case NAND_CMD_READ0:
|
||||
column = 0;
|
||||
/* Already read? */
|
||||
if (nfc->page == page)
|
||||
return;
|
||||
nfc->page = page;
|
||||
vf610_nfc_transfer_size(nfc->regs, nfc->page_sz);
|
||||
page_sz += mtd->oobsize;
|
||||
column = mtd->writesize;
|
||||
vf610_nfc_transfer_size(nfc->regs, page_sz);
|
||||
vf610_nfc_send_commands(nfc->regs, NAND_CMD_READ0,
|
||||
NAND_CMD_READSTART, READ_PAGE_CMD_CODE);
|
||||
vf610_nfc_addr_cycle(mtd, column, page);
|
||||
vf610_nfc_ecc_mode(mtd, ECC_BYPASS);
|
||||
break;
|
||||
|
||||
case NAND_CMD_READ0:
|
||||
page_sz += mtd->writesize + mtd->oobsize;
|
||||
column = 0;
|
||||
vf610_nfc_transfer_size(nfc->regs, page_sz);
|
||||
vf610_nfc_send_commands(nfc->regs, NAND_CMD_READ0,
|
||||
NAND_CMD_READSTART, READ_PAGE_CMD_CODE);
|
||||
vf610_nfc_addr_cycle(mtd, column, page);
|
||||
vf610_nfc_ecc_mode(mtd, ECC_HW_MODE);
|
||||
break;
|
||||
|
||||
case NAND_CMD_PARAM:
|
||||
nfc->alt_buf = ALT_BUF_ONFI;
|
||||
vf610_nfc_transfer_size(nfc->regs, 768);
|
||||
vf610_nfc_send_command(nfc->regs, NAND_CMD_PARAM,
|
||||
READ_ONFI_PARAM_CMD_CODE);
|
||||
vf610_nfc_set_field(mtd, NFC_ROW_ADDR, ROW_ADDR_MASK,
|
||||
ROW_ADDR_SHIFT, column);
|
||||
vf610_nfc_ecc_mode(mtd, ECC_BYPASS);
|
||||
break;
|
||||
|
||||
case NAND_CMD_ERASE1:
|
||||
nfc->page = -1;
|
||||
vf610_nfc_transfer_size(nfc->regs, 0);
|
||||
vf610_nfc_send_commands(nfc->regs, command,
|
||||
NAND_CMD_ERASE2, ERASE_CMD_CODE);
|
||||
|
@ -387,8 +411,11 @@ static void vf610_nfc_command(struct mtd_info *mtd, unsigned command,
|
|||
|
||||
case NAND_CMD_READID:
|
||||
nfc->alt_buf = ALT_BUF_ID;
|
||||
nfc->column = 0;
|
||||
vf610_nfc_transfer_size(nfc->regs, 0);
|
||||
vf610_nfc_send_command(nfc->regs, command, READ_ID_CMD_CODE);
|
||||
vf610_nfc_set_field(mtd, NFC_ROW_ADDR, ROW_ADDR_MASK,
|
||||
ROW_ADDR_SHIFT, column);
|
||||
break;
|
||||
|
||||
case NAND_CMD_STATUS:
|
||||
|
@ -404,46 +431,19 @@ static void vf610_nfc_command(struct mtd_info *mtd, unsigned command,
|
|||
vf610_nfc_done(mtd);
|
||||
}
|
||||
|
||||
static inline void vf610_nfc_read_spare(struct mtd_info *mtd, void *buf,
|
||||
int len)
|
||||
{
|
||||
struct vf610_nfc *nfc = mtd_to_nfc(mtd);
|
||||
|
||||
len = min(mtd->oobsize, (uint)len);
|
||||
if (len > 0)
|
||||
vf610_nfc_memcpy(buf, nfc->regs + mtd->writesize, len);
|
||||
}
|
||||
|
||||
/* Read data from NFC buffers */
|
||||
static void vf610_nfc_read_buf(struct mtd_info *mtd, u_char *buf, int len)
|
||||
{
|
||||
struct vf610_nfc *nfc = mtd_to_nfc(mtd);
|
||||
uint c = nfc->column;
|
||||
uint l;
|
||||
|
||||
/* Handle main area */
|
||||
if (!nfc->spareonly) {
|
||||
l = min((uint)len, mtd->writesize - c);
|
||||
nfc->column += l;
|
||||
/* Alternate buffers are only supported through read_byte */
|
||||
if (nfc->alt_buf)
|
||||
return;
|
||||
|
||||
if (!nfc->alt_buf)
|
||||
vf610_nfc_memcpy(buf, nfc->regs + NFC_MAIN_AREA(0) + c,
|
||||
l);
|
||||
else
|
||||
if (nfc->alt_buf & ALT_BUF_ID)
|
||||
*buf = vf610_nfc_get_id(mtd, c);
|
||||
else
|
||||
*buf = vf610_nfc_get_status(mtd);
|
||||
vf610_nfc_memcpy(buf, nfc->regs + NFC_MAIN_AREA(0) + c, len);
|
||||
|
||||
buf += l;
|
||||
len -= l;
|
||||
}
|
||||
|
||||
/* Handle spare area access */
|
||||
if (len) {
|
||||
nfc->column += len;
|
||||
vf610_nfc_read_spare(mtd, buf, len);
|
||||
}
|
||||
nfc->column += len;
|
||||
}
|
||||
|
||||
/* Write data to NFC buffers */
|
||||
|
@ -462,8 +462,29 @@ static void vf610_nfc_write_buf(struct mtd_info *mtd, const u_char *buf,
|
|||
/* Read byte from NFC buffers */
|
||||
static u8 vf610_nfc_read_byte(struct mtd_info *mtd)
|
||||
{
|
||||
struct vf610_nfc *nfc = mtd_to_nfc(mtd);
|
||||
u8 tmp;
|
||||
vf610_nfc_read_buf(mtd, &tmp, sizeof(tmp));
|
||||
uint c = nfc->column;
|
||||
|
||||
switch (nfc->alt_buf) {
|
||||
case ALT_BUF_ID:
|
||||
tmp = vf610_nfc_get_id(mtd, c);
|
||||
break;
|
||||
case ALT_BUF_STAT:
|
||||
tmp = vf610_nfc_get_status(mtd);
|
||||
break;
|
||||
case ALT_BUF_ONFI:
|
||||
#ifdef __LITTLE_ENDIAN
|
||||
/* Reverse byte since the controller uses big endianness */
|
||||
c = nfc->column ^ 0x3;
|
||||
tmp = *((u8 *)(nfc->regs + NFC_MAIN_AREA(0) + c));
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
tmp = *((u8 *)(nfc->regs + NFC_MAIN_AREA(0) + c));
|
||||
break;
|
||||
}
|
||||
nfc->column++;
|
||||
return tmp;
|
||||
}
|
||||
|
||||
|
@ -532,10 +553,8 @@ static inline int vf610_nfc_correct_data(struct mtd_info *mtd, u_char *dat)
|
|||
flip = count_written_bits(dat, nfc->chip.ecc.size, ecc_count);
|
||||
|
||||
/* ECC failed. */
|
||||
if (flip > ecc_count) {
|
||||
nfc->page = -1;
|
||||
if (flip > ecc_count && flip > (nfc->chip.ecc.strength / 2))
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Erased page. */
|
||||
memset(dat, 0xff, nfc->chip.ecc.size);
|
||||
|
@ -613,13 +632,11 @@ static int vf610_nfc_nand_init(int devnum, void __iomem *addr)
|
|||
mtd->priv = chip;
|
||||
chip->priv = nfc;
|
||||
|
||||
if (cfg.width == 16) {
|
||||
if (cfg.width == 16)
|
||||
chip->options |= NAND_BUSWIDTH_16;
|
||||
vf610_nfc_set(mtd, NFC_FLASH_CONFIG, CONFIG_16BIT);
|
||||
} else {
|
||||
chip->options &= ~NAND_BUSWIDTH_16;
|
||||
vf610_nfc_clear(mtd, NFC_FLASH_CONFIG, CONFIG_16BIT);
|
||||
}
|
||||
|
||||
/* Use 8-bit mode during initialization */
|
||||
vf610_nfc_clear(mtd, NFC_FLASH_CONFIG, CONFIG_16BIT);
|
||||
|
||||
/* Disable subpage writes as we do not provide ecc->hwctl */
|
||||
chip->options |= NAND_NO_SUBPAGE_WRITE;
|
||||
|
@ -634,18 +651,8 @@ static int vf610_nfc_nand_init(int devnum, void __iomem *addr)
|
|||
|
||||
/* Bad block options. */
|
||||
if (cfg.flash_bbt)
|
||||
chip->bbt_options = NAND_BBT_USE_FLASH | NAND_BBT_CREATE;
|
||||
|
||||
/* Default to software ECC until flash ID. */
|
||||
vf610_nfc_set_field(mtd, NFC_FLASH_CONFIG,
|
||||
CONFIG_ECC_MODE_MASK,
|
||||
CONFIG_ECC_MODE_SHIFT, ECC_BYPASS);
|
||||
|
||||
chip->bbt_td = &bbt_main_descr;
|
||||
chip->bbt_md = &bbt_mirror_descr;
|
||||
|
||||
nfc->page_sz = PAGE_2K + OOB_64;
|
||||
nfc->page_sz += cfg.width == 16 ? 1 : 0;
|
||||
chip->bbt_options = NAND_BBT_USE_FLASH | NAND_BBT_NO_OOB |
|
||||
NAND_BBT_CREATE;
|
||||
|
||||
/* Set configuration register. */
|
||||
vf610_nfc_clear(mtd, NFC_FLASH_CONFIG, CONFIG_ADDR_AUTO_INCR_BIT);
|
||||
|
@ -672,17 +679,17 @@ static int vf610_nfc_nand_init(int devnum, void __iomem *addr)
|
|||
goto error;
|
||||
}
|
||||
|
||||
if (cfg.width == 16)
|
||||
vf610_nfc_set(mtd, NFC_FLASH_CONFIG, CONFIG_16BIT);
|
||||
|
||||
chip->ecc.mode = NAND_ECC_SOFT; /* default */
|
||||
|
||||
nfc->page_sz = mtd->writesize + mtd->oobsize;
|
||||
|
||||
/* Single buffer only, max 256 OOB minus ECC status */
|
||||
if (nfc->page_sz > PAGE_2K + 256 - 8) {
|
||||
if (mtd->writesize + mtd->oobsize > PAGE_2K + 256 - 8) {
|
||||
dev_err(nfc->dev, "Unsupported flash size\n");
|
||||
err = -ENXIO;
|
||||
goto error;
|
||||
}
|
||||
nfc->page_sz += cfg.width == 16 ? 1 : 0;
|
||||
|
||||
if (cfg.hardware_ecc) {
|
||||
if (mtd->writesize != PAGE_2K && mtd->oobsize < 64) {
|
||||
|
@ -691,7 +698,9 @@ static int vf610_nfc_nand_init(int devnum, void __iomem *addr)
|
|||
goto error;
|
||||
}
|
||||
|
||||
chip->ecc.layout = &vf610_nfc_ecc45;
|
||||
/* Current HW ECC layouts only use 64 bytes of OOB */
|
||||
if (mtd->oobsize > 64)
|
||||
mtd->oobsize = 64;
|
||||
|
||||
/* propagate ecc.layout to mtd_info */
|
||||
mtd->ecclayout = chip->ecc.layout;
|
||||
|
@ -699,14 +708,15 @@ static int vf610_nfc_nand_init(int devnum, void __iomem *addr)
|
|||
chip->ecc.write_page = vf610_nfc_write_page;
|
||||
chip->ecc.mode = NAND_ECC_HW;
|
||||
|
||||
chip->ecc.bytes = 45;
|
||||
chip->ecc.size = PAGE_2K;
|
||||
chip->ecc.layout = &vf610_nfc_ecc;
|
||||
#if defined(CONFIG_SYS_NAND_VF610_NFC_45_ECC_BYTES)
|
||||
chip->ecc.strength = 24;
|
||||
|
||||
/* set ECC mode to 45 bytes OOB with 24 bits correction */
|
||||
vf610_nfc_set_field(mtd, NFC_FLASH_CONFIG,
|
||||
CONFIG_ECC_MODE_MASK,
|
||||
CONFIG_ECC_MODE_SHIFT, ECC_45_BYTE);
|
||||
chip->ecc.bytes = 45;
|
||||
#elif defined(CONFIG_SYS_NAND_VF610_NFC_60_ECC_BYTES)
|
||||
chip->ecc.strength = 32;
|
||||
chip->ecc.bytes = 60;
|
||||
#endif
|
||||
|
||||
/* Enable ECC_STATUS */
|
||||
vf610_nfc_set(mtd, NFC_FLASH_CONFIG, CONFIG_ECC_SRAM_REQ_BIT);
|
||||
|
|
|
@ -50,8 +50,7 @@
|
|||
|
||||
/* NAND support */
|
||||
#define CONFIG_CMD_NAND
|
||||
#define CONFIG_NAND_VF610_NFC
|
||||
#define CONFIG_SYS_NAND_SELF_INIT
|
||||
#define CONFIG_SYS_NAND_ONFI_DETECTION
|
||||
#define CONFIG_SYS_MAX_NAND_DEVICE 1
|
||||
#define CONFIG_SYS_NAND_BASE NFC_BASE_ADDR
|
||||
|
||||
|
|
|
@ -48,12 +48,10 @@
|
|||
/* NAND support */
|
||||
#define CONFIG_CMD_NAND
|
||||
#define CONFIG_CMD_NAND_TRIMFFS
|
||||
#define CONFIG_SYS_NAND_ONFI_DETECTION
|
||||
|
||||
#ifdef CONFIG_CMD_NAND
|
||||
#define CONFIG_NAND_VF610_NFC
|
||||
#define CONFIG_SYS_NAND_SELF_INIT
|
||||
#define CONFIG_USE_ARCH_MEMCPY
|
||||
#define CONFIG_SYS_NAND_BUSWIDTH_16BIT
|
||||
#define CONFIG_SYS_MAX_NAND_DEVICE 1
|
||||
#define CONFIG_SYS_NAND_BASE NFC_BASE_ADDR
|
||||
|
||||
|
|
|
@ -14,6 +14,10 @@
|
|||
|
||||
#include "compiler.h"
|
||||
|
||||
/* Taken from <linux/kernel.h> */
|
||||
#define __round_mask(x, y) ((__typeof__(x))((y)-1))
|
||||
#define round_down(x, y) ((x) & ~__round_mask(x, y))
|
||||
|
||||
/*
|
||||
* Default BCB layout.
|
||||
*
|
||||
|
@ -48,6 +52,7 @@ static uint32_t sd_sector = 2048;
|
|||
#define MXS_NAND_DMA_DESCRIPTOR_COUNT 4
|
||||
#define MXS_NAND_CHUNK_DATA_CHUNK_SIZE 512
|
||||
#define MXS_NAND_METADATA_SIZE 10
|
||||
#define MXS_NAND_BITS_PER_ECC_LEVEL 13
|
||||
#define MXS_NAND_COMMAND_BUFFER_SIZE 32
|
||||
|
||||
struct mx28_nand_fcb {
|
||||
|
@ -125,29 +130,34 @@ struct mx28_sd_config_block {
|
|||
struct mx28_sd_drive_info drv_info[1];
|
||||
};
|
||||
|
||||
static inline uint32_t mx28_nand_ecc_chunk_cnt(uint32_t page_data_size)
|
||||
{
|
||||
return page_data_size / MXS_NAND_CHUNK_DATA_CHUNK_SIZE;
|
||||
}
|
||||
|
||||
static inline uint32_t mx28_nand_ecc_size_in_bits(uint32_t ecc_strength)
|
||||
{
|
||||
return ecc_strength * 13;
|
||||
return ecc_strength * MXS_NAND_BITS_PER_ECC_LEVEL;
|
||||
}
|
||||
|
||||
static inline uint32_t mx28_nand_get_ecc_strength(uint32_t page_data_size,
|
||||
uint32_t page_oob_size)
|
||||
{
|
||||
if (page_data_size == 2048)
|
||||
return 8;
|
||||
int ecc_strength;
|
||||
|
||||
if (page_data_size == 4096) {
|
||||
if (page_oob_size == 128)
|
||||
return 8;
|
||||
/*
|
||||
* Determine the ECC layout with the formula:
|
||||
* ECC bits per chunk = (total page spare data bits) /
|
||||
* (bits per ECC level) / (chunks per page)
|
||||
* where:
|
||||
* total page spare data bits =
|
||||
* (page oob size - meta data size) * (bits per byte)
|
||||
*/
|
||||
ecc_strength = ((page_oob_size - MXS_NAND_METADATA_SIZE) * 8)
|
||||
/ (MXS_NAND_BITS_PER_ECC_LEVEL *
|
||||
mx28_nand_ecc_chunk_cnt(page_data_size));
|
||||
|
||||
if (page_oob_size == 218)
|
||||
return 16;
|
||||
|
||||
if (page_oob_size == 224)
|
||||
return 16;
|
||||
}
|
||||
|
||||
return 0;
|
||||
return round_down(ecc_strength, 2);
|
||||
}
|
||||
|
||||
static inline uint32_t mx28_nand_get_mark_offset(uint32_t page_data_size,
|
||||
|
|
Loading…
Add table
Reference in a new issue