ARM: S3C2410: Add S3C2410A sysdev.
[safe/jmp/linux-2.6] / arch / arm / plat-s3c24xx / s3c2410-iotiming.c
1 /* linux/arch/arm/plat-s3c24xx/s3c2410-iotiming.c
2  *
3  * Copyright (c) 2006,2008,2009 Simtec Electronics
4  *      http://armlinux.simtec.co.uk/
5  *      Ben Dooks <ben@simtec.co.uk>
6  *
7  * S3C24XX CPU Frequency scaling - IO timing for S3C2410/S3C2440/S3C2442
8  *
9  * This program is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License version 2 as
11  * published by the Free Software Foundation.
12 */
13
14 #include <linux/init.h>
15 #include <linux/kernel.h>
16 #include <linux/errno.h>
17 #include <linux/cpufreq.h>
18 #include <linux/io.h>
19
20 #include <mach/map.h>
21 #include <mach/regs-mem.h>
22 #include <mach/regs-clock.h>
23
24 #include <plat/cpu-freq-core.h>
25
26 #define print_ns(x) ((x) / 10), ((x) % 10)
27
28 /**
29  * s3c2410_print_timing - print bank timing data for debug purposes
30  * @pfx: The prefix to put on the output
31  * @timings: The timing inforamtion to print.
32 */
33 static void s3c2410_print_timing(const char *pfx,
34                                  struct s3c_iotimings *timings)
35 {
36         struct s3c2410_iobank_timing *bt;
37         int bank;
38
39         for (bank = 0; bank < MAX_BANKS; bank++) {
40                 bt = timings->bank[bank].io_2410;
41                 if (!bt)
42                         continue;
43
44                 printk(KERN_DEBUG "%s %d: Tacs=%d.%d, Tcos=%d.%d, Tacc=%d.%d, "
45                        "Tcoh=%d.%d, Tcah=%d.%d\n", pfx, bank,
46                        print_ns(bt->tacs),
47                        print_ns(bt->tcos),
48                        print_ns(bt->tacc),
49                        print_ns(bt->tcoh),
50                        print_ns(bt->tcah));
51         }
52 }
53
54 /**
55  * bank_reg - convert bank number to pointer to the control register.
56  * @bank: The IO bank number.
57  */
58 static inline void __iomem *bank_reg(unsigned int bank)
59 {
60         return S3C2410_BANKCON0 + (bank << 2);
61 }
62
63 /**
64  * bank_is_io - test whether bank is used for IO
65  * @bankcon: The bank control register.
66  *
67  * This is a simplistic test to see if any BANKCON[x] is not an IO
68  * bank. It currently does not take into account whether BWSCON has
69  * an illegal width-setting in it, or if the pin connected to nCS[x]
70  * is actually being handled as a chip-select.
71  */
72 static inline int bank_is_io(unsigned long bankcon)
73 {
74         return !(bankcon & S3C2410_BANKCON_SDRAM);
75 }
76
77 /**
78  * to_div - convert cycle time to divisor
79  * @cyc: The cycle time, in 10ths of nanoseconds.
80  * @hclk_tns: The cycle time for HCLK, in 10ths of nanoseconds.
81  *
82  * Convert the given cycle time into the divisor to use to obtain it from
83  * HCLK.
84 */
85 static inline unsigned int to_div(unsigned int cyc, unsigned int hclk_tns)
86 {
87         if (cyc == 0)
88                 return 0;
89
90         return DIV_ROUND_UP(cyc, hclk_tns);
91 }
92
93 /**
94  * calc_0124 - calculate divisor control for divisors that do /0, /1. /2 and /4
95  * @cyc: The cycle time, in 10ths of nanoseconds.
96  * @hclk_tns: The cycle time for HCLK, in 10ths of nanoseconds.
97  * @v: Pointer to register to alter.
98  * @shift: The shift to get to the control bits.
99  *
100  * Calculate the divisor, and turn it into the correct control bits to
101  * set in the result, @v.
102  */
103 static unsigned int calc_0124(unsigned int cyc, unsigned long hclk_tns,
104                               unsigned long *v, int shift)
105 {
106         unsigned int div = to_div(cyc, hclk_tns);
107         unsigned long val;
108
109         s3c_freq_iodbg("%s: cyc=%d, hclk=%lu, shift=%d => div %d\n",
110                        __func__, cyc, hclk_tns, shift, div);
111
112         switch (div) {
113         case 0:
114                 val = 0;
115                 break;
116         case 1:
117                 val = 1;
118                 break;
119         case 2:
120                 val = 2;
121                 break;
122         case 3:
123         case 4:
124                 val = 3;
125                 break;
126         default:
127                 return -1;
128         }
129
130         *v |= val << shift;
131         return 0;
132 }
133
134 int calc_tacp(unsigned int cyc, unsigned long hclk, unsigned long *v)
135 {
136         /* Currently no support for Tacp calculations. */
137         return 0;
138 }
139
140 /**
141  * calc_tacc - calculate divisor control for tacc.
142  * @cyc: The cycle time, in 10ths of nanoseconds.
143  * @nwait_en: IS nWAIT enabled for this bank.
144  * @hclk_tns: The cycle time for HCLK, in 10ths of nanoseconds.
145  * @v: Pointer to register to alter.
146  *
147  * Calculate the divisor control for tACC, taking into account whether
148  * the bank has nWAIT enabled. The result is used to modify the value
149  * pointed to by @v.
150 */
151 static int calc_tacc(unsigned int cyc, int nwait_en,
152                      unsigned long hclk_tns, unsigned long *v)
153 {
154         unsigned int div = to_div(cyc, hclk_tns);
155         unsigned long val;
156
157         s3c_freq_iodbg("%s: cyc=%u, nwait=%d, hclk=%lu => div=%u\n",
158                        __func__, cyc, nwait_en, hclk_tns, div);
159
160         /* if nWait enabled on an bank, Tacc must be at-least 4 cycles. */
161         if (nwait_en && div < 4)
162                 div = 4;
163
164         switch (div) {
165         case 0:
166                 val = 0;
167                 break;
168
169         case 1:
170         case 2:
171         case 3:
172         case 4:
173                 val = div - 1;
174                 break;
175
176         case 5:
177         case 6:
178                 val = 4;
179                 break;
180
181         case 7:
182         case 8:
183                 val = 5;
184                 break;
185
186         case 9:
187         case 10:
188                 val = 6;
189                 break;
190
191         case 11:
192         case 12:
193         case 13:
194         case 14:
195                 val = 7;
196                 break;
197
198         default:
199                 return -1;
200         }
201
202         *v |= val << 8;
203         return 0;
204 }
205
206 /**
207  * s3c2410_calc_bank - calculate bank timing infromation
208  * @cfg: The configuration we need to calculate for.
209  * @bt: The bank timing information.
210  *
211  * Given the cycle timine for a bank @bt, calculate the new BANKCON
212  * setting for the @cfg timing. This updates the timing information
213  * ready for the cpu frequency change.
214  */
215 static int s3c2410_calc_bank(struct s3c_cpufreq_config *cfg,
216                              struct s3c2410_iobank_timing *bt)
217 {
218         unsigned long hclk = cfg->freq.hclk_tns;
219         unsigned long res;
220         int ret;
221
222         res  = bt->bankcon;
223         res &= (S3C2410_BANKCON_SDRAM | S3C2410_BANKCON_PMC16);
224
225         /* tacp: 2,3,4,5 */
226         /* tcah: 0,1,2,4 */
227         /* tcoh: 0,1,2,4 */
228         /* tacc: 1,2,3,4,6,7,10,14 (>4 for nwait) */
229         /* tcos: 0,1,2,4 */
230         /* tacs: 0,1,2,4 */
231
232         ret  = calc_0124(bt->tacs, hclk, &res, S3C2410_BANKCON_Tacs_SHIFT);
233         ret |= calc_0124(bt->tcos, hclk, &res, S3C2410_BANKCON_Tcos_SHIFT);
234         ret |= calc_0124(bt->tcah, hclk, &res, S3C2410_BANKCON_Tcah_SHIFT);
235         ret |= calc_0124(bt->tcoh, hclk, &res, S3C2410_BANKCON_Tcoh_SHIFT);
236
237         if (ret)
238                 return -EINVAL;
239
240         ret |= calc_tacp(bt->tacp, hclk, &res);
241         ret |= calc_tacc(bt->tacc, bt->nwait_en, hclk, &res);
242
243         if (ret)
244                 return -EINVAL;
245
246         bt->bankcon = res;
247         return 0;
248 }
249
250 static unsigned int tacc_tab[] = {
251         [0]     = 1,
252         [1]     = 2,
253         [2]     = 3,
254         [3]     = 4,
255         [4]     = 6,
256         [5]     = 9,
257         [6]     = 10,
258         [7]     = 14,
259 };
260
261 /**
262  * get_tacc - turn tACC value into cycle time
263  * @hclk_tns: The cycle time for HCLK, in 10ths of nanoseconds.
264  * @val: The bank timing register value, shifed down.
265  */
266 static unsigned int get_tacc(unsigned long hclk_tns,
267                              unsigned long val)
268 {
269         val &= 7;
270         return hclk_tns * tacc_tab[val];
271 }
272
273 /**
274  * get_0124 - turn 0/1/2/4 divider into cycle time
275  * @hclk_tns: The cycle time for HCLK, in 10ths of nanoseconds.
276  * @val: The bank timing register value, shifed down.
277  */
278 static unsigned int get_0124(unsigned long hclk_tns,
279                              unsigned long val)
280 {
281         val &= 3;
282         return hclk_tns * ((val == 3) ? 4 : val);
283 }
284
285 /**
286  * s3c2410_iotiming_getbank - turn BANKCON into cycle time information
287  * @cfg: The frequency configuration
288  * @bt: The bank timing to fill in (uses cached BANKCON)
289  *
290  * Given the BANKCON setting in @bt and the current frequency settings
291  * in @cfg, update the cycle timing information.
292  */
293 void s3c2410_iotiming_getbank(struct s3c_cpufreq_config *cfg,
294                               struct s3c2410_iobank_timing *bt)
295 {
296         unsigned long bankcon = bt->bankcon;
297         unsigned long hclk = cfg->freq.hclk_tns;
298
299         bt->tcah = get_0124(hclk, bankcon >> S3C2410_BANKCON_Tcah_SHIFT);
300         bt->tcoh = get_0124(hclk, bankcon >> S3C2410_BANKCON_Tcoh_SHIFT);
301         bt->tcos = get_0124(hclk, bankcon >> S3C2410_BANKCON_Tcos_SHIFT);
302         bt->tacs = get_0124(hclk, bankcon >> S3C2410_BANKCON_Tacs_SHIFT);
303         bt->tacc = get_tacc(hclk, bankcon >> S3C2410_BANKCON_Tacc_SHIFT);
304 }
305
306 /**
307  * s3c2410_iotiming_calc - Calculate bank timing for frequency change.
308  * @cfg: The frequency configuration
309  * @iot: The IO timing information to fill out.
310  *
311  * Calculate the new values for the banks in @iot based on the new
312  * frequency information in @cfg. This is then used by s3c2410_iotiming_set()
313  * to update the timing when necessary.
314  */
315 int s3c2410_iotiming_calc(struct s3c_cpufreq_config *cfg,
316                           struct s3c_iotimings *iot)
317 {
318         struct s3c2410_iobank_timing *bt;
319         unsigned long bankcon;
320         int bank;
321         int ret;
322
323         for (bank = 0; bank < MAX_BANKS; bank++) {
324                 bankcon = __raw_readl(bank_reg(bank));
325                 bt = iot->bank[bank].io_2410;
326
327                 if (!bt)
328                         continue;
329
330                 bt->bankcon = bankcon;
331
332                 ret = s3c2410_calc_bank(cfg, bt);
333                 if (ret) {
334                         printk(KERN_ERR "%s: cannot calculate bank %d io\n",
335                                __func__, bank);
336                         goto err;
337                 }
338
339                 s3c_freq_iodbg("%s: bank %d: con=%08lx\n",
340                                __func__, bank, bt->bankcon);
341         }
342
343         return 0;
344  err:
345         return ret;
346 }
347
348 /**
349  * s3c2410_iotiming_set - set the IO timings from the given setup.
350  * @cfg: The frequency configuration
351  * @iot: The IO timing information to use.
352  *
353  * Set all the currently used IO bank timing information generated
354  * by s3c2410_iotiming_calc() once the core has validated that all
355  * the new values are within permitted bounds.
356  */
357 void s3c2410_iotiming_set(struct s3c_cpufreq_config *cfg,
358                           struct s3c_iotimings *iot)
359 {
360         struct s3c2410_iobank_timing *bt;
361         int bank;
362
363         /* set the io timings from the specifier */
364
365         for (bank = 0; bank < MAX_BANKS; bank++) {
366                 bt = iot->bank[bank].io_2410;
367                 if (!bt)
368                         continue;
369
370                 __raw_writel(bt->bankcon, bank_reg(bank));
371         }
372 }
373
374 /**
375  * s3c2410_iotiming_get - Get the timing information from current registers.
376  * @cfg: The frequency configuration
377  * @timings: The IO timing information to fill out.
378  *
379  * Calculate the @timings timing information from the current frequency
380  * information in @cfg, and the new frequency configur
381  * through all the IO banks, reading the state and then updating @iot
382  * as necessary.
383  *
384  * This is used at the moment on initialisation to get the current
385  * configuration so that boards do not have to carry their own setup
386  * if the timings are correct on initialisation.
387  */
388
389 int s3c2410_iotiming_get(struct s3c_cpufreq_config *cfg,
390                          struct s3c_iotimings *timings)
391 {
392         struct s3c2410_iobank_timing *bt;
393         unsigned long bankcon;
394         unsigned long bwscon;
395         int bank;
396
397         bwscon = __raw_readl(S3C2410_BWSCON);
398
399         /* look through all banks to see what is currently set. */
400
401         for (bank = 0; bank < MAX_BANKS; bank++) {
402                 bankcon = __raw_readl(bank_reg(bank));
403
404                 if (!bank_is_io(bankcon))
405                         continue;
406
407                 s3c_freq_iodbg("%s: bank %d: con %08lx\n",
408                                __func__, bank, bankcon);
409
410                 bt = kzalloc(sizeof(struct s3c2410_iobank_timing), GFP_KERNEL);
411                 if (!bt) {
412                         printk(KERN_ERR "%s: no memory for bank\n", __func__);
413                         return -ENOMEM;
414                 }
415
416                 /* find out in nWait is enabled for bank. */
417
418                 if (bank != 0) {
419                         unsigned long tmp  = S3C2410_BWSCON_GET(bwscon, bank);
420                         if (tmp & S3C2410_BWSCON_WS)
421                                 bt->nwait_en = 1;
422                 }
423
424                 timings->bank[bank].io_2410 = bt;
425                 bt->bankcon = bankcon;
426
427                 s3c2410_iotiming_getbank(cfg, bt);
428         }
429
430         s3c2410_print_timing("get", timings);
431         return 0;
432 }