Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 /*
0003  * Copyright (c) 2014 Marvell Technology Group Ltd.
0004  *
0005  * Alexandre Belloni <alexandre.belloni@free-electrons.com>
0006  * Sebastian Hesselbarth <sebastian.hesselbarth@gmail.com>
0007  */
0008 
0009 #include <linux/clk.h>
0010 #include <linux/clk-provider.h>
0011 #include <linux/io.h>
0012 #include <linux/kernel.h>
0013 #include <linux/of.h>
0014 #include <linux/of_address.h>
0015 #include <linux/slab.h>
0016 
0017 #include <dt-bindings/clock/berlin2q.h>
0018 
0019 #include "berlin2-div.h"
0020 #include "berlin2-pll.h"
0021 #include "common.h"
0022 
0023 #define REG_PINMUX0     0x0018
0024 #define REG_PINMUX5     0x002c
0025 #define REG_SYSPLLCTL0      0x0030
0026 #define REG_SYSPLLCTL4      0x0040
0027 #define REG_CLKENABLE       0x00e8
0028 #define REG_CLKSELECT0      0x00ec
0029 #define REG_CLKSELECT1      0x00f0
0030 #define REG_CLKSELECT2      0x00f4
0031 #define REG_CLKSWITCH0      0x00f8
0032 #define REG_CLKSWITCH1      0x00fc
0033 #define REG_SW_GENERIC0     0x0110
0034 #define REG_SW_GENERIC3     0x011c
0035 #define REG_SDIO0XIN_CLKCTL 0x0158
0036 #define REG_SDIO1XIN_CLKCTL 0x015c
0037 
0038 #define MAX_CLKS 28
0039 static struct clk_hw_onecell_data *clk_data;
0040 static DEFINE_SPINLOCK(lock);
0041 static void __iomem *gbase;
0042 static void __iomem *cpupll_base;
0043 
0044 enum {
0045     REFCLK,
0046     SYSPLL, CPUPLL,
0047     AVPLL_B1, AVPLL_B2, AVPLL_B3, AVPLL_B4,
0048     AVPLL_B5, AVPLL_B6, AVPLL_B7, AVPLL_B8,
0049 };
0050 
0051 static const char *clk_names[] = {
0052     [REFCLK]        = "refclk",
0053     [SYSPLL]        = "syspll",
0054     [CPUPLL]        = "cpupll",
0055     [AVPLL_B1]      = "avpll_b1",
0056     [AVPLL_B2]      = "avpll_b2",
0057     [AVPLL_B3]      = "avpll_b3",
0058     [AVPLL_B4]      = "avpll_b4",
0059     [AVPLL_B5]      = "avpll_b5",
0060     [AVPLL_B6]      = "avpll_b6",
0061     [AVPLL_B7]      = "avpll_b7",
0062     [AVPLL_B8]      = "avpll_b8",
0063 };
0064 
0065 static const struct berlin2_pll_map bg2q_pll_map __initconst = {
0066     .vcodiv     = {1, 0, 2, 0, 3, 4, 0, 6, 8},
0067     .mult       = 1,
0068     .fbdiv_shift    = 7,
0069     .rfdiv_shift    = 2,
0070     .divsel_shift   = 9,
0071 };
0072 
0073 static const u8 default_parent_ids[] = {
0074     SYSPLL, AVPLL_B4, AVPLL_B5, AVPLL_B6, AVPLL_B7, SYSPLL
0075 };
0076 
0077 static const struct berlin2_div_data bg2q_divs[] __initconst = {
0078     {
0079         .name = "sys",
0080         .parent_ids = default_parent_ids,
0081         .num_parents = ARRAY_SIZE(default_parent_ids),
0082         .map = {
0083             BERLIN2_DIV_GATE(REG_CLKENABLE, 0),
0084             BERLIN2_PLL_SELECT(REG_CLKSELECT0, 0),
0085             BERLIN2_DIV_SELECT(REG_CLKSELECT0, 3),
0086             BERLIN2_PLL_SWITCH(REG_CLKSWITCH0, 3),
0087             BERLIN2_DIV_SWITCH(REG_CLKSWITCH0, 4),
0088             BERLIN2_DIV_D3SWITCH(REG_CLKSWITCH0, 5),
0089         },
0090         .div_flags = BERLIN2_DIV_HAS_GATE | BERLIN2_DIV_HAS_MUX,
0091         .flags = CLK_IGNORE_UNUSED,
0092     },
0093     {
0094         .name = "drmfigo",
0095         .parent_ids = default_parent_ids,
0096         .num_parents = ARRAY_SIZE(default_parent_ids),
0097         .map = {
0098             BERLIN2_DIV_GATE(REG_CLKENABLE, 17),
0099             BERLIN2_PLL_SELECT(REG_CLKSELECT0, 6),
0100             BERLIN2_DIV_SELECT(REG_CLKSELECT0, 9),
0101             BERLIN2_PLL_SWITCH(REG_CLKSWITCH0, 6),
0102             BERLIN2_DIV_SWITCH(REG_CLKSWITCH0, 7),
0103             BERLIN2_DIV_D3SWITCH(REG_CLKSWITCH0, 8),
0104         },
0105         .div_flags = BERLIN2_DIV_HAS_GATE | BERLIN2_DIV_HAS_MUX,
0106         .flags = 0,
0107     },
0108     {
0109         .name = "cfg",
0110         .parent_ids = default_parent_ids,
0111         .num_parents = ARRAY_SIZE(default_parent_ids),
0112         .map = {
0113             BERLIN2_DIV_GATE(REG_CLKENABLE, 1),
0114             BERLIN2_PLL_SELECT(REG_CLKSELECT0, 12),
0115             BERLIN2_DIV_SELECT(REG_CLKSELECT0, 15),
0116             BERLIN2_PLL_SWITCH(REG_CLKSWITCH0, 9),
0117             BERLIN2_DIV_SWITCH(REG_CLKSWITCH0, 10),
0118             BERLIN2_DIV_D3SWITCH(REG_CLKSWITCH0, 11),
0119         },
0120         .div_flags = BERLIN2_DIV_HAS_GATE | BERLIN2_DIV_HAS_MUX,
0121         .flags = 0,
0122     },
0123     {
0124         .name = "gfx2d",
0125         .parent_ids = default_parent_ids,
0126         .num_parents = ARRAY_SIZE(default_parent_ids),
0127         .map = {
0128             BERLIN2_DIV_GATE(REG_CLKENABLE, 4),
0129             BERLIN2_PLL_SELECT(REG_CLKSELECT0, 18),
0130             BERLIN2_DIV_SELECT(REG_CLKSELECT0, 21),
0131             BERLIN2_PLL_SWITCH(REG_CLKSWITCH0, 12),
0132             BERLIN2_DIV_SWITCH(REG_CLKSWITCH0, 13),
0133             BERLIN2_DIV_D3SWITCH(REG_CLKSWITCH0, 14),
0134         },
0135         .div_flags = BERLIN2_DIV_HAS_GATE | BERLIN2_DIV_HAS_MUX,
0136         .flags = 0,
0137     },
0138     {
0139         .name = "zsp",
0140         .parent_ids = default_parent_ids,
0141         .num_parents = ARRAY_SIZE(default_parent_ids),
0142         .map = {
0143             BERLIN2_DIV_GATE(REG_CLKENABLE, 6),
0144             BERLIN2_PLL_SELECT(REG_CLKSELECT0, 24),
0145             BERLIN2_DIV_SELECT(REG_CLKSELECT0, 27),
0146             BERLIN2_PLL_SWITCH(REG_CLKSWITCH0, 15),
0147             BERLIN2_DIV_SWITCH(REG_CLKSWITCH0, 16),
0148             BERLIN2_DIV_D3SWITCH(REG_CLKSWITCH0, 17),
0149         },
0150         .div_flags = BERLIN2_DIV_HAS_GATE | BERLIN2_DIV_HAS_MUX,
0151         .flags = 0,
0152     },
0153     {
0154         .name = "perif",
0155         .parent_ids = default_parent_ids,
0156         .num_parents = ARRAY_SIZE(default_parent_ids),
0157         .map = {
0158             BERLIN2_DIV_GATE(REG_CLKENABLE, 7),
0159             BERLIN2_PLL_SELECT(REG_CLKSELECT1, 0),
0160             BERLIN2_DIV_SELECT(REG_CLKSELECT1, 3),
0161             BERLIN2_PLL_SWITCH(REG_CLKSWITCH0, 18),
0162             BERLIN2_DIV_SWITCH(REG_CLKSWITCH0, 19),
0163             BERLIN2_DIV_D3SWITCH(REG_CLKSWITCH0, 20),
0164         },
0165         .div_flags = BERLIN2_DIV_HAS_GATE | BERLIN2_DIV_HAS_MUX,
0166         .flags = CLK_IGNORE_UNUSED,
0167     },
0168     {
0169         .name = "pcube",
0170         .parent_ids = default_parent_ids,
0171         .num_parents = ARRAY_SIZE(default_parent_ids),
0172         .map = {
0173             BERLIN2_DIV_GATE(REG_CLKENABLE, 2),
0174             BERLIN2_PLL_SELECT(REG_CLKSELECT1, 6),
0175             BERLIN2_DIV_SELECT(REG_CLKSELECT1, 9),
0176             BERLIN2_PLL_SWITCH(REG_CLKSWITCH0, 21),
0177             BERLIN2_DIV_SWITCH(REG_CLKSWITCH0, 22),
0178             BERLIN2_DIV_D3SWITCH(REG_CLKSWITCH0, 23),
0179         },
0180         .div_flags = BERLIN2_DIV_HAS_GATE | BERLIN2_DIV_HAS_MUX,
0181         .flags = 0,
0182     },
0183     {
0184         .name = "vscope",
0185         .parent_ids = default_parent_ids,
0186         .num_parents = ARRAY_SIZE(default_parent_ids),
0187         .map = {
0188             BERLIN2_DIV_GATE(REG_CLKENABLE, 3),
0189             BERLIN2_PLL_SELECT(REG_CLKSELECT1, 12),
0190             BERLIN2_DIV_SELECT(REG_CLKSELECT1, 15),
0191             BERLIN2_PLL_SWITCH(REG_CLKSWITCH0, 24),
0192             BERLIN2_DIV_SWITCH(REG_CLKSWITCH0, 25),
0193             BERLIN2_DIV_D3SWITCH(REG_CLKSWITCH0, 26),
0194         },
0195         .div_flags = BERLIN2_DIV_HAS_GATE | BERLIN2_DIV_HAS_MUX,
0196         .flags = 0,
0197     },
0198     {
0199         .name = "nfc_ecc",
0200         .parent_ids = default_parent_ids,
0201         .num_parents = ARRAY_SIZE(default_parent_ids),
0202         .map = {
0203             BERLIN2_DIV_GATE(REG_CLKENABLE, 19),
0204             BERLIN2_PLL_SELECT(REG_CLKSELECT1, 18),
0205             BERLIN2_DIV_SELECT(REG_CLKSELECT1, 21),
0206             BERLIN2_PLL_SWITCH(REG_CLKSWITCH0, 27),
0207             BERLIN2_DIV_SWITCH(REG_CLKSWITCH0, 28),
0208             BERLIN2_DIV_D3SWITCH(REG_CLKSWITCH0, 29),
0209         },
0210         .div_flags = BERLIN2_DIV_HAS_GATE | BERLIN2_DIV_HAS_MUX,
0211         .flags = 0,
0212     },
0213     {
0214         .name = "vpp",
0215         .parent_ids = default_parent_ids,
0216         .num_parents = ARRAY_SIZE(default_parent_ids),
0217         .map = {
0218             BERLIN2_DIV_GATE(REG_CLKENABLE, 21),
0219             BERLIN2_PLL_SELECT(REG_CLKSELECT1, 24),
0220             BERLIN2_DIV_SELECT(REG_CLKSELECT1, 27),
0221             BERLIN2_PLL_SWITCH(REG_CLKSWITCH0, 30),
0222             BERLIN2_DIV_SWITCH(REG_CLKSWITCH0, 31),
0223             BERLIN2_DIV_D3SWITCH(REG_CLKSWITCH1, 0),
0224         },
0225         .div_flags = BERLIN2_DIV_HAS_GATE | BERLIN2_DIV_HAS_MUX,
0226         .flags = 0,
0227     },
0228     {
0229         .name = "app",
0230         .parent_ids = default_parent_ids,
0231         .num_parents = ARRAY_SIZE(default_parent_ids),
0232         .map = {
0233             BERLIN2_DIV_GATE(REG_CLKENABLE, 20),
0234             BERLIN2_PLL_SELECT(REG_CLKSELECT2, 0),
0235             BERLIN2_DIV_SELECT(REG_CLKSELECT2, 3),
0236             BERLIN2_PLL_SWITCH(REG_CLKSWITCH1, 1),
0237             BERLIN2_DIV_SWITCH(REG_CLKSWITCH1, 2),
0238             BERLIN2_DIV_D3SWITCH(REG_CLKSWITCH1, 3),
0239         },
0240         .div_flags = BERLIN2_DIV_HAS_GATE | BERLIN2_DIV_HAS_MUX,
0241         .flags = 0,
0242     },
0243     {
0244         .name = "sdio0xin",
0245         .parent_ids = default_parent_ids,
0246         .num_parents = ARRAY_SIZE(default_parent_ids),
0247         .map = {
0248             BERLIN2_SINGLE_DIV(REG_SDIO0XIN_CLKCTL),
0249         },
0250         .div_flags = BERLIN2_DIV_HAS_GATE | BERLIN2_DIV_HAS_MUX,
0251         .flags = 0,
0252     },
0253     {
0254         .name = "sdio1xin",
0255         .parent_ids = default_parent_ids,
0256         .num_parents = ARRAY_SIZE(default_parent_ids),
0257         .map = {
0258             BERLIN2_SINGLE_DIV(REG_SDIO1XIN_CLKCTL),
0259         },
0260         .div_flags = BERLIN2_DIV_HAS_GATE | BERLIN2_DIV_HAS_MUX,
0261         .flags = 0,
0262     },
0263 };
0264 
0265 static const struct berlin2_gate_data bg2q_gates[] __initconst = {
0266     { "gfx2daxi",   "perif",    5 },
0267     { "geth0",  "perif",    8 },
0268     { "sata",   "perif",    9 },
0269     { "ahbapb", "perif",    10, CLK_IGNORE_UNUSED },
0270     { "usb0",   "perif",    11 },
0271     { "usb1",   "perif",    12 },
0272     { "usb2",   "perif",    13 },
0273     { "usb3",   "perif",    14 },
0274     { "pbridge",    "perif",    15, CLK_IGNORE_UNUSED },
0275     { "sdio",   "perif",    16 },
0276     { "nfc",    "perif",    18 },
0277     { "pcie",   "perif",    22 },
0278 };
0279 
0280 static void __init berlin2q_clock_setup(struct device_node *np)
0281 {
0282     struct device_node *parent_np = of_get_parent(np);
0283     const char *parent_names[9];
0284     struct clk *clk;
0285     struct clk_hw **hws;
0286     int n, ret;
0287 
0288     clk_data = kzalloc(struct_size(clk_data, hws, MAX_CLKS), GFP_KERNEL);
0289     if (!clk_data)
0290         return;
0291     clk_data->num = MAX_CLKS;
0292     hws = clk_data->hws;
0293 
0294     gbase = of_iomap(parent_np, 0);
0295     if (!gbase) {
0296         pr_err("%pOF: Unable to map global base\n", np);
0297         return;
0298     }
0299 
0300     /* BG2Q CPU PLL is not part of global registers */
0301     cpupll_base = of_iomap(parent_np, 1);
0302     if (!cpupll_base) {
0303         pr_err("%pOF: Unable to map cpupll base\n", np);
0304         iounmap(gbase);
0305         return;
0306     }
0307 
0308     /* overwrite default clock names with DT provided ones */
0309     clk = of_clk_get_by_name(np, clk_names[REFCLK]);
0310     if (!IS_ERR(clk)) {
0311         clk_names[REFCLK] = __clk_get_name(clk);
0312         clk_put(clk);
0313     }
0314 
0315     /* simple register PLLs */
0316     ret = berlin2_pll_register(&bg2q_pll_map, gbase + REG_SYSPLLCTL0,
0317                    clk_names[SYSPLL], clk_names[REFCLK], 0);
0318     if (ret)
0319         goto bg2q_fail;
0320 
0321     ret = berlin2_pll_register(&bg2q_pll_map, cpupll_base,
0322                    clk_names[CPUPLL], clk_names[REFCLK], 0);
0323     if (ret)
0324         goto bg2q_fail;
0325 
0326     /* TODO: add BG2Q AVPLL */
0327 
0328     /*
0329      * TODO: add reference clock bypass switches:
0330      * memPLLSWBypass, cpuPLLSWBypass, and sysPLLSWBypass
0331      */
0332 
0333     /* clock divider cells */
0334     for (n = 0; n < ARRAY_SIZE(bg2q_divs); n++) {
0335         const struct berlin2_div_data *dd = &bg2q_divs[n];
0336         int k;
0337 
0338         for (k = 0; k < dd->num_parents; k++)
0339             parent_names[k] = clk_names[dd->parent_ids[k]];
0340 
0341         hws[CLKID_SYS + n] = berlin2_div_register(&dd->map, gbase,
0342                 dd->name, dd->div_flags, parent_names,
0343                 dd->num_parents, dd->flags, &lock);
0344     }
0345 
0346     /* clock gate cells */
0347     for (n = 0; n < ARRAY_SIZE(bg2q_gates); n++) {
0348         const struct berlin2_gate_data *gd = &bg2q_gates[n];
0349 
0350         hws[CLKID_GFX2DAXI + n] = clk_hw_register_gate(NULL, gd->name,
0351                 gd->parent_name, gd->flags, gbase + REG_CLKENABLE,
0352                 gd->bit_idx, 0, &lock);
0353     }
0354 
0355     /* cpuclk divider is fixed to 1 */
0356     hws[CLKID_CPU] =
0357         clk_hw_register_fixed_factor(NULL, "cpu", clk_names[CPUPLL],
0358                       0, 1, 1);
0359     /* twdclk is derived from cpu/3 */
0360     hws[CLKID_TWD] =
0361         clk_hw_register_fixed_factor(NULL, "twd", "cpu", 0, 1, 3);
0362 
0363     /* check for errors on leaf clocks */
0364     for (n = 0; n < MAX_CLKS; n++) {
0365         if (!IS_ERR(hws[n]))
0366             continue;
0367 
0368         pr_err("%pOF: Unable to register leaf clock %d\n", np, n);
0369         goto bg2q_fail;
0370     }
0371 
0372     /* register clk-provider */
0373     of_clk_add_hw_provider(np, of_clk_hw_onecell_get, clk_data);
0374 
0375     return;
0376 
0377 bg2q_fail:
0378     iounmap(cpupll_base);
0379     iounmap(gbase);
0380 }
0381 CLK_OF_DECLARE(berlin2q_clk, "marvell,berlin2q-clk",
0382            berlin2q_clock_setup);