]> git.proxmox.com Git - mirror_ubuntu-bionic-kernel.git/blame - arch/arm/mach-omap2/gpmc-onenand.c
ARM: OMAP: Remove unused old gpio-switch.h
[mirror_ubuntu-bionic-kernel.git] / arch / arm / mach-omap2 / gpmc-onenand.c
CommitLineData
aa62e90f
JY
1/*
2 * linux/arch/arm/mach-omap2/gpmc-onenand.c
3 *
4 * Copyright (C) 2006 - 2009 Nokia Corporation
5 * Contacts: Juha Yrjola
6 * Tony Lindgren
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License version 2 as
10 * published by the Free Software Foundation.
11 */
12
d44b28c4 13#include <linux/string.h>
aa62e90f
JY
14#include <linux/kernel.h>
15#include <linux/platform_device.h>
16#include <linux/mtd/onenand_regs.h>
17#include <linux/io.h>
18
19#include <asm/mach/flash.h>
20
2c799cef 21#include <plat/cpu.h>
ce491cf8 22#include <plat/onenand.h>
ce491cf8 23#include <plat/gpmc.h>
aa62e90f 24
681988ba
AM
25#define ONENAND_IO_SIZE SZ_128K
26
aa62e90f
JY
27static struct omap_onenand_platform_data *gpmc_onenand_data;
28
681988ba
AM
29static struct resource gpmc_onenand_resource = {
30 .flags = IORESOURCE_MEM,
31};
32
aa62e90f
JY
33static struct platform_device gpmc_onenand_device = {
34 .name = "omap2-onenand",
35 .id = -1,
681988ba
AM
36 .num_resources = 1,
37 .resource = &gpmc_onenand_resource,
aa62e90f
JY
38};
39
40static int omap2_onenand_set_async_mode(int cs, void __iomem *onenand_base)
41{
42 struct gpmc_timings t;
6d453e84
AH
43 u32 reg;
44 int err;
aa62e90f
JY
45
46 const int t_cer = 15;
47 const int t_avdp = 12;
48 const int t_aavdh = 7;
49 const int t_ce = 76;
50 const int t_aa = 76;
51 const int t_oe = 20;
52 const int t_cez = 20; /* max of t_cez, t_oez */
53 const int t_ds = 30;
54 const int t_wpl = 40;
55 const int t_wph = 30;
56
6d453e84
AH
57 /* Ensure sync read and sync write are disabled */
58 reg = readw(onenand_base + ONENAND_REG_SYS_CFG1);
59 reg &= ~ONENAND_SYS_CFG1_SYNC_READ & ~ONENAND_SYS_CFG1_SYNC_WRITE;
60 writew(reg, onenand_base + ONENAND_REG_SYS_CFG1);
61
aa62e90f
JY
62 memset(&t, 0, sizeof(t));
63 t.sync_clk = 0;
64 t.cs_on = 0;
65 t.adv_on = 0;
66
67 /* Read */
68 t.adv_rd_off = gpmc_round_ns_to_ticks(max_t(int, t_avdp, t_cer));
69 t.oe_on = t.adv_rd_off + gpmc_round_ns_to_ticks(t_aavdh);
70 t.access = t.adv_on + gpmc_round_ns_to_ticks(t_aa);
71 t.access = max_t(int, t.access, t.cs_on + gpmc_round_ns_to_ticks(t_ce));
72 t.access = max_t(int, t.access, t.oe_on + gpmc_round_ns_to_ticks(t_oe));
73 t.oe_off = t.access + gpmc_round_ns_to_ticks(1);
74 t.cs_rd_off = t.oe_off;
75 t.rd_cycle = t.cs_rd_off + gpmc_round_ns_to_ticks(t_cez);
76
77 /* Write */
78 t.adv_wr_off = t.adv_rd_off;
79 t.we_on = t.oe_on;
80 if (cpu_is_omap34xx()) {
81 t.wr_data_mux_bus = t.we_on;
82 t.wr_access = t.we_on + gpmc_round_ns_to_ticks(t_ds);
83 }
84 t.we_off = t.we_on + gpmc_round_ns_to_ticks(t_wpl);
85 t.cs_wr_off = t.we_off + gpmc_round_ns_to_ticks(t_wph);
86 t.wr_cycle = t.cs_wr_off + gpmc_round_ns_to_ticks(t_cez);
87
88 /* Configure GPMC for asynchronous read */
89 gpmc_cs_write_reg(cs, GPMC_CS_CONFIG1,
90 GPMC_CONFIG1_DEVICESIZE_16 |
91 GPMC_CONFIG1_MUXADDDATA);
92
6d453e84
AH
93 err = gpmc_cs_set_timings(cs, &t);
94 if (err)
95 return err;
96
97 /* Ensure sync read and sync write are disabled */
98 reg = readw(onenand_base + ONENAND_REG_SYS_CFG1);
99 reg &= ~ONENAND_SYS_CFG1_SYNC_READ & ~ONENAND_SYS_CFG1_SYNC_WRITE;
100 writew(reg, onenand_base + ONENAND_REG_SYS_CFG1);
101
102 return 0;
aa62e90f
JY
103}
104
105static void set_onenand_cfg(void __iomem *onenand_base, int latency,
1435ca0f 106 int sync_read, int sync_write, int hf, int vhf)
aa62e90f
JY
107{
108 u32 reg;
109
110 reg = readw(onenand_base + ONENAND_REG_SYS_CFG1);
111 reg &= ~((0x7 << ONENAND_SYS_CFG1_BRL_SHIFT) | (0x7 << 9));
112 reg |= (latency << ONENAND_SYS_CFG1_BRL_SHIFT) |
113 ONENAND_SYS_CFG1_BL_16;
114 if (sync_read)
115 reg |= ONENAND_SYS_CFG1_SYNC_READ;
116 else
117 reg &= ~ONENAND_SYS_CFG1_SYNC_READ;
118 if (sync_write)
119 reg |= ONENAND_SYS_CFG1_SYNC_WRITE;
120 else
121 reg &= ~ONENAND_SYS_CFG1_SYNC_WRITE;
122 if (hf)
123 reg |= ONENAND_SYS_CFG1_HF;
124 else
125 reg &= ~ONENAND_SYS_CFG1_HF;
1435ca0f
AH
126 if (vhf)
127 reg |= ONENAND_SYS_CFG1_VHF;
128 else
129 reg &= ~ONENAND_SYS_CFG1_VHF;
aa62e90f
JY
130 writew(reg, onenand_base + ONENAND_REG_SYS_CFG1);
131}
132
5714b7ed
AH
133static int omap2_onenand_get_freq(struct omap_onenand_platform_data *cfg,
134 void __iomem *onenand_base, bool *clk_dep)
135{
136 u16 ver = readw(onenand_base + ONENAND_REG_VERSION_ID);
137 int freq = 0;
138
139 if (cfg->get_freq) {
140 struct onenand_freq_info fi;
141
142 fi.maf_id = readw(onenand_base + ONENAND_REG_MANUFACTURER_ID);
143 fi.dev_id = readw(onenand_base + ONENAND_REG_DEVICE_ID);
144 fi.ver_id = ver;
145 freq = cfg->get_freq(&fi, clk_dep);
146 if (freq)
147 return freq;
148 }
149
150 switch ((ver >> 4) & 0xf) {
151 case 0:
152 freq = 40;
153 break;
154 case 1:
155 freq = 54;
156 break;
157 case 2:
158 freq = 66;
159 break;
160 case 3:
161 freq = 83;
162 break;
163 case 4:
164 freq = 104;
165 break;
166 default:
167 freq = 54;
168 break;
169 }
170
171 return freq;
172}
173
aa62e90f
JY
174static int omap2_onenand_set_sync_mode(struct omap_onenand_platform_data *cfg,
175 void __iomem *onenand_base,
3ad2d861 176 int *freq_ptr)
aa62e90f
JY
177{
178 struct gpmc_timings t;
179 const int t_cer = 15;
180 const int t_avdp = 12;
181 const int t_cez = 20; /* max of t_cez, t_oez */
182 const int t_ds = 30;
183 const int t_wpl = 40;
184 const int t_wph = 30;
185 int min_gpmc_clk_period, t_ces, t_avds, t_avdh, t_ach, t_aavdh, t_rdyo;
eeb3711b 186 int div, fclk_offset_ns, fclk_offset, gpmc_clk_ns, latency;
1435ca0f 187 int first_time = 0, hf = 0, vhf = 0, sync_read = 0, sync_write = 0;
aa62e90f 188 int err, ticks_cez;
3ad2d861 189 int cs = cfg->cs, freq = *freq_ptr;
aa62e90f 190 u32 reg;
5714b7ed 191 bool clk_dep = false;
aa62e90f
JY
192
193 if (cfg->flags & ONENAND_SYNC_READ) {
194 sync_read = 1;
195 } else if (cfg->flags & ONENAND_SYNC_READWRITE) {
196 sync_read = 1;
197 sync_write = 1;
6d453e84
AH
198 } else
199 return omap2_onenand_set_async_mode(cs, onenand_base);
aa62e90f
JY
200
201 if (!freq) {
202 /* Very first call freq is not known */
203 err = omap2_onenand_set_async_mode(cs, onenand_base);
204 if (err)
205 return err;
5714b7ed 206 freq = omap2_onenand_get_freq(cfg, onenand_base, &clk_dep);
aa62e90f
JY
207 first_time = 1;
208 }
209
210 switch (freq) {
4931445b
AH
211 case 104:
212 min_gpmc_clk_period = 9600; /* 104 MHz */
213 t_ces = 3;
214 t_avds = 4;
215 t_avdh = 2;
216 t_ach = 3;
217 t_aavdh = 6;
1435ca0f 218 t_rdyo = 6;
4931445b 219 break;
aa62e90f 220 case 83:
a3551f5b 221 min_gpmc_clk_period = 12000; /* 83 MHz */
aa62e90f
JY
222 t_ces = 5;
223 t_avds = 4;
224 t_avdh = 2;
225 t_ach = 6;
226 t_aavdh = 6;
227 t_rdyo = 9;
228 break;
229 case 66:
a3551f5b 230 min_gpmc_clk_period = 15000; /* 66 MHz */
aa62e90f
JY
231 t_ces = 6;
232 t_avds = 5;
233 t_avdh = 2;
234 t_ach = 6;
235 t_aavdh = 6;
236 t_rdyo = 11;
237 break;
238 default:
a3551f5b 239 min_gpmc_clk_period = 18500; /* 54 MHz */
aa62e90f
JY
240 t_ces = 7;
241 t_avds = 7;
242 t_avdh = 7;
243 t_ach = 9;
244 t_aavdh = 7;
245 t_rdyo = 15;
246 sync_write = 0;
247 break;
248 }
249
aa62e90f
JY
250 div = gpmc_cs_calc_divider(cs, min_gpmc_clk_period);
251 gpmc_clk_ns = gpmc_ticks_to_ns(div);
252 if (gpmc_clk_ns < 15) /* >66Mhz */
253 hf = 1;
1435ca0f
AH
254 if (gpmc_clk_ns < 12) /* >83Mhz */
255 vhf = 1;
256 if (vhf)
257 latency = 8;
258 else if (hf)
aa62e90f
JY
259 latency = 6;
260 else if (gpmc_clk_ns >= 25) /* 40 MHz*/
261 latency = 3;
262 else
263 latency = 4;
264
5714b7ed
AH
265 if (clk_dep) {
266 if (gpmc_clk_ns < 12) { /* >83Mhz */
267 t_ces = 3;
268 t_avds = 4;
269 } else if (gpmc_clk_ns < 15) { /* >66Mhz */
270 t_ces = 5;
271 t_avds = 4;
272 } else if (gpmc_clk_ns < 25) { /* >40Mhz */
273 t_ces = 6;
274 t_avds = 5;
275 } else {
276 t_ces = 7;
277 t_avds = 7;
278 }
279 }
280
aa62e90f
JY
281 if (first_time)
282 set_onenand_cfg(onenand_base, latency,
1435ca0f 283 sync_read, sync_write, hf, vhf);
aa62e90f
JY
284
285 if (div == 1) {
286 reg = gpmc_cs_read_reg(cs, GPMC_CS_CONFIG2);
287 reg |= (1 << 7);
288 gpmc_cs_write_reg(cs, GPMC_CS_CONFIG2, reg);
289 reg = gpmc_cs_read_reg(cs, GPMC_CS_CONFIG3);
290 reg |= (1 << 7);
291 gpmc_cs_write_reg(cs, GPMC_CS_CONFIG3, reg);
292 reg = gpmc_cs_read_reg(cs, GPMC_CS_CONFIG4);
293 reg |= (1 << 7);
294 reg |= (1 << 23);
295 gpmc_cs_write_reg(cs, GPMC_CS_CONFIG4, reg);
296 } else {
297 reg = gpmc_cs_read_reg(cs, GPMC_CS_CONFIG2);
298 reg &= ~(1 << 7);
299 gpmc_cs_write_reg(cs, GPMC_CS_CONFIG2, reg);
300 reg = gpmc_cs_read_reg(cs, GPMC_CS_CONFIG3);
301 reg &= ~(1 << 7);
302 gpmc_cs_write_reg(cs, GPMC_CS_CONFIG3, reg);
303 reg = gpmc_cs_read_reg(cs, GPMC_CS_CONFIG4);
304 reg &= ~(1 << 7);
305 reg &= ~(1 << 23);
306 gpmc_cs_write_reg(cs, GPMC_CS_CONFIG4, reg);
307 }
308
309 /* Set synchronous read timings */
310 memset(&t, 0, sizeof(t));
311 t.sync_clk = min_gpmc_clk_period;
312 t.cs_on = 0;
313 t.adv_on = 0;
314 fclk_offset_ns = gpmc_round_ns_to_ticks(max_t(int, t_ces, t_avds));
315 fclk_offset = gpmc_ns_to_ticks(fclk_offset_ns);
316 t.page_burst_access = gpmc_clk_ns;
317
318 /* Read */
319 t.adv_rd_off = gpmc_ticks_to_ns(fclk_offset + gpmc_ns_to_ticks(t_avdh));
320 t.oe_on = gpmc_ticks_to_ns(fclk_offset + gpmc_ns_to_ticks(t_ach));
1435ca0f
AH
321 /* Force at least 1 clk between AVD High to OE Low */
322 if (t.oe_on <= t.adv_rd_off)
323 t.oe_on = t.adv_rd_off + gpmc_round_ns_to_ticks(1);
aa62e90f
JY
324 t.access = gpmc_ticks_to_ns(fclk_offset + (latency + 1) * div);
325 t.oe_off = t.access + gpmc_round_ns_to_ticks(1);
326 t.cs_rd_off = t.oe_off;
327 ticks_cez = ((gpmc_ns_to_ticks(t_cez) + div - 1) / div) * div;
328 t.rd_cycle = gpmc_ticks_to_ns(fclk_offset + (latency + 1) * div +
329 ticks_cez);
330
331 /* Write */
332 if (sync_write) {
333 t.adv_wr_off = t.adv_rd_off;
334 t.we_on = 0;
335 t.we_off = t.cs_rd_off;
336 t.cs_wr_off = t.cs_rd_off;
337 t.wr_cycle = t.rd_cycle;
338 if (cpu_is_omap34xx()) {
339 t.wr_data_mux_bus = gpmc_ticks_to_ns(fclk_offset +
a3551f5b
AH
340 gpmc_ps_to_ticks(min_gpmc_clk_period +
341 t_rdyo * 1000));
aa62e90f
JY
342 t.wr_access = t.access;
343 }
344 } else {
345 t.adv_wr_off = gpmc_round_ns_to_ticks(max_t(int,
346 t_avdp, t_cer));
347 t.we_on = t.adv_wr_off + gpmc_round_ns_to_ticks(t_aavdh);
348 t.we_off = t.we_on + gpmc_round_ns_to_ticks(t_wpl);
349 t.cs_wr_off = t.we_off + gpmc_round_ns_to_ticks(t_wph);
350 t.wr_cycle = t.cs_wr_off + gpmc_round_ns_to_ticks(t_cez);
351 if (cpu_is_omap34xx()) {
352 t.wr_data_mux_bus = t.we_on;
353 t.wr_access = t.we_on + gpmc_round_ns_to_ticks(t_ds);
354 }
355 }
356
357 /* Configure GPMC for synchronous read */
358 gpmc_cs_write_reg(cs, GPMC_CS_CONFIG1,
359 GPMC_CONFIG1_WRAPBURST_SUPP |
360 GPMC_CONFIG1_READMULTIPLE_SUPP |
361 (sync_read ? GPMC_CONFIG1_READTYPE_SYNC : 0) |
362 (sync_write ? GPMC_CONFIG1_WRITEMULTIPLE_SUPP : 0) |
363 (sync_write ? GPMC_CONFIG1_WRITETYPE_SYNC : 0) |
364 GPMC_CONFIG1_CLKACTIVATIONTIME(fclk_offset) |
365 GPMC_CONFIG1_PAGE_LEN(2) |
366 (cpu_is_omap34xx() ? 0 :
367 (GPMC_CONFIG1_WAIT_READ_MON |
368 GPMC_CONFIG1_WAIT_PIN_SEL(0))) |
369 GPMC_CONFIG1_DEVICESIZE_16 |
370 GPMC_CONFIG1_DEVICETYPE_NOR |
371 GPMC_CONFIG1_MUXADDDATA);
372
373 err = gpmc_cs_set_timings(cs, &t);
374 if (err)
375 return err;
376
1435ca0f 377 set_onenand_cfg(onenand_base, latency, sync_read, sync_write, hf, vhf);
aa62e90f 378
3ad2d861
AH
379 *freq_ptr = freq;
380
aa62e90f
JY
381 return 0;
382}
383
3ad2d861 384static int gpmc_onenand_setup(void __iomem *onenand_base, int *freq_ptr)
aa62e90f
JY
385{
386 struct device *dev = &gpmc_onenand_device.dev;
387
388 /* Set sync timings in GPMC */
389 if (omap2_onenand_set_sync_mode(gpmc_onenand_data, onenand_base,
3ad2d861 390 freq_ptr) < 0) {
aa62e90f
JY
391 dev_err(dev, "Unable to set synchronous mode\n");
392 return -EINVAL;
393 }
394
395 return 0;
396}
397
398void __init gpmc_onenand_init(struct omap_onenand_platform_data *_onenand_data)
399{
681988ba
AM
400 int err;
401
aa62e90f
JY
402 gpmc_onenand_data = _onenand_data;
403 gpmc_onenand_data->onenand_setup = gpmc_onenand_setup;
404 gpmc_onenand_device.dev.platform_data = gpmc_onenand_data;
405
406 if (cpu_is_omap24xx() &&
407 (gpmc_onenand_data->flags & ONENAND_SYNC_READWRITE)) {
408 printk(KERN_ERR "Onenand using only SYNC_READ on 24xx\n");
409 gpmc_onenand_data->flags &= ~ONENAND_SYNC_READWRITE;
410 gpmc_onenand_data->flags |= ONENAND_SYNC_READ;
411 }
412
681988ba
AM
413 err = gpmc_cs_request(gpmc_onenand_data->cs, ONENAND_IO_SIZE,
414 (unsigned long *)&gpmc_onenand_resource.start);
415 if (err < 0) {
416 pr_err("%s: Cannot request GPMC CS\n", __func__);
417 return;
418 }
419
420 gpmc_onenand_resource.end = gpmc_onenand_resource.start +
421 ONENAND_IO_SIZE - 1;
422
aa62e90f 423 if (platform_device_register(&gpmc_onenand_device) < 0) {
681988ba
AM
424 pr_err("%s: Unable to register OneNAND device\n", __func__);
425 gpmc_cs_free(gpmc_onenand_data->cs);
aa62e90f
JY
426 return;
427 }
428}