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