diff options
author | Afzal Mohammed <afzal@ti.com> | 2012-06-05 00:41:48 -0400 |
---|---|---|
committer | Afzal Mohammed <afzal@ti.com> | 2012-10-15 05:10:26 -0400 |
commit | 46376884ce0a98c276187a169620a766f0941f08 (patch) | |
tree | f378b7eb948522d4ca5ae277ed42a4d264fa46a8 /arch/arm/mach-omap2/gpmc-onenand.c | |
parent | 2e618261c96d72e5c5409d134d6d93e679683ab8 (diff) |
ARM: OMAP2+: onenand: refactor for clarity
Refactor set_async_mode & set_sync_mode functions to
separate out timing calculation & actual configuration
(GPMC & OneNAND side).
Thanks to Jon for his suggestions.
Signed-off-by: Afzal Mohammed <afzal@ti.com>
Reviewed-by: Jon Hunter <jon-hunter@ti.com>
Diffstat (limited to 'arch/arm/mach-omap2/gpmc-onenand.c')
-rw-r--r-- | arch/arm/mach-omap2/gpmc-onenand.c | 174 |
1 files changed, 110 insertions, 64 deletions
diff --git a/arch/arm/mach-omap2/gpmc-onenand.c b/arch/arm/mach-omap2/gpmc-onenand.c index 916716e1da3b..29d391b273fc 100644 --- a/arch/arm/mach-omap2/gpmc-onenand.c +++ b/arch/arm/mach-omap2/gpmc-onenand.c | |||
@@ -16,6 +16,7 @@ | |||
16 | #include <linux/mtd/onenand_regs.h> | 16 | #include <linux/mtd/onenand_regs.h> |
17 | #include <linux/io.h> | 17 | #include <linux/io.h> |
18 | #include <linux/platform_data/mtd-onenand-omap2.h> | 18 | #include <linux/platform_data/mtd-onenand-omap2.h> |
19 | #include <linux/err.h> | ||
19 | 20 | ||
20 | #include <asm/mach/flash.h> | 21 | #include <asm/mach/flash.h> |
21 | 22 | ||
@@ -25,6 +26,15 @@ | |||
25 | 26 | ||
26 | #define ONENAND_IO_SIZE SZ_128K | 27 | #define ONENAND_IO_SIZE SZ_128K |
27 | 28 | ||
29 | #define ONENAND_FLAG_SYNCREAD (1 << 0) | ||
30 | #define ONENAND_FLAG_SYNCWRITE (1 << 1) | ||
31 | #define ONENAND_FLAG_HF (1 << 2) | ||
32 | #define ONENAND_FLAG_VHF (1 << 3) | ||
33 | |||
34 | static unsigned onenand_flags; | ||
35 | static unsigned latency; | ||
36 | static int fclk_offset; | ||
37 | |||
28 | static struct omap_onenand_platform_data *gpmc_onenand_data; | 38 | static struct omap_onenand_platform_data *gpmc_onenand_data; |
29 | 39 | ||
30 | static struct resource gpmc_onenand_resource = { | 40 | static struct resource gpmc_onenand_resource = { |
@@ -38,11 +48,9 @@ static struct platform_device gpmc_onenand_device = { | |||
38 | .resource = &gpmc_onenand_resource, | 48 | .resource = &gpmc_onenand_resource, |
39 | }; | 49 | }; |
40 | 50 | ||
41 | static int omap2_onenand_set_async_mode(int cs, void __iomem *onenand_base) | 51 | static struct gpmc_timings omap2_onenand_calc_async_timings(void) |
42 | { | 52 | { |
43 | struct gpmc_timings t; | 53 | struct gpmc_timings t; |
44 | u32 reg; | ||
45 | int err; | ||
46 | 54 | ||
47 | const int t_cer = 15; | 55 | const int t_cer = 15; |
48 | const int t_avdp = 12; | 56 | const int t_avdp = 12; |
@@ -55,11 +63,6 @@ static int omap2_onenand_set_async_mode(int cs, void __iomem *onenand_base) | |||
55 | const int t_wpl = 40; | 63 | const int t_wpl = 40; |
56 | const int t_wph = 30; | 64 | const int t_wph = 30; |
57 | 65 | ||
58 | /* Ensure sync read and sync write are disabled */ | ||
59 | reg = readw(onenand_base + ONENAND_REG_SYS_CFG1); | ||
60 | reg &= ~ONENAND_SYS_CFG1_SYNC_READ & ~ONENAND_SYS_CFG1_SYNC_WRITE; | ||
61 | writew(reg, onenand_base + ONENAND_REG_SYS_CFG1); | ||
62 | |||
63 | memset(&t, 0, sizeof(t)); | 66 | memset(&t, 0, sizeof(t)); |
64 | t.sync_clk = 0; | 67 | t.sync_clk = 0; |
65 | t.cs_on = 0; | 68 | t.cs_on = 0; |
@@ -86,25 +89,30 @@ static int omap2_onenand_set_async_mode(int cs, void __iomem *onenand_base) | |||
86 | t.cs_wr_off = t.we_off + gpmc_round_ns_to_ticks(t_wph); | 89 | t.cs_wr_off = t.we_off + gpmc_round_ns_to_ticks(t_wph); |
87 | t.wr_cycle = t.cs_wr_off + gpmc_round_ns_to_ticks(t_cez); | 90 | t.wr_cycle = t.cs_wr_off + gpmc_round_ns_to_ticks(t_cez); |
88 | 91 | ||
92 | return t; | ||
93 | } | ||
94 | |||
95 | static int gpmc_set_async_mode(int cs, struct gpmc_timings *t) | ||
96 | { | ||
89 | /* Configure GPMC for asynchronous read */ | 97 | /* Configure GPMC for asynchronous read */ |
90 | gpmc_cs_write_reg(cs, GPMC_CS_CONFIG1, | 98 | gpmc_cs_write_reg(cs, GPMC_CS_CONFIG1, |
91 | GPMC_CONFIG1_DEVICESIZE_16 | | 99 | GPMC_CONFIG1_DEVICESIZE_16 | |
92 | GPMC_CONFIG1_MUXADDDATA); | 100 | GPMC_CONFIG1_MUXADDDATA); |
93 | 101 | ||
94 | err = gpmc_cs_set_timings(cs, &t); | 102 | return gpmc_cs_set_timings(cs, t); |
95 | if (err) | 103 | } |
96 | return err; | 104 | |
105 | static void omap2_onenand_set_async_mode(void __iomem *onenand_base) | ||
106 | { | ||
107 | u32 reg; | ||
97 | 108 | ||
98 | /* Ensure sync read and sync write are disabled */ | 109 | /* Ensure sync read and sync write are disabled */ |
99 | reg = readw(onenand_base + ONENAND_REG_SYS_CFG1); | 110 | reg = readw(onenand_base + ONENAND_REG_SYS_CFG1); |
100 | reg &= ~ONENAND_SYS_CFG1_SYNC_READ & ~ONENAND_SYS_CFG1_SYNC_WRITE; | 111 | reg &= ~ONENAND_SYS_CFG1_SYNC_READ & ~ONENAND_SYS_CFG1_SYNC_WRITE; |
101 | writew(reg, onenand_base + ONENAND_REG_SYS_CFG1); | 112 | writew(reg, onenand_base + ONENAND_REG_SYS_CFG1); |
102 | |||
103 | return 0; | ||
104 | } | 113 | } |
105 | 114 | ||
106 | static void set_onenand_cfg(void __iomem *onenand_base, int latency, | 115 | static void set_onenand_cfg(void __iomem *onenand_base) |
107 | int sync_read, int sync_write, int hf, int vhf) | ||
108 | { | 116 | { |
109 | u32 reg; | 117 | u32 reg; |
110 | 118 | ||
@@ -112,19 +120,19 @@ static void set_onenand_cfg(void __iomem *onenand_base, int latency, | |||
112 | reg &= ~((0x7 << ONENAND_SYS_CFG1_BRL_SHIFT) | (0x7 << 9)); | 120 | reg &= ~((0x7 << ONENAND_SYS_CFG1_BRL_SHIFT) | (0x7 << 9)); |
113 | reg |= (latency << ONENAND_SYS_CFG1_BRL_SHIFT) | | 121 | reg |= (latency << ONENAND_SYS_CFG1_BRL_SHIFT) | |
114 | ONENAND_SYS_CFG1_BL_16; | 122 | ONENAND_SYS_CFG1_BL_16; |
115 | if (sync_read) | 123 | if (onenand_flags & ONENAND_FLAG_SYNCREAD) |
116 | reg |= ONENAND_SYS_CFG1_SYNC_READ; | 124 | reg |= ONENAND_SYS_CFG1_SYNC_READ; |
117 | else | 125 | else |
118 | reg &= ~ONENAND_SYS_CFG1_SYNC_READ; | 126 | reg &= ~ONENAND_SYS_CFG1_SYNC_READ; |
119 | if (sync_write) | 127 | if (onenand_flags & ONENAND_FLAG_SYNCWRITE) |
120 | reg |= ONENAND_SYS_CFG1_SYNC_WRITE; | 128 | reg |= ONENAND_SYS_CFG1_SYNC_WRITE; |
121 | else | 129 | else |
122 | reg &= ~ONENAND_SYS_CFG1_SYNC_WRITE; | 130 | reg &= ~ONENAND_SYS_CFG1_SYNC_WRITE; |
123 | if (hf) | 131 | if (onenand_flags & ONENAND_FLAG_HF) |
124 | reg |= ONENAND_SYS_CFG1_HF; | 132 | reg |= ONENAND_SYS_CFG1_HF; |
125 | else | 133 | else |
126 | reg &= ~ONENAND_SYS_CFG1_HF; | 134 | reg &= ~ONENAND_SYS_CFG1_HF; |
127 | if (vhf) | 135 | if (onenand_flags & ONENAND_FLAG_VHF) |
128 | reg |= ONENAND_SYS_CFG1_VHF; | 136 | reg |= ONENAND_SYS_CFG1_VHF; |
129 | else | 137 | else |
130 | reg &= ~ONENAND_SYS_CFG1_VHF; | 138 | reg &= ~ONENAND_SYS_CFG1_VHF; |
@@ -172,9 +180,9 @@ static int omap2_onenand_get_freq(struct omap_onenand_platform_data *cfg, | |||
172 | return freq; | 180 | return freq; |
173 | } | 181 | } |
174 | 182 | ||
175 | static int omap2_onenand_set_sync_mode(struct omap_onenand_platform_data *cfg, | 183 | static struct gpmc_timings |
176 | void __iomem *onenand_base, | 184 | omap2_onenand_calc_sync_timings(struct omap_onenand_platform_data *cfg, |
177 | int *freq_ptr) | 185 | int freq, bool clk_dep) |
178 | { | 186 | { |
179 | struct gpmc_timings t; | 187 | struct gpmc_timings t; |
180 | const int t_cer = 15; | 188 | const int t_cer = 15; |
@@ -184,29 +192,15 @@ static int omap2_onenand_set_sync_mode(struct omap_onenand_platform_data *cfg, | |||
184 | const int t_wpl = 40; | 192 | const int t_wpl = 40; |
185 | const int t_wph = 30; | 193 | const int t_wph = 30; |
186 | int min_gpmc_clk_period, t_ces, t_avds, t_avdh, t_ach, t_aavdh, t_rdyo; | 194 | int min_gpmc_clk_period, t_ces, t_avds, t_avdh, t_ach, t_aavdh, t_rdyo; |
187 | int div, fclk_offset_ns, fclk_offset, gpmc_clk_ns, latency; | ||
188 | int first_time = 0, hf = 0, vhf = 0, sync_read = 0, sync_write = 0; | ||
189 | int err, ticks_cez; | ||
190 | int cs = cfg->cs, freq = *freq_ptr; | ||
191 | u32 reg; | 195 | u32 reg; |
192 | bool clk_dep = false; | 196 | int div, fclk_offset_ns, gpmc_clk_ns; |
193 | 197 | int ticks_cez; | |
194 | if (cfg->flags & ONENAND_SYNC_READ) { | 198 | int cs = cfg->cs; |
195 | sync_read = 1; | ||
196 | } else if (cfg->flags & ONENAND_SYNC_READWRITE) { | ||
197 | sync_read = 1; | ||
198 | sync_write = 1; | ||
199 | } else | ||
200 | return omap2_onenand_set_async_mode(cs, onenand_base); | ||
201 | 199 | ||
202 | if (!freq) { | 200 | if (cfg->flags & ONENAND_SYNC_READ) |
203 | /* Very first call freq is not known */ | 201 | onenand_flags = ONENAND_FLAG_SYNCREAD; |
204 | err = omap2_onenand_set_async_mode(cs, onenand_base); | 202 | else if (cfg->flags & ONENAND_SYNC_READWRITE) |
205 | if (err) | 203 | onenand_flags = ONENAND_FLAG_SYNCREAD | ONENAND_FLAG_SYNCWRITE; |
206 | return err; | ||
207 | freq = omap2_onenand_get_freq(cfg, onenand_base, &clk_dep); | ||
208 | first_time = 1; | ||
209 | } | ||
210 | 204 | ||
211 | switch (freq) { | 205 | switch (freq) { |
212 | case 104: | 206 | case 104: |
@@ -244,19 +238,23 @@ static int omap2_onenand_set_sync_mode(struct omap_onenand_platform_data *cfg, | |||
244 | t_ach = 9; | 238 | t_ach = 9; |
245 | t_aavdh = 7; | 239 | t_aavdh = 7; |
246 | t_rdyo = 15; | 240 | t_rdyo = 15; |
247 | sync_write = 0; | 241 | onenand_flags &= ~ONENAND_FLAG_SYNCWRITE; |
248 | break; | 242 | break; |
249 | } | 243 | } |
250 | 244 | ||
251 | div = gpmc_cs_calc_divider(cs, min_gpmc_clk_period); | 245 | div = gpmc_cs_calc_divider(cs, min_gpmc_clk_period); |
252 | gpmc_clk_ns = gpmc_ticks_to_ns(div); | 246 | gpmc_clk_ns = gpmc_ticks_to_ns(div); |
253 | if (gpmc_clk_ns < 15) /* >66Mhz */ | 247 | if (gpmc_clk_ns < 15) /* >66Mhz */ |
254 | hf = 1; | 248 | onenand_flags |= ONENAND_FLAG_HF; |
249 | else | ||
250 | onenand_flags &= ~ONENAND_FLAG_HF; | ||
255 | if (gpmc_clk_ns < 12) /* >83Mhz */ | 251 | if (gpmc_clk_ns < 12) /* >83Mhz */ |
256 | vhf = 1; | 252 | onenand_flags |= ONENAND_FLAG_VHF; |
257 | if (vhf) | 253 | else |
254 | onenand_flags &= ~ONENAND_FLAG_VHF; | ||
255 | if (onenand_flags & ONENAND_FLAG_VHF) | ||
258 | latency = 8; | 256 | latency = 8; |
259 | else if (hf) | 257 | else if (onenand_flags & ONENAND_FLAG_HF) |
260 | latency = 6; | 258 | latency = 6; |
261 | else if (gpmc_clk_ns >= 25) /* 40 MHz*/ | 259 | else if (gpmc_clk_ns >= 25) /* 40 MHz*/ |
262 | latency = 3; | 260 | latency = 3; |
@@ -279,9 +277,8 @@ static int omap2_onenand_set_sync_mode(struct omap_onenand_platform_data *cfg, | |||
279 | } | 277 | } |
280 | } | 278 | } |
281 | 279 | ||
282 | if (first_time) | 280 | /* Set synchronous read timings */ |
283 | set_onenand_cfg(onenand_base, latency, | 281 | memset(&t, 0, sizeof(t)); |
284 | sync_read, sync_write, hf, vhf); | ||
285 | 282 | ||
286 | if (div == 1) { | 283 | if (div == 1) { |
287 | reg = gpmc_cs_read_reg(cs, GPMC_CS_CONFIG2); | 284 | reg = gpmc_cs_read_reg(cs, GPMC_CS_CONFIG2); |
@@ -307,8 +304,6 @@ static int omap2_onenand_set_sync_mode(struct omap_onenand_platform_data *cfg, | |||
307 | gpmc_cs_write_reg(cs, GPMC_CS_CONFIG4, reg); | 304 | gpmc_cs_write_reg(cs, GPMC_CS_CONFIG4, reg); |
308 | } | 305 | } |
309 | 306 | ||
310 | /* Set synchronous read timings */ | ||
311 | memset(&t, 0, sizeof(t)); | ||
312 | t.sync_clk = min_gpmc_clk_period; | 307 | t.sync_clk = min_gpmc_clk_period; |
313 | t.cs_on = 0; | 308 | t.cs_on = 0; |
314 | t.adv_on = 0; | 309 | t.adv_on = 0; |
@@ -330,7 +325,7 @@ static int omap2_onenand_set_sync_mode(struct omap_onenand_platform_data *cfg, | |||
330 | ticks_cez); | 325 | ticks_cez); |
331 | 326 | ||
332 | /* Write */ | 327 | /* Write */ |
333 | if (sync_write) { | 328 | if (onenand_flags & ONENAND_FLAG_SYNCWRITE) { |
334 | t.adv_wr_off = t.adv_rd_off; | 329 | t.adv_wr_off = t.adv_rd_off; |
335 | t.we_on = 0; | 330 | t.we_on = 0; |
336 | t.we_off = t.cs_rd_off; | 331 | t.we_off = t.cs_rd_off; |
@@ -355,6 +350,14 @@ static int omap2_onenand_set_sync_mode(struct omap_onenand_platform_data *cfg, | |||
355 | } | 350 | } |
356 | } | 351 | } |
357 | 352 | ||
353 | return t; | ||
354 | } | ||
355 | |||
356 | static int gpmc_set_sync_mode(int cs, struct gpmc_timings *t) | ||
357 | { | ||
358 | unsigned sync_read = onenand_flags & ONENAND_FLAG_SYNCREAD; | ||
359 | unsigned sync_write = onenand_flags & ONENAND_FLAG_SYNCWRITE; | ||
360 | |||
358 | /* Configure GPMC for synchronous read */ | 361 | /* Configure GPMC for synchronous read */ |
359 | gpmc_cs_write_reg(cs, GPMC_CS_CONFIG1, | 362 | gpmc_cs_write_reg(cs, GPMC_CS_CONFIG1, |
360 | GPMC_CONFIG1_WRAPBURST_SUPP | | 363 | GPMC_CONFIG1_WRAPBURST_SUPP | |
@@ -371,11 +374,47 @@ static int omap2_onenand_set_sync_mode(struct omap_onenand_platform_data *cfg, | |||
371 | GPMC_CONFIG1_DEVICETYPE_NOR | | 374 | GPMC_CONFIG1_DEVICETYPE_NOR | |
372 | GPMC_CONFIG1_MUXADDDATA); | 375 | GPMC_CONFIG1_MUXADDDATA); |
373 | 376 | ||
374 | err = gpmc_cs_set_timings(cs, &t); | 377 | return gpmc_cs_set_timings(cs, t); |
375 | if (err) | 378 | } |
376 | return err; | 379 | |
380 | static int omap2_onenand_setup_async(void __iomem *onenand_base) | ||
381 | { | ||
382 | struct gpmc_timings t; | ||
383 | int ret; | ||
384 | |||
385 | omap2_onenand_set_async_mode(onenand_base); | ||
386 | |||
387 | t = omap2_onenand_calc_async_timings(); | ||
388 | |||
389 | ret = gpmc_set_async_mode(gpmc_onenand_data->cs, &t); | ||
390 | if (IS_ERR_VALUE(ret)) | ||
391 | return ret; | ||
392 | |||
393 | omap2_onenand_set_async_mode(onenand_base); | ||
394 | |||
395 | return 0; | ||
396 | } | ||
397 | |||
398 | static int omap2_onenand_setup_sync(void __iomem *onenand_base, int *freq_ptr) | ||
399 | { | ||
400 | int ret, freq = *freq_ptr; | ||
401 | struct gpmc_timings t; | ||
402 | bool clk_dep = false; | ||
403 | |||
404 | if (!freq) { | ||
405 | /* Very first call freq is not known */ | ||
406 | freq = omap2_onenand_get_freq(gpmc_onenand_data, | ||
407 | onenand_base, &clk_dep); | ||
408 | set_onenand_cfg(onenand_base); | ||
409 | } | ||
410 | |||
411 | t = omap2_onenand_calc_sync_timings(gpmc_onenand_data, freq, clk_dep); | ||
377 | 412 | ||
378 | set_onenand_cfg(onenand_base, latency, sync_read, sync_write, hf, vhf); | 413 | ret = gpmc_set_sync_mode(gpmc_onenand_data->cs, &t); |
414 | if (IS_ERR_VALUE(ret)) | ||
415 | return ret; | ||
416 | |||
417 | set_onenand_cfg(onenand_base); | ||
379 | 418 | ||
380 | *freq_ptr = freq; | 419 | *freq_ptr = freq; |
381 | 420 | ||
@@ -385,15 +424,22 @@ static int omap2_onenand_set_sync_mode(struct omap_onenand_platform_data *cfg, | |||
385 | static int gpmc_onenand_setup(void __iomem *onenand_base, int *freq_ptr) | 424 | static int gpmc_onenand_setup(void __iomem *onenand_base, int *freq_ptr) |
386 | { | 425 | { |
387 | struct device *dev = &gpmc_onenand_device.dev; | 426 | struct device *dev = &gpmc_onenand_device.dev; |
427 | unsigned l = ONENAND_SYNC_READ | ONENAND_SYNC_READWRITE; | ||
428 | int ret; | ||
388 | 429 | ||
389 | /* Set sync timings in GPMC */ | 430 | ret = omap2_onenand_setup_async(onenand_base); |
390 | if (omap2_onenand_set_sync_mode(gpmc_onenand_data, onenand_base, | 431 | if (ret) { |
391 | freq_ptr) < 0) { | 432 | dev_err(dev, "unable to set to async mode\n"); |
392 | dev_err(dev, "Unable to set synchronous mode\n"); | 433 | return ret; |
393 | return -EINVAL; | ||
394 | } | 434 | } |
395 | 435 | ||
396 | return 0; | 436 | if (!(gpmc_onenand_data->flags & l)) |
437 | return 0; | ||
438 | |||
439 | ret = omap2_onenand_setup_sync(onenand_base, freq_ptr); | ||
440 | if (ret) | ||
441 | dev_err(dev, "unable to set to sync mode\n"); | ||
442 | return ret; | ||
397 | } | 443 | } |
398 | 444 | ||
399 | void __init gpmc_onenand_init(struct omap_onenand_platform_data *_onenand_data) | 445 | void __init gpmc_onenand_init(struct omap_onenand_platform_data *_onenand_data) |