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