Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

clk: berlin: add core clock driver for BG2/BG2CD

This driver deals with the core clocks found on Marvell Berlin
BG2 and BG2CD. For the shared register dividers, make use of the
corresponding driver and add some single clock muxes and gates for
the rest.

Signed-off-by: Sebastian Hesselbarth <sebastian.hesselbarth@gmail.com>
Acked-by: Alexandre Belloni <alexandre.belloni@free-electrons.com>
Signed-off-by: Mike Turquette <mturquette@linaro.org>

authored by

Sebastian Hesselbarth and committed by
Mike Turquette
ba0fae3b 6f9ba9b4

+722
+2
drivers/clk/berlin/Makefile
··· 1 1 obj-y += berlin2-avpll.o berlin2-pll.o berlin2-div.o 2 + obj-$(CONFIG_MACH_BERLIN_BG2) += bg2.o 3 + obj-$(CONFIG_MACH_BERLIN_BG2CD) += bg2.o
+691
drivers/clk/berlin/bg2.c
··· 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 *clks[MAX_CLKS]; 96 + static struct clk_onecell_data clk_data; 97 + static DEFINE_SPINLOCK(lock); 98 + static void __iomem *gbase; 99 + 100 + enum { 101 + REFCLK, VIDEO_EXT0, 102 + SYSPLL, MEMPLL, CPUPLL, 103 + AVPLL_A1, AVPLL_A2, AVPLL_A3, AVPLL_A4, 104 + AVPLL_A5, AVPLL_A6, AVPLL_A7, AVPLL_A8, 105 + AVPLL_B1, AVPLL_B2, AVPLL_B3, AVPLL_B4, 106 + AVPLL_B5, AVPLL_B6, AVPLL_B7, AVPLL_B8, 107 + AUDIO1_PLL, AUDIO_FAST_PLL, 108 + VIDEO0_PLL, VIDEO0_IN, 109 + VIDEO1_PLL, VIDEO1_IN, 110 + VIDEO2_PLL, VIDEO2_IN, 111 + }; 112 + 113 + static const char *clk_names[] = { 114 + [REFCLK] = "refclk", 115 + [VIDEO_EXT0] = "video_ext0", 116 + [SYSPLL] = "syspll", 117 + [MEMPLL] = "mempll", 118 + [CPUPLL] = "cpupll", 119 + [AVPLL_A1] = "avpll_a1", 120 + [AVPLL_A2] = "avpll_a2", 121 + [AVPLL_A3] = "avpll_a3", 122 + [AVPLL_A4] = "avpll_a4", 123 + [AVPLL_A5] = "avpll_a5", 124 + [AVPLL_A6] = "avpll_a6", 125 + [AVPLL_A7] = "avpll_a7", 126 + [AVPLL_A8] = "avpll_a8", 127 + [AVPLL_B1] = "avpll_b1", 128 + [AVPLL_B2] = "avpll_b2", 129 + [AVPLL_B3] = "avpll_b3", 130 + [AVPLL_B4] = "avpll_b4", 131 + [AVPLL_B5] = "avpll_b5", 132 + [AVPLL_B6] = "avpll_b6", 133 + [AVPLL_B7] = "avpll_b7", 134 + [AVPLL_B8] = "avpll_b8", 135 + [AUDIO1_PLL] = "audio1_pll", 136 + [AUDIO_FAST_PLL] = "audio_fast_pll", 137 + [VIDEO0_PLL] = "video0_pll", 138 + [VIDEO0_IN] = "video0_in", 139 + [VIDEO1_PLL] = "video1_pll", 140 + [VIDEO1_IN] = "video1_in", 141 + [VIDEO2_PLL] = "video2_pll", 142 + [VIDEO2_IN] = "video2_in", 143 + }; 144 + 145 + static const struct berlin2_pll_map bg2_pll_map __initconst = { 146 + .vcodiv = {10, 15, 20, 25, 30, 40, 50, 60, 80}, 147 + .mult = 10, 148 + .fbdiv_shift = 6, 149 + .rfdiv_shift = 1, 150 + .divsel_shift = 7, 151 + }; 152 + 153 + static const u8 default_parent_ids[] = { 154 + SYSPLL, AVPLL_B4, AVPLL_A5, AVPLL_B6, AVPLL_B7, SYSPLL 155 + }; 156 + 157 + static const struct berlin2_div_data bg2_divs[] __initconst = { 158 + { 159 + .name = "sys", 160 + .parent_ids = (const u8 []){ 161 + SYSPLL, AVPLL_B4, AVPLL_B5, AVPLL_B6, AVPLL_B7, SYSPLL 162 + }, 163 + .num_parents = 6, 164 + .map = { 165 + BERLIN2_DIV_GATE(REG_CLKENABLE, 0), 166 + BERLIN2_PLL_SELECT(REG_CLKSELECT0, 0), 167 + BERLIN2_DIV_SELECT(REG_CLKSELECT0, 3), 168 + BERLIN2_PLL_SWITCH(REG_CLKSWITCH0, 3), 169 + BERLIN2_DIV_SWITCH(REG_CLKSWITCH0, 4), 170 + BERLIN2_DIV_D3SWITCH(REG_CLKSWITCH0, 5), 171 + }, 172 + .div_flags = BERLIN2_DIV_HAS_GATE | BERLIN2_DIV_HAS_MUX, 173 + .flags = CLK_IGNORE_UNUSED, 174 + }, 175 + { 176 + .name = "cpu", 177 + .parent_ids = (const u8 []){ 178 + CPUPLL, MEMPLL, MEMPLL, MEMPLL, MEMPLL 179 + }, 180 + .num_parents = 5, 181 + .map = { 182 + BERLIN2_PLL_SELECT(REG_CLKSELECT0, 6), 183 + BERLIN2_DIV_SELECT(REG_CLKSELECT0, 9), 184 + BERLIN2_PLL_SWITCH(REG_CLKSWITCH0, 6), 185 + BERLIN2_DIV_SWITCH(REG_CLKSWITCH0, 7), 186 + BERLIN2_DIV_D3SWITCH(REG_CLKSWITCH0, 8), 187 + }, 188 + .div_flags = BERLIN2_DIV_HAS_MUX, 189 + .flags = 0, 190 + }, 191 + { 192 + .name = "drmfigo", 193 + .parent_ids = default_parent_ids, 194 + .num_parents = ARRAY_SIZE(default_parent_ids), 195 + .map = { 196 + BERLIN2_DIV_GATE(REG_CLKENABLE, 16), 197 + BERLIN2_PLL_SELECT(REG_CLKSELECT0, 17), 198 + BERLIN2_DIV_SELECT(REG_CLKSELECT0, 20), 199 + BERLIN2_PLL_SWITCH(REG_CLKSWITCH0, 12), 200 + BERLIN2_DIV_SWITCH(REG_CLKSWITCH0, 13), 201 + BERLIN2_DIV_D3SWITCH(REG_CLKSWITCH0, 14), 202 + }, 203 + .div_flags = BERLIN2_DIV_HAS_GATE | BERLIN2_DIV_HAS_MUX, 204 + .flags = 0, 205 + }, 206 + { 207 + .name = "cfg", 208 + .parent_ids = default_parent_ids, 209 + .num_parents = ARRAY_SIZE(default_parent_ids), 210 + .map = { 211 + BERLIN2_DIV_GATE(REG_CLKENABLE, 1), 212 + BERLIN2_PLL_SELECT(REG_CLKSELECT0, 23), 213 + BERLIN2_DIV_SELECT(REG_CLKSELECT0, 26), 214 + BERLIN2_PLL_SWITCH(REG_CLKSWITCH0, 15), 215 + BERLIN2_DIV_SWITCH(REG_CLKSWITCH0, 16), 216 + BERLIN2_DIV_D3SWITCH(REG_CLKSWITCH0, 17), 217 + }, 218 + .div_flags = BERLIN2_DIV_HAS_GATE | BERLIN2_DIV_HAS_MUX, 219 + .flags = 0, 220 + }, 221 + { 222 + .name = "gfx", 223 + .parent_ids = default_parent_ids, 224 + .num_parents = ARRAY_SIZE(default_parent_ids), 225 + .map = { 226 + BERLIN2_DIV_GATE(REG_CLKENABLE, 4), 227 + BERLIN2_PLL_SELECT(REG_CLKSELECT0, 29), 228 + BERLIN2_DIV_SELECT(REG_CLKSELECT1, 0), 229 + BERLIN2_PLL_SWITCH(REG_CLKSWITCH0, 18), 230 + BERLIN2_DIV_SWITCH(REG_CLKSWITCH0, 19), 231 + BERLIN2_DIV_D3SWITCH(REG_CLKSWITCH0, 20), 232 + }, 233 + .div_flags = BERLIN2_DIV_HAS_GATE | BERLIN2_DIV_HAS_MUX, 234 + .flags = 0, 235 + }, 236 + { 237 + .name = "zsp", 238 + .parent_ids = default_parent_ids, 239 + .num_parents = ARRAY_SIZE(default_parent_ids), 240 + .map = { 241 + BERLIN2_DIV_GATE(REG_CLKENABLE, 5), 242 + BERLIN2_PLL_SELECT(REG_CLKSELECT1, 3), 243 + BERLIN2_DIV_SELECT(REG_CLKSELECT1, 6), 244 + BERLIN2_PLL_SWITCH(REG_CLKSWITCH0, 21), 245 + BERLIN2_DIV_SWITCH(REG_CLKSWITCH0, 22), 246 + BERLIN2_DIV_D3SWITCH(REG_CLKSWITCH0, 23), 247 + }, 248 + .div_flags = BERLIN2_DIV_HAS_GATE | BERLIN2_DIV_HAS_MUX, 249 + .flags = 0, 250 + }, 251 + { 252 + .name = "perif", 253 + .parent_ids = default_parent_ids, 254 + .num_parents = ARRAY_SIZE(default_parent_ids), 255 + .map = { 256 + BERLIN2_DIV_GATE(REG_CLKENABLE, 6), 257 + BERLIN2_PLL_SELECT(REG_CLKSELECT1, 9), 258 + BERLIN2_DIV_SELECT(REG_CLKSELECT1, 12), 259 + BERLIN2_PLL_SWITCH(REG_CLKSWITCH0, 24), 260 + BERLIN2_DIV_SWITCH(REG_CLKSWITCH0, 25), 261 + BERLIN2_DIV_D3SWITCH(REG_CLKSWITCH0, 26), 262 + }, 263 + .div_flags = BERLIN2_DIV_HAS_GATE | BERLIN2_DIV_HAS_MUX, 264 + .flags = CLK_IGNORE_UNUSED, 265 + }, 266 + { 267 + .name = "pcube", 268 + .parent_ids = default_parent_ids, 269 + .num_parents = ARRAY_SIZE(default_parent_ids), 270 + .map = { 271 + BERLIN2_DIV_GATE(REG_CLKENABLE, 2), 272 + BERLIN2_PLL_SELECT(REG_CLKSELECT1, 15), 273 + BERLIN2_DIV_SELECT(REG_CLKSELECT1, 18), 274 + BERLIN2_PLL_SWITCH(REG_CLKSWITCH0, 27), 275 + BERLIN2_DIV_SWITCH(REG_CLKSWITCH0, 28), 276 + BERLIN2_DIV_D3SWITCH(REG_CLKSWITCH0, 29), 277 + }, 278 + .div_flags = BERLIN2_DIV_HAS_GATE | BERLIN2_DIV_HAS_MUX, 279 + .flags = 0, 280 + }, 281 + { 282 + .name = "vscope", 283 + .parent_ids = default_parent_ids, 284 + .num_parents = ARRAY_SIZE(default_parent_ids), 285 + .map = { 286 + BERLIN2_DIV_GATE(REG_CLKENABLE, 3), 287 + BERLIN2_PLL_SELECT(REG_CLKSELECT1, 21), 288 + BERLIN2_DIV_SELECT(REG_CLKSELECT1, 24), 289 + BERLIN2_PLL_SWITCH(REG_CLKSWITCH0, 30), 290 + BERLIN2_DIV_SWITCH(REG_CLKSWITCH0, 31), 291 + BERLIN2_DIV_D3SWITCH(REG_CLKSWITCH1, 0), 292 + }, 293 + .div_flags = BERLIN2_DIV_HAS_GATE | BERLIN2_DIV_HAS_MUX, 294 + .flags = 0, 295 + }, 296 + { 297 + .name = "nfc_ecc", 298 + .parent_ids = default_parent_ids, 299 + .num_parents = ARRAY_SIZE(default_parent_ids), 300 + .map = { 301 + BERLIN2_DIV_GATE(REG_CLKENABLE, 18), 302 + BERLIN2_PLL_SELECT(REG_CLKSELECT1, 27), 303 + BERLIN2_DIV_SELECT(REG_CLKSELECT2, 0), 304 + BERLIN2_PLL_SWITCH(REG_CLKSWITCH1, 1), 305 + BERLIN2_DIV_SWITCH(REG_CLKSWITCH1, 2), 306 + BERLIN2_DIV_D3SWITCH(REG_CLKSWITCH1, 3), 307 + }, 308 + .div_flags = BERLIN2_DIV_HAS_GATE | BERLIN2_DIV_HAS_MUX, 309 + .flags = 0, 310 + }, 311 + { 312 + .name = "vpp", 313 + .parent_ids = default_parent_ids, 314 + .num_parents = ARRAY_SIZE(default_parent_ids), 315 + .map = { 316 + BERLIN2_DIV_GATE(REG_CLKENABLE, 21), 317 + BERLIN2_PLL_SELECT(REG_CLKSELECT2, 3), 318 + BERLIN2_DIV_SELECT(REG_CLKSELECT2, 6), 319 + BERLIN2_PLL_SWITCH(REG_CLKSWITCH1, 4), 320 + BERLIN2_DIV_SWITCH(REG_CLKSWITCH1, 5), 321 + BERLIN2_DIV_D3SWITCH(REG_CLKSWITCH1, 6), 322 + }, 323 + .div_flags = BERLIN2_DIV_HAS_GATE | BERLIN2_DIV_HAS_MUX, 324 + .flags = 0, 325 + }, 326 + { 327 + .name = "app", 328 + .parent_ids = default_parent_ids, 329 + .num_parents = ARRAY_SIZE(default_parent_ids), 330 + .map = { 331 + BERLIN2_DIV_GATE(REG_CLKENABLE, 20), 332 + BERLIN2_PLL_SELECT(REG_CLKSELECT2, 9), 333 + BERLIN2_DIV_SELECT(REG_CLKSELECT2, 12), 334 + BERLIN2_PLL_SWITCH(REG_CLKSWITCH1, 7), 335 + BERLIN2_DIV_SWITCH(REG_CLKSWITCH1, 8), 336 + BERLIN2_DIV_D3SWITCH(REG_CLKSWITCH1, 9), 337 + }, 338 + .div_flags = BERLIN2_DIV_HAS_GATE | BERLIN2_DIV_HAS_MUX, 339 + .flags = 0, 340 + }, 341 + { 342 + .name = "audio0", 343 + .parent_ids = (const u8 []){ AUDIO_FAST_PLL }, 344 + .num_parents = 1, 345 + .map = { 346 + BERLIN2_DIV_GATE(REG_CLKENABLE, 22), 347 + BERLIN2_DIV_SELECT(REG_CLKSELECT2, 17), 348 + BERLIN2_DIV_SWITCH(REG_CLKSWITCH1, 10), 349 + BERLIN2_DIV_D3SWITCH(REG_CLKSWITCH1, 11), 350 + }, 351 + .div_flags = BERLIN2_DIV_HAS_GATE, 352 + .flags = 0, 353 + }, 354 + { 355 + .name = "audio2", 356 + .parent_ids = (const u8 []){ AUDIO_FAST_PLL }, 357 + .num_parents = 1, 358 + .map = { 359 + BERLIN2_DIV_GATE(REG_CLKENABLE, 24), 360 + BERLIN2_DIV_SELECT(REG_CLKSELECT2, 20), 361 + BERLIN2_DIV_SWITCH(REG_CLKSWITCH1, 14), 362 + BERLIN2_DIV_D3SWITCH(REG_CLKSWITCH1, 15), 363 + }, 364 + .div_flags = BERLIN2_DIV_HAS_GATE, 365 + .flags = 0, 366 + }, 367 + { 368 + .name = "audio3", 369 + .parent_ids = (const u8 []){ AUDIO_FAST_PLL }, 370 + .num_parents = 1, 371 + .map = { 372 + BERLIN2_DIV_GATE(REG_CLKENABLE, 25), 373 + BERLIN2_DIV_SELECT(REG_CLKSELECT2, 23), 374 + BERLIN2_DIV_SWITCH(REG_CLKSWITCH1, 16), 375 + BERLIN2_DIV_D3SWITCH(REG_CLKSWITCH1, 17), 376 + }, 377 + .div_flags = BERLIN2_DIV_HAS_GATE, 378 + .flags = 0, 379 + }, 380 + { 381 + .name = "audio1", 382 + .parent_ids = (const u8 []){ AUDIO1_PLL }, 383 + .num_parents = 1, 384 + .map = { 385 + BERLIN2_DIV_GATE(REG_CLKENABLE, 23), 386 + BERLIN2_DIV_SELECT(REG_CLKSELECT3, 0), 387 + BERLIN2_DIV_SWITCH(REG_CLKSWITCH1, 12), 388 + BERLIN2_DIV_D3SWITCH(REG_CLKSWITCH1, 13), 389 + }, 390 + .div_flags = BERLIN2_DIV_HAS_GATE, 391 + .flags = 0, 392 + }, 393 + { 394 + .name = "gfx3d_core", 395 + .parent_ids = default_parent_ids, 396 + .num_parents = ARRAY_SIZE(default_parent_ids), 397 + .map = { 398 + BERLIN2_SINGLE_DIV(REG_GFX3DCORE_CLKCTL), 399 + }, 400 + .div_flags = BERLIN2_DIV_HAS_GATE | BERLIN2_DIV_HAS_MUX, 401 + .flags = 0, 402 + }, 403 + { 404 + .name = "gfx3d_sys", 405 + .parent_ids = default_parent_ids, 406 + .num_parents = ARRAY_SIZE(default_parent_ids), 407 + .map = { 408 + BERLIN2_SINGLE_DIV(REG_GFX3DSYS_CLKCTL), 409 + }, 410 + .div_flags = BERLIN2_DIV_HAS_GATE | BERLIN2_DIV_HAS_MUX, 411 + .flags = 0, 412 + }, 413 + { 414 + .name = "arc", 415 + .parent_ids = default_parent_ids, 416 + .num_parents = ARRAY_SIZE(default_parent_ids), 417 + .map = { 418 + BERLIN2_SINGLE_DIV(REG_ARC_CLKCTL), 419 + }, 420 + .div_flags = BERLIN2_DIV_HAS_GATE | BERLIN2_DIV_HAS_MUX, 421 + .flags = 0, 422 + }, 423 + { 424 + .name = "vip", 425 + .parent_ids = default_parent_ids, 426 + .num_parents = ARRAY_SIZE(default_parent_ids), 427 + .map = { 428 + BERLIN2_SINGLE_DIV(REG_VIP_CLKCTL), 429 + }, 430 + .div_flags = BERLIN2_DIV_HAS_GATE | BERLIN2_DIV_HAS_MUX, 431 + .flags = 0, 432 + }, 433 + { 434 + .name = "sdio0xin", 435 + .parent_ids = default_parent_ids, 436 + .num_parents = ARRAY_SIZE(default_parent_ids), 437 + .map = { 438 + BERLIN2_SINGLE_DIV(REG_SDIO0XIN_CLKCTL), 439 + }, 440 + .div_flags = BERLIN2_DIV_HAS_GATE | BERLIN2_DIV_HAS_MUX, 441 + .flags = 0, 442 + }, 443 + { 444 + .name = "sdio1xin", 445 + .parent_ids = default_parent_ids, 446 + .num_parents = ARRAY_SIZE(default_parent_ids), 447 + .map = { 448 + BERLIN2_SINGLE_DIV(REG_SDIO1XIN_CLKCTL), 449 + }, 450 + .div_flags = BERLIN2_DIV_HAS_GATE | BERLIN2_DIV_HAS_MUX, 451 + .flags = 0, 452 + }, 453 + { 454 + .name = "gfx3d_extra", 455 + .parent_ids = default_parent_ids, 456 + .num_parents = ARRAY_SIZE(default_parent_ids), 457 + .map = { 458 + BERLIN2_SINGLE_DIV(REG_GFX3DEXTRA_CLKCTL), 459 + }, 460 + .div_flags = BERLIN2_DIV_HAS_GATE | BERLIN2_DIV_HAS_MUX, 461 + .flags = 0, 462 + }, 463 + { 464 + .name = "gc360", 465 + .parent_ids = default_parent_ids, 466 + .num_parents = ARRAY_SIZE(default_parent_ids), 467 + .map = { 468 + BERLIN2_SINGLE_DIV(REG_GC360_CLKCTL), 469 + }, 470 + .div_flags = BERLIN2_DIV_HAS_GATE | BERLIN2_DIV_HAS_MUX, 471 + .flags = 0, 472 + }, 473 + { 474 + .name = "sdio_dllmst", 475 + .parent_ids = default_parent_ids, 476 + .num_parents = ARRAY_SIZE(default_parent_ids), 477 + .map = { 478 + BERLIN2_SINGLE_DIV(REG_SDIO_DLLMST_CLKCTL), 479 + }, 480 + .div_flags = BERLIN2_DIV_HAS_GATE | BERLIN2_DIV_HAS_MUX, 481 + .flags = 0, 482 + }, 483 + }; 484 + 485 + static const struct berlin2_gate_data bg2_gates[] __initconst = { 486 + { "geth0", "perif", 7 }, 487 + { "geth1", "perif", 8 }, 488 + { "sata", "perif", 9 }, 489 + { "ahbapb", "perif", 10, CLK_IGNORE_UNUSED }, 490 + { "usb0", "perif", 11 }, 491 + { "usb1", "perif", 12 }, 492 + { "pbridge", "perif", 13, CLK_IGNORE_UNUSED }, 493 + { "sdio0", "perif", 14, CLK_IGNORE_UNUSED }, 494 + { "sdio1", "perif", 15, CLK_IGNORE_UNUSED }, 495 + { "nfc", "perif", 17 }, 496 + { "smemc", "perif", 19 }, 497 + { "audiohd", "audiohd_pll", 26 }, 498 + { "video0", "video0_in", 27 }, 499 + { "video1", "video1_in", 28 }, 500 + { "video2", "video2_in", 29 }, 501 + }; 502 + 503 + static void __init berlin2_clock_setup(struct device_node *np) 504 + { 505 + const char *parent_names[9]; 506 + struct clk *clk; 507 + u8 avpll_flags = 0; 508 + int n; 509 + 510 + gbase = of_iomap(np, 0); 511 + if (!gbase) 512 + return; 513 + 514 + /* overwrite default clock names with DT provided ones */ 515 + clk = of_clk_get_by_name(np, clk_names[REFCLK]); 516 + if (!IS_ERR(clk)) { 517 + clk_names[REFCLK] = __clk_get_name(clk); 518 + clk_put(clk); 519 + } 520 + 521 + clk = of_clk_get_by_name(np, clk_names[VIDEO_EXT0]); 522 + if (!IS_ERR(clk)) { 523 + clk_names[VIDEO_EXT0] = __clk_get_name(clk); 524 + clk_put(clk); 525 + } 526 + 527 + /* simple register PLLs */ 528 + clk = berlin2_pll_register(&bg2_pll_map, gbase + REG_SYSPLLCTL0, 529 + clk_names[SYSPLL], clk_names[REFCLK], 0); 530 + if (IS_ERR(clk)) 531 + goto bg2_fail; 532 + 533 + clk = berlin2_pll_register(&bg2_pll_map, gbase + REG_MEMPLLCTL0, 534 + clk_names[MEMPLL], clk_names[REFCLK], 0); 535 + if (IS_ERR(clk)) 536 + goto bg2_fail; 537 + 538 + clk = berlin2_pll_register(&bg2_pll_map, gbase + REG_CPUPLLCTL0, 539 + clk_names[CPUPLL], clk_names[REFCLK], 0); 540 + if (IS_ERR(clk)) 541 + goto bg2_fail; 542 + 543 + if (of_device_is_compatible(np, "marvell,berlin2-global-register")) 544 + avpll_flags |= BERLIN2_AVPLL_SCRAMBLE_QUIRK; 545 + 546 + /* audio/video VCOs */ 547 + clk = berlin2_avpll_vco_register(gbase + REG_AVPLLCTL0, "avpll_vcoA", 548 + clk_names[REFCLK], avpll_flags, 0); 549 + if (IS_ERR(clk)) 550 + goto bg2_fail; 551 + 552 + for (n = 0; n < 8; n++) { 553 + clk = berlin2_avpll_channel_register(gbase + REG_AVPLLCTL0, 554 + clk_names[AVPLL_A1 + n], n, "avpll_vcoA", 555 + avpll_flags, 0); 556 + if (IS_ERR(clk)) 557 + goto bg2_fail; 558 + } 559 + 560 + clk = berlin2_avpll_vco_register(gbase + REG_AVPLLCTL31, "avpll_vcoB", 561 + clk_names[REFCLK], BERLIN2_AVPLL_BIT_QUIRK | 562 + avpll_flags, 0); 563 + if (IS_ERR(clk)) 564 + goto bg2_fail; 565 + 566 + for (n = 0; n < 8; n++) { 567 + clk = berlin2_avpll_channel_register(gbase + REG_AVPLLCTL31, 568 + clk_names[AVPLL_B1 + n], n, "avpll_vcoB", 569 + BERLIN2_AVPLL_BIT_QUIRK | avpll_flags, 0); 570 + if (IS_ERR(clk)) 571 + goto bg2_fail; 572 + } 573 + 574 + /* reference clock bypass switches */ 575 + parent_names[0] = clk_names[SYSPLL]; 576 + parent_names[1] = clk_names[REFCLK]; 577 + clk = clk_register_mux(NULL, "syspll_byp", parent_names, 2, 578 + 0, gbase + REG_CLKSWITCH0, 0, 1, 0, &lock); 579 + if (IS_ERR(clk)) 580 + goto bg2_fail; 581 + clk_names[SYSPLL] = __clk_get_name(clk); 582 + 583 + parent_names[0] = clk_names[MEMPLL]; 584 + parent_names[1] = clk_names[REFCLK]; 585 + clk = clk_register_mux(NULL, "mempll_byp", parent_names, 2, 586 + 0, gbase + REG_CLKSWITCH0, 1, 1, 0, &lock); 587 + if (IS_ERR(clk)) 588 + goto bg2_fail; 589 + clk_names[MEMPLL] = __clk_get_name(clk); 590 + 591 + parent_names[0] = clk_names[CPUPLL]; 592 + parent_names[1] = clk_names[REFCLK]; 593 + clk = clk_register_mux(NULL, "cpupll_byp", parent_names, 2, 594 + 0, gbase + REG_CLKSWITCH0, 2, 1, 0, &lock); 595 + if (IS_ERR(clk)) 596 + goto bg2_fail; 597 + clk_names[CPUPLL] = __clk_get_name(clk); 598 + 599 + /* clock muxes */ 600 + parent_names[0] = clk_names[AVPLL_B3]; 601 + parent_names[1] = clk_names[AVPLL_A3]; 602 + clk = clk_register_mux(NULL, clk_names[AUDIO1_PLL], parent_names, 2, 603 + 0, gbase + REG_CLKSELECT2, 29, 1, 0, &lock); 604 + if (IS_ERR(clk)) 605 + goto bg2_fail; 606 + 607 + parent_names[0] = clk_names[VIDEO0_PLL]; 608 + parent_names[1] = clk_names[VIDEO_EXT0]; 609 + clk = clk_register_mux(NULL, clk_names[VIDEO0_IN], parent_names, 2, 610 + 0, gbase + REG_CLKSELECT3, 4, 1, 0, &lock); 611 + if (IS_ERR(clk)) 612 + goto bg2_fail; 613 + 614 + parent_names[0] = clk_names[VIDEO1_PLL]; 615 + parent_names[1] = clk_names[VIDEO_EXT0]; 616 + clk = clk_register_mux(NULL, clk_names[VIDEO1_IN], parent_names, 2, 617 + 0, gbase + REG_CLKSELECT3, 6, 1, 0, &lock); 618 + if (IS_ERR(clk)) 619 + goto bg2_fail; 620 + 621 + parent_names[0] = clk_names[AVPLL_A2]; 622 + parent_names[1] = clk_names[AVPLL_B2]; 623 + clk = clk_register_mux(NULL, clk_names[VIDEO1_PLL], parent_names, 2, 624 + 0, gbase + REG_CLKSELECT3, 7, 1, 0, &lock); 625 + if (IS_ERR(clk)) 626 + goto bg2_fail; 627 + 628 + parent_names[0] = clk_names[VIDEO2_PLL]; 629 + parent_names[1] = clk_names[VIDEO_EXT0]; 630 + clk = clk_register_mux(NULL, clk_names[VIDEO2_IN], parent_names, 2, 631 + 0, gbase + REG_CLKSELECT3, 9, 1, 0, &lock); 632 + if (IS_ERR(clk)) 633 + goto bg2_fail; 634 + 635 + parent_names[0] = clk_names[AVPLL_B1]; 636 + parent_names[1] = clk_names[AVPLL_A5]; 637 + clk = clk_register_mux(NULL, clk_names[VIDEO2_PLL], parent_names, 2, 638 + 0, gbase + REG_CLKSELECT3, 10, 1, 0, &lock); 639 + if (IS_ERR(clk)) 640 + goto bg2_fail; 641 + 642 + /* clock divider cells */ 643 + for (n = 0; n < ARRAY_SIZE(bg2_divs); n++) { 644 + const struct berlin2_div_data *dd = &bg2_divs[n]; 645 + int k; 646 + 647 + for (k = 0; k < dd->num_parents; k++) 648 + parent_names[k] = clk_names[dd->parent_ids[k]]; 649 + 650 + clks[CLKID_SYS + n] = berlin2_div_register(&dd->map, gbase, 651 + dd->name, dd->div_flags, parent_names, 652 + dd->num_parents, dd->flags, &lock); 653 + } 654 + 655 + /* clock gate cells */ 656 + for (n = 0; n < ARRAY_SIZE(bg2_gates); n++) { 657 + const struct berlin2_gate_data *gd = &bg2_gates[n]; 658 + 659 + clks[CLKID_GETH0 + n] = clk_register_gate(NULL, gd->name, 660 + gd->parent_name, gd->flags, gbase + REG_CLKENABLE, 661 + gd->bit_idx, 0, &lock); 662 + } 663 + 664 + /* twdclk is derived from cpu/3 */ 665 + clks[CLKID_TWD] = 666 + clk_register_fixed_factor(NULL, "twd", "cpu", 0, 1, 3); 667 + 668 + /* check for errors on leaf clocks */ 669 + for (n = 0; n < MAX_CLKS; n++) { 670 + if (!IS_ERR(clks[n])) 671 + continue; 672 + 673 + pr_err("%s: Unable to register leaf clock %d\n", 674 + np->full_name, n); 675 + goto bg2_fail; 676 + } 677 + 678 + /* register clk-provider */ 679 + clk_data.clks = clks; 680 + clk_data.clk_num = MAX_CLKS; 681 + of_clk_add_provider(np, of_clk_src_onecell_get, &clk_data); 682 + 683 + return; 684 + 685 + bg2_fail: 686 + iounmap(gbase); 687 + } 688 + CLK_OF_DECLARE(berlin2_clock, "marvell,berlin2-chip-ctrl", 689 + berlin2_clock_setup); 690 + CLK_OF_DECLARE(berlin2cd_clock, "marvell,berlin2cd-chip-ctrl", 691 + berlin2_clock_setup);
+29
drivers/clk/berlin/common.h
··· 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 + #ifndef __BERLIN2_COMMON_H 20 + #define __BERLIN2_COMMON_H 21 + 22 + struct berlin2_gate_data { 23 + const char *name; 24 + const char *parent_name; 25 + u8 bit_idx; 26 + unsigned long flags; 27 + }; 28 + 29 + #endif /* BERLIN2_COMMON_H */