linux/drivers/clk/berlin/bg2.c
<<
>>
Prefs
   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
  95static struct clk_hw_onecell_data *clk_data;
  96static DEFINE_SPINLOCK(lock);
  97static void __iomem *gbase;
  98
  99enum {
 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
 112static 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
 144static 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
 152static const u8 default_parent_ids[] = {
 153        SYSPLL, AVPLL_B4, AVPLL_A5, AVPLL_B6, AVPLL_B7, SYSPLL
 154};
 155
 156static 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
 484static 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
 502static 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("%pOF: Unable to register leaf clock %d\n", np, n);
 683                goto bg2_fail;
 684        }
 685
 686        /* register clk-provider */
 687        of_clk_add_hw_provider(np, of_clk_hw_onecell_get, clk_data);
 688
 689        return;
 690
 691bg2_fail:
 692        iounmap(gbase);
 693}
 694CLK_OF_DECLARE(berlin2_clk, "marvell,berlin2-clk",
 695               berlin2_clock_setup);
 696