aboutsummaryrefslogtreecommitdiffstats
path: root/arch/arm/mach-omap2/gpmc-onenand.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/arm/mach-omap2/gpmc-onenand.c')
-rw-r--r--arch/arm/mach-omap2/gpmc-onenand.c130
1 files changed, 95 insertions, 35 deletions
diff --git a/arch/arm/mach-omap2/gpmc-onenand.c b/arch/arm/mach-omap2/gpmc-onenand.c
index 7bb69220adfa..d776ded9830d 100644
--- a/arch/arm/mach-omap2/gpmc-onenand.c
+++ b/arch/arm/mach-omap2/gpmc-onenand.c
@@ -94,7 +94,7 @@ static int omap2_onenand_set_async_mode(int cs, void __iomem *onenand_base)
94} 94}
95 95
96static void set_onenand_cfg(void __iomem *onenand_base, int latency, 96static void set_onenand_cfg(void __iomem *onenand_base, int latency,
97 int sync_read, int sync_write, int hf) 97 int sync_read, int sync_write, int hf, int vhf)
98{ 98{
99 u32 reg; 99 u32 reg;
100 100
@@ -114,12 +114,57 @@ static void set_onenand_cfg(void __iomem *onenand_base, int latency,
114 reg |= ONENAND_SYS_CFG1_HF; 114 reg |= ONENAND_SYS_CFG1_HF;
115 else 115 else
116 reg &= ~ONENAND_SYS_CFG1_HF; 116 reg &= ~ONENAND_SYS_CFG1_HF;
117 if (vhf)
118 reg |= ONENAND_SYS_CFG1_VHF;
119 else
120 reg &= ~ONENAND_SYS_CFG1_VHF;
117 writew(reg, onenand_base + ONENAND_REG_SYS_CFG1); 121 writew(reg, onenand_base + ONENAND_REG_SYS_CFG1);
118} 122}
119 123
124static int omap2_onenand_get_freq(struct omap_onenand_platform_data *cfg,
125 void __iomem *onenand_base, bool *clk_dep)
126{
127 u16 ver = readw(onenand_base + ONENAND_REG_VERSION_ID);
128 int freq = 0;
129
130 if (cfg->get_freq) {
131 struct onenand_freq_info fi;
132
133 fi.maf_id = readw(onenand_base + ONENAND_REG_MANUFACTURER_ID);
134 fi.dev_id = readw(onenand_base + ONENAND_REG_DEVICE_ID);
135 fi.ver_id = ver;
136 freq = cfg->get_freq(&fi, clk_dep);
137 if (freq)
138 return freq;
139 }
140
141 switch ((ver >> 4) & 0xf) {
142 case 0:
143 freq = 40;
144 break;
145 case 1:
146 freq = 54;
147 break;
148 case 2:
149 freq = 66;
150 break;
151 case 3:
152 freq = 83;
153 break;
154 case 4:
155 freq = 104;
156 break;
157 default:
158 freq = 54;
159 break;
160 }
161
162 return freq;
163}
164
120static int omap2_onenand_set_sync_mode(struct omap_onenand_platform_data *cfg, 165static int omap2_onenand_set_sync_mode(struct omap_onenand_platform_data *cfg,
121 void __iomem *onenand_base, 166 void __iomem *onenand_base,
122 int freq) 167 int *freq_ptr)
123{ 168{
124 struct gpmc_timings t; 169 struct gpmc_timings t;
125 const int t_cer = 15; 170 const int t_cer = 15;
@@ -130,10 +175,11 @@ static int omap2_onenand_set_sync_mode(struct omap_onenand_platform_data *cfg,
130 const int t_wph = 30; 175 const int t_wph = 30;
131 int min_gpmc_clk_period, t_ces, t_avds, t_avdh, t_ach, t_aavdh, t_rdyo; 176 int min_gpmc_clk_period, t_ces, t_avds, t_avdh, t_ach, t_aavdh, t_rdyo;
132 int tick_ns, div, fclk_offset_ns, fclk_offset, gpmc_clk_ns, latency; 177 int tick_ns, div, fclk_offset_ns, fclk_offset, gpmc_clk_ns, latency;
133 int first_time = 0, hf = 0, sync_read = 0, sync_write = 0; 178 int first_time = 0, hf = 0, vhf = 0, sync_read = 0, sync_write = 0;
134 int err, ticks_cez; 179 int err, ticks_cez;
135 int cs = cfg->cs; 180 int cs = cfg->cs, freq = *freq_ptr;
136 u32 reg; 181 u32 reg;
182 bool clk_dep = false;
137 183
138 if (cfg->flags & ONENAND_SYNC_READ) { 184 if (cfg->flags & ONENAND_SYNC_READ) {
139 sync_read = 1; 185 sync_read = 1;
@@ -148,33 +194,22 @@ static int omap2_onenand_set_sync_mode(struct omap_onenand_platform_data *cfg,
148 err = omap2_onenand_set_async_mode(cs, onenand_base); 194 err = omap2_onenand_set_async_mode(cs, onenand_base);
149 if (err) 195 if (err)
150 return err; 196 return err;
151 reg = readw(onenand_base + ONENAND_REG_VERSION_ID); 197 freq = omap2_onenand_get_freq(cfg, onenand_base, &clk_dep);
152 switch ((reg >> 4) & 0xf) {
153 case 0:
154 freq = 40;
155 break;
156 case 1:
157 freq = 54;
158 break;
159 case 2:
160 freq = 66;
161 break;
162 case 3:
163 freq = 83;
164 break;
165 case 4:
166 freq = 104;
167 break;
168 default:
169 freq = 54;
170 break;
171 }
172 first_time = 1; 198 first_time = 1;
173 } 199 }
174 200
175 switch (freq) { 201 switch (freq) {
202 case 104:
203 min_gpmc_clk_period = 9600; /* 104 MHz */
204 t_ces = 3;
205 t_avds = 4;
206 t_avdh = 2;
207 t_ach = 3;
208 t_aavdh = 6;
209 t_rdyo = 6;
210 break;
176 case 83: 211 case 83:
177 min_gpmc_clk_period = 12; /* 83 MHz */ 212 min_gpmc_clk_period = 12000; /* 83 MHz */
178 t_ces = 5; 213 t_ces = 5;
179 t_avds = 4; 214 t_avds = 4;
180 t_avdh = 2; 215 t_avdh = 2;
@@ -183,7 +218,7 @@ static int omap2_onenand_set_sync_mode(struct omap_onenand_platform_data *cfg,
183 t_rdyo = 9; 218 t_rdyo = 9;
184 break; 219 break;
185 case 66: 220 case 66:
186 min_gpmc_clk_period = 15; /* 66 MHz */ 221 min_gpmc_clk_period = 15000; /* 66 MHz */
187 t_ces = 6; 222 t_ces = 6;
188 t_avds = 5; 223 t_avds = 5;
189 t_avdh = 2; 224 t_avdh = 2;
@@ -192,7 +227,7 @@ static int omap2_onenand_set_sync_mode(struct omap_onenand_platform_data *cfg,
192 t_rdyo = 11; 227 t_rdyo = 11;
193 break; 228 break;
194 default: 229 default:
195 min_gpmc_clk_period = 18; /* 54 MHz */ 230 min_gpmc_clk_period = 18500; /* 54 MHz */
196 t_ces = 7; 231 t_ces = 7;
197 t_avds = 7; 232 t_avds = 7;
198 t_avdh = 7; 233 t_avdh = 7;
@@ -208,16 +243,36 @@ static int omap2_onenand_set_sync_mode(struct omap_onenand_platform_data *cfg,
208 gpmc_clk_ns = gpmc_ticks_to_ns(div); 243 gpmc_clk_ns = gpmc_ticks_to_ns(div);
209 if (gpmc_clk_ns < 15) /* >66Mhz */ 244 if (gpmc_clk_ns < 15) /* >66Mhz */
210 hf = 1; 245 hf = 1;
211 if (hf) 246 if (gpmc_clk_ns < 12) /* >83Mhz */
247 vhf = 1;
248 if (vhf)
249 latency = 8;
250 else if (hf)
212 latency = 6; 251 latency = 6;
213 else if (gpmc_clk_ns >= 25) /* 40 MHz*/ 252 else if (gpmc_clk_ns >= 25) /* 40 MHz*/
214 latency = 3; 253 latency = 3;
215 else 254 else
216 latency = 4; 255 latency = 4;
217 256
257 if (clk_dep) {
258 if (gpmc_clk_ns < 12) { /* >83Mhz */
259 t_ces = 3;
260 t_avds = 4;
261 } else if (gpmc_clk_ns < 15) { /* >66Mhz */
262 t_ces = 5;
263 t_avds = 4;
264 } else if (gpmc_clk_ns < 25) { /* >40Mhz */
265 t_ces = 6;
266 t_avds = 5;
267 } else {
268 t_ces = 7;
269 t_avds = 7;
270 }
271 }
272
218 if (first_time) 273 if (first_time)
219 set_onenand_cfg(onenand_base, latency, 274 set_onenand_cfg(onenand_base, latency,
220 sync_read, sync_write, hf); 275 sync_read, sync_write, hf, vhf);
221 276
222 if (div == 1) { 277 if (div == 1) {
223 reg = gpmc_cs_read_reg(cs, GPMC_CS_CONFIG2); 278 reg = gpmc_cs_read_reg(cs, GPMC_CS_CONFIG2);
@@ -255,6 +310,9 @@ static int omap2_onenand_set_sync_mode(struct omap_onenand_platform_data *cfg,
255 /* Read */ 310 /* Read */
256 t.adv_rd_off = gpmc_ticks_to_ns(fclk_offset + gpmc_ns_to_ticks(t_avdh)); 311 t.adv_rd_off = gpmc_ticks_to_ns(fclk_offset + gpmc_ns_to_ticks(t_avdh));
257 t.oe_on = gpmc_ticks_to_ns(fclk_offset + gpmc_ns_to_ticks(t_ach)); 312 t.oe_on = gpmc_ticks_to_ns(fclk_offset + gpmc_ns_to_ticks(t_ach));
313 /* Force at least 1 clk between AVD High to OE Low */
314 if (t.oe_on <= t.adv_rd_off)
315 t.oe_on = t.adv_rd_off + gpmc_round_ns_to_ticks(1);
258 t.access = gpmc_ticks_to_ns(fclk_offset + (latency + 1) * div); 316 t.access = gpmc_ticks_to_ns(fclk_offset + (latency + 1) * div);
259 t.oe_off = t.access + gpmc_round_ns_to_ticks(1); 317 t.oe_off = t.access + gpmc_round_ns_to_ticks(1);
260 t.cs_rd_off = t.oe_off; 318 t.cs_rd_off = t.oe_off;
@@ -271,8 +329,8 @@ static int omap2_onenand_set_sync_mode(struct omap_onenand_platform_data *cfg,
271 t.wr_cycle = t.rd_cycle; 329 t.wr_cycle = t.rd_cycle;
272 if (cpu_is_omap34xx()) { 330 if (cpu_is_omap34xx()) {
273 t.wr_data_mux_bus = gpmc_ticks_to_ns(fclk_offset + 331 t.wr_data_mux_bus = gpmc_ticks_to_ns(fclk_offset +
274 gpmc_ns_to_ticks(min_gpmc_clk_period + 332 gpmc_ps_to_ticks(min_gpmc_clk_period +
275 t_rdyo)); 333 t_rdyo * 1000));
276 t.wr_access = t.access; 334 t.wr_access = t.access;
277 } 335 }
278 } else { 336 } else {
@@ -308,18 +366,20 @@ static int omap2_onenand_set_sync_mode(struct omap_onenand_platform_data *cfg,
308 if (err) 366 if (err)
309 return err; 367 return err;
310 368
311 set_onenand_cfg(onenand_base, latency, sync_read, sync_write, hf); 369 set_onenand_cfg(onenand_base, latency, sync_read, sync_write, hf, vhf);
370
371 *freq_ptr = freq;
312 372
313 return 0; 373 return 0;
314} 374}
315 375
316static int gpmc_onenand_setup(void __iomem *onenand_base, int freq) 376static int gpmc_onenand_setup(void __iomem *onenand_base, int *freq_ptr)
317{ 377{
318 struct device *dev = &gpmc_onenand_device.dev; 378 struct device *dev = &gpmc_onenand_device.dev;
319 379
320 /* Set sync timings in GPMC */ 380 /* Set sync timings in GPMC */
321 if (omap2_onenand_set_sync_mode(gpmc_onenand_data, onenand_base, 381 if (omap2_onenand_set_sync_mode(gpmc_onenand_data, onenand_base,
322 freq) < 0) { 382 freq_ptr) < 0) {
323 dev_err(dev, "Unable to set synchronous mode\n"); 383 dev_err(dev, "Unable to set synchronous mode\n");
324 return -EINVAL; 384 return -EINVAL;
325 } 385 }