1 /* 2 * Copyright (c) 2014 Marvell Technology Group Ltd. 3 * 4 * Sebastian Hesselbarth <sebastian.hesselbarth@gmail.com> 5 * Alexandre Belloni <alexandre.belloni@free-electrons.com> 6 * 7 * This program is free software; you can redistribute it and/or modify it 8 * under the terms and conditions of the GNU General Public License, 9 * version 2, as published by the Free Software Foundation. 10 * 11 * This program is distributed in the hope it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for 14 * more details. 15 * 16 * You should have received a copy of the GNU General Public License along with 17 * this program. If not, see <http://www.gnu.org/licenses/>. 18 */ 19 20 #include <linux/clk.h> 21 #include <linux/clk-provider.h> 22 #include <linux/kernel.h> 23 #include <linux/of.h> 24 #include <linux/of_address.h> 25 #include <linux/slab.h> 26 27 #include <dt-bindings/clock/berlin2.h> 28 29 #include "berlin2-avpll.h" 30 #include "berlin2-div.h" 31 #include "berlin2-pll.h" 32 #include "common.h" 33 34 #define REG_PINMUX0 0x0000 35 #define REG_PINMUX1 0x0004 36 #define REG_SYSPLLCTL0 0x0014 37 #define REG_SYSPLLCTL4 0x0024 38 #define REG_MEMPLLCTL0 0x0028 39 #define REG_MEMPLLCTL4 0x0038 40 #define REG_CPUPLLCTL0 0x003c 41 #define REG_CPUPLLCTL4 0x004c 42 #define REG_AVPLLCTL0 0x0050 43 #define REG_AVPLLCTL31 0x00cc 44 #define REG_AVPLLCTL62 0x0148 45 #define REG_PLLSTATUS 0x014c 46 #define REG_CLKENABLE 0x0150 47 #define REG_CLKSELECT0 0x0154 48 #define REG_CLKSELECT1 0x0158 49 #define REG_CLKSELECT2 0x015c 50 #define REG_CLKSELECT3 0x0160 51 #define REG_CLKSWITCH0 0x0164 52 #define REG_CLKSWITCH1 0x0168 53 #define REG_RESET_TRIGGER 0x0178 54 #define REG_RESET_STATUS0 0x017c 55 #define REG_RESET_STATUS1 0x0180 56 #define REG_SW_GENERIC0 0x0184 57 #define REG_SW_GENERIC3 0x0190 58 #define REG_PRODUCTID 0x01cc 59 #define REG_PRODUCTID_EXT 0x01d0 60 #define REG_GFX3DCORE_CLKCTL 0x022c 61 #define REG_GFX3DSYS_CLKCTL 0x0230 62 #define REG_ARC_CLKCTL 0x0234 63 #define REG_VIP_CLKCTL 0x0238 64 #define REG_SDIO0XIN_CLKCTL 0x023c 65 #define REG_SDIO1XIN_CLKCTL 0x0240 66 #define REG_GFX3DEXTRA_CLKCTL 0x0244 67 #define REG_GFX3D_RESET 0x0248 68 #define REG_GC360_CLKCTL 0x024c 69 #define REG_SDIO_DLLMST_CLKCTL 0x0250 70 71 /* 72 * BG2/BG2CD SoCs have the following audio/video I/O units: 73 * 74 * audiohd: HDMI TX audio 75 * audio0: 7.1ch TX 76 * audio1: 2ch TX 77 * audio2: 2ch RX 78 * audio3: SPDIF TX 79 * video0: HDMI video 80 * video1: Secondary video 81 * video2: SD auxiliary video 82 * 83 * There are no external audio clocks (ACLKI0, ACLKI1) and 84 * only one external video clock (VCLKI0). 85 * 86 * Currently missing bits and pieces: 87 * - audio_fast_pll is unknown 88 * - audiohd_pll is unknown 89 * - video0_pll is unknown 90 * - audio[023], audiohd parent pll is assumed to be audio_fast_pll 91 * 92 */ 93 94 #define MAX_CLKS 41 95 static struct clk_hw_onecell_data *clk_data; 96 static DEFINE_SPINLOCK(lock); 97 static void __iomem *gbase; 98 99 enum { 100 REFCLK, VIDEO_EXT0, 101 SYSPLL, MEMPLL, CPUPLL, 102 AVPLL_A1, AVPLL_A2, AVPLL_A3, AVPLL_A4, 103 AVPLL_A5, AVPLL_A6, AVPLL_A7, AVPLL_A8, 104 AVPLL_B1, AVPLL_B2, AVPLL_B3, AVPLL_B4, 105 AVPLL_B5, AVPLL_B6, AVPLL_B7, AVPLL_B8, 106 AUDIO1_PLL, AUDIO_FAST_PLL, 107 VIDEO0_PLL, VIDEO0_IN, 108 VIDEO1_PLL, VIDEO1_IN, 109 VIDEO2_PLL, VIDEO2_IN, 110 }; 111 112 static const char *clk_names[] = { 113 [REFCLK] = "refclk", 114 [VIDEO_EXT0] = "video_ext0", 115 [SYSPLL] = "syspll", 116 [MEMPLL] = "mempll", 117 [CPUPLL] = "cpupll", 118 [AVPLL_A1] = "avpll_a1", 119 [AVPLL_A2] = "avpll_a2", 120 [AVPLL_A3] = "avpll_a3", 121 [AVPLL_A4] = "avpll_a4", 122 [AVPLL_A5] = "avpll_a5", 123 [AVPLL_A6] = "avpll_a6", 124 [AVPLL_A7] = "avpll_a7", 125 [AVPLL_A8] = "avpll_a8", 126 [AVPLL_B1] = "avpll_b1", 127 [AVPLL_B2] = "avpll_b2", 128 [AVPLL_B3] = "avpll_b3", 129 [AVPLL_B4] = "avpll_b4", 130 [AVPLL_B5] = "avpll_b5", 131 [AVPLL_B6] = "avpll_b6", 132 [AVPLL_B7] = "avpll_b7", 133 [AVPLL_B8] = "avpll_b8", 134 [AUDIO1_PLL] = "audio1_pll", 135 [AUDIO_FAST_PLL] = "audio_fast_pll", 136 [VIDEO0_PLL] = "video0_pll", 137 [VIDEO0_IN] = "video0_in", 138 [VIDEO1_PLL] = "video1_pll", 139 [VIDEO1_IN] = "video1_in", 140 [VIDEO2_PLL] = "video2_pll", 141 [VIDEO2_IN] = "video2_in", 142 }; 143 144 static const struct berlin2_pll_map bg2_pll_map __initconst = { 145 .vcodiv = {10, 15, 20, 25, 30, 40, 50, 60, 80}, 146 .mult = 10, 147 .fbdiv_shift = 6, 148 .rfdiv_shift = 1, 149 .divsel_shift = 7, 150 }; 151 152 static const u8 default_parent_ids[] = { 153 SYSPLL, AVPLL_B4, AVPLL_A5, AVPLL_B6, AVPLL_B7, SYSPLL 154 }; 155 156 static const struct berlin2_div_data bg2_divs[] __initconst = { 157 { 158 .name = "sys", 159 .parent_ids = (const u8 []){ 160 SYSPLL, AVPLL_B4, AVPLL_B5, AVPLL_B6, AVPLL_B7, SYSPLL 161 }, 162 .num_parents = 6, 163 .map = { 164 BERLIN2_DIV_GATE(REG_CLKENABLE, 0), 165 BERLIN2_PLL_SELECT(REG_CLKSELECT0, 0), 166 BERLIN2_DIV_SELECT(REG_CLKSELECT0, 3), 167 BERLIN2_PLL_SWITCH(REG_CLKSWITCH0, 3), 168 BERLIN2_DIV_SWITCH(REG_CLKSWITCH0, 4), 169 BERLIN2_DIV_D3SWITCH(REG_CLKSWITCH0, 5), 170 }, 171 .div_flags = BERLIN2_DIV_HAS_GATE | BERLIN2_DIV_HAS_MUX, 172 .flags = CLK_IGNORE_UNUSED, 173 }, 174 { 175 .name = "cpu", 176 .parent_ids = (const u8 []){ 177 CPUPLL, MEMPLL, MEMPLL, MEMPLL, MEMPLL 178 }, 179 .num_parents = 5, 180 .map = { 181 BERLIN2_PLL_SELECT(REG_CLKSELECT0, 6), 182 BERLIN2_DIV_SELECT(REG_CLKSELECT0, 9), 183 BERLIN2_PLL_SWITCH(REG_CLKSWITCH0, 6), 184 BERLIN2_DIV_SWITCH(REG_CLKSWITCH0, 7), 185 BERLIN2_DIV_D3SWITCH(REG_CLKSWITCH0, 8), 186 }, 187 .div_flags = BERLIN2_DIV_HAS_MUX, 188 .flags = 0, 189 }, 190 { 191 .name = "drmfigo", 192 .parent_ids = default_parent_ids, 193 .num_parents = ARRAY_SIZE(default_parent_ids), 194 .map = { 195 BERLIN2_DIV_GATE(REG_CLKENABLE, 16), 196 BERLIN2_PLL_SELECT(REG_CLKSELECT0, 17), 197 BERLIN2_DIV_SELECT(REG_CLKSELECT0, 20), 198 BERLIN2_PLL_SWITCH(REG_CLKSWITCH0, 12), 199 BERLIN2_DIV_SWITCH(REG_CLKSWITCH0, 13), 200 BERLIN2_DIV_D3SWITCH(REG_CLKSWITCH0, 14), 201 }, 202 .div_flags = BERLIN2_DIV_HAS_GATE | BERLIN2_DIV_HAS_MUX, 203 .flags = 0, 204 }, 205 { 206 .name = "cfg", 207 .parent_ids = default_parent_ids, 208 .num_parents = ARRAY_SIZE(default_parent_ids), 209 .map = { 210 BERLIN2_DIV_GATE(REG_CLKENABLE, 1), 211 BERLIN2_PLL_SELECT(REG_CLKSELECT0, 23), 212 BERLIN2_DIV_SELECT(REG_CLKSELECT0, 26), 213 BERLIN2_PLL_SWITCH(REG_CLKSWITCH0, 15), 214 BERLIN2_DIV_SWITCH(REG_CLKSWITCH0, 16), 215 BERLIN2_DIV_D3SWITCH(REG_CLKSWITCH0, 17), 216 }, 217 .div_flags = BERLIN2_DIV_HAS_GATE | BERLIN2_DIV_HAS_MUX, 218 .flags = 0, 219 }, 220 { 221 .name = "gfx", 222 .parent_ids = default_parent_ids, 223 .num_parents = ARRAY_SIZE(default_parent_ids), 224 .map = { 225 BERLIN2_DIV_GATE(REG_CLKENABLE, 4), 226 BERLIN2_PLL_SELECT(REG_CLKSELECT0, 29), 227 BERLIN2_DIV_SELECT(REG_CLKSELECT1, 0), 228 BERLIN2_PLL_SWITCH(REG_CLKSWITCH0, 18), 229 BERLIN2_DIV_SWITCH(REG_CLKSWITCH0, 19), 230 BERLIN2_DIV_D3SWITCH(REG_CLKSWITCH0, 20), 231 }, 232 .div_flags = BERLIN2_DIV_HAS_GATE | BERLIN2_DIV_HAS_MUX, 233 .flags = 0, 234 }, 235 { 236 .name = "zsp", 237 .parent_ids = default_parent_ids, 238 .num_parents = ARRAY_SIZE(default_parent_ids), 239 .map = { 240 BERLIN2_DIV_GATE(REG_CLKENABLE, 5), 241 BERLIN2_PLL_SELECT(REG_CLKSELECT1, 3), 242 BERLIN2_DIV_SELECT(REG_CLKSELECT1, 6), 243 BERLIN2_PLL_SWITCH(REG_CLKSWITCH0, 21), 244 BERLIN2_DIV_SWITCH(REG_CLKSWITCH0, 22), 245 BERLIN2_DIV_D3SWITCH(REG_CLKSWITCH0, 23), 246 }, 247 .div_flags = BERLIN2_DIV_HAS_GATE | BERLIN2_DIV_HAS_MUX, 248 .flags = 0, 249 }, 250 { 251 .name = "perif", 252 .parent_ids = default_parent_ids, 253 .num_parents = ARRAY_SIZE(default_parent_ids), 254 .map = { 255 BERLIN2_DIV_GATE(REG_CLKENABLE, 6), 256 BERLIN2_PLL_SELECT(REG_CLKSELECT1, 9), 257 BERLIN2_DIV_SELECT(REG_CLKSELECT1, 12), 258 BERLIN2_PLL_SWITCH(REG_CLKSWITCH0, 24), 259 BERLIN2_DIV_SWITCH(REG_CLKSWITCH0, 25), 260 BERLIN2_DIV_D3SWITCH(REG_CLKSWITCH0, 26), 261 }, 262 .div_flags = BERLIN2_DIV_HAS_GATE | BERLIN2_DIV_HAS_MUX, 263 .flags = CLK_IGNORE_UNUSED, 264 }, 265 { 266 .name = "pcube", 267 .parent_ids = default_parent_ids, 268 .num_parents = ARRAY_SIZE(default_parent_ids), 269 .map = { 270 BERLIN2_DIV_GATE(REG_CLKENABLE, 2), 271 BERLIN2_PLL_SELECT(REG_CLKSELECT1, 15), 272 BERLIN2_DIV_SELECT(REG_CLKSELECT1, 18), 273 BERLIN2_PLL_SWITCH(REG_CLKSWITCH0, 27), 274 BERLIN2_DIV_SWITCH(REG_CLKSWITCH0, 28), 275 BERLIN2_DIV_D3SWITCH(REG_CLKSWITCH0, 29), 276 }, 277 .div_flags = BERLIN2_DIV_HAS_GATE | BERLIN2_DIV_HAS_MUX, 278 .flags = 0, 279 }, 280 { 281 .name = "vscope", 282 .parent_ids = default_parent_ids, 283 .num_parents = ARRAY_SIZE(default_parent_ids), 284 .map = { 285 BERLIN2_DIV_GATE(REG_CLKENABLE, 3), 286 BERLIN2_PLL_SELECT(REG_CLKSELECT1, 21), 287 BERLIN2_DIV_SELECT(REG_CLKSELECT1, 24), 288 BERLIN2_PLL_SWITCH(REG_CLKSWITCH0, 30), 289 BERLIN2_DIV_SWITCH(REG_CLKSWITCH0, 31), 290 BERLIN2_DIV_D3SWITCH(REG_CLKSWITCH1, 0), 291 }, 292 .div_flags = BERLIN2_DIV_HAS_GATE | BERLIN2_DIV_HAS_MUX, 293 .flags = 0, 294 }, 295 { 296 .name = "nfc_ecc", 297 .parent_ids = default_parent_ids, 298 .num_parents = ARRAY_SIZE(default_parent_ids), 299 .map = { 300 BERLIN2_DIV_GATE(REG_CLKENABLE, 18), 301 BERLIN2_PLL_SELECT(REG_CLKSELECT1, 27), 302 BERLIN2_DIV_SELECT(REG_CLKSELECT2, 0), 303 BERLIN2_PLL_SWITCH(REG_CLKSWITCH1, 1), 304 BERLIN2_DIV_SWITCH(REG_CLKSWITCH1, 2), 305 BERLIN2_DIV_D3SWITCH(REG_CLKSWITCH1, 3), 306 }, 307 .div_flags = BERLIN2_DIV_HAS_GATE | BERLIN2_DIV_HAS_MUX, 308 .flags = 0, 309 }, 310 { 311 .name = "vpp", 312 .parent_ids = default_parent_ids, 313 .num_parents = ARRAY_SIZE(default_parent_ids), 314 .map = { 315 BERLIN2_DIV_GATE(REG_CLKENABLE, 21), 316 BERLIN2_PLL_SELECT(REG_CLKSELECT2, 3), 317 BERLIN2_DIV_SELECT(REG_CLKSELECT2, 6), 318 BERLIN2_PLL_SWITCH(REG_CLKSWITCH1, 4), 319 BERLIN2_DIV_SWITCH(REG_CLKSWITCH1, 5), 320 BERLIN2_DIV_D3SWITCH(REG_CLKSWITCH1, 6), 321 }, 322 .div_flags = BERLIN2_DIV_HAS_GATE | BERLIN2_DIV_HAS_MUX, 323 .flags = 0, 324 }, 325 { 326 .name = "app", 327 .parent_ids = default_parent_ids, 328 .num_parents = ARRAY_SIZE(default_parent_ids), 329 .map = { 330 BERLIN2_DIV_GATE(REG_CLKENABLE, 20), 331 BERLIN2_PLL_SELECT(REG_CLKSELECT2, 9), 332 BERLIN2_DIV_SELECT(REG_CLKSELECT2, 12), 333 BERLIN2_PLL_SWITCH(REG_CLKSWITCH1, 7), 334 BERLIN2_DIV_SWITCH(REG_CLKSWITCH1, 8), 335 BERLIN2_DIV_D3SWITCH(REG_CLKSWITCH1, 9), 336 }, 337 .div_flags = BERLIN2_DIV_HAS_GATE | BERLIN2_DIV_HAS_MUX, 338 .flags = 0, 339 }, 340 { 341 .name = "audio0", 342 .parent_ids = (const u8 []){ AUDIO_FAST_PLL }, 343 .num_parents = 1, 344 .map = { 345 BERLIN2_DIV_GATE(REG_CLKENABLE, 22), 346 BERLIN2_DIV_SELECT(REG_CLKSELECT2, 17), 347 BERLIN2_DIV_SWITCH(REG_CLKSWITCH1, 10), 348 BERLIN2_DIV_D3SWITCH(REG_CLKSWITCH1, 11), 349 }, 350 .div_flags = BERLIN2_DIV_HAS_GATE, 351 .flags = 0, 352 }, 353 { 354 .name = "audio2", 355 .parent_ids = (const u8 []){ AUDIO_FAST_PLL }, 356 .num_parents = 1, 357 .map = { 358 BERLIN2_DIV_GATE(REG_CLKENABLE, 24), 359 BERLIN2_DIV_SELECT(REG_CLKSELECT2, 20), 360 BERLIN2_DIV_SWITCH(REG_CLKSWITCH1, 14), 361 BERLIN2_DIV_D3SWITCH(REG_CLKSWITCH1, 15), 362 }, 363 .div_flags = BERLIN2_DIV_HAS_GATE, 364 .flags = 0, 365 }, 366 { 367 .name = "audio3", 368 .parent_ids = (const u8 []){ AUDIO_FAST_PLL }, 369 .num_parents = 1, 370 .map = { 371 BERLIN2_DIV_GATE(REG_CLKENABLE, 25), 372 BERLIN2_DIV_SELECT(REG_CLKSELECT2, 23), 373 BERLIN2_DIV_SWITCH(REG_CLKSWITCH1, 16), 374 BERLIN2_DIV_D3SWITCH(REG_CLKSWITCH1, 17), 375 }, 376 .div_flags = BERLIN2_DIV_HAS_GATE, 377 .flags = 0, 378 }, 379 { 380 .name = "audio1", 381 .parent_ids = (const u8 []){ AUDIO1_PLL }, 382 .num_parents = 1, 383 .map = { 384 BERLIN2_DIV_GATE(REG_CLKENABLE, 23), 385 BERLIN2_DIV_SELECT(REG_CLKSELECT3, 0), 386 BERLIN2_DIV_SWITCH(REG_CLKSWITCH1, 12), 387 BERLIN2_DIV_D3SWITCH(REG_CLKSWITCH1, 13), 388 }, 389 .div_flags = BERLIN2_DIV_HAS_GATE, 390 .flags = 0, 391 }, 392 { 393 .name = "gfx3d_core", 394 .parent_ids = default_parent_ids, 395 .num_parents = ARRAY_SIZE(default_parent_ids), 396 .map = { 397 BERLIN2_SINGLE_DIV(REG_GFX3DCORE_CLKCTL), 398 }, 399 .div_flags = BERLIN2_DIV_HAS_GATE | BERLIN2_DIV_HAS_MUX, 400 .flags = 0, 401 }, 402 { 403 .name = "gfx3d_sys", 404 .parent_ids = default_parent_ids, 405 .num_parents = ARRAY_SIZE(default_parent_ids), 406 .map = { 407 BERLIN2_SINGLE_DIV(REG_GFX3DSYS_CLKCTL), 408 }, 409 .div_flags = BERLIN2_DIV_HAS_GATE | BERLIN2_DIV_HAS_MUX, 410 .flags = 0, 411 }, 412 { 413 .name = "arc", 414 .parent_ids = default_parent_ids, 415 .num_parents = ARRAY_SIZE(default_parent_ids), 416 .map = { 417 BERLIN2_SINGLE_DIV(REG_ARC_CLKCTL), 418 }, 419 .div_flags = BERLIN2_DIV_HAS_GATE | BERLIN2_DIV_HAS_MUX, 420 .flags = 0, 421 }, 422 { 423 .name = "vip", 424 .parent_ids = default_parent_ids, 425 .num_parents = ARRAY_SIZE(default_parent_ids), 426 .map = { 427 BERLIN2_SINGLE_DIV(REG_VIP_CLKCTL), 428 }, 429 .div_flags = BERLIN2_DIV_HAS_GATE | BERLIN2_DIV_HAS_MUX, 430 .flags = 0, 431 }, 432 { 433 .name = "sdio0xin", 434 .parent_ids = default_parent_ids, 435 .num_parents = ARRAY_SIZE(default_parent_ids), 436 .map = { 437 BERLIN2_SINGLE_DIV(REG_SDIO0XIN_CLKCTL), 438 }, 439 .div_flags = BERLIN2_DIV_HAS_GATE | BERLIN2_DIV_HAS_MUX, 440 .flags = 0, 441 }, 442 { 443 .name = "sdio1xin", 444 .parent_ids = default_parent_ids, 445 .num_parents = ARRAY_SIZE(default_parent_ids), 446 .map = { 447 BERLIN2_SINGLE_DIV(REG_SDIO1XIN_CLKCTL), 448 }, 449 .div_flags = BERLIN2_DIV_HAS_GATE | BERLIN2_DIV_HAS_MUX, 450 .flags = 0, 451 }, 452 { 453 .name = "gfx3d_extra", 454 .parent_ids = default_parent_ids, 455 .num_parents = ARRAY_SIZE(default_parent_ids), 456 .map = { 457 BERLIN2_SINGLE_DIV(REG_GFX3DEXTRA_CLKCTL), 458 }, 459 .div_flags = BERLIN2_DIV_HAS_GATE | BERLIN2_DIV_HAS_MUX, 460 .flags = 0, 461 }, 462 { 463 .name = "gc360", 464 .parent_ids = default_parent_ids, 465 .num_parents = ARRAY_SIZE(default_parent_ids), 466 .map = { 467 BERLIN2_SINGLE_DIV(REG_GC360_CLKCTL), 468 }, 469 .div_flags = BERLIN2_DIV_HAS_GATE | BERLIN2_DIV_HAS_MUX, 470 .flags = 0, 471 }, 472 { 473 .name = "sdio_dllmst", 474 .parent_ids = default_parent_ids, 475 .num_parents = ARRAY_SIZE(default_parent_ids), 476 .map = { 477 BERLIN2_SINGLE_DIV(REG_SDIO_DLLMST_CLKCTL), 478 }, 479 .div_flags = BERLIN2_DIV_HAS_GATE | BERLIN2_DIV_HAS_MUX, 480 .flags = 0, 481 }, 482 }; 483 484 static const struct berlin2_gate_data bg2_gates[] __initconst = { 485 { "geth0", "perif", 7 }, 486 { "geth1", "perif", 8 }, 487 { "sata", "perif", 9 }, 488 { "ahbapb", "perif", 10, CLK_IGNORE_UNUSED }, 489 { "usb0", "perif", 11 }, 490 { "usb1", "perif", 12 }, 491 { "pbridge", "perif", 13, CLK_IGNORE_UNUSED }, 492 { "sdio0", "perif", 14 }, 493 { "sdio1", "perif", 15 }, 494 { "nfc", "perif", 17 }, 495 { "smemc", "perif", 19 }, 496 { "audiohd", "audiohd_pll", 26 }, 497 { "video0", "video0_in", 27 }, 498 { "video1", "video1_in", 28 }, 499 { "video2", "video2_in", 29 }, 500 }; 501 502 static void __init berlin2_clock_setup(struct device_node *np) 503 { 504 struct device_node *parent_np = of_get_parent(np); 505 const char *parent_names[9]; 506 struct clk *clk; 507 struct clk_hw *hw; 508 struct clk_hw **hws; 509 u8 avpll_flags = 0; 510 int n, ret; 511 512 clk_data = kzalloc(sizeof(*clk_data) + 513 sizeof(*clk_data->hws) * MAX_CLKS, GFP_KERNEL); 514 if (!clk_data) 515 return; 516 clk_data->num = MAX_CLKS; 517 hws = clk_data->hws; 518 519 gbase = of_iomap(parent_np, 0); 520 if (!gbase) 521 return; 522 523 /* overwrite default clock names with DT provided ones */ 524 clk = of_clk_get_by_name(np, clk_names[REFCLK]); 525 if (!IS_ERR(clk)) { 526 clk_names[REFCLK] = __clk_get_name(clk); 527 clk_put(clk); 528 } 529 530 clk = of_clk_get_by_name(np, clk_names[VIDEO_EXT0]); 531 if (!IS_ERR(clk)) { 532 clk_names[VIDEO_EXT0] = __clk_get_name(clk); 533 clk_put(clk); 534 } 535 536 /* simple register PLLs */ 537 ret = berlin2_pll_register(&bg2_pll_map, gbase + REG_SYSPLLCTL0, 538 clk_names[SYSPLL], clk_names[REFCLK], 0); 539 if (ret) 540 goto bg2_fail; 541 542 ret = berlin2_pll_register(&bg2_pll_map, gbase + REG_MEMPLLCTL0, 543 clk_names[MEMPLL], clk_names[REFCLK], 0); 544 if (ret) 545 goto bg2_fail; 546 547 ret = berlin2_pll_register(&bg2_pll_map, gbase + REG_CPUPLLCTL0, 548 clk_names[CPUPLL], clk_names[REFCLK], 0); 549 if (ret) 550 goto bg2_fail; 551 552 if (of_device_is_compatible(np, "marvell,berlin2-global-register")) 553 avpll_flags |= BERLIN2_AVPLL_SCRAMBLE_QUIRK; 554 555 /* audio/video VCOs */ 556 ret = berlin2_avpll_vco_register(gbase + REG_AVPLLCTL0, "avpll_vcoA", 557 clk_names[REFCLK], avpll_flags, 0); 558 if (ret) 559 goto bg2_fail; 560 561 for (n = 0; n < 8; n++) { 562 ret = berlin2_avpll_channel_register(gbase + REG_AVPLLCTL0, 563 clk_names[AVPLL_A1 + n], n, "avpll_vcoA", 564 avpll_flags, 0); 565 if (ret) 566 goto bg2_fail; 567 } 568 569 ret = berlin2_avpll_vco_register(gbase + REG_AVPLLCTL31, "avpll_vcoB", 570 clk_names[REFCLK], BERLIN2_AVPLL_BIT_QUIRK | 571 avpll_flags, 0); 572 if (ret) 573 goto bg2_fail; 574 575 for (n = 0; n < 8; n++) { 576 ret = berlin2_avpll_channel_register(gbase + REG_AVPLLCTL31, 577 clk_names[AVPLL_B1 + n], n, "avpll_vcoB", 578 BERLIN2_AVPLL_BIT_QUIRK | avpll_flags, 0); 579 if (ret) 580 goto bg2_fail; 581 } 582 583 /* reference clock bypass switches */ 584 parent_names[0] = clk_names[SYSPLL]; 585 parent_names[1] = clk_names[REFCLK]; 586 hw = clk_hw_register_mux(NULL, "syspll_byp", parent_names, 2, 587 0, gbase + REG_CLKSWITCH0, 0, 1, 0, &lock); 588 if (IS_ERR(hw)) 589 goto bg2_fail; 590 clk_names[SYSPLL] = clk_hw_get_name(hw); 591 592 parent_names[0] = clk_names[MEMPLL]; 593 parent_names[1] = clk_names[REFCLK]; 594 hw = clk_hw_register_mux(NULL, "mempll_byp", parent_names, 2, 595 0, gbase + REG_CLKSWITCH0, 1, 1, 0, &lock); 596 if (IS_ERR(hw)) 597 goto bg2_fail; 598 clk_names[MEMPLL] = clk_hw_get_name(hw); 599 600 parent_names[0] = clk_names[CPUPLL]; 601 parent_names[1] = clk_names[REFCLK]; 602 hw = clk_hw_register_mux(NULL, "cpupll_byp", parent_names, 2, 603 0, gbase + REG_CLKSWITCH0, 2, 1, 0, &lock); 604 if (IS_ERR(hw)) 605 goto bg2_fail; 606 clk_names[CPUPLL] = clk_hw_get_name(hw); 607 608 /* clock muxes */ 609 parent_names[0] = clk_names[AVPLL_B3]; 610 parent_names[1] = clk_names[AVPLL_A3]; 611 hw = clk_hw_register_mux(NULL, clk_names[AUDIO1_PLL], parent_names, 2, 612 0, gbase + REG_CLKSELECT2, 29, 1, 0, &lock); 613 if (IS_ERR(hw)) 614 goto bg2_fail; 615 616 parent_names[0] = clk_names[VIDEO0_PLL]; 617 parent_names[1] = clk_names[VIDEO_EXT0]; 618 hw = clk_hw_register_mux(NULL, clk_names[VIDEO0_IN], parent_names, 2, 619 0, gbase + REG_CLKSELECT3, 4, 1, 0, &lock); 620 if (IS_ERR(hw)) 621 goto bg2_fail; 622 623 parent_names[0] = clk_names[VIDEO1_PLL]; 624 parent_names[1] = clk_names[VIDEO_EXT0]; 625 hw = clk_hw_register_mux(NULL, clk_names[VIDEO1_IN], parent_names, 2, 626 0, gbase + REG_CLKSELECT3, 6, 1, 0, &lock); 627 if (IS_ERR(hw)) 628 goto bg2_fail; 629 630 parent_names[0] = clk_names[AVPLL_A2]; 631 parent_names[1] = clk_names[AVPLL_B2]; 632 hw = clk_hw_register_mux(NULL, clk_names[VIDEO1_PLL], parent_names, 2, 633 0, gbase + REG_CLKSELECT3, 7, 1, 0, &lock); 634 if (IS_ERR(hw)) 635 goto bg2_fail; 636 637 parent_names[0] = clk_names[VIDEO2_PLL]; 638 parent_names[1] = clk_names[VIDEO_EXT0]; 639 hw = clk_hw_register_mux(NULL, clk_names[VIDEO2_IN], parent_names, 2, 640 0, gbase + REG_CLKSELECT3, 9, 1, 0, &lock); 641 if (IS_ERR(hw)) 642 goto bg2_fail; 643 644 parent_names[0] = clk_names[AVPLL_B1]; 645 parent_names[1] = clk_names[AVPLL_A5]; 646 hw = clk_hw_register_mux(NULL, clk_names[VIDEO2_PLL], parent_names, 2, 647 0, gbase + REG_CLKSELECT3, 10, 1, 0, &lock); 648 if (IS_ERR(hw)) 649 goto bg2_fail; 650 651 /* clock divider cells */ 652 for (n = 0; n < ARRAY_SIZE(bg2_divs); n++) { 653 const struct berlin2_div_data *dd = &bg2_divs[n]; 654 int k; 655 656 for (k = 0; k < dd->num_parents; k++) 657 parent_names[k] = clk_names[dd->parent_ids[k]]; 658 659 hws[CLKID_SYS + n] = berlin2_div_register(&dd->map, gbase, 660 dd->name, dd->div_flags, parent_names, 661 dd->num_parents, dd->flags, &lock); 662 } 663 664 /* clock gate cells */ 665 for (n = 0; n < ARRAY_SIZE(bg2_gates); n++) { 666 const struct berlin2_gate_data *gd = &bg2_gates[n]; 667 668 hws[CLKID_GETH0 + n] = clk_hw_register_gate(NULL, gd->name, 669 gd->parent_name, gd->flags, gbase + REG_CLKENABLE, 670 gd->bit_idx, 0, &lock); 671 } 672 673 /* twdclk is derived from cpu/3 */ 674 hws[CLKID_TWD] = 675 clk_hw_register_fixed_factor(NULL, "twd", "cpu", 0, 1, 3); 676 677 /* check for errors on leaf clocks */ 678 for (n = 0; n < MAX_CLKS; n++) { 679 if (!IS_ERR(hws[n])) 680 continue; 681 682 pr_err("%s: Unable to register leaf clock %d\n", 683 np->full_name, n); 684 goto bg2_fail; 685 } 686 687 /* register clk-provider */ 688 of_clk_add_hw_provider(np, of_clk_hw_onecell_get, clk_data); 689 690 return; 691 692 bg2_fail: 693 iounmap(gbase); 694 } 695 CLK_OF_DECLARE(berlin2_clk, "marvell,berlin2-clk", 696 berlin2_clock_setup); 697