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