diff options
Diffstat (limited to 'drivers/memory/omap-gpmc.c')
-rw-r--r-- | drivers/memory/omap-gpmc.c | 143 |
1 files changed, 37 insertions, 106 deletions
diff --git a/drivers/memory/omap-gpmc.c b/drivers/memory/omap-gpmc.c index e28d6bc2500a..8dc6e3b1c44a 100644 --- a/drivers/memory/omap-gpmc.c +++ b/drivers/memory/omap-gpmc.c | |||
@@ -30,7 +30,6 @@ | |||
30 | #include <linux/of_device.h> | 30 | #include <linux/of_device.h> |
31 | #include <linux/of_platform.h> | 31 | #include <linux/of_platform.h> |
32 | #include <linux/omap-gpmc.h> | 32 | #include <linux/omap-gpmc.h> |
33 | #include <linux/mtd/nand.h> | ||
34 | #include <linux/pm_runtime.h> | 33 | #include <linux/pm_runtime.h> |
35 | 34 | ||
36 | #include <linux/platform_data/mtd-nand-omap2.h> | 35 | #include <linux/platform_data/mtd-nand-omap2.h> |
@@ -1852,105 +1851,6 @@ static void __maybe_unused gpmc_read_timings_dt(struct device_node *np, | |||
1852 | of_property_read_bool(np, "gpmc,time-para-granularity"); | 1851 | of_property_read_bool(np, "gpmc,time-para-granularity"); |
1853 | } | 1852 | } |
1854 | 1853 | ||
1855 | #if IS_ENABLED(CONFIG_MTD_NAND) | ||
1856 | |||
1857 | static const char * const nand_xfer_types[] = { | ||
1858 | [NAND_OMAP_PREFETCH_POLLED] = "prefetch-polled", | ||
1859 | [NAND_OMAP_POLLED] = "polled", | ||
1860 | [NAND_OMAP_PREFETCH_DMA] = "prefetch-dma", | ||
1861 | [NAND_OMAP_PREFETCH_IRQ] = "prefetch-irq", | ||
1862 | }; | ||
1863 | |||
1864 | static int gpmc_probe_nand_child(struct platform_device *pdev, | ||
1865 | struct device_node *child) | ||
1866 | { | ||
1867 | u32 val; | ||
1868 | const char *s; | ||
1869 | struct gpmc_timings gpmc_t; | ||
1870 | struct omap_nand_platform_data *gpmc_nand_data; | ||
1871 | |||
1872 | if (of_property_read_u32(child, "reg", &val) < 0) { | ||
1873 | dev_err(&pdev->dev, "%s has no 'reg' property\n", | ||
1874 | child->full_name); | ||
1875 | return -ENODEV; | ||
1876 | } | ||
1877 | |||
1878 | gpmc_nand_data = devm_kzalloc(&pdev->dev, sizeof(*gpmc_nand_data), | ||
1879 | GFP_KERNEL); | ||
1880 | if (!gpmc_nand_data) | ||
1881 | return -ENOMEM; | ||
1882 | |||
1883 | gpmc_nand_data->cs = val; | ||
1884 | gpmc_nand_data->of_node = child; | ||
1885 | |||
1886 | /* Detect availability of ELM module */ | ||
1887 | gpmc_nand_data->elm_of_node = of_parse_phandle(child, "ti,elm-id", 0); | ||
1888 | if (gpmc_nand_data->elm_of_node == NULL) | ||
1889 | gpmc_nand_data->elm_of_node = | ||
1890 | of_parse_phandle(child, "elm_id", 0); | ||
1891 | |||
1892 | /* select ecc-scheme for NAND */ | ||
1893 | if (of_property_read_string(child, "ti,nand-ecc-opt", &s)) { | ||
1894 | pr_err("%s: ti,nand-ecc-opt not found\n", __func__); | ||
1895 | return -ENODEV; | ||
1896 | } | ||
1897 | |||
1898 | if (!strcmp(s, "sw")) | ||
1899 | gpmc_nand_data->ecc_opt = OMAP_ECC_HAM1_CODE_SW; | ||
1900 | else if (!strcmp(s, "ham1") || | ||
1901 | !strcmp(s, "hw") || !strcmp(s, "hw-romcode")) | ||
1902 | gpmc_nand_data->ecc_opt = | ||
1903 | OMAP_ECC_HAM1_CODE_HW; | ||
1904 | else if (!strcmp(s, "bch4")) | ||
1905 | if (gpmc_nand_data->elm_of_node) | ||
1906 | gpmc_nand_data->ecc_opt = | ||
1907 | OMAP_ECC_BCH4_CODE_HW; | ||
1908 | else | ||
1909 | gpmc_nand_data->ecc_opt = | ||
1910 | OMAP_ECC_BCH4_CODE_HW_DETECTION_SW; | ||
1911 | else if (!strcmp(s, "bch8")) | ||
1912 | if (gpmc_nand_data->elm_of_node) | ||
1913 | gpmc_nand_data->ecc_opt = | ||
1914 | OMAP_ECC_BCH8_CODE_HW; | ||
1915 | else | ||
1916 | gpmc_nand_data->ecc_opt = | ||
1917 | OMAP_ECC_BCH8_CODE_HW_DETECTION_SW; | ||
1918 | else if (!strcmp(s, "bch16")) | ||
1919 | if (gpmc_nand_data->elm_of_node) | ||
1920 | gpmc_nand_data->ecc_opt = | ||
1921 | OMAP_ECC_BCH16_CODE_HW; | ||
1922 | else | ||
1923 | pr_err("%s: BCH16 requires ELM support\n", __func__); | ||
1924 | else | ||
1925 | pr_err("%s: ti,nand-ecc-opt invalid value\n", __func__); | ||
1926 | |||
1927 | /* select data transfer mode for NAND controller */ | ||
1928 | if (!of_property_read_string(child, "ti,nand-xfer-type", &s)) | ||
1929 | for (val = 0; val < ARRAY_SIZE(nand_xfer_types); val++) | ||
1930 | if (!strcasecmp(s, nand_xfer_types[val])) { | ||
1931 | gpmc_nand_data->xfer_type = val; | ||
1932 | break; | ||
1933 | } | ||
1934 | |||
1935 | gpmc_nand_data->flash_bbt = of_get_nand_on_flash_bbt(child); | ||
1936 | |||
1937 | val = of_get_nand_bus_width(child); | ||
1938 | if (val == 16) | ||
1939 | gpmc_nand_data->devsize = NAND_BUSWIDTH_16; | ||
1940 | |||
1941 | gpmc_read_timings_dt(child, &gpmc_t); | ||
1942 | gpmc_nand_init(gpmc_nand_data, &gpmc_t); | ||
1943 | |||
1944 | return 0; | ||
1945 | } | ||
1946 | #else | ||
1947 | static int gpmc_probe_nand_child(struct platform_device *pdev, | ||
1948 | struct device_node *child) | ||
1949 | { | ||
1950 | return 0; | ||
1951 | } | ||
1952 | #endif | ||
1953 | |||
1954 | #if IS_ENABLED(CONFIG_MTD_ONENAND) | 1854 | #if IS_ENABLED(CONFIG_MTD_ONENAND) |
1955 | static int gpmc_probe_onenand_child(struct platform_device *pdev, | 1855 | static int gpmc_probe_onenand_child(struct platform_device *pdev, |
1956 | struct device_node *child) | 1856 | struct device_node *child) |
@@ -2069,9 +1969,42 @@ static int gpmc_probe_generic_child(struct platform_device *pdev, | |||
2069 | goto err; | 1969 | goto err; |
2070 | } | 1970 | } |
2071 | 1971 | ||
2072 | ret = of_property_read_u32(child, "bank-width", &gpmc_s.device_width); | 1972 | if (of_node_cmp(child->name, "nand") == 0) { |
2073 | if (ret < 0) | 1973 | /* Warn about older DT blobs with no compatible property */ |
2074 | goto err; | 1974 | if (!of_property_read_bool(child, "compatible")) { |
1975 | dev_warn(&pdev->dev, | ||
1976 | "Incompatible NAND node: missing compatible"); | ||
1977 | ret = -EINVAL; | ||
1978 | goto err; | ||
1979 | } | ||
1980 | } | ||
1981 | |||
1982 | if (of_device_is_compatible(child, "ti,omap2-nand")) { | ||
1983 | /* NAND specific setup */ | ||
1984 | val = of_get_nand_bus_width(child); | ||
1985 | switch (val) { | ||
1986 | case 8: | ||
1987 | gpmc_s.device_width = GPMC_DEVWIDTH_8BIT; | ||
1988 | break; | ||
1989 | case 16: | ||
1990 | gpmc_s.device_width = GPMC_DEVWIDTH_16BIT; | ||
1991 | break; | ||
1992 | default: | ||
1993 | dev_err(&pdev->dev, "%s: invalid 'nand-bus-width'\n", | ||
1994 | child->name); | ||
1995 | ret = -EINVAL; | ||
1996 | goto err; | ||
1997 | } | ||
1998 | |||
1999 | /* disable write protect */ | ||
2000 | gpmc_configure(GPMC_CONFIG_WP, 0); | ||
2001 | gpmc_s.device_nand = true; | ||
2002 | } else { | ||
2003 | ret = of_property_read_u32(child, "bank-width", | ||
2004 | &gpmc_s.device_width); | ||
2005 | if (ret < 0) | ||
2006 | goto err; | ||
2007 | } | ||
2075 | 2008 | ||
2076 | gpmc_cs_show_timings(cs, "before gpmc_cs_program_settings"); | 2009 | gpmc_cs_show_timings(cs, "before gpmc_cs_program_settings"); |
2077 | ret = gpmc_cs_program_settings(cs, &gpmc_s); | 2010 | ret = gpmc_cs_program_settings(cs, &gpmc_s); |
@@ -2155,9 +2088,7 @@ static int gpmc_probe_dt(struct platform_device *pdev) | |||
2155 | if (!child->name) | 2088 | if (!child->name) |
2156 | continue; | 2089 | continue; |
2157 | 2090 | ||
2158 | if (of_node_cmp(child->name, "nand") == 0) | 2091 | if (of_node_cmp(child->name, "onenand") == 0) |
2159 | ret = gpmc_probe_nand_child(pdev, child); | ||
2160 | else if (of_node_cmp(child->name, "onenand") == 0) | ||
2161 | ret = gpmc_probe_onenand_child(pdev, child); | 2092 | ret = gpmc_probe_onenand_child(pdev, child); |
2162 | else | 2093 | else |
2163 | ret = gpmc_probe_generic_child(pdev, child); | 2094 | ret = gpmc_probe_generic_child(pdev, child); |