18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Copyright (c) 2014 Marvell Technology Group Ltd. 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Alexandre Belloni <alexandre.belloni@free-electrons.com> 68c2ecf20Sopenharmony_ci * Sebastian Hesselbarth <sebastian.hesselbarth@gmail.com> 78c2ecf20Sopenharmony_ci */ 88c2ecf20Sopenharmony_ci 98c2ecf20Sopenharmony_ci#include <linux/clk.h> 108c2ecf20Sopenharmony_ci#include <linux/clk-provider.h> 118c2ecf20Sopenharmony_ci#include <linux/io.h> 128c2ecf20Sopenharmony_ci#include <linux/kernel.h> 138c2ecf20Sopenharmony_ci#include <linux/of.h> 148c2ecf20Sopenharmony_ci#include <linux/of_address.h> 158c2ecf20Sopenharmony_ci#include <linux/slab.h> 168c2ecf20Sopenharmony_ci 178c2ecf20Sopenharmony_ci#include <dt-bindings/clock/berlin2q.h> 188c2ecf20Sopenharmony_ci 198c2ecf20Sopenharmony_ci#include "berlin2-div.h" 208c2ecf20Sopenharmony_ci#include "berlin2-pll.h" 218c2ecf20Sopenharmony_ci#include "common.h" 228c2ecf20Sopenharmony_ci 238c2ecf20Sopenharmony_ci#define REG_PINMUX0 0x0018 248c2ecf20Sopenharmony_ci#define REG_PINMUX5 0x002c 258c2ecf20Sopenharmony_ci#define REG_SYSPLLCTL0 0x0030 268c2ecf20Sopenharmony_ci#define REG_SYSPLLCTL4 0x0040 278c2ecf20Sopenharmony_ci#define REG_CLKENABLE 0x00e8 288c2ecf20Sopenharmony_ci#define REG_CLKSELECT0 0x00ec 298c2ecf20Sopenharmony_ci#define REG_CLKSELECT1 0x00f0 308c2ecf20Sopenharmony_ci#define REG_CLKSELECT2 0x00f4 318c2ecf20Sopenharmony_ci#define REG_CLKSWITCH0 0x00f8 328c2ecf20Sopenharmony_ci#define REG_CLKSWITCH1 0x00fc 338c2ecf20Sopenharmony_ci#define REG_SW_GENERIC0 0x0110 348c2ecf20Sopenharmony_ci#define REG_SW_GENERIC3 0x011c 358c2ecf20Sopenharmony_ci#define REG_SDIO0XIN_CLKCTL 0x0158 368c2ecf20Sopenharmony_ci#define REG_SDIO1XIN_CLKCTL 0x015c 378c2ecf20Sopenharmony_ci 388c2ecf20Sopenharmony_ci#define MAX_CLKS 28 398c2ecf20Sopenharmony_cistatic struct clk_hw_onecell_data *clk_data; 408c2ecf20Sopenharmony_cistatic DEFINE_SPINLOCK(lock); 418c2ecf20Sopenharmony_cistatic void __iomem *gbase; 428c2ecf20Sopenharmony_cistatic void __iomem *cpupll_base; 438c2ecf20Sopenharmony_ci 448c2ecf20Sopenharmony_cienum { 458c2ecf20Sopenharmony_ci REFCLK, 468c2ecf20Sopenharmony_ci SYSPLL, CPUPLL, 478c2ecf20Sopenharmony_ci AVPLL_B1, AVPLL_B2, AVPLL_B3, AVPLL_B4, 488c2ecf20Sopenharmony_ci AVPLL_B5, AVPLL_B6, AVPLL_B7, AVPLL_B8, 498c2ecf20Sopenharmony_ci}; 508c2ecf20Sopenharmony_ci 518c2ecf20Sopenharmony_cistatic const char *clk_names[] = { 528c2ecf20Sopenharmony_ci [REFCLK] = "refclk", 538c2ecf20Sopenharmony_ci [SYSPLL] = "syspll", 548c2ecf20Sopenharmony_ci [CPUPLL] = "cpupll", 558c2ecf20Sopenharmony_ci [AVPLL_B1] = "avpll_b1", 568c2ecf20Sopenharmony_ci [AVPLL_B2] = "avpll_b2", 578c2ecf20Sopenharmony_ci [AVPLL_B3] = "avpll_b3", 588c2ecf20Sopenharmony_ci [AVPLL_B4] = "avpll_b4", 598c2ecf20Sopenharmony_ci [AVPLL_B5] = "avpll_b5", 608c2ecf20Sopenharmony_ci [AVPLL_B6] = "avpll_b6", 618c2ecf20Sopenharmony_ci [AVPLL_B7] = "avpll_b7", 628c2ecf20Sopenharmony_ci [AVPLL_B8] = "avpll_b8", 638c2ecf20Sopenharmony_ci}; 648c2ecf20Sopenharmony_ci 658c2ecf20Sopenharmony_cistatic const struct berlin2_pll_map bg2q_pll_map __initconst = { 668c2ecf20Sopenharmony_ci .vcodiv = {1, 0, 2, 0, 3, 4, 0, 6, 8}, 678c2ecf20Sopenharmony_ci .mult = 1, 688c2ecf20Sopenharmony_ci .fbdiv_shift = 7, 698c2ecf20Sopenharmony_ci .rfdiv_shift = 2, 708c2ecf20Sopenharmony_ci .divsel_shift = 9, 718c2ecf20Sopenharmony_ci}; 728c2ecf20Sopenharmony_ci 738c2ecf20Sopenharmony_cistatic const u8 default_parent_ids[] = { 748c2ecf20Sopenharmony_ci SYSPLL, AVPLL_B4, AVPLL_B5, AVPLL_B6, AVPLL_B7, SYSPLL 758c2ecf20Sopenharmony_ci}; 768c2ecf20Sopenharmony_ci 778c2ecf20Sopenharmony_cistatic const struct berlin2_div_data bg2q_divs[] __initconst = { 788c2ecf20Sopenharmony_ci { 798c2ecf20Sopenharmony_ci .name = "sys", 808c2ecf20Sopenharmony_ci .parent_ids = default_parent_ids, 818c2ecf20Sopenharmony_ci .num_parents = ARRAY_SIZE(default_parent_ids), 828c2ecf20Sopenharmony_ci .map = { 838c2ecf20Sopenharmony_ci BERLIN2_DIV_GATE(REG_CLKENABLE, 0), 848c2ecf20Sopenharmony_ci BERLIN2_PLL_SELECT(REG_CLKSELECT0, 0), 858c2ecf20Sopenharmony_ci BERLIN2_DIV_SELECT(REG_CLKSELECT0, 3), 868c2ecf20Sopenharmony_ci BERLIN2_PLL_SWITCH(REG_CLKSWITCH0, 3), 878c2ecf20Sopenharmony_ci BERLIN2_DIV_SWITCH(REG_CLKSWITCH0, 4), 888c2ecf20Sopenharmony_ci BERLIN2_DIV_D3SWITCH(REG_CLKSWITCH0, 5), 898c2ecf20Sopenharmony_ci }, 908c2ecf20Sopenharmony_ci .div_flags = BERLIN2_DIV_HAS_GATE | BERLIN2_DIV_HAS_MUX, 918c2ecf20Sopenharmony_ci .flags = CLK_IGNORE_UNUSED, 928c2ecf20Sopenharmony_ci }, 938c2ecf20Sopenharmony_ci { 948c2ecf20Sopenharmony_ci .name = "drmfigo", 958c2ecf20Sopenharmony_ci .parent_ids = default_parent_ids, 968c2ecf20Sopenharmony_ci .num_parents = ARRAY_SIZE(default_parent_ids), 978c2ecf20Sopenharmony_ci .map = { 988c2ecf20Sopenharmony_ci BERLIN2_DIV_GATE(REG_CLKENABLE, 17), 998c2ecf20Sopenharmony_ci BERLIN2_PLL_SELECT(REG_CLKSELECT0, 6), 1008c2ecf20Sopenharmony_ci BERLIN2_DIV_SELECT(REG_CLKSELECT0, 9), 1018c2ecf20Sopenharmony_ci BERLIN2_PLL_SWITCH(REG_CLKSWITCH0, 6), 1028c2ecf20Sopenharmony_ci BERLIN2_DIV_SWITCH(REG_CLKSWITCH0, 7), 1038c2ecf20Sopenharmony_ci BERLIN2_DIV_D3SWITCH(REG_CLKSWITCH0, 8), 1048c2ecf20Sopenharmony_ci }, 1058c2ecf20Sopenharmony_ci .div_flags = BERLIN2_DIV_HAS_GATE | BERLIN2_DIV_HAS_MUX, 1068c2ecf20Sopenharmony_ci .flags = 0, 1078c2ecf20Sopenharmony_ci }, 1088c2ecf20Sopenharmony_ci { 1098c2ecf20Sopenharmony_ci .name = "cfg", 1108c2ecf20Sopenharmony_ci .parent_ids = default_parent_ids, 1118c2ecf20Sopenharmony_ci .num_parents = ARRAY_SIZE(default_parent_ids), 1128c2ecf20Sopenharmony_ci .map = { 1138c2ecf20Sopenharmony_ci BERLIN2_DIV_GATE(REG_CLKENABLE, 1), 1148c2ecf20Sopenharmony_ci BERLIN2_PLL_SELECT(REG_CLKSELECT0, 12), 1158c2ecf20Sopenharmony_ci BERLIN2_DIV_SELECT(REG_CLKSELECT0, 15), 1168c2ecf20Sopenharmony_ci BERLIN2_PLL_SWITCH(REG_CLKSWITCH0, 9), 1178c2ecf20Sopenharmony_ci BERLIN2_DIV_SWITCH(REG_CLKSWITCH0, 10), 1188c2ecf20Sopenharmony_ci BERLIN2_DIV_D3SWITCH(REG_CLKSWITCH0, 11), 1198c2ecf20Sopenharmony_ci }, 1208c2ecf20Sopenharmony_ci .div_flags = BERLIN2_DIV_HAS_GATE | BERLIN2_DIV_HAS_MUX, 1218c2ecf20Sopenharmony_ci .flags = 0, 1228c2ecf20Sopenharmony_ci }, 1238c2ecf20Sopenharmony_ci { 1248c2ecf20Sopenharmony_ci .name = "gfx2d", 1258c2ecf20Sopenharmony_ci .parent_ids = default_parent_ids, 1268c2ecf20Sopenharmony_ci .num_parents = ARRAY_SIZE(default_parent_ids), 1278c2ecf20Sopenharmony_ci .map = { 1288c2ecf20Sopenharmony_ci BERLIN2_DIV_GATE(REG_CLKENABLE, 4), 1298c2ecf20Sopenharmony_ci BERLIN2_PLL_SELECT(REG_CLKSELECT0, 18), 1308c2ecf20Sopenharmony_ci BERLIN2_DIV_SELECT(REG_CLKSELECT0, 21), 1318c2ecf20Sopenharmony_ci BERLIN2_PLL_SWITCH(REG_CLKSWITCH0, 12), 1328c2ecf20Sopenharmony_ci BERLIN2_DIV_SWITCH(REG_CLKSWITCH0, 13), 1338c2ecf20Sopenharmony_ci BERLIN2_DIV_D3SWITCH(REG_CLKSWITCH0, 14), 1348c2ecf20Sopenharmony_ci }, 1358c2ecf20Sopenharmony_ci .div_flags = BERLIN2_DIV_HAS_GATE | BERLIN2_DIV_HAS_MUX, 1368c2ecf20Sopenharmony_ci .flags = 0, 1378c2ecf20Sopenharmony_ci }, 1388c2ecf20Sopenharmony_ci { 1398c2ecf20Sopenharmony_ci .name = "zsp", 1408c2ecf20Sopenharmony_ci .parent_ids = default_parent_ids, 1418c2ecf20Sopenharmony_ci .num_parents = ARRAY_SIZE(default_parent_ids), 1428c2ecf20Sopenharmony_ci .map = { 1438c2ecf20Sopenharmony_ci BERLIN2_DIV_GATE(REG_CLKENABLE, 6), 1448c2ecf20Sopenharmony_ci BERLIN2_PLL_SELECT(REG_CLKSELECT0, 24), 1458c2ecf20Sopenharmony_ci BERLIN2_DIV_SELECT(REG_CLKSELECT0, 27), 1468c2ecf20Sopenharmony_ci BERLIN2_PLL_SWITCH(REG_CLKSWITCH0, 15), 1478c2ecf20Sopenharmony_ci BERLIN2_DIV_SWITCH(REG_CLKSWITCH0, 16), 1488c2ecf20Sopenharmony_ci BERLIN2_DIV_D3SWITCH(REG_CLKSWITCH0, 17), 1498c2ecf20Sopenharmony_ci }, 1508c2ecf20Sopenharmony_ci .div_flags = BERLIN2_DIV_HAS_GATE | BERLIN2_DIV_HAS_MUX, 1518c2ecf20Sopenharmony_ci .flags = 0, 1528c2ecf20Sopenharmony_ci }, 1538c2ecf20Sopenharmony_ci { 1548c2ecf20Sopenharmony_ci .name = "perif", 1558c2ecf20Sopenharmony_ci .parent_ids = default_parent_ids, 1568c2ecf20Sopenharmony_ci .num_parents = ARRAY_SIZE(default_parent_ids), 1578c2ecf20Sopenharmony_ci .map = { 1588c2ecf20Sopenharmony_ci BERLIN2_DIV_GATE(REG_CLKENABLE, 7), 1598c2ecf20Sopenharmony_ci BERLIN2_PLL_SELECT(REG_CLKSELECT1, 0), 1608c2ecf20Sopenharmony_ci BERLIN2_DIV_SELECT(REG_CLKSELECT1, 3), 1618c2ecf20Sopenharmony_ci BERLIN2_PLL_SWITCH(REG_CLKSWITCH0, 18), 1628c2ecf20Sopenharmony_ci BERLIN2_DIV_SWITCH(REG_CLKSWITCH0, 19), 1638c2ecf20Sopenharmony_ci BERLIN2_DIV_D3SWITCH(REG_CLKSWITCH0, 20), 1648c2ecf20Sopenharmony_ci }, 1658c2ecf20Sopenharmony_ci .div_flags = BERLIN2_DIV_HAS_GATE | BERLIN2_DIV_HAS_MUX, 1668c2ecf20Sopenharmony_ci .flags = CLK_IGNORE_UNUSED, 1678c2ecf20Sopenharmony_ci }, 1688c2ecf20Sopenharmony_ci { 1698c2ecf20Sopenharmony_ci .name = "pcube", 1708c2ecf20Sopenharmony_ci .parent_ids = default_parent_ids, 1718c2ecf20Sopenharmony_ci .num_parents = ARRAY_SIZE(default_parent_ids), 1728c2ecf20Sopenharmony_ci .map = { 1738c2ecf20Sopenharmony_ci BERLIN2_DIV_GATE(REG_CLKENABLE, 2), 1748c2ecf20Sopenharmony_ci BERLIN2_PLL_SELECT(REG_CLKSELECT1, 6), 1758c2ecf20Sopenharmony_ci BERLIN2_DIV_SELECT(REG_CLKSELECT1, 9), 1768c2ecf20Sopenharmony_ci BERLIN2_PLL_SWITCH(REG_CLKSWITCH0, 21), 1778c2ecf20Sopenharmony_ci BERLIN2_DIV_SWITCH(REG_CLKSWITCH0, 22), 1788c2ecf20Sopenharmony_ci BERLIN2_DIV_D3SWITCH(REG_CLKSWITCH0, 23), 1798c2ecf20Sopenharmony_ci }, 1808c2ecf20Sopenharmony_ci .div_flags = BERLIN2_DIV_HAS_GATE | BERLIN2_DIV_HAS_MUX, 1818c2ecf20Sopenharmony_ci .flags = 0, 1828c2ecf20Sopenharmony_ci }, 1838c2ecf20Sopenharmony_ci { 1848c2ecf20Sopenharmony_ci .name = "vscope", 1858c2ecf20Sopenharmony_ci .parent_ids = default_parent_ids, 1868c2ecf20Sopenharmony_ci .num_parents = ARRAY_SIZE(default_parent_ids), 1878c2ecf20Sopenharmony_ci .map = { 1888c2ecf20Sopenharmony_ci BERLIN2_DIV_GATE(REG_CLKENABLE, 3), 1898c2ecf20Sopenharmony_ci BERLIN2_PLL_SELECT(REG_CLKSELECT1, 12), 1908c2ecf20Sopenharmony_ci BERLIN2_DIV_SELECT(REG_CLKSELECT1, 15), 1918c2ecf20Sopenharmony_ci BERLIN2_PLL_SWITCH(REG_CLKSWITCH0, 24), 1928c2ecf20Sopenharmony_ci BERLIN2_DIV_SWITCH(REG_CLKSWITCH0, 25), 1938c2ecf20Sopenharmony_ci BERLIN2_DIV_D3SWITCH(REG_CLKSWITCH0, 26), 1948c2ecf20Sopenharmony_ci }, 1958c2ecf20Sopenharmony_ci .div_flags = BERLIN2_DIV_HAS_GATE | BERLIN2_DIV_HAS_MUX, 1968c2ecf20Sopenharmony_ci .flags = 0, 1978c2ecf20Sopenharmony_ci }, 1988c2ecf20Sopenharmony_ci { 1998c2ecf20Sopenharmony_ci .name = "nfc_ecc", 2008c2ecf20Sopenharmony_ci .parent_ids = default_parent_ids, 2018c2ecf20Sopenharmony_ci .num_parents = ARRAY_SIZE(default_parent_ids), 2028c2ecf20Sopenharmony_ci .map = { 2038c2ecf20Sopenharmony_ci BERLIN2_DIV_GATE(REG_CLKENABLE, 19), 2048c2ecf20Sopenharmony_ci BERLIN2_PLL_SELECT(REG_CLKSELECT1, 18), 2058c2ecf20Sopenharmony_ci BERLIN2_DIV_SELECT(REG_CLKSELECT1, 21), 2068c2ecf20Sopenharmony_ci BERLIN2_PLL_SWITCH(REG_CLKSWITCH0, 27), 2078c2ecf20Sopenharmony_ci BERLIN2_DIV_SWITCH(REG_CLKSWITCH0, 28), 2088c2ecf20Sopenharmony_ci BERLIN2_DIV_D3SWITCH(REG_CLKSWITCH0, 29), 2098c2ecf20Sopenharmony_ci }, 2108c2ecf20Sopenharmony_ci .div_flags = BERLIN2_DIV_HAS_GATE | BERLIN2_DIV_HAS_MUX, 2118c2ecf20Sopenharmony_ci .flags = 0, 2128c2ecf20Sopenharmony_ci }, 2138c2ecf20Sopenharmony_ci { 2148c2ecf20Sopenharmony_ci .name = "vpp", 2158c2ecf20Sopenharmony_ci .parent_ids = default_parent_ids, 2168c2ecf20Sopenharmony_ci .num_parents = ARRAY_SIZE(default_parent_ids), 2178c2ecf20Sopenharmony_ci .map = { 2188c2ecf20Sopenharmony_ci BERLIN2_DIV_GATE(REG_CLKENABLE, 21), 2198c2ecf20Sopenharmony_ci BERLIN2_PLL_SELECT(REG_CLKSELECT1, 24), 2208c2ecf20Sopenharmony_ci BERLIN2_DIV_SELECT(REG_CLKSELECT1, 27), 2218c2ecf20Sopenharmony_ci BERLIN2_PLL_SWITCH(REG_CLKSWITCH0, 30), 2228c2ecf20Sopenharmony_ci BERLIN2_DIV_SWITCH(REG_CLKSWITCH0, 31), 2238c2ecf20Sopenharmony_ci BERLIN2_DIV_D3SWITCH(REG_CLKSWITCH1, 0), 2248c2ecf20Sopenharmony_ci }, 2258c2ecf20Sopenharmony_ci .div_flags = BERLIN2_DIV_HAS_GATE | BERLIN2_DIV_HAS_MUX, 2268c2ecf20Sopenharmony_ci .flags = 0, 2278c2ecf20Sopenharmony_ci }, 2288c2ecf20Sopenharmony_ci { 2298c2ecf20Sopenharmony_ci .name = "app", 2308c2ecf20Sopenharmony_ci .parent_ids = default_parent_ids, 2318c2ecf20Sopenharmony_ci .num_parents = ARRAY_SIZE(default_parent_ids), 2328c2ecf20Sopenharmony_ci .map = { 2338c2ecf20Sopenharmony_ci BERLIN2_DIV_GATE(REG_CLKENABLE, 20), 2348c2ecf20Sopenharmony_ci BERLIN2_PLL_SELECT(REG_CLKSELECT2, 0), 2358c2ecf20Sopenharmony_ci BERLIN2_DIV_SELECT(REG_CLKSELECT2, 3), 2368c2ecf20Sopenharmony_ci BERLIN2_PLL_SWITCH(REG_CLKSWITCH1, 1), 2378c2ecf20Sopenharmony_ci BERLIN2_DIV_SWITCH(REG_CLKSWITCH1, 2), 2388c2ecf20Sopenharmony_ci BERLIN2_DIV_D3SWITCH(REG_CLKSWITCH1, 3), 2398c2ecf20Sopenharmony_ci }, 2408c2ecf20Sopenharmony_ci .div_flags = BERLIN2_DIV_HAS_GATE | BERLIN2_DIV_HAS_MUX, 2418c2ecf20Sopenharmony_ci .flags = 0, 2428c2ecf20Sopenharmony_ci }, 2438c2ecf20Sopenharmony_ci { 2448c2ecf20Sopenharmony_ci .name = "sdio0xin", 2458c2ecf20Sopenharmony_ci .parent_ids = default_parent_ids, 2468c2ecf20Sopenharmony_ci .num_parents = ARRAY_SIZE(default_parent_ids), 2478c2ecf20Sopenharmony_ci .map = { 2488c2ecf20Sopenharmony_ci BERLIN2_SINGLE_DIV(REG_SDIO0XIN_CLKCTL), 2498c2ecf20Sopenharmony_ci }, 2508c2ecf20Sopenharmony_ci .div_flags = BERLIN2_DIV_HAS_GATE | BERLIN2_DIV_HAS_MUX, 2518c2ecf20Sopenharmony_ci .flags = 0, 2528c2ecf20Sopenharmony_ci }, 2538c2ecf20Sopenharmony_ci { 2548c2ecf20Sopenharmony_ci .name = "sdio1xin", 2558c2ecf20Sopenharmony_ci .parent_ids = default_parent_ids, 2568c2ecf20Sopenharmony_ci .num_parents = ARRAY_SIZE(default_parent_ids), 2578c2ecf20Sopenharmony_ci .map = { 2588c2ecf20Sopenharmony_ci BERLIN2_SINGLE_DIV(REG_SDIO1XIN_CLKCTL), 2598c2ecf20Sopenharmony_ci }, 2608c2ecf20Sopenharmony_ci .div_flags = BERLIN2_DIV_HAS_GATE | BERLIN2_DIV_HAS_MUX, 2618c2ecf20Sopenharmony_ci .flags = 0, 2628c2ecf20Sopenharmony_ci }, 2638c2ecf20Sopenharmony_ci}; 2648c2ecf20Sopenharmony_ci 2658c2ecf20Sopenharmony_cistatic const struct berlin2_gate_data bg2q_gates[] __initconst = { 2668c2ecf20Sopenharmony_ci { "gfx2daxi", "perif", 5 }, 2678c2ecf20Sopenharmony_ci { "geth0", "perif", 8 }, 2688c2ecf20Sopenharmony_ci { "sata", "perif", 9 }, 2698c2ecf20Sopenharmony_ci { "ahbapb", "perif", 10, CLK_IGNORE_UNUSED }, 2708c2ecf20Sopenharmony_ci { "usb0", "perif", 11 }, 2718c2ecf20Sopenharmony_ci { "usb1", "perif", 12 }, 2728c2ecf20Sopenharmony_ci { "usb2", "perif", 13 }, 2738c2ecf20Sopenharmony_ci { "usb3", "perif", 14 }, 2748c2ecf20Sopenharmony_ci { "pbridge", "perif", 15, CLK_IGNORE_UNUSED }, 2758c2ecf20Sopenharmony_ci { "sdio", "perif", 16 }, 2768c2ecf20Sopenharmony_ci { "nfc", "perif", 18 }, 2778c2ecf20Sopenharmony_ci { "pcie", "perif", 22 }, 2788c2ecf20Sopenharmony_ci}; 2798c2ecf20Sopenharmony_ci 2808c2ecf20Sopenharmony_cistatic void __init berlin2q_clock_setup(struct device_node *np) 2818c2ecf20Sopenharmony_ci{ 2828c2ecf20Sopenharmony_ci struct device_node *parent_np = of_get_parent(np); 2838c2ecf20Sopenharmony_ci const char *parent_names[9]; 2848c2ecf20Sopenharmony_ci struct clk *clk; 2858c2ecf20Sopenharmony_ci struct clk_hw **hws; 2868c2ecf20Sopenharmony_ci int n, ret; 2878c2ecf20Sopenharmony_ci 2888c2ecf20Sopenharmony_ci clk_data = kzalloc(struct_size(clk_data, hws, MAX_CLKS), GFP_KERNEL); 2898c2ecf20Sopenharmony_ci if (!clk_data) { 2908c2ecf20Sopenharmony_ci of_node_put(parent_np); 2918c2ecf20Sopenharmony_ci return; 2928c2ecf20Sopenharmony_ci } 2938c2ecf20Sopenharmony_ci clk_data->num = MAX_CLKS; 2948c2ecf20Sopenharmony_ci hws = clk_data->hws; 2958c2ecf20Sopenharmony_ci 2968c2ecf20Sopenharmony_ci gbase = of_iomap(parent_np, 0); 2978c2ecf20Sopenharmony_ci if (!gbase) { 2988c2ecf20Sopenharmony_ci of_node_put(parent_np); 2998c2ecf20Sopenharmony_ci pr_err("%pOF: Unable to map global base\n", np); 3008c2ecf20Sopenharmony_ci return; 3018c2ecf20Sopenharmony_ci } 3028c2ecf20Sopenharmony_ci 3038c2ecf20Sopenharmony_ci /* BG2Q CPU PLL is not part of global registers */ 3048c2ecf20Sopenharmony_ci cpupll_base = of_iomap(parent_np, 1); 3058c2ecf20Sopenharmony_ci of_node_put(parent_np); 3068c2ecf20Sopenharmony_ci if (!cpupll_base) { 3078c2ecf20Sopenharmony_ci pr_err("%pOF: Unable to map cpupll base\n", np); 3088c2ecf20Sopenharmony_ci iounmap(gbase); 3098c2ecf20Sopenharmony_ci return; 3108c2ecf20Sopenharmony_ci } 3118c2ecf20Sopenharmony_ci 3128c2ecf20Sopenharmony_ci /* overwrite default clock names with DT provided ones */ 3138c2ecf20Sopenharmony_ci clk = of_clk_get_by_name(np, clk_names[REFCLK]); 3148c2ecf20Sopenharmony_ci if (!IS_ERR(clk)) { 3158c2ecf20Sopenharmony_ci clk_names[REFCLK] = __clk_get_name(clk); 3168c2ecf20Sopenharmony_ci clk_put(clk); 3178c2ecf20Sopenharmony_ci } 3188c2ecf20Sopenharmony_ci 3198c2ecf20Sopenharmony_ci /* simple register PLLs */ 3208c2ecf20Sopenharmony_ci ret = berlin2_pll_register(&bg2q_pll_map, gbase + REG_SYSPLLCTL0, 3218c2ecf20Sopenharmony_ci clk_names[SYSPLL], clk_names[REFCLK], 0); 3228c2ecf20Sopenharmony_ci if (ret) 3238c2ecf20Sopenharmony_ci goto bg2q_fail; 3248c2ecf20Sopenharmony_ci 3258c2ecf20Sopenharmony_ci ret = berlin2_pll_register(&bg2q_pll_map, cpupll_base, 3268c2ecf20Sopenharmony_ci clk_names[CPUPLL], clk_names[REFCLK], 0); 3278c2ecf20Sopenharmony_ci if (ret) 3288c2ecf20Sopenharmony_ci goto bg2q_fail; 3298c2ecf20Sopenharmony_ci 3308c2ecf20Sopenharmony_ci /* TODO: add BG2Q AVPLL */ 3318c2ecf20Sopenharmony_ci 3328c2ecf20Sopenharmony_ci /* 3338c2ecf20Sopenharmony_ci * TODO: add reference clock bypass switches: 3348c2ecf20Sopenharmony_ci * memPLLSWBypass, cpuPLLSWBypass, and sysPLLSWBypass 3358c2ecf20Sopenharmony_ci */ 3368c2ecf20Sopenharmony_ci 3378c2ecf20Sopenharmony_ci /* clock divider cells */ 3388c2ecf20Sopenharmony_ci for (n = 0; n < ARRAY_SIZE(bg2q_divs); n++) { 3398c2ecf20Sopenharmony_ci const struct berlin2_div_data *dd = &bg2q_divs[n]; 3408c2ecf20Sopenharmony_ci int k; 3418c2ecf20Sopenharmony_ci 3428c2ecf20Sopenharmony_ci for (k = 0; k < dd->num_parents; k++) 3438c2ecf20Sopenharmony_ci parent_names[k] = clk_names[dd->parent_ids[k]]; 3448c2ecf20Sopenharmony_ci 3458c2ecf20Sopenharmony_ci hws[CLKID_SYS + n] = berlin2_div_register(&dd->map, gbase, 3468c2ecf20Sopenharmony_ci dd->name, dd->div_flags, parent_names, 3478c2ecf20Sopenharmony_ci dd->num_parents, dd->flags, &lock); 3488c2ecf20Sopenharmony_ci } 3498c2ecf20Sopenharmony_ci 3508c2ecf20Sopenharmony_ci /* clock gate cells */ 3518c2ecf20Sopenharmony_ci for (n = 0; n < ARRAY_SIZE(bg2q_gates); n++) { 3528c2ecf20Sopenharmony_ci const struct berlin2_gate_data *gd = &bg2q_gates[n]; 3538c2ecf20Sopenharmony_ci 3548c2ecf20Sopenharmony_ci hws[CLKID_GFX2DAXI + n] = clk_hw_register_gate(NULL, gd->name, 3558c2ecf20Sopenharmony_ci gd->parent_name, gd->flags, gbase + REG_CLKENABLE, 3568c2ecf20Sopenharmony_ci gd->bit_idx, 0, &lock); 3578c2ecf20Sopenharmony_ci } 3588c2ecf20Sopenharmony_ci 3598c2ecf20Sopenharmony_ci /* cpuclk divider is fixed to 1 */ 3608c2ecf20Sopenharmony_ci hws[CLKID_CPU] = 3618c2ecf20Sopenharmony_ci clk_hw_register_fixed_factor(NULL, "cpu", clk_names[CPUPLL], 3628c2ecf20Sopenharmony_ci 0, 1, 1); 3638c2ecf20Sopenharmony_ci /* twdclk is derived from cpu/3 */ 3648c2ecf20Sopenharmony_ci hws[CLKID_TWD] = 3658c2ecf20Sopenharmony_ci clk_hw_register_fixed_factor(NULL, "twd", "cpu", 0, 1, 3); 3668c2ecf20Sopenharmony_ci 3678c2ecf20Sopenharmony_ci /* check for errors on leaf clocks */ 3688c2ecf20Sopenharmony_ci for (n = 0; n < MAX_CLKS; n++) { 3698c2ecf20Sopenharmony_ci if (!IS_ERR(hws[n])) 3708c2ecf20Sopenharmony_ci continue; 3718c2ecf20Sopenharmony_ci 3728c2ecf20Sopenharmony_ci pr_err("%pOF: Unable to register leaf clock %d\n", np, n); 3738c2ecf20Sopenharmony_ci goto bg2q_fail; 3748c2ecf20Sopenharmony_ci } 3758c2ecf20Sopenharmony_ci 3768c2ecf20Sopenharmony_ci /* register clk-provider */ 3778c2ecf20Sopenharmony_ci of_clk_add_hw_provider(np, of_clk_hw_onecell_get, clk_data); 3788c2ecf20Sopenharmony_ci 3798c2ecf20Sopenharmony_ci return; 3808c2ecf20Sopenharmony_ci 3818c2ecf20Sopenharmony_cibg2q_fail: 3828c2ecf20Sopenharmony_ci iounmap(cpupll_base); 3838c2ecf20Sopenharmony_ci iounmap(gbase); 3848c2ecf20Sopenharmony_ci} 3858c2ecf20Sopenharmony_ciCLK_OF_DECLARE(berlin2q_clk, "marvell,berlin2q-clk", 3868c2ecf20Sopenharmony_ci berlin2q_clock_setup); 387