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