2018-06-22 15:19:46 +00:00
|
|
|
/* SPDX-License-Identifier: GPL-2.0+ */
|
|
|
|
/*
|
|
|
|
* NXP GPMI NAND flash driver
|
|
|
|
*
|
|
|
|
* Copyright (C) 2018 Toradex
|
|
|
|
* Authors:
|
|
|
|
* Stefan Agner <stefan.agner@toradex.com>
|
|
|
|
*/
|
|
|
|
|
2018-06-22 16:06:16 +00:00
|
|
|
#include <linux/mtd/mtd.h>
|
2021-09-22 18:50:35 +00:00
|
|
|
#include <linux/mtd/rawnand.h>
|
2018-06-22 16:06:16 +00:00
|
|
|
#include <asm/cache.h>
|
|
|
|
#include <nand.h>
|
|
|
|
#include <asm/mach-imx/dma.h>
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @gf_len: The length of Galois Field. (e.g., 13 or 14)
|
|
|
|
* @ecc_strength: A number that describes the strength of the ECC
|
|
|
|
* algorithm.
|
mtd: gpmi: change the BCH layout setting for large oob NAND
The code change updated the NAND driver BCH ECC layout algorithm to
support large oob size NAND chips(oob > 1024 bytes) and proposed a new
way to set ECC layout.
Current implementation requires each chunk size larger than oob size so
the bad block marker (BBM) can be guaranteed located in data chunk. The
ECC layout always using the unbalanced layout(Ecc for both meta and
Data0 chunk), but for the NAND chips with oob larger than 1k, the driver
cannot support because BCH doesn’t support GF 15 for 2K chunk.
The change keeps the data chunk no larger than 1k and adjust the ECC
strength or ECC layout to locate the BBM in data chunk. General idea for
large oob NAND chips is
1.Try all ECC strength from the minimum value required by NAND spec to
the maximum one that works, any ECC makes the BBM locate in data chunk
can be chosen.
2.If none of them works, using separate ECC for meta, which will add one
extra ecc with the same ECC strength as other data chunks. This extra
ECC can guarantee BBM located in data chunk, of course, we need to check
if oob can afford it.
Previous code has two methods for ECC layout setting, the
legacy_calc_ecc_layout and calc_ecc_layout_by_info, the difference
between these two methods is, legacy_calc_ecc_layout set the chunk size
larger chan oob size and then set the maximum ECC strength that oob can
afford. While the calc_ecc_layout_by_info set chunk size and ECC
strength according to NAND spec. It has been proved that the first
method cannot provide safe ECC strength for some modern NAND chips, so
in current code,
1. Driver read NAND parameters first and then chose the proper ECC
layout setting method.
2. If the oob is large or NAND required data chunk larger than oob size,
chose calc_ecc_for_large_oob, otherwise use calc_ecc_layout_by_info
3. legacy_calc_ecc_layout only used for some NAND chips does not contains
necessary information. So this is only a backup plan, it is NOT
recommended to use these NAND chips.
Signed-off-by: Han Xu <b45815@freescale.com>
Signed-off-by: Ye Li <ye.li@nxp.com>
Signed-off-by: Peng Fan <peng.fan@nxp.com>
2020-05-04 14:08:50 +00:00
|
|
|
* @ecc_chunk0_size: The size, in bytes, of a first ECC chunk.
|
|
|
|
* @ecc_chunkn_size: The size, in bytes, of a single ECC chunk after
|
|
|
|
* the first chunk in the page.
|
2018-06-22 16:06:16 +00:00
|
|
|
* @ecc_chunk_count: The number of ECC chunks in the page,
|
|
|
|
* @block_mark_byte_offset: The byte offset in the ECC-based page view at
|
|
|
|
* which the underlying physical block mark appears.
|
|
|
|
* @block_mark_bit_offset: The bit offset into the ECC-based page view at
|
|
|
|
* which the underlying physical block mark appears.
|
mtd: gpmi: change the BCH layout setting for large oob NAND
The code change updated the NAND driver BCH ECC layout algorithm to
support large oob size NAND chips(oob > 1024 bytes) and proposed a new
way to set ECC layout.
Current implementation requires each chunk size larger than oob size so
the bad block marker (BBM) can be guaranteed located in data chunk. The
ECC layout always using the unbalanced layout(Ecc for both meta and
Data0 chunk), but for the NAND chips with oob larger than 1k, the driver
cannot support because BCH doesn’t support GF 15 for 2K chunk.
The change keeps the data chunk no larger than 1k and adjust the ECC
strength or ECC layout to locate the BBM in data chunk. General idea for
large oob NAND chips is
1.Try all ECC strength from the minimum value required by NAND spec to
the maximum one that works, any ECC makes the BBM locate in data chunk
can be chosen.
2.If none of them works, using separate ECC for meta, which will add one
extra ecc with the same ECC strength as other data chunks. This extra
ECC can guarantee BBM located in data chunk, of course, we need to check
if oob can afford it.
Previous code has two methods for ECC layout setting, the
legacy_calc_ecc_layout and calc_ecc_layout_by_info, the difference
between these two methods is, legacy_calc_ecc_layout set the chunk size
larger chan oob size and then set the maximum ECC strength that oob can
afford. While the calc_ecc_layout_by_info set chunk size and ECC
strength according to NAND spec. It has been proved that the first
method cannot provide safe ECC strength for some modern NAND chips, so
in current code,
1. Driver read NAND parameters first and then chose the proper ECC
layout setting method.
2. If the oob is large or NAND required data chunk larger than oob size,
chose calc_ecc_for_large_oob, otherwise use calc_ecc_layout_by_info
3. legacy_calc_ecc_layout only used for some NAND chips does not contains
necessary information. So this is only a backup plan, it is NOT
recommended to use these NAND chips.
Signed-off-by: Han Xu <b45815@freescale.com>
Signed-off-by: Ye Li <ye.li@nxp.com>
Signed-off-by: Peng Fan <peng.fan@nxp.com>
2020-05-04 14:08:50 +00:00
|
|
|
* @ecc_for_meta: The flag to indicate if there is a dedicate ecc
|
|
|
|
* for meta.
|
2018-06-22 16:06:16 +00:00
|
|
|
*/
|
|
|
|
struct bch_geometry {
|
|
|
|
unsigned int gf_len;
|
|
|
|
unsigned int ecc_strength;
|
mtd: gpmi: change the BCH layout setting for large oob NAND
The code change updated the NAND driver BCH ECC layout algorithm to
support large oob size NAND chips(oob > 1024 bytes) and proposed a new
way to set ECC layout.
Current implementation requires each chunk size larger than oob size so
the bad block marker (BBM) can be guaranteed located in data chunk. The
ECC layout always using the unbalanced layout(Ecc for both meta and
Data0 chunk), but for the NAND chips with oob larger than 1k, the driver
cannot support because BCH doesn’t support GF 15 for 2K chunk.
The change keeps the data chunk no larger than 1k and adjust the ECC
strength or ECC layout to locate the BBM in data chunk. General idea for
large oob NAND chips is
1.Try all ECC strength from the minimum value required by NAND spec to
the maximum one that works, any ECC makes the BBM locate in data chunk
can be chosen.
2.If none of them works, using separate ECC for meta, which will add one
extra ecc with the same ECC strength as other data chunks. This extra
ECC can guarantee BBM located in data chunk, of course, we need to check
if oob can afford it.
Previous code has two methods for ECC layout setting, the
legacy_calc_ecc_layout and calc_ecc_layout_by_info, the difference
between these two methods is, legacy_calc_ecc_layout set the chunk size
larger chan oob size and then set the maximum ECC strength that oob can
afford. While the calc_ecc_layout_by_info set chunk size and ECC
strength according to NAND spec. It has been proved that the first
method cannot provide safe ECC strength for some modern NAND chips, so
in current code,
1. Driver read NAND parameters first and then chose the proper ECC
layout setting method.
2. If the oob is large or NAND required data chunk larger than oob size,
chose calc_ecc_for_large_oob, otherwise use calc_ecc_layout_by_info
3. legacy_calc_ecc_layout only used for some NAND chips does not contains
necessary information. So this is only a backup plan, it is NOT
recommended to use these NAND chips.
Signed-off-by: Han Xu <b45815@freescale.com>
Signed-off-by: Ye Li <ye.li@nxp.com>
Signed-off-by: Peng Fan <peng.fan@nxp.com>
2020-05-04 14:08:50 +00:00
|
|
|
unsigned int ecc_chunk0_size;
|
|
|
|
unsigned int ecc_chunkn_size;
|
2018-06-22 16:06:16 +00:00
|
|
|
unsigned int ecc_chunk_count;
|
|
|
|
unsigned int block_mark_byte_offset;
|
|
|
|
unsigned int block_mark_bit_offset;
|
mtd: gpmi: change the BCH layout setting for large oob NAND
The code change updated the NAND driver BCH ECC layout algorithm to
support large oob size NAND chips(oob > 1024 bytes) and proposed a new
way to set ECC layout.
Current implementation requires each chunk size larger than oob size so
the bad block marker (BBM) can be guaranteed located in data chunk. The
ECC layout always using the unbalanced layout(Ecc for both meta and
Data0 chunk), but for the NAND chips with oob larger than 1k, the driver
cannot support because BCH doesn’t support GF 15 for 2K chunk.
The change keeps the data chunk no larger than 1k and adjust the ECC
strength or ECC layout to locate the BBM in data chunk. General idea for
large oob NAND chips is
1.Try all ECC strength from the minimum value required by NAND spec to
the maximum one that works, any ECC makes the BBM locate in data chunk
can be chosen.
2.If none of them works, using separate ECC for meta, which will add one
extra ecc with the same ECC strength as other data chunks. This extra
ECC can guarantee BBM located in data chunk, of course, we need to check
if oob can afford it.
Previous code has two methods for ECC layout setting, the
legacy_calc_ecc_layout and calc_ecc_layout_by_info, the difference
between these two methods is, legacy_calc_ecc_layout set the chunk size
larger chan oob size and then set the maximum ECC strength that oob can
afford. While the calc_ecc_layout_by_info set chunk size and ECC
strength according to NAND spec. It has been proved that the first
method cannot provide safe ECC strength for some modern NAND chips, so
in current code,
1. Driver read NAND parameters first and then chose the proper ECC
layout setting method.
2. If the oob is large or NAND required data chunk larger than oob size,
chose calc_ecc_for_large_oob, otherwise use calc_ecc_layout_by_info
3. legacy_calc_ecc_layout only used for some NAND chips does not contains
necessary information. So this is only a backup plan, it is NOT
recommended to use these NAND chips.
Signed-off-by: Han Xu <b45815@freescale.com>
Signed-off-by: Ye Li <ye.li@nxp.com>
Signed-off-by: Peng Fan <peng.fan@nxp.com>
2020-05-04 14:08:50 +00:00
|
|
|
unsigned int ecc_for_meta; /* ECC for meta data */
|
2018-06-22 16:06:16 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
struct mxs_nand_info {
|
|
|
|
struct nand_chip chip;
|
|
|
|
struct udevice *dev;
|
|
|
|
unsigned int max_ecc_strength_supported;
|
|
|
|
bool use_minimum_ecc;
|
|
|
|
int cur_chip;
|
|
|
|
|
|
|
|
uint32_t cmd_queue_len;
|
|
|
|
uint32_t data_buf_size;
|
|
|
|
struct bch_geometry bch_geometry;
|
|
|
|
|
|
|
|
uint8_t *cmd_buf;
|
|
|
|
uint8_t *data_buf;
|
|
|
|
uint8_t *oob_buf;
|
|
|
|
|
|
|
|
uint8_t marking_block_bad;
|
|
|
|
uint8_t raw_oob_mode;
|
|
|
|
|
|
|
|
struct mxs_gpmi_regs *gpmi_regs;
|
|
|
|
struct mxs_bch_regs *bch_regs;
|
|
|
|
|
|
|
|
/* Functions with altered behaviour */
|
|
|
|
int (*hooked_read_oob)(struct mtd_info *mtd,
|
|
|
|
loff_t from, struct mtd_oob_ops *ops);
|
|
|
|
int (*hooked_write_oob)(struct mtd_info *mtd,
|
|
|
|
loff_t to, struct mtd_oob_ops *ops);
|
|
|
|
int (*hooked_block_markbad)(struct mtd_info *mtd,
|
|
|
|
loff_t ofs);
|
|
|
|
|
|
|
|
/* DMA descriptors */
|
|
|
|
struct mxs_dma_desc **desc;
|
|
|
|
uint32_t desc_index;
|
2019-11-03 15:49:43 +00:00
|
|
|
|
|
|
|
/* Hardware BCH interface and randomizer */
|
|
|
|
u32 en_randomizer;
|
|
|
|
u32 writesize;
|
|
|
|
u32 oobsize;
|
|
|
|
u32 bch_flash0layout0;
|
|
|
|
u32 bch_flash0layout1;
|
|
|
|
};
|
|
|
|
|
|
|
|
struct mxs_nand_layout {
|
|
|
|
u32 nblocks;
|
|
|
|
u32 meta_size;
|
|
|
|
u32 data0_size;
|
|
|
|
u32 ecc0;
|
|
|
|
u32 datan_size;
|
|
|
|
u32 eccn;
|
2020-05-04 14:08:58 +00:00
|
|
|
u32 gf_len;
|
2018-06-22 16:06:16 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
int mxs_nand_init_ctrl(struct mxs_nand_info *nand_info);
|
2018-06-22 15:19:46 +00:00
|
|
|
int mxs_nand_init_spl(struct nand_chip *nand);
|
2018-06-22 15:19:47 +00:00
|
|
|
int mxs_nand_setup_ecc(struct mtd_info *mtd);
|
2019-11-03 15:49:43 +00:00
|
|
|
|
2020-05-06 12:59:19 +00:00
|
|
|
void mxs_nand_mode_fcb_62bit(struct mtd_info *mtd);
|
|
|
|
void mxs_nand_mode_fcb_40bit(struct mtd_info *mtd);
|
2019-11-03 15:49:43 +00:00
|
|
|
void mxs_nand_mode_normal(struct mtd_info *mtd);
|
|
|
|
u32 mxs_nand_mark_byte_offset(struct mtd_info *mtd);
|
|
|
|
u32 mxs_nand_mark_bit_offset(struct mtd_info *mtd);
|
|
|
|
void mxs_nand_get_layout(struct mtd_info *mtd, struct mxs_nand_layout *l);
|