0001
0002
0003
0004
0005
0006
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
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
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
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
0327
0328
0329
0330
0331
0332
0333
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
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
0356 hws[CLKID_CPU] =
0357 clk_hw_register_fixed_factor(NULL, "cpu", clk_names[CPUPLL],
0358 0, 1, 1);
0359
0360 hws[CLKID_TWD] =
0361 clk_hw_register_fixed_factor(NULL, "twd", "cpu", 0, 1, 3);
0362
0363
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
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);