|
32 | 32 | #include <linux/pm_runtime.h>
|
33 | 33 |
|
34 | 34 | #include <linux/platform_data/mtd-nand-omap2.h>
|
35 |
| -#include <linux/platform_data/mtd-onenand-omap2.h> |
36 | 35 |
|
37 | 36 | #include <asm/mach-types.h>
|
38 | 37 |
|
@@ -1138,6 +1137,112 @@ struct gpmc_nand_ops *gpmc_omap_get_nand_ops(struct gpmc_nand_regs *reg, int cs)
|
1138 | 1137 | }
|
1139 | 1138 | EXPORT_SYMBOL_GPL(gpmc_omap_get_nand_ops);
|
1140 | 1139 |
|
| 1140 | +static void gpmc_omap_onenand_calc_sync_timings(struct gpmc_timings *t, |
| 1141 | + struct gpmc_settings *s, |
| 1142 | + int freq, int latency) |
| 1143 | +{ |
| 1144 | + struct gpmc_device_timings dev_t; |
| 1145 | + const int t_cer = 15; |
| 1146 | + const int t_avdp = 12; |
| 1147 | + const int t_cez = 20; /* max of t_cez, t_oez */ |
| 1148 | + const int t_wpl = 40; |
| 1149 | + const int t_wph = 30; |
| 1150 | + int min_gpmc_clk_period, t_ces, t_avds, t_avdh, t_ach, t_aavdh, t_rdyo; |
| 1151 | + |
| 1152 | + switch (freq) { |
| 1153 | + case 104: |
| 1154 | + min_gpmc_clk_period = 9600; /* 104 MHz */ |
| 1155 | + t_ces = 3; |
| 1156 | + t_avds = 4; |
| 1157 | + t_avdh = 2; |
| 1158 | + t_ach = 3; |
| 1159 | + t_aavdh = 6; |
| 1160 | + t_rdyo = 6; |
| 1161 | + break; |
| 1162 | + case 83: |
| 1163 | + min_gpmc_clk_period = 12000; /* 83 MHz */ |
| 1164 | + t_ces = 5; |
| 1165 | + t_avds = 4; |
| 1166 | + t_avdh = 2; |
| 1167 | + t_ach = 6; |
| 1168 | + t_aavdh = 6; |
| 1169 | + t_rdyo = 9; |
| 1170 | + break; |
| 1171 | + case 66: |
| 1172 | + min_gpmc_clk_period = 15000; /* 66 MHz */ |
| 1173 | + t_ces = 6; |
| 1174 | + t_avds = 5; |
| 1175 | + t_avdh = 2; |
| 1176 | + t_ach = 6; |
| 1177 | + t_aavdh = 6; |
| 1178 | + t_rdyo = 11; |
| 1179 | + break; |
| 1180 | + default: |
| 1181 | + min_gpmc_clk_period = 18500; /* 54 MHz */ |
| 1182 | + t_ces = 7; |
| 1183 | + t_avds = 7; |
| 1184 | + t_avdh = 7; |
| 1185 | + t_ach = 9; |
| 1186 | + t_aavdh = 7; |
| 1187 | + t_rdyo = 15; |
| 1188 | + break; |
| 1189 | + } |
| 1190 | + |
| 1191 | + /* Set synchronous read timings */ |
| 1192 | + memset(&dev_t, 0, sizeof(dev_t)); |
| 1193 | + |
| 1194 | + if (!s->sync_write) { |
| 1195 | + dev_t.t_avdp_w = max(t_avdp, t_cer) * 1000; |
| 1196 | + dev_t.t_wpl = t_wpl * 1000; |
| 1197 | + dev_t.t_wph = t_wph * 1000; |
| 1198 | + dev_t.t_aavdh = t_aavdh * 1000; |
| 1199 | + } |
| 1200 | + dev_t.ce_xdelay = true; |
| 1201 | + dev_t.avd_xdelay = true; |
| 1202 | + dev_t.oe_xdelay = true; |
| 1203 | + dev_t.we_xdelay = true; |
| 1204 | + dev_t.clk = min_gpmc_clk_period; |
| 1205 | + dev_t.t_bacc = dev_t.clk; |
| 1206 | + dev_t.t_ces = t_ces * 1000; |
| 1207 | + dev_t.t_avds = t_avds * 1000; |
| 1208 | + dev_t.t_avdh = t_avdh * 1000; |
| 1209 | + dev_t.t_ach = t_ach * 1000; |
| 1210 | + dev_t.cyc_iaa = (latency + 1); |
| 1211 | + dev_t.t_cez_r = t_cez * 1000; |
| 1212 | + dev_t.t_cez_w = dev_t.t_cez_r; |
| 1213 | + dev_t.cyc_aavdh_oe = 1; |
| 1214 | + dev_t.t_rdyo = t_rdyo * 1000 + min_gpmc_clk_period; |
| 1215 | + |
| 1216 | + gpmc_calc_timings(t, s, &dev_t); |
| 1217 | +} |
| 1218 | + |
| 1219 | +int gpmc_omap_onenand_set_timings(struct device *dev, int cs, int freq, |
| 1220 | + int latency, |
| 1221 | + struct gpmc_onenand_info *info) |
| 1222 | +{ |
| 1223 | + int ret; |
| 1224 | + struct gpmc_timings gpmc_t; |
| 1225 | + struct gpmc_settings gpmc_s; |
| 1226 | + |
| 1227 | + gpmc_read_settings_dt(dev->of_node, &gpmc_s); |
| 1228 | + |
| 1229 | + info->sync_read = gpmc_s.sync_read; |
| 1230 | + info->sync_write = gpmc_s.sync_write; |
| 1231 | + info->burst_len = gpmc_s.burst_len; |
| 1232 | + |
| 1233 | + if (!gpmc_s.sync_read && !gpmc_s.sync_write) |
| 1234 | + return 0; |
| 1235 | + |
| 1236 | + gpmc_omap_onenand_calc_sync_timings(&gpmc_t, &gpmc_s, freq, latency); |
| 1237 | + |
| 1238 | + ret = gpmc_cs_program_settings(cs, &gpmc_s); |
| 1239 | + if (ret < 0) |
| 1240 | + return ret; |
| 1241 | + |
| 1242 | + return gpmc_cs_set_timings(cs, &gpmc_t, &gpmc_s); |
| 1243 | +} |
| 1244 | +EXPORT_SYMBOL_GPL(gpmc_omap_onenand_set_timings); |
| 1245 | + |
1141 | 1246 | int gpmc_get_client_irq(unsigned irq_config)
|
1142 | 1247 | {
|
1143 | 1248 | if (!gpmc_irq_domain) {
|
@@ -1916,41 +2021,6 @@ static void __maybe_unused gpmc_read_timings_dt(struct device_node *np,
|
1916 | 2021 | of_property_read_bool(np, "gpmc,time-para-granularity");
|
1917 | 2022 | }
|
1918 | 2023 |
|
1919 |
| -#if IS_ENABLED(CONFIG_MTD_ONENAND) |
1920 |
| -static int gpmc_probe_onenand_child(struct platform_device *pdev, |
1921 |
| - struct device_node *child) |
1922 |
| -{ |
1923 |
| - u32 val; |
1924 |
| - struct omap_onenand_platform_data *gpmc_onenand_data; |
1925 |
| - |
1926 |
| - if (of_property_read_u32(child, "reg", &val) < 0) { |
1927 |
| - dev_err(&pdev->dev, "%pOF has no 'reg' property\n", |
1928 |
| - child); |
1929 |
| - return -ENODEV; |
1930 |
| - } |
1931 |
| - |
1932 |
| - gpmc_onenand_data = devm_kzalloc(&pdev->dev, sizeof(*gpmc_onenand_data), |
1933 |
| - GFP_KERNEL); |
1934 |
| - if (!gpmc_onenand_data) |
1935 |
| - return -ENOMEM; |
1936 |
| - |
1937 |
| - gpmc_onenand_data->cs = val; |
1938 |
| - gpmc_onenand_data->of_node = child; |
1939 |
| - gpmc_onenand_data->dma_channel = -1; |
1940 |
| - |
1941 |
| - if (!of_property_read_u32(child, "dma-channel", &val)) |
1942 |
| - gpmc_onenand_data->dma_channel = val; |
1943 |
| - |
1944 |
| - return gpmc_onenand_init(gpmc_onenand_data); |
1945 |
| -} |
1946 |
| -#else |
1947 |
| -static int gpmc_probe_onenand_child(struct platform_device *pdev, |
1948 |
| - struct device_node *child) |
1949 |
| -{ |
1950 |
| - return 0; |
1951 |
| -} |
1952 |
| -#endif |
1953 |
| - |
1954 | 2024 | /**
|
1955 | 2025 | * gpmc_probe_generic_child - configures the gpmc for a child device
|
1956 | 2026 | * @pdev: pointer to gpmc platform device
|
@@ -2053,6 +2123,16 @@ static int gpmc_probe_generic_child(struct platform_device *pdev,
|
2053 | 2123 | }
|
2054 | 2124 | }
|
2055 | 2125 |
|
| 2126 | + if (of_node_cmp(child->name, "onenand") == 0) { |
| 2127 | + /* Warn about older DT blobs with no compatible property */ |
| 2128 | + if (!of_property_read_bool(child, "compatible")) { |
| 2129 | + dev_warn(&pdev->dev, |
| 2130 | + "Incompatible OneNAND node: missing compatible"); |
| 2131 | + ret = -EINVAL; |
| 2132 | + goto err; |
| 2133 | + } |
| 2134 | + } |
| 2135 | + |
2056 | 2136 | if (of_device_is_compatible(child, "ti,omap2-nand")) {
|
2057 | 2137 | /* NAND specific setup */
|
2058 | 2138 | val = 8;
|
@@ -2189,11 +2269,7 @@ static void gpmc_probe_dt_children(struct platform_device *pdev)
|
2189 | 2269 | if (!child->name)
|
2190 | 2270 | continue;
|
2191 | 2271 |
|
2192 |
| - if (of_node_cmp(child->name, "onenand") == 0) |
2193 |
| - ret = gpmc_probe_onenand_child(pdev, child); |
2194 |
| - else |
2195 |
| - ret = gpmc_probe_generic_child(pdev, child); |
2196 |
| - |
| 2272 | + ret = gpmc_probe_generic_child(pdev, child); |
2197 | 2273 | if (ret) {
|
2198 | 2274 | dev_err(&pdev->dev, "failed to probe DT child '%s': %d\n",
|
2199 | 2275 | child->name, ret);
|
|
0 commit comments