1/* 2 * Port on Texas Instruments TMS320C6x architecture 3 * 4 * Copyright (C) 2011 Texas Instruments Incorporated 5 * Author: Mark Salter <msalter@redhat.com> 6 * 7 * This program is free software; you can redistribute it and/or modify 8 * it under the terms of the GNU General Public License version 2 as 9 * published by the Free Software Foundation. 10 */ 11#include <linux/kernel.h> 12#include <linux/delay.h> 13#include <linux/errno.h> 14#include <linux/string.h> 15#include <linux/ioport.h> 16#include <linux/clkdev.h> 17#include <linux/of.h> 18#include <linux/of_address.h> 19 20#include <asm/clock.h> 21#include <asm/setup.h> 22#include <asm/irq.h> 23 24/* 25 * Common SoC clock support. 26 */ 27 28/* Default input for PLL1 */ 29struct clk clkin1 = { 30 .name = "clkin1", 31 .node = LIST_HEAD_INIT(clkin1.node), 32 .children = LIST_HEAD_INIT(clkin1.children), 33 .childnode = LIST_HEAD_INIT(clkin1.childnode), 34}; 35 36struct pll_data c6x_soc_pll1 = { 37 .num = 1, 38 .sysclks = { 39 { 40 .name = "pll1", 41 .parent = &clkin1, 42 .pll_data = &c6x_soc_pll1, 43 .flags = CLK_PLL, 44 }, 45 { 46 .name = "pll1_sysclk1", 47 .parent = &c6x_soc_pll1.sysclks[0], 48 .flags = CLK_PLL, 49 }, 50 { 51 .name = "pll1_sysclk2", 52 .parent = &c6x_soc_pll1.sysclks[0], 53 .flags = CLK_PLL, 54 }, 55 { 56 .name = "pll1_sysclk3", 57 .parent = &c6x_soc_pll1.sysclks[0], 58 .flags = CLK_PLL, 59 }, 60 { 61 .name = "pll1_sysclk4", 62 .parent = &c6x_soc_pll1.sysclks[0], 63 .flags = CLK_PLL, 64 }, 65 { 66 .name = "pll1_sysclk5", 67 .parent = &c6x_soc_pll1.sysclks[0], 68 .flags = CLK_PLL, 69 }, 70 { 71 .name = "pll1_sysclk6", 72 .parent = &c6x_soc_pll1.sysclks[0], 73 .flags = CLK_PLL, 74 }, 75 { 76 .name = "pll1_sysclk7", 77 .parent = &c6x_soc_pll1.sysclks[0], 78 .flags = CLK_PLL, 79 }, 80 { 81 .name = "pll1_sysclk8", 82 .parent = &c6x_soc_pll1.sysclks[0], 83 .flags = CLK_PLL, 84 }, 85 { 86 .name = "pll1_sysclk9", 87 .parent = &c6x_soc_pll1.sysclks[0], 88 .flags = CLK_PLL, 89 }, 90 { 91 .name = "pll1_sysclk10", 92 .parent = &c6x_soc_pll1.sysclks[0], 93 .flags = CLK_PLL, 94 }, 95 { 96 .name = "pll1_sysclk11", 97 .parent = &c6x_soc_pll1.sysclks[0], 98 .flags = CLK_PLL, 99 }, 100 { 101 .name = "pll1_sysclk12", 102 .parent = &c6x_soc_pll1.sysclks[0], 103 .flags = CLK_PLL, 104 }, 105 { 106 .name = "pll1_sysclk13", 107 .parent = &c6x_soc_pll1.sysclks[0], 108 .flags = CLK_PLL, 109 }, 110 { 111 .name = "pll1_sysclk14", 112 .parent = &c6x_soc_pll1.sysclks[0], 113 .flags = CLK_PLL, 114 }, 115 { 116 .name = "pll1_sysclk15", 117 .parent = &c6x_soc_pll1.sysclks[0], 118 .flags = CLK_PLL, 119 }, 120 { 121 .name = "pll1_sysclk16", 122 .parent = &c6x_soc_pll1.sysclks[0], 123 .flags = CLK_PLL, 124 }, 125 }, 126}; 127 128/* CPU core clock */ 129struct clk c6x_core_clk = { 130 .name = "core", 131}; 132 133/* miscellaneous IO clocks */ 134struct clk c6x_i2c_clk = { 135 .name = "i2c", 136}; 137 138struct clk c6x_watchdog_clk = { 139 .name = "watchdog", 140}; 141 142struct clk c6x_mcbsp1_clk = { 143 .name = "mcbsp1", 144}; 145 146struct clk c6x_mcbsp2_clk = { 147 .name = "mcbsp2", 148}; 149 150struct clk c6x_mdio_clk = { 151 .name = "mdio", 152}; 153 154 155#ifdef CONFIG_SOC_TMS320C6455 156static struct clk_lookup c6455_clks[] = { 157 CLK(NULL, "pll1", &c6x_soc_pll1.sysclks[0]), 158 CLK(NULL, "pll1_sysclk2", &c6x_soc_pll1.sysclks[2]), 159 CLK(NULL, "pll1_sysclk3", &c6x_soc_pll1.sysclks[3]), 160 CLK(NULL, "pll1_sysclk4", &c6x_soc_pll1.sysclks[4]), 161 CLK(NULL, "pll1_sysclk5", &c6x_soc_pll1.sysclks[5]), 162 CLK(NULL, "core", &c6x_core_clk), 163 CLK("i2c_davinci.1", NULL, &c6x_i2c_clk), 164 CLK("watchdog", NULL, &c6x_watchdog_clk), 165 CLK("2c81800.mdio", NULL, &c6x_mdio_clk), 166 CLK("", NULL, NULL) 167}; 168 169 170static void __init c6455_setup_clocks(struct device_node *node) 171{ 172 struct pll_data *pll = &c6x_soc_pll1; 173 struct clk *sysclks = pll->sysclks; 174 175 pll->flags = PLL_HAS_PRE | PLL_HAS_MUL; 176 177 sysclks[2].flags |= FIXED_DIV_PLL; 178 sysclks[2].div = 3; 179 sysclks[3].flags |= FIXED_DIV_PLL; 180 sysclks[3].div = 6; 181 sysclks[4].div = PLLDIV4; 182 sysclks[5].div = PLLDIV5; 183 184 c6x_core_clk.parent = &sysclks[0]; 185 c6x_i2c_clk.parent = &sysclks[3]; 186 c6x_watchdog_clk.parent = &sysclks[3]; 187 c6x_mdio_clk.parent = &sysclks[3]; 188 189 c6x_clks_init(c6455_clks); 190} 191#endif /* CONFIG_SOC_TMS320C6455 */ 192 193#ifdef CONFIG_SOC_TMS320C6457 194static struct clk_lookup c6457_clks[] = { 195 CLK(NULL, "pll1", &c6x_soc_pll1.sysclks[0]), 196 CLK(NULL, "pll1_sysclk1", &c6x_soc_pll1.sysclks[1]), 197 CLK(NULL, "pll1_sysclk2", &c6x_soc_pll1.sysclks[2]), 198 CLK(NULL, "pll1_sysclk3", &c6x_soc_pll1.sysclks[3]), 199 CLK(NULL, "pll1_sysclk4", &c6x_soc_pll1.sysclks[4]), 200 CLK(NULL, "pll1_sysclk5", &c6x_soc_pll1.sysclks[5]), 201 CLK(NULL, "core", &c6x_core_clk), 202 CLK("i2c_davinci.1", NULL, &c6x_i2c_clk), 203 CLK("watchdog", NULL, &c6x_watchdog_clk), 204 CLK("2c81800.mdio", NULL, &c6x_mdio_clk), 205 CLK("", NULL, NULL) 206}; 207 208static void __init c6457_setup_clocks(struct device_node *node) 209{ 210 struct pll_data *pll = &c6x_soc_pll1; 211 struct clk *sysclks = pll->sysclks; 212 213 pll->flags = PLL_HAS_MUL | PLL_HAS_POST; 214 215 sysclks[1].flags |= FIXED_DIV_PLL; 216 sysclks[1].div = 1; 217 sysclks[2].flags |= FIXED_DIV_PLL; 218 sysclks[2].div = 3; 219 sysclks[3].flags |= FIXED_DIV_PLL; 220 sysclks[3].div = 6; 221 sysclks[4].div = PLLDIV4; 222 sysclks[5].div = PLLDIV5; 223 224 c6x_core_clk.parent = &sysclks[1]; 225 c6x_i2c_clk.parent = &sysclks[3]; 226 c6x_watchdog_clk.parent = &sysclks[5]; 227 c6x_mdio_clk.parent = &sysclks[5]; 228 229 c6x_clks_init(c6457_clks); 230} 231#endif /* CONFIG_SOC_TMS320C6455 */ 232 233#ifdef CONFIG_SOC_TMS320C6472 234static struct clk_lookup c6472_clks[] = { 235 CLK(NULL, "pll1", &c6x_soc_pll1.sysclks[0]), 236 CLK(NULL, "pll1_sysclk1", &c6x_soc_pll1.sysclks[1]), 237 CLK(NULL, "pll1_sysclk2", &c6x_soc_pll1.sysclks[2]), 238 CLK(NULL, "pll1_sysclk3", &c6x_soc_pll1.sysclks[3]), 239 CLK(NULL, "pll1_sysclk4", &c6x_soc_pll1.sysclks[4]), 240 CLK(NULL, "pll1_sysclk5", &c6x_soc_pll1.sysclks[5]), 241 CLK(NULL, "pll1_sysclk6", &c6x_soc_pll1.sysclks[6]), 242 CLK(NULL, "pll1_sysclk7", &c6x_soc_pll1.sysclks[7]), 243 CLK(NULL, "pll1_sysclk8", &c6x_soc_pll1.sysclks[8]), 244 CLK(NULL, "pll1_sysclk9", &c6x_soc_pll1.sysclks[9]), 245 CLK(NULL, "pll1_sysclk10", &c6x_soc_pll1.sysclks[10]), 246 CLK(NULL, "core", &c6x_core_clk), 247 CLK("i2c_davinci.1", NULL, &c6x_i2c_clk), 248 CLK("watchdog", NULL, &c6x_watchdog_clk), 249 CLK("2c81800.mdio", NULL, &c6x_mdio_clk), 250 CLK("", NULL, NULL) 251}; 252 253/* assumptions used for delay loop calculations */ 254#define MIN_CLKIN1_KHz 15625 255#define MAX_CORE_KHz 700000 256#define MIN_PLLOUT_KHz MIN_CLKIN1_KHz 257 258static void __init c6472_setup_clocks(struct device_node *node) 259{ 260 struct pll_data *pll = &c6x_soc_pll1; 261 struct clk *sysclks = pll->sysclks; 262 int i; 263 264 pll->flags = PLL_HAS_MUL; 265 266 for (i = 1; i <= 6; i++) { 267 sysclks[i].flags |= FIXED_DIV_PLL; 268 sysclks[i].div = 1; 269 } 270 271 sysclks[7].flags |= FIXED_DIV_PLL; 272 sysclks[7].div = 3; 273 sysclks[8].flags |= FIXED_DIV_PLL; 274 sysclks[8].div = 6; 275 sysclks[9].flags |= FIXED_DIV_PLL; 276 sysclks[9].div = 2; 277 sysclks[10].div = PLLDIV10; 278 279 c6x_core_clk.parent = &sysclks[get_coreid() + 1]; 280 c6x_i2c_clk.parent = &sysclks[8]; 281 c6x_watchdog_clk.parent = &sysclks[8]; 282 c6x_mdio_clk.parent = &sysclks[5]; 283 284 c6x_clks_init(c6472_clks); 285} 286#endif /* CONFIG_SOC_TMS320C6472 */ 287 288 289#ifdef CONFIG_SOC_TMS320C6474 290static struct clk_lookup c6474_clks[] = { 291 CLK(NULL, "pll1", &c6x_soc_pll1.sysclks[0]), 292 CLK(NULL, "pll1_sysclk7", &c6x_soc_pll1.sysclks[7]), 293 CLK(NULL, "pll1_sysclk9", &c6x_soc_pll1.sysclks[9]), 294 CLK(NULL, "pll1_sysclk10", &c6x_soc_pll1.sysclks[10]), 295 CLK(NULL, "pll1_sysclk11", &c6x_soc_pll1.sysclks[11]), 296 CLK(NULL, "pll1_sysclk12", &c6x_soc_pll1.sysclks[12]), 297 CLK(NULL, "pll1_sysclk13", &c6x_soc_pll1.sysclks[13]), 298 CLK(NULL, "core", &c6x_core_clk), 299 CLK("i2c_davinci.1", NULL, &c6x_i2c_clk), 300 CLK("mcbsp.1", NULL, &c6x_mcbsp1_clk), 301 CLK("mcbsp.2", NULL, &c6x_mcbsp2_clk), 302 CLK("watchdog", NULL, &c6x_watchdog_clk), 303 CLK("2c81800.mdio", NULL, &c6x_mdio_clk), 304 CLK("", NULL, NULL) 305}; 306 307static void __init c6474_setup_clocks(struct device_node *node) 308{ 309 struct pll_data *pll = &c6x_soc_pll1; 310 struct clk *sysclks = pll->sysclks; 311 312 pll->flags = PLL_HAS_MUL; 313 314 sysclks[7].flags |= FIXED_DIV_PLL; 315 sysclks[7].div = 1; 316 sysclks[9].flags |= FIXED_DIV_PLL; 317 sysclks[9].div = 3; 318 sysclks[10].flags |= FIXED_DIV_PLL; 319 sysclks[10].div = 6; 320 321 sysclks[11].div = PLLDIV11; 322 323 sysclks[12].flags |= FIXED_DIV_PLL; 324 sysclks[12].div = 2; 325 326 sysclks[13].div = PLLDIV13; 327 328 c6x_core_clk.parent = &sysclks[7]; 329 c6x_i2c_clk.parent = &sysclks[10]; 330 c6x_watchdog_clk.parent = &sysclks[10]; 331 c6x_mcbsp1_clk.parent = &sysclks[10]; 332 c6x_mcbsp2_clk.parent = &sysclks[10]; 333 334 c6x_clks_init(c6474_clks); 335} 336#endif /* CONFIG_SOC_TMS320C6474 */ 337 338#ifdef CONFIG_SOC_TMS320C6678 339static struct clk_lookup c6678_clks[] = { 340 CLK(NULL, "pll1", &c6x_soc_pll1.sysclks[0]), 341 CLK(NULL, "pll1_refclk", &c6x_soc_pll1.sysclks[1]), 342 CLK(NULL, "pll1_sysclk2", &c6x_soc_pll1.sysclks[2]), 343 CLK(NULL, "pll1_sysclk3", &c6x_soc_pll1.sysclks[3]), 344 CLK(NULL, "pll1_sysclk4", &c6x_soc_pll1.sysclks[4]), 345 CLK(NULL, "pll1_sysclk5", &c6x_soc_pll1.sysclks[5]), 346 CLK(NULL, "pll1_sysclk6", &c6x_soc_pll1.sysclks[6]), 347 CLK(NULL, "pll1_sysclk7", &c6x_soc_pll1.sysclks[7]), 348 CLK(NULL, "pll1_sysclk8", &c6x_soc_pll1.sysclks[8]), 349 CLK(NULL, "pll1_sysclk9", &c6x_soc_pll1.sysclks[9]), 350 CLK(NULL, "pll1_sysclk10", &c6x_soc_pll1.sysclks[10]), 351 CLK(NULL, "pll1_sysclk11", &c6x_soc_pll1.sysclks[11]), 352 CLK(NULL, "core", &c6x_core_clk), 353 CLK("", NULL, NULL) 354}; 355 356static void __init c6678_setup_clocks(struct device_node *node) 357{ 358 struct pll_data *pll = &c6x_soc_pll1; 359 struct clk *sysclks = pll->sysclks; 360 361 pll->flags = PLL_HAS_MUL; 362 363 sysclks[1].flags |= FIXED_DIV_PLL; 364 sysclks[1].div = 1; 365 366 sysclks[2].div = PLLDIV2; 367 368 sysclks[3].flags |= FIXED_DIV_PLL; 369 sysclks[3].div = 2; 370 371 sysclks[4].flags |= FIXED_DIV_PLL; 372 sysclks[4].div = 3; 373 374 sysclks[5].div = PLLDIV5; 375 376 sysclks[6].flags |= FIXED_DIV_PLL; 377 sysclks[6].div = 64; 378 379 sysclks[7].flags |= FIXED_DIV_PLL; 380 sysclks[7].div = 6; 381 382 sysclks[8].div = PLLDIV8; 383 384 sysclks[9].flags |= FIXED_DIV_PLL; 385 sysclks[9].div = 12; 386 387 sysclks[10].flags |= FIXED_DIV_PLL; 388 sysclks[10].div = 3; 389 390 sysclks[11].flags |= FIXED_DIV_PLL; 391 sysclks[11].div = 6; 392 393 c6x_core_clk.parent = &sysclks[0]; 394 c6x_i2c_clk.parent = &sysclks[7]; 395 396 c6x_clks_init(c6678_clks); 397} 398#endif /* CONFIG_SOC_TMS320C6678 */ 399 400static struct of_device_id c6x_clkc_match[] __initdata = { 401#ifdef CONFIG_SOC_TMS320C6455 402 { .compatible = "ti,c6455-pll", .data = c6455_setup_clocks }, 403#endif 404#ifdef CONFIG_SOC_TMS320C6457 405 { .compatible = "ti,c6457-pll", .data = c6457_setup_clocks }, 406#endif 407#ifdef CONFIG_SOC_TMS320C6472 408 { .compatible = "ti,c6472-pll", .data = c6472_setup_clocks }, 409#endif 410#ifdef CONFIG_SOC_TMS320C6474 411 { .compatible = "ti,c6474-pll", .data = c6474_setup_clocks }, 412#endif 413#ifdef CONFIG_SOC_TMS320C6678 414 { .compatible = "ti,c6678-pll", .data = c6678_setup_clocks }, 415#endif 416 { .compatible = "ti,c64x+pll" }, 417 {} 418}; 419 420void __init c64x_setup_clocks(void) 421{ 422 void (*__setup_clocks)(struct device_node *np); 423 struct pll_data *pll = &c6x_soc_pll1; 424 struct device_node *node; 425 const struct of_device_id *id; 426 int err; 427 u32 val; 428 429 node = of_find_matching_node(NULL, c6x_clkc_match); 430 if (!node) 431 return; 432 433 pll->base = of_iomap(node, 0); 434 if (!pll->base) 435 goto out; 436 437 err = of_property_read_u32(node, "clock-frequency", &val); 438 if (err || val == 0) { 439 pr_err("%s: no clock-frequency found! Using %dMHz\n", 440 node->full_name, (int)val / 1000000); 441 val = 25000000; 442 } 443 clkin1.rate = val; 444 445 err = of_property_read_u32(node, "ti,c64x+pll-bypass-delay", &val); 446 if (err) 447 val = 5000; 448 pll->bypass_delay = val; 449 450 err = of_property_read_u32(node, "ti,c64x+pll-reset-delay", &val); 451 if (err) 452 val = 30000; 453 pll->reset_delay = val; 454 455 err = of_property_read_u32(node, "ti,c64x+pll-lock-delay", &val); 456 if (err) 457 val = 30000; 458 pll->lock_delay = val; 459 460 /* id->data is a pointer to SoC-specific setup */ 461 id = of_match_node(c6x_clkc_match, node); 462 if (id && id->data) { 463 __setup_clocks = id->data; 464 __setup_clocks(node); 465 } 466 467out: 468 of_node_put(node); 469} 470