0001
0002
0003
0004
0005
0006
0007
0008
0009 #include <linux/init.h>
0010 #include <linux/kernel.h>
0011 #include <linux/errno.h>
0012 #include <linux/cpufreq.h>
0013 #include <linux/seq_file.h>
0014 #include <linux/io.h>
0015 #include <linux/slab.h>
0016
0017 #include "map.h"
0018 #include "regs-clock.h"
0019
0020 #include <linux/soc/samsung/s3c-cpufreq-core.h>
0021
0022 #include "regs-mem-s3c24xx.h"
0023
0024 #define print_ns(x) ((x) / 10), ((x) % 10)
0025
0026
0027
0028
0029
0030
0031 static void s3c2410_print_timing(const char *pfx,
0032 struct s3c_iotimings *timings)
0033 {
0034 struct s3c2410_iobank_timing *bt;
0035 int bank;
0036
0037 for (bank = 0; bank < MAX_BANKS; bank++) {
0038 bt = timings->bank[bank].io_2410;
0039 if (!bt)
0040 continue;
0041
0042 printk(KERN_DEBUG "%s %d: Tacs=%d.%d, Tcos=%d.%d, Tacc=%d.%d, "
0043 "Tcoh=%d.%d, Tcah=%d.%d\n", pfx, bank,
0044 print_ns(bt->tacs),
0045 print_ns(bt->tcos),
0046 print_ns(bt->tacc),
0047 print_ns(bt->tcoh),
0048 print_ns(bt->tcah));
0049 }
0050 }
0051
0052
0053
0054
0055
0056 static inline void __iomem *bank_reg(unsigned int bank)
0057 {
0058 return S3C2410_BANKCON0 + (bank << 2);
0059 }
0060
0061
0062
0063
0064
0065
0066
0067
0068
0069
0070 static inline int bank_is_io(unsigned long bankcon)
0071 {
0072 return !(bankcon & S3C2410_BANKCON_SDRAM);
0073 }
0074
0075
0076
0077
0078
0079
0080
0081
0082
0083 static inline unsigned int to_div(unsigned int cyc, unsigned int hclk_tns)
0084 {
0085 if (cyc == 0)
0086 return 0;
0087
0088 return DIV_ROUND_UP(cyc, hclk_tns);
0089 }
0090
0091
0092
0093
0094
0095
0096
0097
0098
0099
0100
0101 static unsigned int calc_0124(unsigned int cyc, unsigned long hclk_tns,
0102 unsigned long *v, int shift)
0103 {
0104 unsigned int div = to_div(cyc, hclk_tns);
0105 unsigned long val;
0106
0107 s3c_freq_iodbg("%s: cyc=%d, hclk=%lu, shift=%d => div %d\n",
0108 __func__, cyc, hclk_tns, shift, div);
0109
0110 switch (div) {
0111 case 0:
0112 val = 0;
0113 break;
0114 case 1:
0115 val = 1;
0116 break;
0117 case 2:
0118 val = 2;
0119 break;
0120 case 3:
0121 case 4:
0122 val = 3;
0123 break;
0124 default:
0125 return -1;
0126 }
0127
0128 *v |= val << shift;
0129 return 0;
0130 }
0131
0132 static int calc_tacp(unsigned int cyc, unsigned long hclk, unsigned long *v)
0133 {
0134
0135 return 0;
0136 }
0137
0138
0139
0140
0141
0142
0143
0144
0145
0146
0147
0148
0149 static int calc_tacc(unsigned int cyc, int nwait_en,
0150 unsigned long hclk_tns, unsigned long *v)
0151 {
0152 unsigned int div = to_div(cyc, hclk_tns);
0153 unsigned long val;
0154
0155 s3c_freq_iodbg("%s: cyc=%u, nwait=%d, hclk=%lu => div=%u\n",
0156 __func__, cyc, nwait_en, hclk_tns, div);
0157
0158
0159 if (nwait_en && div < 4)
0160 div = 4;
0161
0162 switch (div) {
0163 case 0:
0164 val = 0;
0165 break;
0166
0167 case 1:
0168 case 2:
0169 case 3:
0170 case 4:
0171 val = div - 1;
0172 break;
0173
0174 case 5:
0175 case 6:
0176 val = 4;
0177 break;
0178
0179 case 7:
0180 case 8:
0181 val = 5;
0182 break;
0183
0184 case 9:
0185 case 10:
0186 val = 6;
0187 break;
0188
0189 case 11:
0190 case 12:
0191 case 13:
0192 case 14:
0193 val = 7;
0194 break;
0195
0196 default:
0197 return -1;
0198 }
0199
0200 *v |= val << 8;
0201 return 0;
0202 }
0203
0204
0205
0206
0207
0208
0209
0210
0211
0212
0213 static int s3c2410_calc_bank(struct s3c_cpufreq_config *cfg,
0214 struct s3c2410_iobank_timing *bt)
0215 {
0216 unsigned long hclk = cfg->freq.hclk_tns;
0217 unsigned long res;
0218 int ret;
0219
0220 res = bt->bankcon;
0221 res &= (S3C2410_BANKCON_SDRAM | S3C2410_BANKCON_PMC16);
0222
0223
0224
0225
0226
0227
0228
0229
0230 ret = calc_0124(bt->tacs, hclk, &res, S3C2410_BANKCON_Tacs_SHIFT);
0231 ret |= calc_0124(bt->tcos, hclk, &res, S3C2410_BANKCON_Tcos_SHIFT);
0232 ret |= calc_0124(bt->tcah, hclk, &res, S3C2410_BANKCON_Tcah_SHIFT);
0233 ret |= calc_0124(bt->tcoh, hclk, &res, S3C2410_BANKCON_Tcoh_SHIFT);
0234
0235 if (ret)
0236 return -EINVAL;
0237
0238 ret |= calc_tacp(bt->tacp, hclk, &res);
0239 ret |= calc_tacc(bt->tacc, bt->nwait_en, hclk, &res);
0240
0241 if (ret)
0242 return -EINVAL;
0243
0244 bt->bankcon = res;
0245 return 0;
0246 }
0247
0248 static const unsigned int tacc_tab[] = {
0249 [0] = 1,
0250 [1] = 2,
0251 [2] = 3,
0252 [3] = 4,
0253 [4] = 6,
0254 [5] = 9,
0255 [6] = 10,
0256 [7] = 14,
0257 };
0258
0259
0260
0261
0262
0263
0264 static unsigned int get_tacc(unsigned long hclk_tns,
0265 unsigned long val)
0266 {
0267 val &= 7;
0268 return hclk_tns * tacc_tab[val];
0269 }
0270
0271
0272
0273
0274
0275
0276 static unsigned int get_0124(unsigned long hclk_tns,
0277 unsigned long val)
0278 {
0279 val &= 3;
0280 return hclk_tns * ((val == 3) ? 4 : val);
0281 }
0282
0283
0284
0285
0286
0287
0288
0289
0290
0291 static void s3c2410_iotiming_getbank(struct s3c_cpufreq_config *cfg,
0292 struct s3c2410_iobank_timing *bt)
0293 {
0294 unsigned long bankcon = bt->bankcon;
0295 unsigned long hclk = cfg->freq.hclk_tns;
0296
0297 bt->tcah = get_0124(hclk, bankcon >> S3C2410_BANKCON_Tcah_SHIFT);
0298 bt->tcoh = get_0124(hclk, bankcon >> S3C2410_BANKCON_Tcoh_SHIFT);
0299 bt->tcos = get_0124(hclk, bankcon >> S3C2410_BANKCON_Tcos_SHIFT);
0300 bt->tacs = get_0124(hclk, bankcon >> S3C2410_BANKCON_Tacs_SHIFT);
0301 bt->tacc = get_tacc(hclk, bankcon >> S3C2410_BANKCON_Tacc_SHIFT);
0302 }
0303
0304
0305
0306
0307
0308
0309
0310 void s3c2410_iotiming_debugfs(struct seq_file *seq,
0311 struct s3c_cpufreq_config *cfg,
0312 union s3c_iobank *iob)
0313 {
0314 struct s3c2410_iobank_timing *bt = iob->io_2410;
0315 unsigned long bankcon = bt->bankcon;
0316 unsigned long hclk = cfg->freq.hclk_tns;
0317 unsigned int tacs;
0318 unsigned int tcos;
0319 unsigned int tacc;
0320 unsigned int tcoh;
0321 unsigned int tcah;
0322
0323 seq_printf(seq, "BANKCON=0x%08lx\n", bankcon);
0324
0325 tcah = get_0124(hclk, bankcon >> S3C2410_BANKCON_Tcah_SHIFT);
0326 tcoh = get_0124(hclk, bankcon >> S3C2410_BANKCON_Tcoh_SHIFT);
0327 tcos = get_0124(hclk, bankcon >> S3C2410_BANKCON_Tcos_SHIFT);
0328 tacs = get_0124(hclk, bankcon >> S3C2410_BANKCON_Tacs_SHIFT);
0329 tacc = get_tacc(hclk, bankcon >> S3C2410_BANKCON_Tacc_SHIFT);
0330
0331 seq_printf(seq,
0332 "\tRead: Tacs=%d.%d, Tcos=%d.%d, Tacc=%d.%d, Tcoh=%d.%d, Tcah=%d.%d\n",
0333 print_ns(bt->tacs),
0334 print_ns(bt->tcos),
0335 print_ns(bt->tacc),
0336 print_ns(bt->tcoh),
0337 print_ns(bt->tcah));
0338
0339 seq_printf(seq,
0340 "\t Set: Tacs=%d.%d, Tcos=%d.%d, Tacc=%d.%d, Tcoh=%d.%d, Tcah=%d.%d\n",
0341 print_ns(tacs),
0342 print_ns(tcos),
0343 print_ns(tacc),
0344 print_ns(tcoh),
0345 print_ns(tcah));
0346 }
0347
0348
0349
0350
0351
0352
0353
0354
0355
0356
0357 int s3c2410_iotiming_calc(struct s3c_cpufreq_config *cfg,
0358 struct s3c_iotimings *iot)
0359 {
0360 struct s3c2410_iobank_timing *bt;
0361 unsigned long bankcon;
0362 int bank;
0363 int ret;
0364
0365 for (bank = 0; bank < MAX_BANKS; bank++) {
0366 bankcon = __raw_readl(bank_reg(bank));
0367 bt = iot->bank[bank].io_2410;
0368
0369 if (!bt)
0370 continue;
0371
0372 bt->bankcon = bankcon;
0373
0374 ret = s3c2410_calc_bank(cfg, bt);
0375 if (ret) {
0376 printk(KERN_ERR "%s: cannot calculate bank %d io\n",
0377 __func__, bank);
0378 goto err;
0379 }
0380
0381 s3c_freq_iodbg("%s: bank %d: con=%08lx\n",
0382 __func__, bank, bt->bankcon);
0383 }
0384
0385 return 0;
0386 err:
0387 return ret;
0388 }
0389
0390
0391
0392
0393
0394
0395
0396
0397
0398
0399 void s3c2410_iotiming_set(struct s3c_cpufreq_config *cfg,
0400 struct s3c_iotimings *iot)
0401 {
0402 struct s3c2410_iobank_timing *bt;
0403 int bank;
0404
0405
0406
0407 for (bank = 0; bank < MAX_BANKS; bank++) {
0408 bt = iot->bank[bank].io_2410;
0409 if (!bt)
0410 continue;
0411
0412 __raw_writel(bt->bankcon, bank_reg(bank));
0413 }
0414 }
0415
0416
0417
0418
0419
0420
0421
0422
0423
0424
0425
0426
0427
0428
0429
0430
0431 int s3c2410_iotiming_get(struct s3c_cpufreq_config *cfg,
0432 struct s3c_iotimings *timings)
0433 {
0434 struct s3c2410_iobank_timing *bt;
0435 unsigned long bankcon;
0436 unsigned long bwscon;
0437 int bank;
0438
0439 bwscon = __raw_readl(S3C2410_BWSCON);
0440
0441
0442
0443 for (bank = 0; bank < MAX_BANKS; bank++) {
0444 bankcon = __raw_readl(bank_reg(bank));
0445
0446 if (!bank_is_io(bankcon))
0447 continue;
0448
0449 s3c_freq_iodbg("%s: bank %d: con %08lx\n",
0450 __func__, bank, bankcon);
0451
0452 bt = kzalloc(sizeof(*bt), GFP_KERNEL);
0453 if (!bt)
0454 return -ENOMEM;
0455
0456
0457
0458 if (bank != 0) {
0459 unsigned long tmp = S3C2410_BWSCON_GET(bwscon, bank);
0460 if (tmp & S3C2410_BWSCON_WS)
0461 bt->nwait_en = 1;
0462 }
0463
0464 timings->bank[bank].io_2410 = bt;
0465 bt->bankcon = bankcon;
0466
0467 s3c2410_iotiming_getbank(cfg, bt);
0468 }
0469
0470 s3c2410_print_timing("get", timings);
0471 return 0;
0472 }