aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPekon Gupta <pekon@ti.com>2013-10-24 08:50:22 -0400
committerBrian Norris <computersforpeace@gmail.com>2013-11-07 02:33:10 -0500
commitb491da7233d5dc1a24d46ca1ad0209900329c5d0 (patch)
tree02a0e314f92d8de31339bfe9b2a5ab06c3d80ef4
parenta919e51161b58ed7e6e663daba99ab7d558808f3 (diff)
mtd: nand: omap: clean-up ecc layout for BCH ecc schemes
In current implementation omap3_init_bch_tail() is a common function to define ecc layout for different BCHx ecc schemes.This patch: (1) removes omap3_init_bch_tail() and defines ecc layout for individual ecc-schemes along with populating their nand_chip->ecc data in omap_nand_probe(). This improves the readability and scalability of code for add new ecc schemes in future. (2) removes 'struct nand_bbt_descr bb_descrip_flashbased' because default nand_bbt_descr in nand_bbt.c matches the same (.len=1 for x8 devices). (3) add the check to see if NAND device has enough OOB/Spare bytes to store ECC signature of whole page, as defined by ecc-scheme. Signed-off-by: Pekon Gupta <pekon@ti.com> Tested-by: Ezequiel Garcia <ezequiel.garcia@free-electrons.com> Signed-off-by: Brian Norris <computersforpeace@gmail.com>
-rw-r--r--drivers/mtd/nand/omap2.c161
1 files changed, 62 insertions, 99 deletions
diff --git a/drivers/mtd/nand/omap2.c b/drivers/mtd/nand/omap2.c
index 86ce48b2c47a..b6a08b23853b 100644
--- a/drivers/mtd/nand/omap2.c
+++ b/drivers/mtd/nand/omap2.c
@@ -139,6 +139,7 @@
139#define BCH_ECC_SIZE0 0x0 /* ecc_size0 = 0, no oob protection */ 139#define BCH_ECC_SIZE0 0x0 /* ecc_size0 = 0, no oob protection */
140#define BCH_ECC_SIZE1 0x20 /* ecc_size1 = 32 */ 140#define BCH_ECC_SIZE1 0x20 /* ecc_size1 = 32 */
141 141
142#define BADBLOCK_MARKER_LENGTH 2
142#define OMAP_ECC_BCH8_POLYNOMIAL 0x201b 143#define OMAP_ECC_BCH8_POLYNOMIAL 0x201b
143 144
144#ifdef CONFIG_MTD_NAND_OMAP_BCH 145#ifdef CONFIG_MTD_NAND_OMAP_BCH
@@ -149,17 +150,6 @@ static u_char bch4_vector[] = {0x00, 0x6b, 0x31, 0xdd, 0x41, 0xbc, 0x10};
149 150
150/* oob info generated runtime depending on ecc algorithm and layout selected */ 151/* oob info generated runtime depending on ecc algorithm and layout selected */
151static struct nand_ecclayout omap_oobinfo; 152static struct nand_ecclayout omap_oobinfo;
152/* Define some generic bad / good block scan pattern which are used
153 * while scanning a device for factory marked good / bad blocks
154 */
155static uint8_t scan_ff_pattern[] = { 0xff };
156static struct nand_bbt_descr bb_descrip_flashbased = {
157 .options = NAND_BBT_SCANALLPAGES,
158 .offs = 0,
159 .len = 1,
160 .pattern = scan_ff_pattern,
161};
162
163 153
164struct omap_nand_info { 154struct omap_nand_info {
165 struct nand_hw_control controller; 155 struct nand_hw_control controller;
@@ -184,7 +174,6 @@ struct omap_nand_info {
184 struct gpmc_nand_regs reg; 174 struct gpmc_nand_regs reg;
185 /* fields specific for BCHx_HW ECC scheme */ 175 /* fields specific for BCHx_HW ECC scheme */
186 struct bch_control *bch; 176 struct bch_control *bch;
187 struct nand_ecclayout ecclayout;
188 bool is_elm_used; 177 bool is_elm_used;
189 struct device *elm_dev; 178 struct device *elm_dev;
190 struct device_node *of_node; 179 struct device_node *of_node;
@@ -1686,65 +1675,8 @@ static void omap3_free_bch(struct mtd_info *mtd)
1686 } 1675 }
1687} 1676}
1688 1677
1689/**
1690 * omap3_init_bch_tail - Build an oob layout for BCH ECC correction.
1691 * @mtd: MTD device structure
1692 */
1693static int omap3_init_bch_tail(struct mtd_info *mtd)
1694{
1695 int i, steps, offset;
1696 struct omap_nand_info *info = container_of(mtd, struct omap_nand_info,
1697 mtd);
1698 struct nand_ecclayout *layout = &info->ecclayout;
1699
1700 /* build oob layout */
1701 steps = mtd->writesize/info->nand.ecc.size;
1702 layout->eccbytes = steps*info->nand.ecc.bytes;
1703
1704 /* do not bother creating special oob layouts for small page devices */
1705 if (mtd->oobsize < 64) {
1706 pr_err("BCH ecc is not supported on small page devices\n");
1707 goto fail;
1708 }
1709
1710 /* reserve 2 bytes for bad block marker */
1711 if (layout->eccbytes+2 > mtd->oobsize) {
1712 pr_err("no oob layout available for oobsize %d eccbytes %u\n",
1713 mtd->oobsize, layout->eccbytes);
1714 goto fail;
1715 }
1716
1717 /* ECC layout compatible with RBL for BCH8 */
1718 if (info->is_elm_used && (info->nand.ecc.bytes == BCH8_SIZE))
1719 offset = 2;
1720 else
1721 offset = mtd->oobsize - layout->eccbytes;
1722
1723 /* put ecc bytes at oob tail */
1724 for (i = 0; i < layout->eccbytes; i++)
1725 layout->eccpos[i] = offset + i;
1726
1727 if (info->is_elm_used && (info->nand.ecc.bytes == BCH8_SIZE))
1728 layout->oobfree[0].offset = 2 + layout->eccbytes * steps;
1729 else
1730 layout->oobfree[0].offset = 2;
1731
1732 layout->oobfree[0].length = mtd->oobsize-2-layout->eccbytes;
1733 info->nand.ecc.layout = layout;
1734
1735 if (!(info->nand.options & NAND_BUSWIDTH_16))
1736 info->nand.badblock_pattern = &bb_descrip_flashbased;
1737 return 0;
1738fail:
1739 omap3_free_bch(mtd);
1740 return -1;
1741}
1742
1743#else 1678#else
1744static int omap3_init_bch_tail(struct mtd_info *mtd) 1679
1745{
1746 return -1;
1747}
1748static void omap3_free_bch(struct mtd_info *mtd) 1680static void omap3_free_bch(struct mtd_info *mtd)
1749{ 1681{
1750} 1682}
@@ -1756,8 +1688,9 @@ static int omap_nand_probe(struct platform_device *pdev)
1756 struct omap_nand_platform_data *pdata; 1688 struct omap_nand_platform_data *pdata;
1757 struct mtd_info *mtd; 1689 struct mtd_info *mtd;
1758 struct nand_chip *nand_chip; 1690 struct nand_chip *nand_chip;
1691 struct nand_ecclayout *ecclayout;
1759 int err; 1692 int err;
1760 int i, offset; 1693 int i;
1761 dma_cap_mask_t mask; 1694 dma_cap_mask_t mask;
1762 unsigned sig; 1695 unsigned sig;
1763 struct resource *res; 1696 struct resource *res;
@@ -1840,6 +1773,13 @@ static int omap_nand_probe(struct platform_device *pdev)
1840 goto out_release_mem_region; 1773 goto out_release_mem_region;
1841 } 1774 }
1842 1775
1776 /* check for small page devices */
1777 if ((mtd->oobsize < 64) && (pdata->ecc_opt != OMAP_ECC_HAM1_CODE_HW)) {
1778 pr_err("small page devices are not supported\n");
1779 err = -EINVAL;
1780 goto out_release_mem_region;
1781 }
1782
1843 /* re-populate low-level callbacks based on xfer modes */ 1783 /* re-populate low-level callbacks based on xfer modes */
1844 switch (pdata->xfer_type) { 1784 switch (pdata->xfer_type) {
1845 case NAND_OMAP_PREFETCH_POLLED: 1785 case NAND_OMAP_PREFETCH_POLLED:
@@ -1931,6 +1871,8 @@ static int omap_nand_probe(struct platform_device *pdev)
1931 } 1871 }
1932 1872
1933 /* populate MTD interface based on ECC scheme */ 1873 /* populate MTD interface based on ECC scheme */
1874 nand_chip->ecc.layout = &omap_oobinfo;
1875 ecclayout = &omap_oobinfo;
1934 switch (pdata->ecc_opt) { 1876 switch (pdata->ecc_opt) {
1935 case OMAP_ECC_HAM1_CODE_HW: 1877 case OMAP_ECC_HAM1_CODE_HW:
1936 pr_info("nand: using OMAP_ECC_HAM1_CODE_HW\n"); 1878 pr_info("nand: using OMAP_ECC_HAM1_CODE_HW\n");
@@ -1941,6 +1883,16 @@ static int omap_nand_probe(struct platform_device *pdev)
1941 nand_chip->ecc.calculate = omap_calculate_ecc; 1883 nand_chip->ecc.calculate = omap_calculate_ecc;
1942 nand_chip->ecc.hwctl = omap_enable_hwecc; 1884 nand_chip->ecc.hwctl = omap_enable_hwecc;
1943 nand_chip->ecc.correct = omap_correct_data; 1885 nand_chip->ecc.correct = omap_correct_data;
1886 /* define ECC layout */
1887 ecclayout->eccbytes = nand_chip->ecc.bytes *
1888 (mtd->writesize /
1889 nand_chip->ecc.size);
1890 if (nand_chip->options & NAND_BUSWIDTH_16)
1891 ecclayout->eccpos[0] = BADBLOCK_MARKER_LENGTH;
1892 else
1893 ecclayout->eccpos[0] = 1;
1894 ecclayout->oobfree->offset = ecclayout->eccpos[0] +
1895 ecclayout->eccbytes;
1944 break; 1896 break;
1945 1897
1946 case OMAP_ECC_BCH4_CODE_HW_DETECTION_SW: 1898 case OMAP_ECC_BCH4_CODE_HW_DETECTION_SW:
@@ -1953,6 +1905,13 @@ static int omap_nand_probe(struct platform_device *pdev)
1953 nand_chip->ecc.hwctl = omap3_enable_hwecc_bch; 1905 nand_chip->ecc.hwctl = omap3_enable_hwecc_bch;
1954 nand_chip->ecc.correct = omap3_correct_data_bch; 1906 nand_chip->ecc.correct = omap3_correct_data_bch;
1955 nand_chip->ecc.calculate = omap3_calculate_ecc_bch4; 1907 nand_chip->ecc.calculate = omap3_calculate_ecc_bch4;
1908 /* define ECC layout */
1909 ecclayout->eccbytes = nand_chip->ecc.bytes *
1910 (mtd->writesize /
1911 nand_chip->ecc.size);
1912 ecclayout->eccpos[0] = BADBLOCK_MARKER_LENGTH;
1913 ecclayout->oobfree->offset = ecclayout->eccpos[0] +
1914 ecclayout->eccbytes;
1956 /* software bch library is used for locating errors */ 1915 /* software bch library is used for locating errors */
1957 info->bch = init_bch(nand_chip->ecc.bytes, 1916 info->bch = init_bch(nand_chip->ecc.bytes,
1958 nand_chip->ecc.strength, 1917 nand_chip->ecc.strength,
@@ -1981,6 +1940,13 @@ static int omap_nand_probe(struct platform_device *pdev)
1981 nand_chip->ecc.calculate = omap3_calculate_ecc_bch; 1940 nand_chip->ecc.calculate = omap3_calculate_ecc_bch;
1982 nand_chip->ecc.read_page = omap_read_page_bch; 1941 nand_chip->ecc.read_page = omap_read_page_bch;
1983 nand_chip->ecc.write_page = omap_write_page_bch; 1942 nand_chip->ecc.write_page = omap_write_page_bch;
1943 /* define ECC layout */
1944 ecclayout->eccbytes = nand_chip->ecc.bytes *
1945 (mtd->writesize /
1946 nand_chip->ecc.size);
1947 ecclayout->eccpos[0] = BADBLOCK_MARKER_LENGTH;
1948 ecclayout->oobfree->offset = ecclayout->eccpos[0] +
1949 ecclayout->eccbytes;
1984 /* This ECC scheme requires ELM H/W block */ 1950 /* This ECC scheme requires ELM H/W block */
1985 if (is_elm_present(info, pdata->elm_of_node, BCH4_ECC) < 0) { 1951 if (is_elm_present(info, pdata->elm_of_node, BCH4_ECC) < 0) {
1986 pr_err("nand: error: could not initialize ELM\n"); 1952 pr_err("nand: error: could not initialize ELM\n");
@@ -2004,6 +1970,13 @@ static int omap_nand_probe(struct platform_device *pdev)
2004 nand_chip->ecc.hwctl = omap3_enable_hwecc_bch; 1970 nand_chip->ecc.hwctl = omap3_enable_hwecc_bch;
2005 nand_chip->ecc.correct = omap3_correct_data_bch; 1971 nand_chip->ecc.correct = omap3_correct_data_bch;
2006 nand_chip->ecc.calculate = omap3_calculate_ecc_bch8; 1972 nand_chip->ecc.calculate = omap3_calculate_ecc_bch8;
1973 /* define ECC layout */
1974 ecclayout->eccbytes = nand_chip->ecc.bytes *
1975 (mtd->writesize /
1976 nand_chip->ecc.size);
1977 ecclayout->eccpos[0] = BADBLOCK_MARKER_LENGTH;
1978 ecclayout->oobfree->offset = ecclayout->eccpos[0] +
1979 ecclayout->eccbytes;
2007 /* software bch library is used for locating errors */ 1980 /* software bch library is used for locating errors */
2008 info->bch = init_bch(nand_chip->ecc.bytes, 1981 info->bch = init_bch(nand_chip->ecc.bytes,
2009 nand_chip->ecc.strength, 1982 nand_chip->ecc.strength,
@@ -2038,6 +2011,13 @@ static int omap_nand_probe(struct platform_device *pdev)
2038 pr_err("nand: error: could not initialize ELM\n"); 2011 pr_err("nand: error: could not initialize ELM\n");
2039 goto out_release_mem_region; 2012 goto out_release_mem_region;
2040 } 2013 }
2014 /* define ECC layout */
2015 ecclayout->eccbytes = nand_chip->ecc.bytes *
2016 (mtd->writesize /
2017 nand_chip->ecc.size);
2018 ecclayout->eccpos[0] = BADBLOCK_MARKER_LENGTH;
2019 ecclayout->oobfree->offset = ecclayout->eccpos[0] +
2020 ecclayout->eccbytes;
2041 break; 2021 break;
2042#else 2022#else
2043 pr_err("nand: error: CONFIG_MTD_NAND_OMAP_BCH not enabled\n"); 2023 pr_err("nand: error: CONFIG_MTD_NAND_OMAP_BCH not enabled\n");
@@ -2051,34 +2031,17 @@ static int omap_nand_probe(struct platform_device *pdev)
2051 goto out_release_mem_region; 2031 goto out_release_mem_region;
2052 } 2032 }
2053 2033
2054 /* rom code layout */ 2034 /* populate remaining ECC layout data */
2055 if (pdata->ecc_opt == OMAP_ECC_HAM1_CODE_HW) { 2035 ecclayout->oobfree->length = mtd->oobsize - (BADBLOCK_MARKER_LENGTH +
2056 2036 ecclayout->eccbytes);
2057 if (nand_chip->options & NAND_BUSWIDTH_16) { 2037 for (i = 1; i < ecclayout->eccbytes; i++)
2058 offset = 2; 2038 ecclayout->eccpos[i] = ecclayout->eccpos[0] + i;
2059 } else { 2039 /* check if NAND device's OOB is enough to store ECC signatures */
2060 offset = 1; 2040 if (mtd->oobsize < (ecclayout->eccbytes + BADBLOCK_MARKER_LENGTH)) {
2061 nand_chip->badblock_pattern = &bb_descrip_flashbased; 2041 pr_err("not enough OOB bytes required = %d, available=%d\n",
2062 } 2042 ecclayout->eccbytes, mtd->oobsize);
2063 omap_oobinfo.eccbytes = 3 * (mtd->writesize / 512); 2043 err = -EINVAL;
2064 for (i = 0; i < omap_oobinfo.eccbytes; i++) 2044 goto out_release_mem_region;
2065 omap_oobinfo.eccpos[i] = i+offset;
2066
2067 omap_oobinfo.oobfree->offset = offset + omap_oobinfo.eccbytes;
2068 omap_oobinfo.oobfree->length = mtd->oobsize -
2069 (offset + omap_oobinfo.eccbytes);
2070
2071 nand_chip->ecc.layout = &omap_oobinfo;
2072 } else if ((pdata->ecc_opt == OMAP_ECC_BCH4_CODE_HW) ||
2073 (pdata->ecc_opt == OMAP_ECC_BCH4_CODE_HW_DETECTION_SW) ||
2074 (pdata->ecc_opt == OMAP_ECC_BCH8_CODE_HW_DETECTION_SW) ||
2075 (pdata->ecc_opt == OMAP_ECC_BCH8_CODE_HW)) {
2076 /* build OOB layout for BCH ECC correction */
2077 err = omap3_init_bch_tail(mtd);
2078 if (err) {
2079 err = -EINVAL;
2080 goto out_release_mem_region;
2081 }
2082 } 2045 }
2083 2046
2084 /* second phase scan */ 2047 /* second phase scan */