Changeset 38069


Ignore:
Timestamp:
2013-09-19T20:43:41+02:00 (4 years ago)
Author:
juhosg
Message:

ar71xx: ar934x_nfc: add experimental support for hardware ECC

Signed-off-by: Gabor Juhos <juhosg@…>

Location:
trunk/target/linux/ar71xx
Files:
4 edited

Legend:

Unmodified
Added
Removed
  • trunk/target/linux/ar71xx/config-3.10

    r38063 r38069  
    207207# CONFIG_MTD_MAP_BANK_WIDTH_4 is not set 
    208208CONFIG_MTD_MYLOADER_PARTS=y 
     209# CONFIG_MTD_NAND_AR934X_HW_ECC is not set 
    209210CONFIG_MTD_PHYSMAP=y 
    210211CONFIG_MTD_REDBOOT_DIRECTORY_BLOCK=-2 
  • trunk/target/linux/ar71xx/files/drivers/mtd/nand/ar934x_nfc.c

    r38068 r38069  
    22 * Driver for the built-in NAND controller of the Atheros AR934x SoCs 
    33 * 
    4  * Copyright (C) 2011-2012 Gabor Juhos <juhosg@openwrt.org> 
     4 * Copyright (C) 2011-2013 Gabor Juhos <juhosg@openwrt.org> 
    55 * 
    66 * This program is free software; you can redistribute it and/or modify it 
     
    123123#define AR934X_NFC_INT_CMD_END                  BIT(1) 
    124124 
     125#define AR934X_NFC_ECC_CTRL_ERR_THRES_S         8 
     126#define AR934X_NFC_ECC_CTRL_ERR_THRES_M         0x1f 
     127#define AR934X_NFC_ECC_CTRL_ECC_CAP_S           5 
     128#define AR934X_NFC_ECC_CTRL_ECC_CAP_M           0x7 
     129#define AR934X_NFC_ECC_CTRL_ECC_CAP_2           0 
     130#define AR934X_NFC_ECC_CTRL_ECC_CAP_4           1 
     131#define AR934X_NFC_ECC_CTRL_ECC_CAP_6           2 
     132#define AR934X_NFC_ECC_CTRL_ECC_CAP_8           3 
     133#define AR934X_NFC_ECC_CTRL_ECC_CAP_10          4 
     134#define AR934X_NFC_ECC_CTRL_ECC_CAP_12          5 
     135#define AR934X_NFC_ECC_CTRL_ECC_CAP_14          6 
     136#define AR934X_NFC_ECC_CTRL_ECC_CAP_16          7 
     137#define AR934X_NFC_ECC_CTRL_ERR_OVER            BIT(2) 
     138#define AR934X_NFC_ECC_CTRL_ERR_UNCORRECT       BIT(1) 
     139#define AR934X_NFC_ECC_CTRL_ERR_CORRECT         BIT(0) 
     140 
     141#define AR934X_NFC_ECC_OFFS_OFSET_M             0xffff 
     142 
    125143/* default timing values */ 
    126144#define AR934X_NFC_TIME_SEQ_DEFAULT     0x7fff 
     
    183201 
    184202        u32 ctrl_reg; 
     203        u32 ecc_ctrl_reg; 
     204        u32 ecc_offset_reg; 
     205        u32 ecc_thres; 
     206        u32 ecc_oob_pos; 
     207 
    185208        bool small_page; 
    186209        unsigned int addr_count0; 
     
    205228 
    206229static void ar934x_nfc_restart(struct ar934x_nfc *nfc); 
     230 
     231static inline bool 
     232is_all_ff(u8 *buf, int len) 
     233{ 
     234        while (len--) 
     235                if (buf[len] != 0xff) 
     236                        return false; 
     237 
     238        return true; 
     239} 
    207240 
    208241static inline void 
     
    456489        ar934x_nfc_wr(nfc, AR934X_NFC_REG_CTRL, ctrl_reg); 
    457490        ar934x_nfc_wr(nfc, AR934X_NFC_REG_DMA_CTRL, dma_ctrl); 
     491        ar934x_nfc_wr(nfc, AR934X_NFC_REG_ECC_CTRL, nfc->ecc_ctrl_reg); 
     492        ar934x_nfc_wr(nfc, AR934X_NFC_REG_ECC_OFFSET, nfc->ecc_offset_reg); 
    458493 
    459494        if (ar934x_nfc_use_irq(nfc)) { 
     
    614649{ 
    615650        struct ar934x_nfc *nfc = mtd_to_ar934x_nfc(mtd); 
     651        struct nand_chip *nand = mtd->priv; 
    616652 
    617653        nfc->read_id = false; 
     
    697733 
    698734        case NAND_CMD_PAGEPROG: 
     735                if (nand->ecc.mode == NAND_ECC_HW) { 
     736                        /* the data is already written */ 
     737                        break; 
     738                } 
     739 
    699740                if (nfc->small_page) 
    700741                        ar934x_nfc_send_cmd(nfc, nfc->seqin_read_cmd); 
     
    793834 
    794835        nfc->buf_index = buf_index; 
     836} 
     837 
     838static inline void 
     839ar934x_nfc_enable_hwecc(struct ar934x_nfc *nfc) 
     840{ 
     841        nfc->ctrl_reg |= AR934X_NFC_CTRL_ECC_EN; 
     842        nfc->ctrl_reg &= ~AR934X_NFC_CTRL_CUSTOM_SIZE_EN; 
     843} 
     844 
     845static inline void 
     846ar934x_nfc_disable_hwecc(struct ar934x_nfc *nfc) 
     847{ 
     848        nfc->ctrl_reg &= ~AR934X_NFC_CTRL_ECC_EN; 
     849        nfc->ctrl_reg |= AR934X_NFC_CTRL_CUSTOM_SIZE_EN; 
     850} 
     851 
     852static int 
     853ar934x_nfc_read_oob(struct mtd_info *mtd, struct nand_chip *chip, 
     854                    int page) 
     855{ 
     856        struct ar934x_nfc *nfc = mtd_to_ar934x_nfc(mtd); 
     857        int err; 
     858 
     859        nfc_dbg(nfc, "read_oob: page:%d\n", page); 
     860 
     861        err = ar934x_nfc_send_read(nfc, NAND_CMD_READ0, mtd->writesize, page, 
     862                                   mtd->oobsize); 
     863        if (err) 
     864                return err; 
     865 
     866        memcpy(chip->oob_poi, nfc->buf, mtd->oobsize); 
     867 
     868        return 0; 
     869} 
     870 
     871static int 
     872ar934x_nfc_write_oob(struct mtd_info *mtd, struct nand_chip *chip, 
     873                     int page) 
     874{ 
     875        struct ar934x_nfc *nfc = mtd_to_ar934x_nfc(mtd); 
     876 
     877        nfc_dbg(nfc, "write_oob: page:%d\n", page); 
     878 
     879        memcpy(nfc->buf, chip->oob_poi, mtd->oobsize); 
     880 
     881        return ar934x_nfc_send_write(nfc, NAND_CMD_PAGEPROG, mtd->writesize, 
     882                                     page, mtd->oobsize); 
     883} 
     884 
     885static int 
     886ar934x_nfc_read_page_raw(struct mtd_info *mtd, struct nand_chip *chip, 
     887                         u8 *buf, int oob_required, int page) 
     888{ 
     889        struct ar934x_nfc *nfc = mtd_to_ar934x_nfc(mtd); 
     890        int len; 
     891        int err; 
     892 
     893        nfc_dbg(nfc, "read_page_raw: page:%d oob:%d\n", page, oob_required); 
     894 
     895        len = mtd->writesize; 
     896        if (oob_required) 
     897                len += mtd->oobsize; 
     898 
     899        err = ar934x_nfc_send_read(nfc, NAND_CMD_READ0, 0, page, len); 
     900        if (err) 
     901                return err; 
     902 
     903        memcpy(buf, nfc->buf, mtd->writesize); 
     904 
     905        if (oob_required) 
     906                memcpy(chip->oob_poi, &nfc->buf[mtd->writesize], mtd->oobsize); 
     907 
     908        return 0; 
     909} 
     910 
     911static int 
     912ar934x_nfc_read_page(struct mtd_info *mtd, struct nand_chip *chip, 
     913                     u8 *buf, int oob_required, int page) 
     914{ 
     915        struct ar934x_nfc *nfc = mtd_to_ar934x_nfc(mtd); 
     916        u32 ecc_ctrl; 
     917        int max_bitflips = 0; 
     918        bool ecc_failed; 
     919        bool ecc_corrected; 
     920        int err; 
     921 
     922        nfc_dbg(nfc, "read_page: page:%d oob:%d\n", page, oob_required); 
     923 
     924        ar934x_nfc_enable_hwecc(nfc); 
     925        err = ar934x_nfc_send_read(nfc, NAND_CMD_READ0, 0, page, 
     926                                   mtd->writesize); 
     927        ar934x_nfc_disable_hwecc(nfc); 
     928 
     929        if (err) 
     930                return err; 
     931 
     932        /* TODO: optimize to avoid memcpy */ 
     933        memcpy(buf, nfc->buf, mtd->writesize); 
     934 
     935        /* read the ECC status */ 
     936        ecc_ctrl = ar934x_nfc_rr(nfc, AR934X_NFC_REG_ECC_CTRL); 
     937        ecc_failed = ecc_ctrl & AR934X_NFC_ECC_CTRL_ERR_UNCORRECT; 
     938        ecc_corrected = ecc_ctrl & AR934X_NFC_ECC_CTRL_ERR_CORRECT; 
     939 
     940        if (oob_required || ecc_failed) { 
     941                err = ar934x_nfc_send_read(nfc, NAND_CMD_READ0, mtd->writesize, 
     942                                           page, mtd->oobsize); 
     943                if (err) 
     944                        return err; 
     945 
     946                if (oob_required) 
     947                        memcpy(chip->oob_poi, nfc->buf, mtd->oobsize); 
     948        } 
     949 
     950        if (ecc_failed) { 
     951                /* 
     952                 * The hardware ECC engine reports uncorrectable errors 
     953                 * on empty pages. Check the ECC bytes and the data. If 
     954                 * both contains 0xff bytes only, dont report a failure. 
     955                 * 
     956                 * TODO: prebuild a buffer with 0xff bytes and use memcmp 
     957                 * for better performance? 
     958                 */ 
     959                if (!is_all_ff(&nfc->buf[nfc->ecc_oob_pos], chip->ecc.total) || 
     960                    !is_all_ff(buf, mtd->writesize)) 
     961                                mtd->ecc_stats.failed++; 
     962        } else if (ecc_corrected) { 
     963                /* 
     964                 * The hardware does not report the exact count of the 
     965                 * corrected bitflips, use assumptions based on the 
     966                 * threshold. 
     967                 */ 
     968                if (ecc_ctrl & AR934X_NFC_ECC_CTRL_ERR_OVER) { 
     969                        /* 
     970                         * The number of corrected bitflips exceeds the 
     971                         * threshold. Assume the maximum. 
     972                         */ 
     973                        max_bitflips = chip->ecc.strength * chip->ecc.steps; 
     974                } else { 
     975                        max_bitflips = nfc->ecc_thres * chip->ecc.steps; 
     976                } 
     977 
     978                mtd->ecc_stats.corrected += max_bitflips; 
     979        } 
     980 
     981        return max_bitflips; 
     982} 
     983 
     984static int 
     985ar934x_nfc_write_page_raw(struct mtd_info *mtd, struct nand_chip *chip, 
     986                          const u8 *buf, int oob_required) 
     987{ 
     988        struct ar934x_nfc *nfc = mtd_to_ar934x_nfc(mtd); 
     989        int page; 
     990        int len; 
     991 
     992        page = nfc->seqin_page_addr; 
     993 
     994        nfc_dbg(nfc, "write_page_raw: page:%d oob:%d\n", page, oob_required); 
     995 
     996        memcpy(nfc->buf, buf, mtd->writesize); 
     997        len = mtd->writesize; 
     998 
     999        if (oob_required) { 
     1000                memcpy(&nfc->buf[mtd->writesize], chip->oob_poi, mtd->oobsize); 
     1001                len += mtd->oobsize; 
     1002        } 
     1003 
     1004        return ar934x_nfc_send_write(nfc, NAND_CMD_PAGEPROG, 0, page, len); 
     1005} 
     1006 
     1007static int 
     1008ar934x_nfc_write_page(struct mtd_info *mtd, struct nand_chip *chip, 
     1009                      const u8 *buf, int oob_required) 
     1010{ 
     1011        struct ar934x_nfc *nfc = mtd_to_ar934x_nfc(mtd); 
     1012        int page; 
     1013        int err; 
     1014 
     1015        page = nfc->seqin_page_addr; 
     1016 
     1017        nfc_dbg(nfc, "write_page: page:%d oob:%d\n", page, oob_required); 
     1018 
     1019        /* write OOB first */ 
     1020        if (oob_required && 
     1021            !is_all_ff(chip->oob_poi, mtd->oobsize)) { 
     1022                err = ar934x_nfc_write_oob(mtd, chip, page); 
     1023                if (err) 
     1024                        return err; 
     1025        } 
     1026 
     1027        /* TODO: optimize to avoid memcopy */ 
     1028        memcpy(nfc->buf, buf, mtd->writesize); 
     1029 
     1030        ar934x_nfc_enable_hwecc(nfc); 
     1031        err = ar934x_nfc_send_write(nfc, NAND_CMD_PAGEPROG, 0, page, 
     1032                                    mtd->writesize); 
     1033        ar934x_nfc_disable_hwecc(nfc); 
     1034 
     1035        return err; 
    7951036} 
    7961037 
     
    10071248} 
    10081249 
     1250static struct nand_ecclayout ar934x_nfc_oob_64_hwecc = { 
     1251        .eccbytes = 28, 
     1252        .eccpos = { 
     1253                20, 21, 22, 23, 24, 25, 26, 
     1254                27, 28, 29, 30, 31, 32, 33, 
     1255                34, 35, 36, 37, 38, 39, 40, 
     1256                41, 42, 43, 44, 45, 46, 47, 
     1257        }, 
     1258        .oobfree = { 
     1259                { 
     1260                        .offset = 4, 
     1261                        .length = 16, 
     1262                }, 
     1263                { 
     1264                        .offset = 48, 
     1265                        .length = 16, 
     1266                }, 
     1267        }, 
     1268}; 
     1269 
     1270static int 
     1271ar934x_nfc_setup_hwecc(struct ar934x_nfc *nfc) 
     1272{ 
     1273        struct nand_chip *nand = &nfc->nand_chip; 
     1274        u32 ecc_cap; 
     1275        u32 ecc_thres; 
     1276 
     1277        if (!config_enabled(CONFIG_MTD_NAND_AR934X_HW_ECC)) { 
     1278                dev_err(nfc->parent, "hardware ECC support is disabled\n"); 
     1279                return -EINVAL; 
     1280        } 
     1281 
     1282        switch (nfc->mtd.writesize) { 
     1283        case 2048: 
     1284                nand->ecc.size = 512; 
     1285                nand->ecc.bytes = 7; 
     1286                nand->ecc.strength = 4; 
     1287                nand->ecc.layout = &ar934x_nfc_oob_64_hwecc; 
     1288                break; 
     1289 
     1290        default: 
     1291                dev_err(nfc->parent, 
     1292                        "hardware ECC is not available for %d byte pages\n", 
     1293                        nfc->mtd.writesize); 
     1294                return -EINVAL; 
     1295        } 
     1296 
     1297        BUG_ON(!nand->ecc.layout); 
     1298 
     1299        switch (nand->ecc.strength) { 
     1300        case 4: 
     1301                ecc_cap = AR934X_NFC_ECC_CTRL_ECC_CAP_4; 
     1302                ecc_thres = 4; 
     1303                break; 
     1304 
     1305        default: 
     1306                dev_err(nfc->parent, "unsupported ECC strength %u\n", 
     1307                        nand->ecc.strength); 
     1308                return -EINVAL; 
     1309        } 
     1310 
     1311        nfc->ecc_thres = ecc_thres; 
     1312        nfc->ecc_oob_pos = nand->ecc.layout->eccpos[0]; 
     1313 
     1314        nfc->ecc_ctrl_reg = ecc_cap << AR934X_NFC_ECC_CTRL_ECC_CAP_S; 
     1315        nfc->ecc_ctrl_reg |= ecc_thres << AR934X_NFC_ECC_CTRL_ERR_THRES_S; 
     1316 
     1317        nfc->ecc_offset_reg = nfc->mtd.writesize + nfc->ecc_oob_pos; 
     1318 
     1319        nand->ecc.mode = NAND_ECC_HW; 
     1320        nand->ecc.read_page = ar934x_nfc_read_page; 
     1321        nand->ecc.read_page_raw = ar934x_nfc_read_page_raw; 
     1322        nand->ecc.write_page = ar934x_nfc_write_page; 
     1323        nand->ecc.write_page_raw = ar934x_nfc_write_page_raw; 
     1324        nand->ecc.read_oob = ar934x_nfc_read_oob; 
     1325        nand->ecc.write_oob = ar934x_nfc_write_oob; 
     1326 
     1327        return 0; 
     1328} 
     1329 
    10091330static int 
    10101331ar934x_nfc_probe(struct platform_device *pdev) 
     
    10721393 
    10731394        nand->chip_delay = 25; 
    1074         nand->ecc.mode = NAND_ECC_SOFT; 
    10751395 
    10761396        nand->dev_ready = ar934x_nfc_dev_ready; 
     
    11051425                if (ret) 
    11061426                        goto err_free_buf; 
     1427        } 
     1428 
     1429        switch (pdata->ecc_mode) { 
     1430        case AR934X_NFC_ECC_SOFT: 
     1431                nand->ecc.mode = NAND_ECC_SOFT; 
     1432                break; 
     1433 
     1434        case AR934X_NFC_ECC_HW: 
     1435                ret = ar934x_nfc_setup_hwecc(nfc); 
     1436                if (ret) 
     1437                        goto err_free_buf; 
     1438 
     1439                break; 
     1440 
     1441        default: 
     1442                dev_err(nfc->parent, "unknown ECC mode %d\n", pdata->ecc_mode); 
     1443                return -EINVAL; 
    11071444        } 
    11081445 
  • trunk/target/linux/ar71xx/files/include/linux/platform/ar934x_nfc.h

    r34588 r38069  
    1818struct mtd_partition; 
    1919 
     20enum ar934x_nfc_ecc_mode { 
     21        AR934X_NFC_ECC_SOFT = 0, 
     22        AR934X_NFC_ECC_HW, 
     23}; 
     24 
    2025struct ar934x_nfc_platform_data { 
    2126        const char *name; 
     
    2429 
    2530        bool swap_dma; 
     31        enum ar934x_nfc_ecc_mode ecc_mode; 
     32 
    2633        void (*hw_reset)(bool active); 
    2734        void (*select_chip)(int chip_no); 
  • trunk/target/linux/ar71xx/patches-3.10/413-mtd-ar934x-nand-driver.patch

    r37214 r38069  
    11--- a/drivers/mtd/nand/Kconfig 
    22+++ b/drivers/mtd/nand/Kconfig 
    3 @@ -552,4 +552,8 @@ config MTD_NAND_RB750 
     3@@ -552,4 +552,12 @@ config MTD_NAND_RB750 
    44        tristate "NAND flash driver for the RouterBoard 750" 
    55        depends on MTD_NAND && ATH79_MACH_RB750 
     
    88+       tristate "NAND flash driver for the Qualcomm Atheros AR934x/QCA955x SoCs" 
    99+       depends on (SOC_AR934X || SOC_QCA955X) 
     10+ 
     11+config MTD_NAND_AR934X_HW_ECC 
     12+       bool "Hardware ECC support for the AR934X NAND Controller (EXPERIMENTAL)" 
     13+       depends on MTD_NAND_AR934X 
    1014+ 
    1115 endif # MTD_NAND 
Note: See TracChangeset for help on using the changeset viewer.