diff options
author | Masahiro Yamada <yamada.masahiro@socionext.com> | 2017-06-07 20:52:12 +0900 |
---|---|---|
committer | Boris Brezillon <boris.brezillon@free-electrons.com> | 2017-06-10 13:40:13 +0200 |
commit | 7de117fd5bfe0d84e50714ef5dcf5f3cec7f0eef (patch) | |
tree | 8f2638aa35dc166f2af028350a94dd662626eae8 /drivers/mtd/nand/denali.h | |
parent | a03c60178c181767ecfb26fb311a88742d228118 (diff) | |
download | linux-7de117fd5bfe0d84e50714ef5dcf5f3cec7f0eef.tar.bz2 |
mtd: nand: denali: avoid hard-coding ECC step, strength, bytes
This driver was originally written for the Intel MRST platform with
several platform-specific parameters hard-coded.
Currently, the ECC settings are hard-coded as follows:
#define ECC_SECTOR_SIZE 512
#define ECC_8BITS 14
#define ECC_15BITS 26
Therefore, the driver can only support two cases.
- ecc.size = 512, ecc.strength = 8 --> ecc.bytes = 14
- ecc.size = 512, ecc.strength = 15 --> ecc.bytes = 26
However, these are actually customizable parameters, for example,
UniPhier platform supports the following:
- ecc.size = 1024, ecc.strength = 8 --> ecc.bytes = 14
- ecc.size = 1024, ecc.strength = 16 --> ecc.bytes = 28
- ecc.size = 1024, ecc.strength = 24 --> ecc.bytes = 42
So, we need to handle the ECC parameters in a more generic manner.
Fortunately, the Denali User's Guide explains how to calculate the
ecc.bytes. The formula is:
ecc.bytes = 2 * CEIL(13 * ecc.strength / 16) (for ecc.size = 512)
ecc.bytes = 2 * CEIL(14 * ecc.strength / 16) (for ecc.size = 1024)
For DT platforms, it would be reasonable to allow DT to specify ECC
strength by either "nand-ecc-strength" or "nand-ecc-maximize". If
none of them is specified, the driver will try to meet the chip's ECC
requirement.
For PCI platforms, the max ECC strength is used to keep the original
behavior.
Newer versions of this IP need ecc.size and ecc.steps explicitly
set up via the following registers:
CFG_DATA_BLOCK_SIZE (0x6b0)
CFG_LAST_DATA_BLOCK_SIZE (0x6c0)
CFG_NUM_DATA_BLOCKS (0x6d0)
For older IP versions, write accesses to these registers are just
ignored.
Signed-off-by: Masahiro Yamada <yamada.masahiro@socionext.com>
Acked-by: Rob Herring <robh@kernel.org>
Signed-off-by: Boris Brezillon <boris.brezillon@free-electrons.com>
Diffstat (limited to 'drivers/mtd/nand/denali.h')
-rw-r--r-- | drivers/mtd/nand/denali.h | 12 |
1 files changed, 10 insertions, 2 deletions
diff --git a/drivers/mtd/nand/denali.h b/drivers/mtd/nand/denali.h index 37833535a7a3..a06ed741b550 100644 --- a/drivers/mtd/nand/denali.h +++ b/drivers/mtd/nand/denali.h @@ -259,6 +259,14 @@ #define ECC_COR_INFO__MAX_ERRORS GENMASK(6, 0) #define ECC_COR_INFO__UNCOR_ERR BIT(7) +#define CFG_DATA_BLOCK_SIZE 0x6b0 + +#define CFG_LAST_DATA_BLOCK_SIZE 0x6c0 + +#define CFG_NUM_DATA_BLOCKS 0x6d0 + +#define CFG_META_DATA_SIZE 0x6e0 + #define DMA_ENABLE 0x700 #define DMA_ENABLE__FLAG BIT(0) @@ -301,8 +309,6 @@ #define MODE_10 0x08000000 #define MODE_11 0x0C000000 -#define ECC_SECTOR_SIZE 512 - struct nand_buf { int head; int tail; @@ -337,11 +343,13 @@ struct denali_nand_info { int max_banks; unsigned int revision; unsigned int caps; + const struct nand_ecc_caps *ecc_caps; }; #define DENALI_CAP_HW_ECC_FIXUP BIT(0) #define DENALI_CAP_DMA_64BIT BIT(1) +int denali_calc_ecc_bytes(int step_size, int strength); extern int denali_init(struct denali_nand_info *denali); extern void denali_remove(struct denali_nand_info *denali); |