1 /* 2 * arch/sh/kernel/cpu/sh4a/clock-sh7722.c 3 * 4 * SH7722 support for the clock framework 5 * 6 * Copyright (c) 2006-2007 Nomad Global Solutions Inc 7 * Based on code for sh7343 by Paul Mundt 8 * 9 * This file is subject to the terms and conditions of the GNU General Public 10 * License. See the file "COPYING" in the main directory of this archive 11 * for more details. 12 */ 13 #include <linux/init.h> 14 #include <linux/kernel.h> 15 #include <linux/io.h> 16 #include <linux/errno.h> 17 #include <asm/clock.h> 18 #include <asm/freq.h> 19 20 #define N (-1) 21 #define NM (-2) 22 #define ROUND_NEAREST 0 23 #define ROUND_DOWN -1 24 #define ROUND_UP +1 25 26 static int adjust_algos[][3] = { 27 {}, /* NO_CHANGE */ 28 { NM, N, 1 }, /* N:1, N:1 */ 29 { 3, 2, 2 }, /* 3:2:2 */ 30 { 5, 2, 2 }, /* 5:2:2 */ 31 { N, 1, 1 }, /* N:1:1 */ 32 33 { N, 1 }, /* N:1 */ 34 35 { N, 1 }, /* N:1 */ 36 { 3, 2 }, 37 { 4, 3 }, 38 { 5, 4 }, 39 40 { N, 1 } 41 }; 42 43 static unsigned long adjust_pair_of_clocks(unsigned long r1, unsigned long r2, 44 int m1, int m2, int round_flag) 45 { 46 unsigned long rem, div; 47 int the_one = 0; 48 49 pr_debug( "Actual values: r1 = %ld\n", r1); 50 pr_debug( "...............r2 = %ld\n", r2); 51 52 if (m1 == m2) { 53 r2 = r1; 54 pr_debug( "setting equal rates: r2 now %ld\n", r2); 55 } else if ((m2 == N && m1 == 1) || 56 (m2 == NM && m1 == N)) { /* N:1 or NM:N */ 57 pr_debug( "Setting rates as 1:N (N:N*M)\n"); 58 rem = r2 % r1; 59 pr_debug( "...remainder = %ld\n", rem); 60 if (rem) { 61 div = r2 / r1; 62 pr_debug( "...div = %ld\n", div); 63 switch (round_flag) { 64 case ROUND_NEAREST: 65 the_one = rem >= r1/2 ? 1 : 0; break; 66 case ROUND_UP: 67 the_one = 1; break; 68 case ROUND_DOWN: 69 the_one = 0; break; 70 } 71 72 r2 = r1 * (div + the_one); 73 pr_debug( "...setting r2 to %ld\n", r2); 74 } 75 } else if ((m2 == 1 && m1 == N) || 76 (m2 == N && m1 == NM)) { /* 1:N or N:NM */ 77 pr_debug( "Setting rates as N:1 (N*M:N)\n"); 78 rem = r1 % r2; 79 pr_debug( "...remainder = %ld\n", rem); 80 if (rem) { 81 div = r1 / r2; 82 pr_debug( "...div = %ld\n", div); 83 switch (round_flag) { 84 case ROUND_NEAREST: 85 the_one = rem > r2/2 ? 1 : 0; break; 86 case ROUND_UP: 87 the_one = 0; break; 88 case ROUND_DOWN: 89 the_one = 1; break; 90 } 91 92 r2 = r1 / (div + the_one); 93 pr_debug( "...setting r2 to %ld\n", r2); 94 } 95 } else { /* value:value */ 96 pr_debug( "Setting rates as %d:%d\n", m1, m2); 97 div = r1 / m1; 98 r2 = div * m2; 99 pr_debug( "...div = %ld\n", div); 100 pr_debug( "...setting r2 to %ld\n", r2); 101 } 102 103 return r2; 104 } 105 106 static void adjust_clocks(int originate, int *l, unsigned long v[], 107 int n_in_line) 108 { 109 int x; 110 111 pr_debug( "Go down from %d...\n", originate); 112 /* go up recalculation clocks */ 113 for (x = originate; x>0; x -- ) 114 v[x-1] = adjust_pair_of_clocks(v[x], v[x-1], 115 l[x], l[x-1], 116 ROUND_UP); 117 118 pr_debug( "Go up from %d...\n", originate); 119 /* go down recalculation clocks */ 120 for (x = originate; x<n_in_line - 1; x ++ ) 121 v[x+1] = adjust_pair_of_clocks(v[x], v[x+1], 122 l[x], l[x+1], 123 ROUND_UP); 124 } 125 126 127 /* 128 * SH7722 uses a common set of multipliers and divisors, so this 129 * is quite simple.. 130 */ 131 132 /* 133 * Instead of having two separate multipliers/divisors set, like this: 134 * 135 * static int multipliers[] = { 1, 2, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1 }; 136 * static int divisors[] = { 1, 3, 2, 5, 3, 4, 5, 6, 8, 10, 12, 16, 20 }; 137 * 138 * I created the divisors2 array, which is used to calculate rate like 139 * rate = parent * 2 / divisors2[ divisor ]; 140 */ 141 static int divisors2[] = { 2, 3, 4, 5, 6, 8, 10, 12, 16, 20, 24, 32, 40 }; 142 143 static void master_clk_recalc(struct clk *clk) 144 { 145 unsigned frqcr = ctrl_inl(FRQCR); 146 147 clk->rate = CONFIG_SH_PCLK_FREQ * (((frqcr >> 24) & 0x1f) + 1); 148 } 149 150 static void master_clk_init(struct clk *clk) 151 { 152 clk->parent = NULL; 153 clk->flags |= CLK_RATE_PROPAGATES; 154 clk->rate = CONFIG_SH_PCLK_FREQ; 155 master_clk_recalc(clk); 156 } 157 158 159 static void module_clk_recalc(struct clk *clk) 160 { 161 unsigned long frqcr = ctrl_inl(FRQCR); 162 163 clk->rate = clk->parent->rate / (((frqcr >> 24) & 0x1f) + 1); 164 } 165 166 static int master_clk_setrate(struct clk *clk, unsigned long rate, int id) 167 { 168 int div = rate / clk->rate; 169 int master_divs[] = { 2, 3, 4, 6, 8, 16 }; 170 int index; 171 unsigned long frqcr; 172 173 for (index = 1; index < ARRAY_SIZE(master_divs); index++) 174 if (div >= master_divs[index - 1] && div < master_divs[index]) 175 break; 176 177 if (index >= ARRAY_SIZE(master_divs)) 178 index = ARRAY_SIZE(master_divs); 179 div = master_divs[index - 1]; 180 181 frqcr = ctrl_inl(FRQCR); 182 frqcr &= ~(0xF << 24); 183 frqcr |= ( (div-1) << 24); 184 ctrl_outl(frqcr, FRQCR); 185 186 return 0; 187 } 188 189 static struct clk_ops sh7722_master_clk_ops = { 190 .init = master_clk_init, 191 .recalc = master_clk_recalc, 192 .set_rate = master_clk_setrate, 193 }; 194 195 static struct clk_ops sh7722_module_clk_ops = { 196 .recalc = module_clk_recalc, 197 }; 198 199 struct frqcr_context { 200 unsigned mask; 201 unsigned shift; 202 }; 203 204 struct frqcr_context sh7722_get_clk_context(const char *name) 205 { 206 struct frqcr_context ctx = { 0, }; 207 208 if (!strcmp(name, "peripheral_clk")) { 209 ctx.shift = 0; 210 ctx.mask = 0xF; 211 } else if (!strcmp(name, "sdram_clk")) { 212 ctx.shift = 4; 213 ctx.mask = 0xF; 214 } else if (!strcmp(name, "bus_clk")) { 215 ctx.shift = 8; 216 ctx.mask = 0xF; 217 } else if (!strcmp(name, "sh_clk")) { 218 ctx.shift = 12; 219 ctx.mask = 0xF; 220 } else if (!strcmp(name, "umem_clk")) { 221 ctx.shift = 16; 222 ctx.mask = 0xF; 223 } else if (!strcmp(name, "cpu_clk")) { 224 ctx.shift = 20; 225 ctx.mask = 7; 226 } 227 return ctx; 228 } 229 230 /** 231 * sh7722_find_divisors - find divisor for setting rate 232 * 233 * All sh7722 clocks use the same set of multipliers/divisors. This function 234 * chooses correct divisor to set the rate of clock with parent clock that 235 * generates frequency of 'parent_rate' 236 * 237 * @parent_rate: rate of parent clock 238 * @rate: requested rate to be set 239 */ 240 static int sh7722_find_divisors(unsigned long parent_rate, unsigned rate) 241 { 242 unsigned div2 = parent_rate * 2 / rate; 243 int index; 244 245 if (rate > parent_rate) 246 return -EINVAL; 247 248 for (index = 1; index < ARRAY_SIZE(divisors2); index++) { 249 if (div2 > divisors2[index] && div2 <= divisors2[index]) 250 break; 251 } 252 if (index >= ARRAY_SIZE(divisors2)) 253 index = ARRAY_SIZE(divisors2) - 1; 254 return divisors2[index]; 255 } 256 257 static void sh7722_frqcr_recalc(struct clk *clk) 258 { 259 struct frqcr_context ctx = sh7722_get_clk_context(clk->name); 260 unsigned long frqcr = ctrl_inl(FRQCR); 261 int index; 262 263 index = (frqcr >> ctx.shift) & ctx.mask; 264 clk->rate = clk->parent->rate * 2 / divisors2[index]; 265 } 266 267 static int sh7722_frqcr_set_rate(struct clk *clk, unsigned long rate, 268 int algo_id) 269 { 270 struct frqcr_context ctx = sh7722_get_clk_context(clk->name); 271 unsigned long parent_rate = clk->parent->rate; 272 int div; 273 unsigned long frqcr; 274 int err = 0; 275 276 /* pretty invalid */ 277 if (parent_rate < rate) 278 return -EINVAL; 279 280 /* look for multiplier/divisor pair */ 281 div = sh7722_find_divisors(parent_rate, rate); 282 if (div<0) 283 return div; 284 285 /* calculate new value of clock rate */ 286 clk->rate = parent_rate * 2 / div; 287 frqcr = ctrl_inl(FRQCR); 288 289 /* FIXME: adjust as algo_id specifies */ 290 if (algo_id != NO_CHANGE) { 291 int originator; 292 char *algo_group_1[] = { "cpu_clk", "umem_clk", "sh_clk" }; 293 char *algo_group_2[] = { "sh_clk", "bus_clk" }; 294 char *algo_group_3[] = { "sh_clk", "sdram_clk" }; 295 char *algo_group_4[] = { "bus_clk", "peripheral_clk" }; 296 char *algo_group_5[] = { "cpu_clk", "peripheral_clk" }; 297 char **algo_current = NULL; 298 /* 3 is the maximum number of clocks in relation */ 299 struct clk *ck[3]; 300 unsigned long values[3]; /* the same comment as above */ 301 int part_length = -1; 302 int i; 303 304 /* 305 * all the steps below only required if adjustion was 306 * requested 307 */ 308 if (algo_id == IUS_N1_N1 || 309 algo_id == IUS_322 || 310 algo_id == IUS_522 || 311 algo_id == IUS_N11) { 312 algo_current = algo_group_1; 313 part_length = 3; 314 } 315 if (algo_id == SB_N1) { 316 algo_current = algo_group_2; 317 part_length = 2; 318 } 319 if (algo_id == SB3_N1 || 320 algo_id == SB3_32 || 321 algo_id == SB3_43 || 322 algo_id == SB3_54) { 323 algo_current = algo_group_3; 324 part_length = 2; 325 } 326 if (algo_id == BP_N1) { 327 algo_current = algo_group_4; 328 part_length = 2; 329 } 330 if (algo_id == IP_N1) { 331 algo_current = algo_group_5; 332 part_length = 2; 333 } 334 if (!algo_current) 335 goto incorrect_algo_id; 336 337 originator = -1; 338 for (i = 0; i < part_length; i ++ ) { 339 if (originator >= 0 && !strcmp(clk->name, 340 algo_current[i])) 341 originator = i; 342 ck[i] = clk_get(NULL, algo_current[i]); 343 values[i] = clk_get_rate(ck[i]); 344 } 345 346 if (originator >= 0) 347 adjust_clocks(originator, adjust_algos[algo_id], 348 values, part_length); 349 350 for (i = 0; i < part_length; i ++ ) { 351 struct frqcr_context part_ctx; 352 int part_div; 353 354 if (likely(!err)) { 355 part_div = sh7722_find_divisors(parent_rate, 356 rate); 357 if (part_div > 0) { 358 part_ctx = sh7722_get_clk_context( 359 ck[i]->name); 360 frqcr &= ~(part_ctx.mask << 361 part_ctx.shift); 362 frqcr |= part_div << part_ctx.shift; 363 } else 364 err = part_div; 365 } 366 367 ck[i]->ops->recalc(ck[i]); 368 clk_put(ck[i]); 369 } 370 } 371 372 /* was there any error during recalculation ? If so, bail out.. */ 373 if (unlikely(err!=0)) 374 goto out_err; 375 376 /* clear FRQCR bits */ 377 frqcr &= ~(ctx.mask << ctx.shift); 378 frqcr |= div << ctx.shift; 379 380 /* ...and perform actual change */ 381 ctrl_outl(frqcr, FRQCR); 382 return 0; 383 384 incorrect_algo_id: 385 return -EINVAL; 386 out_err: 387 return err; 388 } 389 390 static long sh7722_frqcr_round_rate(struct clk *clk, unsigned long rate) 391 { 392 unsigned long parent_rate = clk->parent->rate; 393 int div; 394 395 /* look for multiplier/divisor pair */ 396 div = sh7722_find_divisors(parent_rate, rate); 397 if (div < 0) 398 return clk->rate; 399 400 /* calculate new value of clock rate */ 401 return parent_rate * 2 / div; 402 } 403 404 static struct clk_ops sh7722_frqcr_clk_ops = { 405 .recalc = sh7722_frqcr_recalc, 406 .set_rate = sh7722_frqcr_set_rate, 407 .round_rate = sh7722_frqcr_round_rate, 408 }; 409 410 /* 411 * clock ops methods for SIU A/B and IrDA clock 412 * 413 */ 414 static int sh7722_siu_which(struct clk *clk) 415 { 416 if (!strcmp(clk->name, "siu_a_clk")) 417 return 0; 418 if (!strcmp(clk->name, "siu_b_clk")) 419 return 1; 420 if (!strcmp(clk->name, "irda_clk")) 421 return 2; 422 return -EINVAL; 423 } 424 425 static unsigned long sh7722_siu_regs[] = { 426 [0] = SCLKACR, 427 [1] = SCLKBCR, 428 [2] = IrDACLKCR, 429 }; 430 431 static int sh7722_siu_start_stop(struct clk *clk, int enable) 432 { 433 int siu = sh7722_siu_which(clk); 434 unsigned long r; 435 436 if (siu < 0) 437 return siu; 438 BUG_ON(siu > 2); 439 r = ctrl_inl(sh7722_siu_regs[siu]); 440 if (enable) 441 ctrl_outl(r & ~(1 << 8), sh7722_siu_regs[siu]); 442 else 443 ctrl_outl(r | (1 << 8), sh7722_siu_regs[siu]); 444 return 0; 445 } 446 447 static void sh7722_siu_enable(struct clk *clk) 448 { 449 sh7722_siu_start_stop(clk, 1); 450 } 451 452 static void sh7722_siu_disable(struct clk *clk) 453 { 454 sh7722_siu_start_stop(clk, 0); 455 } 456 457 static void sh7722_video_enable(struct clk *clk) 458 { 459 unsigned long r; 460 461 r = ctrl_inl(VCLKCR); 462 ctrl_outl( r & ~(1<<8), VCLKCR); 463 } 464 465 static void sh7722_video_disable(struct clk *clk) 466 { 467 unsigned long r; 468 469 r = ctrl_inl(VCLKCR); 470 ctrl_outl( r | (1<<8), VCLKCR); 471 } 472 473 static int sh7722_video_set_rate(struct clk *clk, unsigned long rate, 474 int algo_id) 475 { 476 unsigned long r; 477 478 r = ctrl_inl(VCLKCR); 479 r &= ~0x3F; 480 r |= ((clk->parent->rate / rate - 1) & 0x3F); 481 ctrl_outl(r, VCLKCR); 482 return 0; 483 } 484 485 static void sh7722_video_recalc(struct clk *clk) 486 { 487 unsigned long r; 488 489 r = ctrl_inl(VCLKCR); 490 clk->rate = clk->parent->rate / ((r & 0x3F) + 1); 491 } 492 493 static int sh7722_siu_set_rate(struct clk *clk, unsigned long rate, int algo_id) 494 { 495 int siu = sh7722_siu_which(clk); 496 unsigned long r; 497 int div; 498 499 if (siu < 0) 500 return siu; 501 BUG_ON(siu > 2); 502 r = ctrl_inl(sh7722_siu_regs[siu]); 503 div = sh7722_find_divisors(clk->parent->rate, rate); 504 if (div < 0) 505 return div; 506 r = (r & ~0xF) | div; 507 ctrl_outl(r, sh7722_siu_regs[siu]); 508 return 0; 509 } 510 511 static void sh7722_siu_recalc(struct clk *clk) 512 { 513 int siu = sh7722_siu_which(clk); 514 unsigned long r; 515 516 if (siu < 0) 517 return /* siu */ ; 518 BUG_ON(siu > 2); 519 r = ctrl_inl(sh7722_siu_regs[siu]); 520 clk->rate = clk->parent->rate * 2 / divisors2[r & 0xF]; 521 } 522 523 static struct clk_ops sh7722_siu_clk_ops = { 524 .recalc = sh7722_siu_recalc, 525 .set_rate = sh7722_siu_set_rate, 526 .enable = sh7722_siu_enable, 527 .disable = sh7722_siu_disable, 528 }; 529 530 static struct clk_ops sh7722_video_clk_ops = { 531 .recalc = sh7722_video_recalc, 532 .set_rate = sh7722_video_set_rate, 533 .enable = sh7722_video_enable, 534 .disable = sh7722_video_disable, 535 }; 536 /* 537 * and at last, clock definitions themselves 538 */ 539 static struct clk sh7722_umem_clock = { 540 .name = "umem_clk", 541 .ops = &sh7722_frqcr_clk_ops, 542 }; 543 544 static struct clk sh7722_sh_clock = { 545 .name = "sh_clk", 546 .ops = &sh7722_frqcr_clk_ops, 547 }; 548 549 static struct clk sh7722_peripheral_clock = { 550 .name = "peripheral_clk", 551 .ops = &sh7722_frqcr_clk_ops, 552 }; 553 554 static struct clk sh7722_sdram_clock = { 555 .name = "sdram_clk", 556 .ops = &sh7722_frqcr_clk_ops, 557 }; 558 559 /* 560 * these three clocks - SIU A, SIU B, IrDA - share the same clk_ops 561 * methods of clk_ops determine which register they should access by 562 * examining clk->name field 563 */ 564 static struct clk sh7722_siu_a_clock = { 565 .name = "siu_a_clk", 566 .ops = &sh7722_siu_clk_ops, 567 }; 568 569 static struct clk sh7722_siu_b_clock = { 570 .name = "siu_b_clk", 571 .ops = &sh7722_siu_clk_ops, 572 }; 573 574 static struct clk sh7722_irda_clock = { 575 .name = "irda_clk", 576 .ops = &sh7722_siu_clk_ops, 577 }; 578 579 static struct clk sh7722_video_clock = { 580 .name = "video_clk", 581 .ops = &sh7722_video_clk_ops, 582 }; 583 584 static struct clk *sh7722_clocks[] = { 585 &sh7722_umem_clock, 586 &sh7722_sh_clock, 587 &sh7722_peripheral_clock, 588 &sh7722_sdram_clock, 589 &sh7722_siu_a_clock, 590 &sh7722_siu_b_clock, 591 &sh7722_irda_clock, 592 &sh7722_video_clock, 593 }; 594 595 /* 596 * init in order: master, module, bus, cpu 597 */ 598 struct clk_ops *onchip_ops[] = { 599 &sh7722_master_clk_ops, 600 &sh7722_module_clk_ops, 601 &sh7722_frqcr_clk_ops, 602 &sh7722_frqcr_clk_ops, 603 }; 604 605 void __init 606 arch_init_clk_ops(struct clk_ops **ops, int type) 607 { 608 BUG_ON(type < 0 || type > ARRAY_SIZE(onchip_ops)); 609 *ops = onchip_ops[type]; 610 } 611 612 int __init arch_clk_init(void) 613 { 614 struct clk *master; 615 int i; 616 617 master = clk_get(NULL, "master_clk"); 618 for (i = 0; i < ARRAY_SIZE(sh7722_clocks); i++) { 619 pr_debug( "Registering clock '%s'\n", sh7722_clocks[i]->name); 620 sh7722_clocks[i]->parent = master; 621 clk_register(sh7722_clocks[i]); 622 } 623 clk_put(master); 624 return 0; 625 } 626