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 26static 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 43static 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 106static 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*/ 141static int divisors2[] = { 2, 3, 4, 5, 6, 8, 10, 12, 16, 20, 24, 32, 40 }; 142 143static 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 150static 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 159static 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 166static 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 189static 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 195static struct clk_ops sh7722_module_clk_ops = { 196 .recalc = module_clk_recalc, 197}; 198 199struct frqcr_context { 200 unsigned mask; 201 unsigned shift; 202}; 203 204struct 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 */ 240static 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 257static 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 267static 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 if (algo_id != NO_CHANGE) { 290 int originator; 291 char *algo_group_1[] = { "cpu_clk", "umem_clk", "sh_clk" }; 292 char *algo_group_2[] = { "sh_clk", "bus_clk" }; 293 char *algo_group_3[] = { "sh_clk", "sdram_clk" }; 294 char *algo_group_4[] = { "bus_clk", "peripheral_clk" }; 295 char *algo_group_5[] = { "cpu_clk", "peripheral_clk" }; 296 char **algo_current = NULL; 297 /* 3 is the maximum number of clocks in relation */ 298 struct clk *ck[3]; 299 unsigned long values[3]; /* the same comment as above */ 300 int part_length = -1; 301 int i; 302 303 /* 304 * all the steps below only required if adjustion was 305 * requested 306 */ 307 if (algo_id == IUS_N1_N1 || 308 algo_id == IUS_322 || 309 algo_id == IUS_522 || 310 algo_id == IUS_N11) { 311 algo_current = algo_group_1; 312 part_length = 3; 313 } 314 if (algo_id == SB_N1) { 315 algo_current = algo_group_2; 316 part_length = 2; 317 } 318 if (algo_id == SB3_N1 || 319 algo_id == SB3_32 || 320 algo_id == SB3_43 || 321 algo_id == SB3_54) { 322 algo_current = algo_group_3; 323 part_length = 2; 324 } 325 if (algo_id == BP_N1) { 326 algo_current = algo_group_4; 327 part_length = 2; 328 } 329 if (algo_id == IP_N1) { 330 algo_current = algo_group_5; 331 part_length = 2; 332 } 333 if (!algo_current) 334 goto incorrect_algo_id; 335 336 originator = -1; 337 for (i = 0; i < part_length; i ++ ) { 338 if (originator >= 0 && !strcmp(clk->name, 339 algo_current[i])) 340 originator = i; 341 ck[i] = clk_get(NULL, algo_current[i]); 342 values[i] = clk_get_rate(ck[i]); 343 } 344 345 if (originator >= 0) 346 adjust_clocks(originator, adjust_algos[algo_id], 347 values, part_length); 348 349 for (i = 0; i < part_length; i ++ ) { 350 struct frqcr_context part_ctx; 351 int part_div; 352 353 if (likely(!err)) { 354 part_div = sh7722_find_divisors(parent_rate, 355 rate); 356 if (part_div > 0) { 357 part_ctx = sh7722_get_clk_context( 358 ck[i]->name); 359 frqcr &= ~(part_ctx.mask << 360 part_ctx.shift); 361 frqcr |= part_div << part_ctx.shift; 362 } else 363 err = part_div; 364 } 365 366 ck[i]->ops->recalc(ck[i]); 367 clk_put(ck[i]); 368 } 369 } 370 371 /* was there any error during recalculation ? If so, bail out.. */ 372 if (unlikely(err!=0)) 373 goto out_err; 374 375 /* clear FRQCR bits */ 376 frqcr &= ~(ctx.mask << ctx.shift); 377 frqcr |= div << ctx.shift; 378 379 /* ...and perform actual change */ 380 ctrl_outl(frqcr, FRQCR); 381 return 0; 382 383incorrect_algo_id: 384 return -EINVAL; 385out_err: 386 return err; 387} 388 389static struct clk_ops sh7722_frqcr_clk_ops = { 390 .recalc = sh7722_frqcr_recalc, 391 .set_rate = sh7722_frqcr_set_rate, 392}; 393 394/* 395 * clock ops methods for SIU A/B and IrDA clock 396 * 397 */ 398static int sh7722_siu_which(struct clk *clk) 399{ 400 if (!strcmp(clk->name, "siu_a_clk")) 401 return 0; 402 if (!strcmp(clk->name, "siu_b_clk")) 403 return 1; 404 if (!strcmp(clk->name, "irda_clk")) 405 return 2; 406 return -EINVAL; 407} 408 409static unsigned long sh7722_siu_regs[] = { 410 [0] = SCLKACR, 411 [1] = SCLKBCR, 412 [2] = IrDACLKCR, 413}; 414 415static int sh7722_siu_start_stop(struct clk *clk, int enable) 416{ 417 int siu = sh7722_siu_which(clk); 418 unsigned long r; 419 420 if (siu < 0) 421 return siu; 422 BUG_ON(siu > 2); 423 r = ctrl_inl(sh7722_siu_regs[siu]); 424 if (enable) 425 ctrl_outl(r & ~(1 << 8), sh7722_siu_regs[siu]); 426 else 427 ctrl_outl(r | (1 << 8), sh7722_siu_regs[siu]); 428 return 0; 429} 430 431static void sh7722_siu_enable(struct clk *clk) 432{ 433 sh7722_siu_start_stop(clk, 1); 434} 435 436static void sh7722_siu_disable(struct clk *clk) 437{ 438 sh7722_siu_start_stop(clk, 0); 439} 440 441static void sh7722_video_enable(struct clk *clk) 442{ 443 unsigned long r; 444 445 r = ctrl_inl(VCLKCR); 446 ctrl_outl( r & ~(1<<8), VCLKCR); 447} 448 449static void sh7722_video_disable(struct clk *clk) 450{ 451 unsigned long r; 452 453 r = ctrl_inl(VCLKCR); 454 ctrl_outl( r | (1<<8), VCLKCR); 455} 456 457static int sh7722_video_set_rate(struct clk *clk, unsigned long rate, 458 int algo_id) 459{ 460 unsigned long r; 461 462 r = ctrl_inl(VCLKCR); 463 r &= ~0x3F; 464 r |= ((clk->parent->rate / rate - 1) & 0x3F); 465 ctrl_outl(r, VCLKCR); 466 return 0; 467} 468 469static void sh7722_video_recalc(struct clk *clk) 470{ 471 unsigned long r; 472 473 r = ctrl_inl(VCLKCR); 474 clk->rate = clk->parent->rate / ((r & 0x3F) + 1); 475} 476 477static int sh7722_siu_set_rate(struct clk *clk, unsigned long rate, int algo_id) 478{ 479 int siu = sh7722_siu_which(clk); 480 unsigned long r; 481 int div; 482 483 if (siu < 0) 484 return siu; 485 BUG_ON(siu > 2); 486 r = ctrl_inl(sh7722_siu_regs[siu]); 487 div = sh7722_find_divisors(clk->parent->rate, rate); 488 if (div < 0) 489 return div; 490 r = (r & ~0xF) | div; 491 ctrl_outl(r, sh7722_siu_regs[siu]); 492 return 0; 493} 494 495static void sh7722_siu_recalc(struct clk *clk) 496{ 497 int siu = sh7722_siu_which(clk); 498 unsigned long r; 499 500 if (siu < 0) 501 return /* siu */ ; 502 BUG_ON(siu > 2); 503 r = ctrl_inl(sh7722_siu_regs[siu]); 504 clk->rate = clk->parent->rate * 2 / divisors2[r & 0xF]; 505} 506 507static struct clk_ops sh7722_siu_clk_ops = { 508 .recalc = sh7722_siu_recalc, 509 .set_rate = sh7722_siu_set_rate, 510 .enable = sh7722_siu_enable, 511 .disable = sh7722_siu_disable, 512}; 513 514static struct clk_ops sh7722_video_clk_ops = { 515 .recalc = sh7722_video_recalc, 516 .set_rate = sh7722_video_set_rate, 517 .enable = sh7722_video_enable, 518 .disable = sh7722_video_disable, 519}; 520/* 521 * and at last, clock definitions themselves 522 */ 523static struct clk sh7722_umem_clock = { 524 .name = "umem_clk", 525 .ops = &sh7722_frqcr_clk_ops, 526}; 527 528static struct clk sh7722_sh_clock = { 529 .name = "sh_clk", 530 .ops = &sh7722_frqcr_clk_ops, 531}; 532 533static struct clk sh7722_peripheral_clock = { 534 .name = "peripheral_clk", 535 .ops = &sh7722_frqcr_clk_ops, 536}; 537 538static struct clk sh7722_sdram_clock = { 539 .name = "sdram_clk", 540 .ops = &sh7722_frqcr_clk_ops, 541}; 542 543/* 544 * these three clocks - SIU A, SIU B, IrDA - share the same clk_ops 545 * methods of clk_ops determine which register they should access by 546 * examining clk->name field 547 */ 548static struct clk sh7722_siu_a_clock = { 549 .name = "siu_a_clk", 550 .ops = &sh7722_siu_clk_ops, 551}; 552 553static struct clk sh7722_siu_b_clock = { 554 .name = "siu_b_clk", 555 .ops = &sh7722_siu_clk_ops, 556}; 557 558static struct clk sh7722_irda_clock = { 559 .name = "irda_clk", 560 .ops = &sh7722_siu_clk_ops, 561}; 562 563static struct clk sh7722_video_clock = { 564 .name = "video_clk", 565 .ops = &sh7722_video_clk_ops, 566}; 567 568static struct clk *sh7722_clocks[] = { 569 &sh7722_umem_clock, 570 &sh7722_sh_clock, 571 &sh7722_peripheral_clock, 572 &sh7722_sdram_clock, 573 &sh7722_siu_a_clock, 574 &sh7722_siu_b_clock, 575 &sh7722_irda_clock, 576 &sh7722_video_clock, 577}; 578 579/* 580 * init in order: master, module, bus, cpu 581 */ 582struct clk_ops *onchip_ops[] = { 583 &sh7722_master_clk_ops, 584 &sh7722_module_clk_ops, 585 &sh7722_frqcr_clk_ops, 586 &sh7722_frqcr_clk_ops, 587}; 588 589void __init 590arch_init_clk_ops(struct clk_ops **ops, int type) 591{ 592 BUG_ON(type < 0 || type > ARRAY_SIZE(onchip_ops)); 593 *ops = onchip_ops[type]; 594} 595 596int __init arch_clk_init(void) 597{ 598 struct clk *master; 599 int i; 600 601 master = clk_get(NULL, "master_clk"); 602 for (i = 0; i < ARRAY_SIZE(sh7722_clocks); i++) { 603 pr_debug( "Registering clock '%s'\n", sh7722_clocks[i]->name); 604 sh7722_clocks[i]->parent = master; 605 clk_register(sh7722_clocks[i]); 606 } 607 clk_put(master); 608 return 0; 609} 610