root/drivers/clk/berlin/bg2q.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. berlin2q_clock_setup

   1 // SPDX-License-Identifier: GPL-2.0
   2 /*
   3  * Copyright (c) 2014 Marvell Technology Group Ltd.
   4  *
   5  * Alexandre Belloni <alexandre.belloni@free-electrons.com>
   6  * Sebastian Hesselbarth <sebastian.hesselbarth@gmail.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/berlin2q.h>
  18 
  19 #include "berlin2-div.h"
  20 #include "berlin2-pll.h"
  21 #include "common.h"
  22 
  23 #define REG_PINMUX0             0x0018
  24 #define REG_PINMUX5             0x002c
  25 #define REG_SYSPLLCTL0          0x0030
  26 #define REG_SYSPLLCTL4          0x0040
  27 #define REG_CLKENABLE           0x00e8
  28 #define REG_CLKSELECT0          0x00ec
  29 #define REG_CLKSELECT1          0x00f0
  30 #define REG_CLKSELECT2          0x00f4
  31 #define REG_CLKSWITCH0          0x00f8
  32 #define REG_CLKSWITCH1          0x00fc
  33 #define REG_SW_GENERIC0         0x0110
  34 #define REG_SW_GENERIC3         0x011c
  35 #define REG_SDIO0XIN_CLKCTL     0x0158
  36 #define REG_SDIO1XIN_CLKCTL     0x015c
  37 
  38 #define MAX_CLKS 28
  39 static struct clk_hw_onecell_data *clk_data;
  40 static DEFINE_SPINLOCK(lock);
  41 static void __iomem *gbase;
  42 static void __iomem *cpupll_base;
  43 
  44 enum {
  45         REFCLK,
  46         SYSPLL, CPUPLL,
  47         AVPLL_B1, AVPLL_B2, AVPLL_B3, AVPLL_B4,
  48         AVPLL_B5, AVPLL_B6, AVPLL_B7, AVPLL_B8,
  49 };
  50 
  51 static const char *clk_names[] = {
  52         [REFCLK]                = "refclk",
  53         [SYSPLL]                = "syspll",
  54         [CPUPLL]                = "cpupll",
  55         [AVPLL_B1]              = "avpll_b1",
  56         [AVPLL_B2]              = "avpll_b2",
  57         [AVPLL_B3]              = "avpll_b3",
  58         [AVPLL_B4]              = "avpll_b4",
  59         [AVPLL_B5]              = "avpll_b5",
  60         [AVPLL_B6]              = "avpll_b6",
  61         [AVPLL_B7]              = "avpll_b7",
  62         [AVPLL_B8]              = "avpll_b8",
  63 };
  64 
  65 static const struct berlin2_pll_map bg2q_pll_map __initconst = {
  66         .vcodiv         = {1, 0, 2, 0, 3, 4, 0, 6, 8},
  67         .mult           = 1,
  68         .fbdiv_shift    = 7,
  69         .rfdiv_shift    = 2,
  70         .divsel_shift   = 9,
  71 };
  72 
  73 static const u8 default_parent_ids[] = {
  74         SYSPLL, AVPLL_B4, AVPLL_B5, AVPLL_B6, AVPLL_B7, SYSPLL
  75 };
  76 
  77 static const struct berlin2_div_data bg2q_divs[] __initconst = {
  78         {
  79                 .name = "sys",
  80                 .parent_ids = default_parent_ids,
  81                 .num_parents = ARRAY_SIZE(default_parent_ids),
  82                 .map = {
  83                         BERLIN2_DIV_GATE(REG_CLKENABLE, 0),
  84                         BERLIN2_PLL_SELECT(REG_CLKSELECT0, 0),
  85                         BERLIN2_DIV_SELECT(REG_CLKSELECT0, 3),
  86                         BERLIN2_PLL_SWITCH(REG_CLKSWITCH0, 3),
  87                         BERLIN2_DIV_SWITCH(REG_CLKSWITCH0, 4),
  88                         BERLIN2_DIV_D3SWITCH(REG_CLKSWITCH0, 5),
  89                 },
  90                 .div_flags = BERLIN2_DIV_HAS_GATE | BERLIN2_DIV_HAS_MUX,
  91                 .flags = CLK_IGNORE_UNUSED,
  92         },
  93         {
  94                 .name = "drmfigo",
  95                 .parent_ids = default_parent_ids,
  96                 .num_parents = ARRAY_SIZE(default_parent_ids),
  97                 .map = {
  98                         BERLIN2_DIV_GATE(REG_CLKENABLE, 17),
  99                         BERLIN2_PLL_SELECT(REG_CLKSELECT0, 6),
 100                         BERLIN2_DIV_SELECT(REG_CLKSELECT0, 9),
 101                         BERLIN2_PLL_SWITCH(REG_CLKSWITCH0, 6),
 102                         BERLIN2_DIV_SWITCH(REG_CLKSWITCH0, 7),
 103                         BERLIN2_DIV_D3SWITCH(REG_CLKSWITCH0, 8),
 104                 },
 105                 .div_flags = BERLIN2_DIV_HAS_GATE | BERLIN2_DIV_HAS_MUX,
 106                 .flags = 0,
 107         },
 108         {
 109                 .name = "cfg",
 110                 .parent_ids = default_parent_ids,
 111                 .num_parents = ARRAY_SIZE(default_parent_ids),
 112                 .map = {
 113                         BERLIN2_DIV_GATE(REG_CLKENABLE, 1),
 114                         BERLIN2_PLL_SELECT(REG_CLKSELECT0, 12),
 115                         BERLIN2_DIV_SELECT(REG_CLKSELECT0, 15),
 116                         BERLIN2_PLL_SWITCH(REG_CLKSWITCH0, 9),
 117                         BERLIN2_DIV_SWITCH(REG_CLKSWITCH0, 10),
 118                         BERLIN2_DIV_D3SWITCH(REG_CLKSWITCH0, 11),
 119                 },
 120                 .div_flags = BERLIN2_DIV_HAS_GATE | BERLIN2_DIV_HAS_MUX,
 121                 .flags = 0,
 122         },
 123         {
 124                 .name = "gfx2d",
 125                 .parent_ids = default_parent_ids,
 126                 .num_parents = ARRAY_SIZE(default_parent_ids),
 127                 .map = {
 128                         BERLIN2_DIV_GATE(REG_CLKENABLE, 4),
 129                         BERLIN2_PLL_SELECT(REG_CLKSELECT0, 18),
 130                         BERLIN2_DIV_SELECT(REG_CLKSELECT0, 21),
 131                         BERLIN2_PLL_SWITCH(REG_CLKSWITCH0, 12),
 132                         BERLIN2_DIV_SWITCH(REG_CLKSWITCH0, 13),
 133                         BERLIN2_DIV_D3SWITCH(REG_CLKSWITCH0, 14),
 134                 },
 135                 .div_flags = BERLIN2_DIV_HAS_GATE | BERLIN2_DIV_HAS_MUX,
 136                 .flags = 0,
 137         },
 138         {
 139                 .name = "zsp",
 140                 .parent_ids = default_parent_ids,
 141                 .num_parents = ARRAY_SIZE(default_parent_ids),
 142                 .map = {
 143                         BERLIN2_DIV_GATE(REG_CLKENABLE, 6),
 144                         BERLIN2_PLL_SELECT(REG_CLKSELECT0, 24),
 145                         BERLIN2_DIV_SELECT(REG_CLKSELECT0, 27),
 146                         BERLIN2_PLL_SWITCH(REG_CLKSWITCH0, 15),
 147                         BERLIN2_DIV_SWITCH(REG_CLKSWITCH0, 16),
 148                         BERLIN2_DIV_D3SWITCH(REG_CLKSWITCH0, 17),
 149                 },
 150                 .div_flags = BERLIN2_DIV_HAS_GATE | BERLIN2_DIV_HAS_MUX,
 151                 .flags = 0,
 152         },
 153         {
 154                 .name = "perif",
 155                 .parent_ids = default_parent_ids,
 156                 .num_parents = ARRAY_SIZE(default_parent_ids),
 157                 .map = {
 158                         BERLIN2_DIV_GATE(REG_CLKENABLE, 7),
 159                         BERLIN2_PLL_SELECT(REG_CLKSELECT1, 0),
 160                         BERLIN2_DIV_SELECT(REG_CLKSELECT1, 3),
 161                         BERLIN2_PLL_SWITCH(REG_CLKSWITCH0, 18),
 162                         BERLIN2_DIV_SWITCH(REG_CLKSWITCH0, 19),
 163                         BERLIN2_DIV_D3SWITCH(REG_CLKSWITCH0, 20),
 164                 },
 165                 .div_flags = BERLIN2_DIV_HAS_GATE | BERLIN2_DIV_HAS_MUX,
 166                 .flags = CLK_IGNORE_UNUSED,
 167         },
 168         {
 169                 .name = "pcube",
 170                 .parent_ids = default_parent_ids,
 171                 .num_parents = ARRAY_SIZE(default_parent_ids),
 172                 .map = {
 173                         BERLIN2_DIV_GATE(REG_CLKENABLE, 2),
 174                         BERLIN2_PLL_SELECT(REG_CLKSELECT1, 6),
 175                         BERLIN2_DIV_SELECT(REG_CLKSELECT1, 9),
 176                         BERLIN2_PLL_SWITCH(REG_CLKSWITCH0, 21),
 177                         BERLIN2_DIV_SWITCH(REG_CLKSWITCH0, 22),
 178                         BERLIN2_DIV_D3SWITCH(REG_CLKSWITCH0, 23),
 179                 },
 180                 .div_flags = BERLIN2_DIV_HAS_GATE | BERLIN2_DIV_HAS_MUX,
 181                 .flags = 0,
 182         },
 183         {
 184                 .name = "vscope",
 185                 .parent_ids = default_parent_ids,
 186                 .num_parents = ARRAY_SIZE(default_parent_ids),
 187                 .map = {
 188                         BERLIN2_DIV_GATE(REG_CLKENABLE, 3),
 189                         BERLIN2_PLL_SELECT(REG_CLKSELECT1, 12),
 190                         BERLIN2_DIV_SELECT(REG_CLKSELECT1, 15),
 191                         BERLIN2_PLL_SWITCH(REG_CLKSWITCH0, 24),
 192                         BERLIN2_DIV_SWITCH(REG_CLKSWITCH0, 25),
 193                         BERLIN2_DIV_D3SWITCH(REG_CLKSWITCH0, 26),
 194                 },
 195                 .div_flags = BERLIN2_DIV_HAS_GATE | BERLIN2_DIV_HAS_MUX,
 196                 .flags = 0,
 197         },
 198         {
 199                 .name = "nfc_ecc",
 200                 .parent_ids = default_parent_ids,
 201                 .num_parents = ARRAY_SIZE(default_parent_ids),
 202                 .map = {
 203                         BERLIN2_DIV_GATE(REG_CLKENABLE, 19),
 204                         BERLIN2_PLL_SELECT(REG_CLKSELECT1, 18),
 205                         BERLIN2_DIV_SELECT(REG_CLKSELECT1, 21),
 206                         BERLIN2_PLL_SWITCH(REG_CLKSWITCH0, 27),
 207                         BERLIN2_DIV_SWITCH(REG_CLKSWITCH0, 28),
 208                         BERLIN2_DIV_D3SWITCH(REG_CLKSWITCH0, 29),
 209                 },
 210                 .div_flags = BERLIN2_DIV_HAS_GATE | BERLIN2_DIV_HAS_MUX,
 211                 .flags = 0,
 212         },
 213         {
 214                 .name = "vpp",
 215                 .parent_ids = default_parent_ids,
 216                 .num_parents = ARRAY_SIZE(default_parent_ids),
 217                 .map = {
 218                         BERLIN2_DIV_GATE(REG_CLKENABLE, 21),
 219                         BERLIN2_PLL_SELECT(REG_CLKSELECT1, 24),
 220                         BERLIN2_DIV_SELECT(REG_CLKSELECT1, 27),
 221                         BERLIN2_PLL_SWITCH(REG_CLKSWITCH0, 30),
 222                         BERLIN2_DIV_SWITCH(REG_CLKSWITCH0, 31),
 223                         BERLIN2_DIV_D3SWITCH(REG_CLKSWITCH1, 0),
 224                 },
 225                 .div_flags = BERLIN2_DIV_HAS_GATE | BERLIN2_DIV_HAS_MUX,
 226                 .flags = 0,
 227         },
 228         {
 229                 .name = "app",
 230                 .parent_ids = default_parent_ids,
 231                 .num_parents = ARRAY_SIZE(default_parent_ids),
 232                 .map = {
 233                         BERLIN2_DIV_GATE(REG_CLKENABLE, 20),
 234                         BERLIN2_PLL_SELECT(REG_CLKSELECT2, 0),
 235                         BERLIN2_DIV_SELECT(REG_CLKSELECT2, 3),
 236                         BERLIN2_PLL_SWITCH(REG_CLKSWITCH1, 1),
 237                         BERLIN2_DIV_SWITCH(REG_CLKSWITCH1, 2),
 238                         BERLIN2_DIV_D3SWITCH(REG_CLKSWITCH1, 3),
 239                 },
 240                 .div_flags = BERLIN2_DIV_HAS_GATE | BERLIN2_DIV_HAS_MUX,
 241                 .flags = 0,
 242         },
 243         {
 244                 .name = "sdio0xin",
 245                 .parent_ids = default_parent_ids,
 246                 .num_parents = ARRAY_SIZE(default_parent_ids),
 247                 .map = {
 248                         BERLIN2_SINGLE_DIV(REG_SDIO0XIN_CLKCTL),
 249                 },
 250                 .div_flags = BERLIN2_DIV_HAS_GATE | BERLIN2_DIV_HAS_MUX,
 251                 .flags = 0,
 252         },
 253         {
 254                 .name = "sdio1xin",
 255                 .parent_ids = default_parent_ids,
 256                 .num_parents = ARRAY_SIZE(default_parent_ids),
 257                 .map = {
 258                         BERLIN2_SINGLE_DIV(REG_SDIO1XIN_CLKCTL),
 259                 },
 260                 .div_flags = BERLIN2_DIV_HAS_GATE | BERLIN2_DIV_HAS_MUX,
 261                 .flags = 0,
 262         },
 263 };
 264 
 265 static const struct berlin2_gate_data bg2q_gates[] __initconst = {
 266         { "gfx2daxi",   "perif",        5 },
 267         { "geth0",      "perif",        8 },
 268         { "sata",       "perif",        9 },
 269         { "ahbapb",     "perif",        10, CLK_IGNORE_UNUSED },
 270         { "usb0",       "perif",        11 },
 271         { "usb1",       "perif",        12 },
 272         { "usb2",       "perif",        13 },
 273         { "usb3",       "perif",        14 },
 274         { "pbridge",    "perif",        15, CLK_IGNORE_UNUSED },
 275         { "sdio",       "perif",        16 },
 276         { "nfc",        "perif",        18 },
 277         { "pcie",       "perif",        22 },
 278 };
 279 
 280 static void __init berlin2q_clock_setup(struct device_node *np)
 281 {
 282         struct device_node *parent_np = of_get_parent(np);
 283         const char *parent_names[9];
 284         struct clk *clk;
 285         struct clk_hw **hws;
 286         int n, ret;
 287 
 288         clk_data = kzalloc(struct_size(clk_data, hws, MAX_CLKS), GFP_KERNEL);
 289         if (!clk_data)
 290                 return;
 291         clk_data->num = MAX_CLKS;
 292         hws = clk_data->hws;
 293 
 294         gbase = of_iomap(parent_np, 0);
 295         if (!gbase) {
 296                 pr_err("%pOF: Unable to map global base\n", np);
 297                 return;
 298         }
 299 
 300         /* BG2Q CPU PLL is not part of global registers */
 301         cpupll_base = of_iomap(parent_np, 1);
 302         if (!cpupll_base) {
 303                 pr_err("%pOF: Unable to map cpupll base\n", np);
 304                 iounmap(gbase);
 305                 return;
 306         }
 307 
 308         /* overwrite default clock names with DT provided ones */
 309         clk = of_clk_get_by_name(np, clk_names[REFCLK]);
 310         if (!IS_ERR(clk)) {
 311                 clk_names[REFCLK] = __clk_get_name(clk);
 312                 clk_put(clk);
 313         }
 314 
 315         /* simple register PLLs */
 316         ret = berlin2_pll_register(&bg2q_pll_map, gbase + REG_SYSPLLCTL0,
 317                                    clk_names[SYSPLL], clk_names[REFCLK], 0);
 318         if (ret)
 319                 goto bg2q_fail;
 320 
 321         ret = berlin2_pll_register(&bg2q_pll_map, cpupll_base,
 322                                    clk_names[CPUPLL], clk_names[REFCLK], 0);
 323         if (ret)
 324                 goto bg2q_fail;
 325 
 326         /* TODO: add BG2Q AVPLL */
 327 
 328         /*
 329          * TODO: add reference clock bypass switches:
 330          * memPLLSWBypass, cpuPLLSWBypass, and sysPLLSWBypass
 331          */
 332 
 333         /* clock divider cells */
 334         for (n = 0; n < ARRAY_SIZE(bg2q_divs); n++) {
 335                 const struct berlin2_div_data *dd = &bg2q_divs[n];
 336                 int k;
 337 
 338                 for (k = 0; k < dd->num_parents; k++)
 339                         parent_names[k] = clk_names[dd->parent_ids[k]];
 340 
 341                 hws[CLKID_SYS + n] = berlin2_div_register(&dd->map, gbase,
 342                                 dd->name, dd->div_flags, parent_names,
 343                                 dd->num_parents, dd->flags, &lock);
 344         }
 345 
 346         /* clock gate cells */
 347         for (n = 0; n < ARRAY_SIZE(bg2q_gates); n++) {
 348                 const struct berlin2_gate_data *gd = &bg2q_gates[n];
 349 
 350                 hws[CLKID_GFX2DAXI + n] = clk_hw_register_gate(NULL, gd->name,
 351                             gd->parent_name, gd->flags, gbase + REG_CLKENABLE,
 352                             gd->bit_idx, 0, &lock);
 353         }
 354 
 355         /* cpuclk divider is fixed to 1 */
 356         hws[CLKID_CPU] =
 357                 clk_hw_register_fixed_factor(NULL, "cpu", clk_names[CPUPLL],
 358                                           0, 1, 1);
 359         /* twdclk is derived from cpu/3 */
 360         hws[CLKID_TWD] =
 361                 clk_hw_register_fixed_factor(NULL, "twd", "cpu", 0, 1, 3);
 362 
 363         /* check for errors on leaf clocks */
 364         for (n = 0; n < MAX_CLKS; n++) {
 365                 if (!IS_ERR(hws[n]))
 366                         continue;
 367 
 368                 pr_err("%pOF: Unable to register leaf clock %d\n", np, n);
 369                 goto bg2q_fail;
 370         }
 371 
 372         /* register clk-provider */
 373         of_clk_add_hw_provider(np, of_clk_hw_onecell_get, clk_data);
 374 
 375         return;
 376 
 377 bg2q_fail:
 378         iounmap(cpupll_base);
 379         iounmap(gbase);
 380 }
 381 CLK_OF_DECLARE(berlin2q_clk, "marvell,berlin2q-clk",
 382                berlin2q_clock_setup);

/* [<][>][^][v][top][bottom][index][help] */