Linux Kernel  3.7.1
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
s3c2410-iotiming.c
Go to the documentation of this file.
1 /* linux/arch/arm/plat-s3c24xx/s3c2410-iotiming.c
2  *
3  * Copyright (c) 2006-2009 Simtec Electronics
4  * http://armlinux.simtec.co.uk/
5  * Ben Dooks <[email protected]>
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/seq_file.h>
19 #include <linux/io.h>
20 #include <linux/slab.h>
21 
22 #include <mach/map.h>
23 #include <mach/regs-mem.h>
24 #include <mach/regs-clock.h>
25 
26 #include <plat/cpu-freq-core.h>
27 
28 #define print_ns(x) ((x) / 10), ((x) % 10)
29 
35 static void s3c2410_print_timing(const char *pfx,
36  struct s3c_iotimings *timings)
37 {
38  struct s3c2410_iobank_timing *bt;
39  int bank;
40 
41  for (bank = 0; bank < MAX_BANKS; bank++) {
42  bt = timings->bank[bank].io_2410;
43  if (!bt)
44  continue;
45 
46  printk(KERN_DEBUG "%s %d: Tacs=%d.%d, Tcos=%d.%d, Tacc=%d.%d, "
47  "Tcoh=%d.%d, Tcah=%d.%d\n", pfx, bank,
48  print_ns(bt->tacs),
49  print_ns(bt->tcos),
50  print_ns(bt->tacc),
51  print_ns(bt->tcoh),
52  print_ns(bt->tcah));
53  }
54 }
55 
60 static inline void __iomem *bank_reg(unsigned int bank)
61 {
62  return S3C2410_BANKCON0 + (bank << 2);
63 }
64 
74 static inline int bank_is_io(unsigned long bankcon)
75 {
76  return !(bankcon & S3C2410_BANKCON_SDRAM);
77 }
78 
87 static inline unsigned int to_div(unsigned int cyc, unsigned int hclk_tns)
88 {
89  if (cyc == 0)
90  return 0;
91 
92  return DIV_ROUND_UP(cyc, hclk_tns);
93 }
94 
105 static unsigned int calc_0124(unsigned int cyc, unsigned long hclk_tns,
106  unsigned long *v, int shift)
107 {
108  unsigned int div = to_div(cyc, hclk_tns);
109  unsigned long val;
110 
111  s3c_freq_iodbg("%s: cyc=%d, hclk=%lu, shift=%d => div %d\n",
112  __func__, cyc, hclk_tns, shift, div);
113 
114  switch (div) {
115  case 0:
116  val = 0;
117  break;
118  case 1:
119  val = 1;
120  break;
121  case 2:
122  val = 2;
123  break;
124  case 3:
125  case 4:
126  val = 3;
127  break;
128  default:
129  return -1;
130  }
131 
132  *v |= val << shift;
133  return 0;
134 }
135 
136 int calc_tacp(unsigned int cyc, unsigned long hclk, unsigned long *v)
137 {
138  /* Currently no support for Tacp calculations. */
139  return 0;
140 }
141 
153 static int calc_tacc(unsigned int cyc, int nwait_en,
154  unsigned long hclk_tns, unsigned long *v)
155 {
156  unsigned int div = to_div(cyc, hclk_tns);
157  unsigned long val;
158 
159  s3c_freq_iodbg("%s: cyc=%u, nwait=%d, hclk=%lu => div=%u\n",
160  __func__, cyc, nwait_en, hclk_tns, div);
161 
162  /* if nWait enabled on an bank, Tacc must be at-least 4 cycles. */
163  if (nwait_en && div < 4)
164  div = 4;
165 
166  switch (div) {
167  case 0:
168  val = 0;
169  break;
170 
171  case 1:
172  case 2:
173  case 3:
174  case 4:
175  val = div - 1;
176  break;
177 
178  case 5:
179  case 6:
180  val = 4;
181  break;
182 
183  case 7:
184  case 8:
185  val = 5;
186  break;
187 
188  case 9:
189  case 10:
190  val = 6;
191  break;
192 
193  case 11:
194  case 12:
195  case 13:
196  case 14:
197  val = 7;
198  break;
199 
200  default:
201  return -1;
202  }
203 
204  *v |= val << 8;
205  return 0;
206 }
207 
217 static int s3c2410_calc_bank(struct s3c_cpufreq_config *cfg,
218  struct s3c2410_iobank_timing *bt)
219 {
220  unsigned long hclk = cfg->freq.hclk_tns;
221  unsigned long res;
222  int ret;
223 
224  res = bt->bankcon;
226 
227  /* tacp: 2,3,4,5 */
228  /* tcah: 0,1,2,4 */
229  /* tcoh: 0,1,2,4 */
230  /* tacc: 1,2,3,4,6,7,10,14 (>4 for nwait) */
231  /* tcos: 0,1,2,4 */
232  /* tacs: 0,1,2,4 */
233 
234  ret = calc_0124(bt->tacs, hclk, &res, S3C2410_BANKCON_Tacs_SHIFT);
235  ret |= calc_0124(bt->tcos, hclk, &res, S3C2410_BANKCON_Tcos_SHIFT);
236  ret |= calc_0124(bt->tcah, hclk, &res, S3C2410_BANKCON_Tcah_SHIFT);
237  ret |= calc_0124(bt->tcoh, hclk, &res, S3C2410_BANKCON_Tcoh_SHIFT);
238 
239  if (ret)
240  return -EINVAL;
241 
242  ret |= calc_tacp(bt->tacp, hclk, &res);
243  ret |= calc_tacc(bt->tacc, bt->nwait_en, hclk, &res);
244 
245  if (ret)
246  return -EINVAL;
247 
248  bt->bankcon = res;
249  return 0;
250 }
251 
252 static unsigned int tacc_tab[] = {
253  [0] = 1,
254  [1] = 2,
255  [2] = 3,
256  [3] = 4,
257  [4] = 6,
258  [5] = 9,
259  [6] = 10,
260  [7] = 14,
261 };
262 
268 static unsigned int get_tacc(unsigned long hclk_tns,
269  unsigned long val)
270 {
271  val &= 7;
272  return hclk_tns * tacc_tab[val];
273 }
274 
280 static unsigned int get_0124(unsigned long hclk_tns,
281  unsigned long val)
282 {
283  val &= 3;
284  return hclk_tns * ((val == 3) ? 4 : val);
285 }
286 
296  struct s3c2410_iobank_timing *bt)
297 {
298  unsigned long bankcon = bt->bankcon;
299  unsigned long hclk = cfg->freq.hclk_tns;
300 
301  bt->tcah = get_0124(hclk, bankcon >> S3C2410_BANKCON_Tcah_SHIFT);
302  bt->tcoh = get_0124(hclk, bankcon >> S3C2410_BANKCON_Tcoh_SHIFT);
303  bt->tcos = get_0124(hclk, bankcon >> S3C2410_BANKCON_Tcos_SHIFT);
304  bt->tacs = get_0124(hclk, bankcon >> S3C2410_BANKCON_Tacs_SHIFT);
305  bt->tacc = get_tacc(hclk, bankcon >> S3C2410_BANKCON_Tacc_SHIFT);
306 }
307 
315  struct s3c_cpufreq_config *cfg,
316  union s3c_iobank *iob)
317 {
318  struct s3c2410_iobank_timing *bt = iob->io_2410;
319  unsigned long bankcon = bt->bankcon;
320  unsigned long hclk = cfg->freq.hclk_tns;
321  unsigned int tacs;
322  unsigned int tcos;
323  unsigned int tacc;
324  unsigned int tcoh;
325  unsigned int tcah;
326 
327  seq_printf(seq, "BANKCON=0x%08lx\n", bankcon);
328 
329  tcah = get_0124(hclk, bankcon >> S3C2410_BANKCON_Tcah_SHIFT);
330  tcoh = get_0124(hclk, bankcon >> S3C2410_BANKCON_Tcoh_SHIFT);
331  tcos = get_0124(hclk, bankcon >> S3C2410_BANKCON_Tcos_SHIFT);
332  tacs = get_0124(hclk, bankcon >> S3C2410_BANKCON_Tacs_SHIFT);
333  tacc = get_tacc(hclk, bankcon >> S3C2410_BANKCON_Tacc_SHIFT);
334 
335  seq_printf(seq,
336  "\tRead: Tacs=%d.%d, Tcos=%d.%d, Tacc=%d.%d, Tcoh=%d.%d, Tcah=%d.%d\n",
337  print_ns(bt->tacs),
338  print_ns(bt->tcos),
339  print_ns(bt->tacc),
340  print_ns(bt->tcoh),
341  print_ns(bt->tcah));
342 
343  seq_printf(seq,
344  "\t Set: Tacs=%d.%d, Tcos=%d.%d, Tacc=%d.%d, Tcoh=%d.%d, Tcah=%d.%d\n",
345  print_ns(tacs),
346  print_ns(tcos),
347  print_ns(tacc),
348  print_ns(tcoh),
349  print_ns(tcah));
350 }
351 
362  struct s3c_iotimings *iot)
363 {
364  struct s3c2410_iobank_timing *bt;
365  unsigned long bankcon;
366  int bank;
367  int ret;
368 
369  for (bank = 0; bank < MAX_BANKS; bank++) {
370  bankcon = __raw_readl(bank_reg(bank));
371  bt = iot->bank[bank].io_2410;
372 
373  if (!bt)
374  continue;
375 
376  bt->bankcon = bankcon;
377 
378  ret = s3c2410_calc_bank(cfg, bt);
379  if (ret) {
380  printk(KERN_ERR "%s: cannot calculate bank %d io\n",
381  __func__, bank);
382  goto err;
383  }
384 
385  s3c_freq_iodbg("%s: bank %d: con=%08lx\n",
386  __func__, bank, bt->bankcon);
387  }
388 
389  return 0;
390  err:
391  return ret;
392 }
393 
404  struct s3c_iotimings *iot)
405 {
406  struct s3c2410_iobank_timing *bt;
407  int bank;
408 
409  /* set the io timings from the specifier */
410 
411  for (bank = 0; bank < MAX_BANKS; bank++) {
412  bt = iot->bank[bank].io_2410;
413  if (!bt)
414  continue;
415 
416  __raw_writel(bt->bankcon, bank_reg(bank));
417  }
418 }
419 
436  struct s3c_iotimings *timings)
437 {
438  struct s3c2410_iobank_timing *bt;
439  unsigned long bankcon;
440  unsigned long bwscon;
441  int bank;
442 
443  bwscon = __raw_readl(S3C2410_BWSCON);
444 
445  /* look through all banks to see what is currently set. */
446 
447  for (bank = 0; bank < MAX_BANKS; bank++) {
448  bankcon = __raw_readl(bank_reg(bank));
449 
450  if (!bank_is_io(bankcon))
451  continue;
452 
453  s3c_freq_iodbg("%s: bank %d: con %08lx\n",
454  __func__, bank, bankcon);
455 
456  bt = kzalloc(sizeof(struct s3c2410_iobank_timing), GFP_KERNEL);
457  if (!bt) {
458  printk(KERN_ERR "%s: no memory for bank\n", __func__);
459  return -ENOMEM;
460  }
461 
462  /* find out in nWait is enabled for bank. */
463 
464  if (bank != 0) {
465  unsigned long tmp = S3C2410_BWSCON_GET(bwscon, bank);
466  if (tmp & S3C2410_BWSCON_WS)
467  bt->nwait_en = 1;
468  }
469 
470  timings->bank[bank].io_2410 = bt;
471  bt->bankcon = bankcon;
472 
473  s3c2410_iotiming_getbank(cfg, bt);
474  }
475 
476  s3c2410_print_timing("get", timings);
477  return 0;
478 }