diff options
author | Pekon Gupta <pekon@ti.com> | 2013-10-24 08:50:21 -0400 |
---|---|---|
committer | Brian Norris <computersforpeace@gmail.com> | 2013-11-07 02:33:09 -0500 |
commit | a919e51161b58ed7e6e663daba99ab7d558808f3 (patch) | |
tree | 3418227e6e03e1c43cea1d6e41a48fcc519307dd /drivers/mtd/nand | |
parent | f18befb57b0779094ac7658fa7be5cf559da835f (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.c | 281 |
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 |
145 | static u_char bch8_vector[] = {0xf3, 0xdb, 0x14, 0x16, 0x8b, 0xd2, 0xbe, 0xcc, | 145 | static 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 | */ |
1643 | static void omap3_free_bch(struct mtd_info *mtd) | 1649 | static 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 | */ |
1658 | static int omap3_init_bch(struct mtd_info *mtd, int ecc_opt) | 1679 | static 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; | ||
1749 | fail: | ||
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 |
1809 | static 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 | } | ||
1814 | static int omap3_init_bch_tail(struct mtd_info *mtd) | 1744 | static 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) | |||
1818 | static void omap3_free_bch(struct mtd_info *mtd) | 1748 | static 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 | ||
1823 | static int omap_nand_probe(struct platform_device *pdev) | 1753 | static 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); |
2072 | out_free_info: | 2106 | out_free_info: |
2107 | omap3_free_bch(mtd); | ||
2073 | kfree(info); | 2108 | kfree(info); |
2074 | 2109 | ||
2075 | return err; | 2110 | return err; |