aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/mtd/nand
diff options
context:
space:
mode:
authorPekon Gupta <pekon@ti.com>2013-10-24 08:50:21 -0400
committerBrian Norris <computersforpeace@gmail.com>2013-11-07 02:33:09 -0500
commita919e51161b58ed7e6e663daba99ab7d558808f3 (patch)
tree3418227e6e03e1c43cea1d6e41a48fcc519307dd /drivers/mtd/nand
parentf18befb57b0779094ac7658fa7be5cf559da835f (diff)
mtd: nand: omap2: clean-up BCHx_HW and BCHx_SW ECC configurations in device_probe
current implementation in omap3_init_bch() has some redundant code like: (1) omap3_init_bch() re-probes the DT-binding to detect presence of ELM h/w engine on SoC. And based on that it selects implemetation of ecc-scheme. However, this is already done as part of GPMC DT parsing. (2) As omap3_init_bch() serves as common function for configuring all types of BCHx ecc-schemes, so there are multiple levels of redudant if..then..else checks while populating nand_chip->ecc. This patch make following changes to OMAP NAND driver: (1) removes omap3_init_bch(): each ecc-scheme is individually configured in omap_nand_probe() there by removing redundant if..then..else checks. (2) adds is_elm_present(): re-probing of ELM device via DT is not required as it's done in GPMC driver probe. Thus is_elm_present() just initializes ELM driver with NAND probe data, when ecc-scheme with h/w based error-detection is used. (3) separates out configuration of different flavours of "BCH4" and "BCH8" ecc-schemes as given in below table (4) conditionally compiles callbacks implementations of ecc.hwctl(), ecc.calculate(), ecc.correct() to avoid warning of un-used functions. +---------------------------------------+---------------+---------------+ | ECC scheme |ECC calculation|Error detection| +---------------------------------------+---------------+---------------+ |OMAP_ECC_HAM1_CODE_HW |H/W (GPMC) |S/W | +---------------------------------------+---------------+---------------+ |OMAP_ECC_BCH4_CODE_HW_DETECTION_SW |H/W (GPMC) |S/W (lib/bch.c)| | (needs CONFIG_MTD_NAND_ECC_BCH) | | | | | | | |OMAP_ECC_BCH4_CODE_HW |H/W (GPMC) |H/W (ELM) | | (needs CONFIG_MTD_NAND_OMAP_BCH && | | | | ti,elm-id) | | | +---------------------------------------+---------------+---------------+ |OMAP_ECC_BCH8_CODE_HW_DETECTION_SW |H/W (GPMC) |S/W (lib/bch.c)| | (needs CONFIG_MTD_NAND_ECC_BCH) | | | | | | | |OMAP_ECC_BCH8_CODE_HW |H/W (GPMC) |H/W (ELM) | | (needs CONFIG_MTD_NAND_OMAP_BCH && | | | | ti,elm-id) | | | +---------------------------------------+---------------+---------------+ - 'CONFIG_MTD_NAND_ECC_BCH' is generic KConfig required to build lib/bch.c which is required for ECC error detection done in software. (mainly used for legacy platforms which do not have on-chip ELM engine) - 'CONFIG_MTD_NAND_OMAP_BCH' is OMAP specific Kconfig to detemine presence on ELM h/w engine on SoC. 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>
Diffstat (limited to 'drivers/mtd/nand')
-rw-r--r--drivers/mtd/nand/omap2.c281
1 files changed, 158 insertions, 123 deletions
diff --git a/drivers/mtd/nand/omap2.c b/drivers/mtd/nand/omap2.c
index f464321c598d..86ce48b2c47a 100644
--- a/drivers/mtd/nand/omap2.c
+++ b/drivers/mtd/nand/omap2.c
@@ -25,10 +25,8 @@
25#include <linux/of.h> 25#include <linux/of.h>
26#include <linux/of_device.h> 26#include <linux/of_device.h>
27 27
28#ifdef CONFIG_MTD_NAND_OMAP_BCH
29#include <linux/bch.h> 28#include <linux/bch.h>
30#include <linux/platform_data/elm.h> 29#include <linux/platform_data/elm.h>
31#endif
32 30
33#include <linux/platform_data/mtd-nand-omap2.h> 31#include <linux/platform_data/mtd-nand-omap2.h>
34 32
@@ -141,6 +139,8 @@
141#define BCH_ECC_SIZE0 0x0 /* ecc_size0 = 0, no oob protection */ 139#define BCH_ECC_SIZE0 0x0 /* ecc_size0 = 0, no oob protection */
142#define BCH_ECC_SIZE1 0x20 /* ecc_size1 = 32 */ 140#define BCH_ECC_SIZE1 0x20 /* ecc_size1 = 32 */
143 141
142#define OMAP_ECC_BCH8_POLYNOMIAL 0x201b
143
144#ifdef CONFIG_MTD_NAND_OMAP_BCH 144#ifdef CONFIG_MTD_NAND_OMAP_BCH
145static u_char bch8_vector[] = {0xf3, 0xdb, 0x14, 0x16, 0x8b, 0xd2, 0xbe, 0xcc, 145static u_char bch8_vector[] = {0xf3, 0xdb, 0x14, 0x16, 0x8b, 0xd2, 0xbe, 0xcc,
146 0xac, 0x6b, 0xff, 0x99, 0x7b}; 146 0xac, 0x6b, 0xff, 0x99, 0x7b};
@@ -182,14 +182,12 @@ struct omap_nand_info {
182 u_char *buf; 182 u_char *buf;
183 int buf_len; 183 int buf_len;
184 struct gpmc_nand_regs reg; 184 struct gpmc_nand_regs reg;
185 185 /* fields specific for BCHx_HW ECC scheme */
186#ifdef CONFIG_MTD_NAND_OMAP_BCH
187 struct bch_control *bch; 186 struct bch_control *bch;
188 struct nand_ecclayout ecclayout; 187 struct nand_ecclayout ecclayout;
189 bool is_elm_used; 188 bool is_elm_used;
190 struct device *elm_dev; 189 struct device *elm_dev;
191 struct device_node *of_node; 190 struct device_node *of_node;
192#endif
193}; 191};
194 192
195/** 193/**
@@ -1058,8 +1056,7 @@ static int omap_dev_ready(struct mtd_info *mtd)
1058 } 1056 }
1059} 1057}
1060 1058
1061#ifdef CONFIG_MTD_NAND_OMAP_BCH 1059#if defined(CONFIG_MTD_NAND_ECC_BCH) || defined(CONFIG_MTD_NAND_OMAP_BCH)
1062
1063/** 1060/**
1064 * omap3_enable_hwecc_bch - Program OMAP3 GPMC to perform BCH ECC correction 1061 * omap3_enable_hwecc_bch - Program OMAP3 GPMC to perform BCH ECC correction
1065 * @mtd: MTD device structure 1062 * @mtd: MTD device structure
@@ -1140,7 +1137,9 @@ static void omap3_enable_hwecc_bch(struct mtd_info *mtd, int mode)
1140 /* Clear ecc and enable bits */ 1137 /* Clear ecc and enable bits */
1141 writel(ECCCLEAR | ECC1, info->reg.gpmc_ecc_control); 1138 writel(ECCCLEAR | ECC1, info->reg.gpmc_ecc_control);
1142} 1139}
1140#endif
1143 1141
1142#ifdef CONFIG_MTD_NAND_ECC_BCH
1144/** 1143/**
1145 * omap3_calculate_ecc_bch4 - Generate 7 bytes of ECC bytes 1144 * omap3_calculate_ecc_bch4 - Generate 7 bytes of ECC bytes
1146 * @mtd: MTD device structure 1145 * @mtd: MTD device structure
@@ -1225,7 +1224,9 @@ static int omap3_calculate_ecc_bch8(struct mtd_info *mtd, const u_char *dat,
1225 1224
1226 return 0; 1225 return 0;
1227} 1226}
1227#endif /* CONFIG_MTD_NAND_ECC_BCH */
1228 1228
1229#ifdef CONFIG_MTD_NAND_OMAP_BCH
1229/** 1230/**
1230 * omap3_calculate_ecc_bch - Generate bytes of ECC bytes 1231 * omap3_calculate_ecc_bch - Generate bytes of ECC bytes
1231 * @mtd: MTD device structure 1232 * @mtd: MTD device structure
@@ -1517,7 +1518,9 @@ static int omap_elm_correct_data(struct mtd_info *mtd, u_char *data,
1517 1518
1518 return stat; 1519 return stat;
1519} 1520}
1521#endif /* CONFIG_MTD_NAND_OMAP_BCH */
1520 1522
1523#ifdef CONFIG_MTD_NAND_ECC_BCH
1521/** 1524/**
1522 * omap3_correct_data_bch - Decode received data and correct errors 1525 * omap3_correct_data_bch - Decode received data and correct errors
1523 * @mtd: MTD device structure 1526 * @mtd: MTD device structure
@@ -1549,7 +1552,9 @@ static int omap3_correct_data_bch(struct mtd_info *mtd, u_char *data,
1549 } 1552 }
1550 return count; 1553 return count;
1551} 1554}
1555#endif /* CONFIG_MTD_NAND_ECC_BCH */
1552 1556
1557#ifdef CONFIG_MTD_NAND_OMAP_BCH
1553/** 1558/**
1554 * omap_write_page_bch - BCH ecc based write page function for entire page 1559 * omap_write_page_bch - BCH ecc based write page function for entire page
1555 * @mtd: mtd info structure 1560 * @mtd: mtd info structure
@@ -1637,118 +1642,48 @@ static int omap_read_page_bch(struct mtd_info *mtd, struct nand_chip *chip,
1637} 1642}
1638 1643
1639/** 1644/**
1640 * omap3_free_bch - Release BCH ecc resources 1645 * is_elm_present - checks for presence of ELM module by scanning DT nodes
1641 * @mtd: MTD device structure 1646 * @omap_nand_info: NAND device structure containing platform data
1647 * @bch_type: 0x0=BCH4, 0x1=BCH8, 0x2=BCH16
1642 */ 1648 */
1643static void omap3_free_bch(struct mtd_info *mtd) 1649static int is_elm_present(struct omap_nand_info *info,
1650 struct device_node *elm_node, enum bch_ecc bch_type)
1644{ 1651{
1645 struct omap_nand_info *info = container_of(mtd, struct omap_nand_info, 1652 struct platform_device *pdev;
1646 mtd); 1653 info->is_elm_used = false;
1647 if (info->bch) { 1654 /* check whether elm-id is passed via DT */
1648 free_bch(info->bch); 1655 if (!elm_node) {
1649 info->bch = NULL; 1656 pr_err("nand: error: ELM DT node not found\n");
1657 return -ENODEV;
1658 }
1659 pdev = of_find_device_by_node(elm_node);
1660 /* check whether ELM device is registered */
1661 if (!pdev) {
1662 pr_err("nand: error: ELM device not found\n");
1663 return -ENODEV;
1650 } 1664 }
1665 /* ELM module available, now configure it */
1666 info->elm_dev = &pdev->dev;
1667 if (elm_config(info->elm_dev, bch_type))
1668 return -ENODEV;
1669 info->is_elm_used = true;
1670 return 0;
1651} 1671}
1672#endif /* CONFIG_MTD_NAND_ECC_BCH */
1652 1673
1674#ifdef CONFIG_MTD_NAND_ECC_BCH
1653/** 1675/**
1654 * omap3_init_bch - Initialize BCH ECC 1676 * omap3_free_bch - Release BCH ecc resources
1655 * @mtd: MTD device structure 1677 * @mtd: MTD device structure
1656 * @ecc_opt: OMAP ECC mode (OMAP_ECC_BCH4_CODE_HW or OMAP_ECC_BCH8_CODE_HW)
1657 */ 1678 */
1658static int omap3_init_bch(struct mtd_info *mtd, int ecc_opt) 1679static void omap3_free_bch(struct mtd_info *mtd)
1659{ 1680{
1660 int max_errors;
1661 struct omap_nand_info *info = container_of(mtd, struct omap_nand_info, 1681 struct omap_nand_info *info = container_of(mtd, struct omap_nand_info,
1662 mtd); 1682 mtd);
1663#ifdef CONFIG_MTD_NAND_OMAP_BCH8 1683 if (info->bch) {
1664 const int hw_errors = BCH8_MAX_ERROR; 1684 free_bch(info->bch);
1665#else 1685 info->bch = NULL;
1666 const int hw_errors = BCH4_MAX_ERROR;
1667#endif
1668 enum bch_ecc bch_type;
1669 const __be32 *parp;
1670 int lenp;
1671 struct device_node *elm_node;
1672
1673 info->bch = NULL;
1674
1675 max_errors = (ecc_opt == OMAP_ECC_BCH8_CODE_HW) ?
1676 BCH8_MAX_ERROR : BCH4_MAX_ERROR;
1677 if (max_errors != hw_errors) {
1678 pr_err("cannot configure %d-bit BCH ecc, only %d-bit supported",
1679 max_errors, hw_errors);
1680 goto fail;
1681 }
1682
1683 info->nand.ecc.size = 512;
1684 info->nand.ecc.hwctl = omap3_enable_hwecc_bch;
1685 info->nand.ecc.mode = NAND_ECC_HW;
1686 info->nand.ecc.strength = max_errors;
1687
1688 if (hw_errors == BCH8_MAX_ERROR)
1689 bch_type = BCH8_ECC;
1690 else
1691 bch_type = BCH4_ECC;
1692
1693 /* Detect availability of ELM module */
1694 parp = of_get_property(info->of_node, "elm_id", &lenp);
1695 if ((parp == NULL) && (lenp != (sizeof(void *) * 2))) {
1696 pr_err("Missing elm_id property, fall back to Software BCH\n");
1697 info->is_elm_used = false;
1698 } else {
1699 struct platform_device *pdev;
1700
1701 elm_node = of_find_node_by_phandle(be32_to_cpup(parp));
1702 pdev = of_find_device_by_node(elm_node);
1703 info->elm_dev = &pdev->dev;
1704
1705 if (elm_config(info->elm_dev, bch_type) == 0)
1706 info->is_elm_used = true;
1707 }
1708
1709 if (info->is_elm_used && (mtd->writesize <= 4096)) {
1710
1711 if (hw_errors == BCH8_MAX_ERROR)
1712 info->nand.ecc.bytes = BCH8_SIZE;
1713 else
1714 info->nand.ecc.bytes = BCH4_SIZE;
1715
1716 info->nand.ecc.correct = omap_elm_correct_data;
1717 info->nand.ecc.calculate = omap3_calculate_ecc_bch;
1718 info->nand.ecc.read_page = omap_read_page_bch;
1719 info->nand.ecc.write_page = omap_write_page_bch;
1720 } else {
1721 /*
1722 * software bch library is only used to detect and
1723 * locate errors
1724 */
1725 info->bch = init_bch(13, max_errors,
1726 0x201b /* hw polynomial */);
1727 if (!info->bch)
1728 goto fail;
1729
1730 info->nand.ecc.correct = omap3_correct_data_bch;
1731
1732 /*
1733 * The number of corrected errors in an ecc block that will
1734 * trigger block scrubbing defaults to the ecc strength (4 or 8)
1735 * Set mtd->bitflip_threshold here to define a custom threshold.
1736 */
1737
1738 if (max_errors == 8) {
1739 info->nand.ecc.bytes = 13;
1740 info->nand.ecc.calculate = omap3_calculate_ecc_bch8;
1741 } else {
1742 info->nand.ecc.bytes = 7;
1743 info->nand.ecc.calculate = omap3_calculate_ecc_bch4;
1744 }
1745 } 1686 }
1746
1747 pr_info("enabling NAND BCH ecc with %d-bit correction\n", max_errors);
1748 return 0;
1749fail:
1750 omap3_free_bch(mtd);
1751 return -1;
1752} 1687}
1753 1688
1754/** 1689/**
@@ -1806,11 +1741,6 @@ fail:
1806} 1741}
1807 1742
1808#else 1743#else
1809static int omap3_init_bch(struct mtd_info *mtd, int ecc_opt)
1810{
1811 pr_err("CONFIG_MTD_NAND_OMAP_BCH is not enabled\n");
1812 return -1;
1813}
1814static int omap3_init_bch_tail(struct mtd_info *mtd) 1744static int omap3_init_bch_tail(struct mtd_info *mtd)
1815{ 1745{
1816 return -1; 1746 return -1;
@@ -1818,7 +1748,7 @@ static int omap3_init_bch_tail(struct mtd_info *mtd)
1818static void omap3_free_bch(struct mtd_info *mtd) 1748static void omap3_free_bch(struct mtd_info *mtd)
1819{ 1749{
1820} 1750}
1821#endif /* CONFIG_MTD_NAND_OMAP_BCH */ 1751#endif /* CONFIG_MTD_NAND_ECC_BCH */
1822 1752
1823static int omap_nand_probe(struct platform_device *pdev) 1753static int omap_nand_probe(struct platform_device *pdev)
1824{ 1754{
@@ -1851,15 +1781,14 @@ static int omap_nand_probe(struct platform_device *pdev)
1851 info->pdev = pdev; 1781 info->pdev = pdev;
1852 info->gpmc_cs = pdata->cs; 1782 info->gpmc_cs = pdata->cs;
1853 info->reg = pdata->reg; 1783 info->reg = pdata->reg;
1784 info->bch = NULL;
1785 info->of_node = pdata->of_node;
1854 mtd = &info->mtd; 1786 mtd = &info->mtd;
1855 mtd->priv = &info->nand; 1787 mtd->priv = &info->nand;
1856 mtd->name = dev_name(&pdev->dev); 1788 mtd->name = dev_name(&pdev->dev);
1857 mtd->owner = THIS_MODULE; 1789 mtd->owner = THIS_MODULE;
1858 nand_chip = &info->nand; 1790 nand_chip = &info->nand;
1859 nand_chip->options |= NAND_SKIP_BBTSCAN; 1791 nand_chip->options |= NAND_SKIP_BBTSCAN;
1860#ifdef CONFIG_MTD_NAND_OMAP_BCH
1861 info->of_node = pdata->of_node;
1862#endif
1863 1792
1864 res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 1793 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
1865 if (res == NULL) { 1794 if (res == NULL) {
@@ -2001,22 +1930,125 @@ static int omap_nand_probe(struct platform_device *pdev)
2001 goto out_release_mem_region; 1930 goto out_release_mem_region;
2002 } 1931 }
2003 1932
2004 /* select the ecc type */ 1933 /* populate MTD interface based on ECC scheme */
2005 if (pdata->ecc_opt == OMAP_ECC_HAM1_CODE_HW) { 1934 switch (pdata->ecc_opt) {
1935 case OMAP_ECC_HAM1_CODE_HW:
1936 pr_info("nand: using OMAP_ECC_HAM1_CODE_HW\n");
1937 nand_chip->ecc.mode = NAND_ECC_HW;
2006 nand_chip->ecc.bytes = 3; 1938 nand_chip->ecc.bytes = 3;
2007 nand_chip->ecc.size = 512; 1939 nand_chip->ecc.size = 512;
2008 nand_chip->ecc.strength = 1; 1940 nand_chip->ecc.strength = 1;
2009 nand_chip->ecc.calculate = omap_calculate_ecc; 1941 nand_chip->ecc.calculate = omap_calculate_ecc;
2010 nand_chip->ecc.hwctl = omap_enable_hwecc; 1942 nand_chip->ecc.hwctl = omap_enable_hwecc;
2011 nand_chip->ecc.correct = omap_correct_data; 1943 nand_chip->ecc.correct = omap_correct_data;
2012 nand_chip->ecc.mode = NAND_ECC_HW; 1944 break;
2013 } else if ((pdata->ecc_opt == OMAP_ECC_BCH4_CODE_HW) || 1945
2014 (pdata->ecc_opt == OMAP_ECC_BCH8_CODE_HW)) { 1946 case OMAP_ECC_BCH4_CODE_HW_DETECTION_SW:
2015 err = omap3_init_bch(mtd, pdata->ecc_opt); 1947#ifdef CONFIG_MTD_NAND_ECC_BCH
2016 if (err) { 1948 pr_info("nand: using OMAP_ECC_BCH4_CODE_HW_DETECTION_SW\n");
1949 nand_chip->ecc.mode = NAND_ECC_HW;
1950 nand_chip->ecc.size = 512;
1951 nand_chip->ecc.bytes = 7;
1952 nand_chip->ecc.strength = 4;
1953 nand_chip->ecc.hwctl = omap3_enable_hwecc_bch;
1954 nand_chip->ecc.correct = omap3_correct_data_bch;
1955 nand_chip->ecc.calculate = omap3_calculate_ecc_bch4;
1956 /* software bch library is used for locating errors */
1957 info->bch = init_bch(nand_chip->ecc.bytes,
1958 nand_chip->ecc.strength,
1959 OMAP_ECC_BCH8_POLYNOMIAL);
1960 if (!info->bch) {
1961 pr_err("nand: error: unable to use s/w BCH library\n");
2017 err = -EINVAL; 1962 err = -EINVAL;
1963 }
1964 break;
1965#else
1966 pr_err("nand: error: CONFIG_MTD_NAND_ECC_BCH not enabled\n");
1967 err = -EINVAL;
1968 goto out_release_mem_region;
1969#endif
1970
1971 case OMAP_ECC_BCH4_CODE_HW:
1972#ifdef CONFIG_MTD_NAND_OMAP_BCH
1973 pr_info("nand: using OMAP_ECC_BCH4_CODE_HW ECC scheme\n");
1974 nand_chip->ecc.mode = NAND_ECC_HW;
1975 nand_chip->ecc.size = 512;
1976 /* 14th bit is kept reserved for ROM-code compatibility */
1977 nand_chip->ecc.bytes = 7 + 1;
1978 nand_chip->ecc.strength = 4;
1979 nand_chip->ecc.hwctl = omap3_enable_hwecc_bch;
1980 nand_chip->ecc.correct = omap_elm_correct_data;
1981 nand_chip->ecc.calculate = omap3_calculate_ecc_bch;
1982 nand_chip->ecc.read_page = omap_read_page_bch;
1983 nand_chip->ecc.write_page = omap_write_page_bch;
1984 /* This ECC scheme requires ELM H/W block */
1985 if (is_elm_present(info, pdata->elm_of_node, BCH4_ECC) < 0) {
1986 pr_err("nand: error: could not initialize ELM\n");
1987 err = -ENODEV;
2018 goto out_release_mem_region; 1988 goto out_release_mem_region;
2019 } 1989 }
1990 break;
1991#else
1992 pr_err("nand: error: CONFIG_MTD_NAND_OMAP_BCH not enabled\n");
1993 err = -EINVAL;
1994 goto out_release_mem_region;
1995#endif
1996
1997 case OMAP_ECC_BCH8_CODE_HW_DETECTION_SW:
1998#ifdef CONFIG_MTD_NAND_ECC_BCH
1999 pr_info("nand: using OMAP_ECC_BCH8_CODE_HW_DETECTION_SW\n");
2000 nand_chip->ecc.mode = NAND_ECC_HW;
2001 nand_chip->ecc.size = 512;
2002 nand_chip->ecc.bytes = 13;
2003 nand_chip->ecc.strength = 8;
2004 nand_chip->ecc.hwctl = omap3_enable_hwecc_bch;
2005 nand_chip->ecc.correct = omap3_correct_data_bch;
2006 nand_chip->ecc.calculate = omap3_calculate_ecc_bch8;
2007 /* software bch library is used for locating errors */
2008 info->bch = init_bch(nand_chip->ecc.bytes,
2009 nand_chip->ecc.strength,
2010 OMAP_ECC_BCH8_POLYNOMIAL);
2011 if (!info->bch) {
2012 pr_err("nand: error: unable to use s/w BCH library\n");
2013 err = -EINVAL;
2014 goto out_release_mem_region;
2015 }
2016 break;
2017#else
2018 pr_err("nand: error: CONFIG_MTD_NAND_ECC_BCH not enabled\n");
2019 err = -EINVAL;
2020 goto out_release_mem_region;
2021#endif
2022
2023 case OMAP_ECC_BCH8_CODE_HW:
2024#ifdef CONFIG_MTD_NAND_OMAP_BCH
2025 pr_info("nand: using OMAP_ECC_BCH8_CODE_HW ECC scheme\n");
2026 nand_chip->ecc.mode = NAND_ECC_HW;
2027 nand_chip->ecc.size = 512;
2028 /* 14th bit is kept reserved for ROM-code compatibility */
2029 nand_chip->ecc.bytes = 13 + 1;
2030 nand_chip->ecc.strength = 8;
2031 nand_chip->ecc.hwctl = omap3_enable_hwecc_bch;
2032 nand_chip->ecc.correct = omap_elm_correct_data;
2033 nand_chip->ecc.calculate = omap3_calculate_ecc_bch;
2034 nand_chip->ecc.read_page = omap_read_page_bch;
2035 nand_chip->ecc.write_page = omap_write_page_bch;
2036 /* This ECC scheme requires ELM H/W block */
2037 if (is_elm_present(info, pdata->elm_of_node, BCH8_ECC) < 0) {
2038 pr_err("nand: error: could not initialize ELM\n");
2039 goto out_release_mem_region;
2040 }
2041 break;
2042#else
2043 pr_err("nand: error: CONFIG_MTD_NAND_OMAP_BCH not enabled\n");
2044 err = -EINVAL;
2045 goto out_release_mem_region;
2046#endif
2047
2048 default:
2049 pr_err("nand: error: invalid or unsupported ECC scheme\n");
2050 err = -EINVAL;
2051 goto out_release_mem_region;
2020 } 2052 }
2021 2053
2022 /* rom code layout */ 2054 /* rom code layout */
@@ -2038,6 +2070,8 @@ static int omap_nand_probe(struct platform_device *pdev)
2038 2070
2039 nand_chip->ecc.layout = &omap_oobinfo; 2071 nand_chip->ecc.layout = &omap_oobinfo;
2040 } else if ((pdata->ecc_opt == OMAP_ECC_BCH4_CODE_HW) || 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) ||
2041 (pdata->ecc_opt == OMAP_ECC_BCH8_CODE_HW)) { 2075 (pdata->ecc_opt == OMAP_ECC_BCH8_CODE_HW)) {
2042 /* build OOB layout for BCH ECC correction */ 2076 /* build OOB layout for BCH ECC correction */
2043 err = omap3_init_bch_tail(mtd); 2077 err = omap3_init_bch_tail(mtd);
@@ -2070,6 +2104,7 @@ out_release_mem_region:
2070 free_irq(info->gpmc_irq_fifo, info); 2104 free_irq(info->gpmc_irq_fifo, info);
2071 release_mem_region(info->phys_base, info->mem_size); 2105 release_mem_region(info->phys_base, info->mem_size);
2072out_free_info: 2106out_free_info:
2107 omap3_free_bch(mtd);
2073 kfree(info); 2108 kfree(info);
2074 2109
2075 return err; 2110 return err;