]> git.kernelconcepts.de Git - karo-tx-linux.git/commitdiff
mtd: nand: denali: avoid hard-coding ECC step, strength, bytes
authorMasahiro Yamada <yamada.masahiro@socionext.com>
Wed, 7 Jun 2017 11:52:12 +0000 (20:52 +0900)
committerBoris Brezillon <boris.brezillon@free-electrons.com>
Sat, 10 Jun 2017 11:40:13 +0000 (13:40 +0200)
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>
Documentation/devicetree/bindings/mtd/denali-nand.txt
drivers/mtd/nand/denali.c
drivers/mtd/nand/denali.h
drivers/mtd/nand/denali_dt.c
drivers/mtd/nand/denali_pci.c

index e593bbeb2115deb92966d593c18f002e5f269e41..b7742a7363ea7a4683cc481253d61ef4d0385a0a 100644 (file)
@@ -7,6 +7,13 @@ Required properties:
   - reg-names: Should contain the reg names "nand_data" and "denali_reg"
   - interrupts : The interrupt number.
 
+Optional properties:
+  - nand-ecc-step-size: see nand.txt for details.  If present, the value must be
+      512        for "altr,socfpga-denali-nand"
+  - nand-ecc-strength: see nand.txt for details.  Valid values are:
+      8, 15      for "altr,socfpga-denali-nand"
+  - nand-ecc-maximize: see nand.txt for details
+
 The device tree may optionally contain sub-nodes describing partitions of the
 address space. See partition.txt for more detail.
 
index b3c99d98fdee990ebde3f35b96cf65633c8e82b4..2d3d9875dfaab91e5e0a0679a478f74b7d4ee58c 100644 (file)
@@ -886,8 +886,6 @@ static int denali_hw_ecc_fixup(struct mtd_info *mtd,
        return max_bitflips;
 }
 
-#define ECC_SECTOR_SIZE 512
-
 #define ECC_SECTOR(x)  (((x) & ECC_ERROR_ADDRESS__SECTOR_NR) >> 12)
 #define ECC_BYTE(x)    (((x) & ECC_ERROR_ADDRESS__OFFSET))
 #define ECC_CORRECTION_VALUE(x) ((x) & ERR_CORRECTION_INFO__BYTEMASK)
@@ -899,6 +897,7 @@ static int denali_sw_ecc_fixup(struct mtd_info *mtd,
                               struct denali_nand_info *denali,
                               unsigned long *uncor_ecc_flags, uint8_t *buf)
 {
+       unsigned int ecc_size = denali->nand.ecc.size;
        unsigned int bitflips = 0;
        unsigned int max_bitflips = 0;
        uint32_t err_addr, err_cor_info;
@@ -928,9 +927,9 @@ static int denali_sw_ecc_fixup(struct mtd_info *mtd,
                         * an erased sector.
                         */
                        *uncor_ecc_flags |= BIT(err_sector);
-               } else if (err_byte < ECC_SECTOR_SIZE) {
+               } else if (err_byte < ecc_size) {
                        /*
-                        * If err_byte is larger than ECC_SECTOR_SIZE, means error
+                        * If err_byte is larger than ecc_size, means error
                         * happened in OOB, so we ignore it. It's no need for
                         * us to correct it err_device is represented the NAND
                         * error bits are happened in if there are more than
@@ -939,7 +938,7 @@ static int denali_sw_ecc_fixup(struct mtd_info *mtd,
                        int offset;
                        unsigned int flips_in_byte;
 
-                       offset = (err_sector * ECC_SECTOR_SIZE + err_byte) *
+                       offset = (err_sector * ecc_size + err_byte) *
                                                denali->devnum + err_device;
 
                        /* correct the ECC error */
@@ -1345,13 +1344,39 @@ static void denali_hw_init(struct denali_nand_info *denali)
        denali_irq_init(denali);
 }
 
-/*
- * Althogh controller spec said SLC ECC is forceb to be 4bit,
- * but denali controller in MRST only support 15bit and 8bit ECC
- * correction
- */
-#define ECC_8BITS      14
-#define ECC_15BITS     26
+int denali_calc_ecc_bytes(int step_size, int strength)
+{
+       /* BCH code.  Denali requires ecc.bytes to be multiple of 2 */
+       return DIV_ROUND_UP(strength * fls(step_size * 8), 16) * 2;
+}
+EXPORT_SYMBOL(denali_calc_ecc_bytes);
+
+static int denali_ecc_setup(struct mtd_info *mtd, struct nand_chip *chip,
+                           struct denali_nand_info *denali)
+{
+       int oobavail = mtd->oobsize - denali->bbtskipbytes;
+       int ret;
+
+       /*
+        * If .size and .strength are already set (usually by DT),
+        * check if they are supported by this controller.
+        */
+       if (chip->ecc.size && chip->ecc.strength)
+               return nand_check_ecc_caps(chip, denali->ecc_caps, oobavail);
+
+       /*
+        * We want .size and .strength closest to the chip's requirement
+        * unless NAND_ECC_MAXIMIZE is requested.
+        */
+       if (!(chip->ecc.options & NAND_ECC_MAXIMIZE)) {
+               ret = nand_match_ecc_req(chip, denali->ecc_caps, oobavail);
+               if (!ret)
+                       return 0;
+       }
+
+       /* Max ECC strength is the last thing we can do */
+       return nand_maximize_ecc(chip, denali->ecc_caps, oobavail);
+}
 
 static int denali_ooblayout_ecc(struct mtd_info *mtd, int section,
                                struct mtd_oob_region *oobregion)
@@ -1588,34 +1613,26 @@ int denali_init(struct denali_nand_info *denali)
        /* no subpage writes on denali */
        chip->options |= NAND_NO_SUBPAGE_WRITE;
 
-       /*
-        * Denali Controller only support 15bit and 8bit ECC in MRST,
-        * so just let controller do 15bit ECC for MLC and 8bit ECC for
-        * SLC if possible.
-        * */
-       if (!nand_is_slc(chip) &&
-                       (mtd->oobsize > (denali->bbtskipbytes +
-                       ECC_15BITS * (mtd->writesize /
-                       ECC_SECTOR_SIZE)))) {
-               /* if MLC OOB size is large enough, use 15bit ECC*/
-               chip->ecc.strength = 15;
-               chip->ecc.bytes = ECC_15BITS;
-               iowrite32(15, denali->flash_reg + ECC_CORRECTION);
-       } else if (mtd->oobsize < (denali->bbtskipbytes +
-                       ECC_8BITS * (mtd->writesize /
-                       ECC_SECTOR_SIZE))) {
-               pr_err("Your NAND chip OOB is not large enough to contain 8bit ECC correction codes");
+       ret = denali_ecc_setup(mtd, chip, denali);
+       if (ret) {
+               dev_err(denali->dev, "Failed to setup ECC settings.\n");
                goto failed_req_irq;
-       } else {
-               chip->ecc.strength = 8;
-               chip->ecc.bytes = ECC_8BITS;
-               iowrite32(8, denali->flash_reg + ECC_CORRECTION);
        }
 
+       dev_dbg(denali->dev,
+               "chosen ECC settings: step=%d, strength=%d, bytes=%d\n",
+               chip->ecc.size, chip->ecc.strength, chip->ecc.bytes);
+
+       iowrite32(chip->ecc.strength, denali->flash_reg + ECC_CORRECTION);
+
+       iowrite32(chip->ecc.size, denali->flash_reg + CFG_DATA_BLOCK_SIZE);
+       iowrite32(chip->ecc.size, denali->flash_reg + CFG_LAST_DATA_BLOCK_SIZE);
+       /* chip->ecc.steps is set by nand_scan_tail(); not available here */
+       iowrite32(mtd->writesize / chip->ecc.size,
+                 denali->flash_reg + CFG_NUM_DATA_BLOCKS);
+
        mtd_set_ooblayout(mtd, &denali_ooblayout_ops);
 
-       /* override the default read operations */
-       chip->ecc.size = ECC_SECTOR_SIZE;
        chip->ecc.read_page = denali_read_page;
        chip->ecc.read_page_raw = denali_read_page_raw;
        chip->ecc.write_page = denali_write_page;
index 37833535a7a38e7ba8d91b52ee95606dcfbc95a5..a06ed741b550d64e8b53b9136ac3a669a856734f 100644 (file)
 #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)
 
 #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);
 
index b48430fe3cd44d28a381d37e420a91b4a42a75e2..bd1aa4cf4457e77c86ae16a8cd4119902fc60349 100644 (file)
@@ -32,10 +32,14 @@ struct denali_dt {
 struct denali_dt_data {
        unsigned int revision;
        unsigned int caps;
+       const struct nand_ecc_caps *ecc_caps;
 };
 
+NAND_ECC_CAPS_SINGLE(denali_socfpga_ecc_caps, denali_calc_ecc_bytes,
+                    512, 8, 15);
 static const struct denali_dt_data denali_socfpga_data = {
        .caps = DENALI_CAP_HW_ECC_FIXUP,
+       .ecc_caps = &denali_socfpga_ecc_caps,
 };
 
 static const struct of_device_id denali_nand_dt_ids[] = {
@@ -64,6 +68,7 @@ static int denali_dt_probe(struct platform_device *pdev)
        if (data) {
                denali->revision = data->revision;
                denali->caps = data->caps;
+               denali->ecc_caps = data->ecc_caps;
        }
 
        denali->platform = DT;
index ac843238b77e72f846c63d2eb9a8299a2d3aceb5..37dc0934c24c169b20d569df374ac66f365d1ebc 100644 (file)
@@ -27,6 +27,8 @@ static const struct pci_device_id denali_pci_ids[] = {
 };
 MODULE_DEVICE_TABLE(pci, denali_pci_ids);
 
+NAND_ECC_CAPS_SINGLE(denali_pci_ecc_caps, denali_calc_ecc_bytes, 512, 8, 15);
+
 static int denali_pci_probe(struct pci_dev *dev, const struct pci_device_id *id)
 {
        int ret;
@@ -65,6 +67,8 @@ static int denali_pci_probe(struct pci_dev *dev, const struct pci_device_id *id)
        pci_set_master(dev);
        denali->dev = &dev->dev;
        denali->irq = dev->irq;
+       denali->ecc_caps = &denali_pci_ecc_caps;
+       denali->nand.ecc.options |= NAND_ECC_MAXIMIZE;
 
        ret = pci_request_regions(dev, DENALI_NAND_NAME);
        if (ret) {