aboutsummaryrefslogtreecommitdiffstats
path: root/arch/arm/mach-omap2/gpmc-onenand.c
diff options
context:
space:
mode:
authorAfzal Mohammed <afzal@ti.com>2012-06-05 00:41:48 -0400
committerAfzal Mohammed <afzal@ti.com>2012-10-15 05:10:26 -0400
commit46376884ce0a98c276187a169620a766f0941f08 (patch)
treef378b7eb948522d4ca5ae277ed42a4d264fa46a8 /arch/arm/mach-omap2/gpmc-onenand.c
parent2e618261c96d72e5c5409d134d6d93e679683ab8 (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.c174
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
34static unsigned onenand_flags;
35static unsigned latency;
36static int fclk_offset;
37
28static struct omap_onenand_platform_data *gpmc_onenand_data; 38static struct omap_onenand_platform_data *gpmc_onenand_data;
29 39
30static struct resource gpmc_onenand_resource = { 40static 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
41static int omap2_onenand_set_async_mode(int cs, void __iomem *onenand_base) 51static 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
95static 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
105static 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
106static void set_onenand_cfg(void __iomem *onenand_base, int latency, 115static 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
175static int omap2_onenand_set_sync_mode(struct omap_onenand_platform_data *cfg, 183static struct gpmc_timings
176 void __iomem *onenand_base, 184omap2_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
356static 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
380static 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
398static 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,
385static int gpmc_onenand_setup(void __iomem *onenand_base, int *freq_ptr) 424static 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
399void __init gpmc_onenand_init(struct omap_onenand_platform_data *_onenand_data) 445void __init gpmc_onenand_init(struct omap_onenand_platform_data *_onenand_data)