162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Copyright (c) 2014 Marvell Technology Group Ltd. 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Alexandre Belloni <alexandre.belloni@free-electrons.com> 662306a36Sopenharmony_ci * Sebastian Hesselbarth <sebastian.hesselbarth@gmail.com> 762306a36Sopenharmony_ci */ 862306a36Sopenharmony_ci 962306a36Sopenharmony_ci#include <linux/clk.h> 1062306a36Sopenharmony_ci#include <linux/clk-provider.h> 1162306a36Sopenharmony_ci#include <linux/io.h> 1262306a36Sopenharmony_ci#include <linux/kernel.h> 1362306a36Sopenharmony_ci#include <linux/of.h> 1462306a36Sopenharmony_ci#include <linux/of_address.h> 1562306a36Sopenharmony_ci#include <linux/slab.h> 1662306a36Sopenharmony_ci 1762306a36Sopenharmony_ci#include <dt-bindings/clock/berlin2q.h> 1862306a36Sopenharmony_ci 1962306a36Sopenharmony_ci#include "berlin2-div.h" 2062306a36Sopenharmony_ci#include "berlin2-pll.h" 2162306a36Sopenharmony_ci#include "common.h" 2262306a36Sopenharmony_ci 2362306a36Sopenharmony_ci#define REG_PINMUX0 0x0018 2462306a36Sopenharmony_ci#define REG_PINMUX5 0x002c 2562306a36Sopenharmony_ci#define REG_SYSPLLCTL0 0x0030 2662306a36Sopenharmony_ci#define REG_SYSPLLCTL4 0x0040 2762306a36Sopenharmony_ci#define REG_CLKENABLE 0x00e8 2862306a36Sopenharmony_ci#define REG_CLKSELECT0 0x00ec 2962306a36Sopenharmony_ci#define REG_CLKSELECT1 0x00f0 3062306a36Sopenharmony_ci#define REG_CLKSELECT2 0x00f4 3162306a36Sopenharmony_ci#define REG_CLKSWITCH0 0x00f8 3262306a36Sopenharmony_ci#define REG_CLKSWITCH1 0x00fc 3362306a36Sopenharmony_ci#define REG_SW_GENERIC0 0x0110 3462306a36Sopenharmony_ci#define REG_SW_GENERIC3 0x011c 3562306a36Sopenharmony_ci#define REG_SDIO0XIN_CLKCTL 0x0158 3662306a36Sopenharmony_ci#define REG_SDIO1XIN_CLKCTL 0x015c 3762306a36Sopenharmony_ci 3862306a36Sopenharmony_ci#define MAX_CLKS 28 3962306a36Sopenharmony_cistatic struct clk_hw_onecell_data *clk_data; 4062306a36Sopenharmony_cistatic DEFINE_SPINLOCK(lock); 4162306a36Sopenharmony_cistatic void __iomem *gbase; 4262306a36Sopenharmony_cistatic void __iomem *cpupll_base; 4362306a36Sopenharmony_ci 4462306a36Sopenharmony_cienum { 4562306a36Sopenharmony_ci REFCLK, 4662306a36Sopenharmony_ci SYSPLL, CPUPLL, 4762306a36Sopenharmony_ci AVPLL_B1, AVPLL_B2, AVPLL_B3, AVPLL_B4, 4862306a36Sopenharmony_ci AVPLL_B5, AVPLL_B6, AVPLL_B7, AVPLL_B8, 4962306a36Sopenharmony_ci}; 5062306a36Sopenharmony_ci 5162306a36Sopenharmony_cistatic const char *clk_names[] = { 5262306a36Sopenharmony_ci [REFCLK] = "refclk", 5362306a36Sopenharmony_ci [SYSPLL] = "syspll", 5462306a36Sopenharmony_ci [CPUPLL] = "cpupll", 5562306a36Sopenharmony_ci [AVPLL_B1] = "avpll_b1", 5662306a36Sopenharmony_ci [AVPLL_B2] = "avpll_b2", 5762306a36Sopenharmony_ci [AVPLL_B3] = "avpll_b3", 5862306a36Sopenharmony_ci [AVPLL_B4] = "avpll_b4", 5962306a36Sopenharmony_ci [AVPLL_B5] = "avpll_b5", 6062306a36Sopenharmony_ci [AVPLL_B6] = "avpll_b6", 6162306a36Sopenharmony_ci [AVPLL_B7] = "avpll_b7", 6262306a36Sopenharmony_ci [AVPLL_B8] = "avpll_b8", 6362306a36Sopenharmony_ci}; 6462306a36Sopenharmony_ci 6562306a36Sopenharmony_cistatic const struct berlin2_pll_map bg2q_pll_map __initconst = { 6662306a36Sopenharmony_ci .vcodiv = {1, 0, 2, 0, 3, 4, 0, 6, 8}, 6762306a36Sopenharmony_ci .mult = 1, 6862306a36Sopenharmony_ci .fbdiv_shift = 7, 6962306a36Sopenharmony_ci .rfdiv_shift = 2, 7062306a36Sopenharmony_ci .divsel_shift = 9, 7162306a36Sopenharmony_ci}; 7262306a36Sopenharmony_ci 7362306a36Sopenharmony_cistatic const u8 default_parent_ids[] = { 7462306a36Sopenharmony_ci SYSPLL, AVPLL_B4, AVPLL_B5, AVPLL_B6, AVPLL_B7, SYSPLL 7562306a36Sopenharmony_ci}; 7662306a36Sopenharmony_ci 7762306a36Sopenharmony_cistatic const struct berlin2_div_data bg2q_divs[] __initconst = { 7862306a36Sopenharmony_ci { 7962306a36Sopenharmony_ci .name = "sys", 8062306a36Sopenharmony_ci .parent_ids = default_parent_ids, 8162306a36Sopenharmony_ci .num_parents = ARRAY_SIZE(default_parent_ids), 8262306a36Sopenharmony_ci .map = { 8362306a36Sopenharmony_ci BERLIN2_DIV_GATE(REG_CLKENABLE, 0), 8462306a36Sopenharmony_ci BERLIN2_PLL_SELECT(REG_CLKSELECT0, 0), 8562306a36Sopenharmony_ci BERLIN2_DIV_SELECT(REG_CLKSELECT0, 3), 8662306a36Sopenharmony_ci BERLIN2_PLL_SWITCH(REG_CLKSWITCH0, 3), 8762306a36Sopenharmony_ci BERLIN2_DIV_SWITCH(REG_CLKSWITCH0, 4), 8862306a36Sopenharmony_ci BERLIN2_DIV_D3SWITCH(REG_CLKSWITCH0, 5), 8962306a36Sopenharmony_ci }, 9062306a36Sopenharmony_ci .div_flags = BERLIN2_DIV_HAS_GATE | BERLIN2_DIV_HAS_MUX, 9162306a36Sopenharmony_ci .flags = CLK_IGNORE_UNUSED, 9262306a36Sopenharmony_ci }, 9362306a36Sopenharmony_ci { 9462306a36Sopenharmony_ci .name = "drmfigo", 9562306a36Sopenharmony_ci .parent_ids = default_parent_ids, 9662306a36Sopenharmony_ci .num_parents = ARRAY_SIZE(default_parent_ids), 9762306a36Sopenharmony_ci .map = { 9862306a36Sopenharmony_ci BERLIN2_DIV_GATE(REG_CLKENABLE, 17), 9962306a36Sopenharmony_ci BERLIN2_PLL_SELECT(REG_CLKSELECT0, 6), 10062306a36Sopenharmony_ci BERLIN2_DIV_SELECT(REG_CLKSELECT0, 9), 10162306a36Sopenharmony_ci BERLIN2_PLL_SWITCH(REG_CLKSWITCH0, 6), 10262306a36Sopenharmony_ci BERLIN2_DIV_SWITCH(REG_CLKSWITCH0, 7), 10362306a36Sopenharmony_ci BERLIN2_DIV_D3SWITCH(REG_CLKSWITCH0, 8), 10462306a36Sopenharmony_ci }, 10562306a36Sopenharmony_ci .div_flags = BERLIN2_DIV_HAS_GATE | BERLIN2_DIV_HAS_MUX, 10662306a36Sopenharmony_ci .flags = 0, 10762306a36Sopenharmony_ci }, 10862306a36Sopenharmony_ci { 10962306a36Sopenharmony_ci .name = "cfg", 11062306a36Sopenharmony_ci .parent_ids = default_parent_ids, 11162306a36Sopenharmony_ci .num_parents = ARRAY_SIZE(default_parent_ids), 11262306a36Sopenharmony_ci .map = { 11362306a36Sopenharmony_ci BERLIN2_DIV_GATE(REG_CLKENABLE, 1), 11462306a36Sopenharmony_ci BERLIN2_PLL_SELECT(REG_CLKSELECT0, 12), 11562306a36Sopenharmony_ci BERLIN2_DIV_SELECT(REG_CLKSELECT0, 15), 11662306a36Sopenharmony_ci BERLIN2_PLL_SWITCH(REG_CLKSWITCH0, 9), 11762306a36Sopenharmony_ci BERLIN2_DIV_SWITCH(REG_CLKSWITCH0, 10), 11862306a36Sopenharmony_ci BERLIN2_DIV_D3SWITCH(REG_CLKSWITCH0, 11), 11962306a36Sopenharmony_ci }, 12062306a36Sopenharmony_ci .div_flags = BERLIN2_DIV_HAS_GATE | BERLIN2_DIV_HAS_MUX, 12162306a36Sopenharmony_ci .flags = 0, 12262306a36Sopenharmony_ci }, 12362306a36Sopenharmony_ci { 12462306a36Sopenharmony_ci .name = "gfx2d", 12562306a36Sopenharmony_ci .parent_ids = default_parent_ids, 12662306a36Sopenharmony_ci .num_parents = ARRAY_SIZE(default_parent_ids), 12762306a36Sopenharmony_ci .map = { 12862306a36Sopenharmony_ci BERLIN2_DIV_GATE(REG_CLKENABLE, 4), 12962306a36Sopenharmony_ci BERLIN2_PLL_SELECT(REG_CLKSELECT0, 18), 13062306a36Sopenharmony_ci BERLIN2_DIV_SELECT(REG_CLKSELECT0, 21), 13162306a36Sopenharmony_ci BERLIN2_PLL_SWITCH(REG_CLKSWITCH0, 12), 13262306a36Sopenharmony_ci BERLIN2_DIV_SWITCH(REG_CLKSWITCH0, 13), 13362306a36Sopenharmony_ci BERLIN2_DIV_D3SWITCH(REG_CLKSWITCH0, 14), 13462306a36Sopenharmony_ci }, 13562306a36Sopenharmony_ci .div_flags = BERLIN2_DIV_HAS_GATE | BERLIN2_DIV_HAS_MUX, 13662306a36Sopenharmony_ci .flags = 0, 13762306a36Sopenharmony_ci }, 13862306a36Sopenharmony_ci { 13962306a36Sopenharmony_ci .name = "zsp", 14062306a36Sopenharmony_ci .parent_ids = default_parent_ids, 14162306a36Sopenharmony_ci .num_parents = ARRAY_SIZE(default_parent_ids), 14262306a36Sopenharmony_ci .map = { 14362306a36Sopenharmony_ci BERLIN2_DIV_GATE(REG_CLKENABLE, 6), 14462306a36Sopenharmony_ci BERLIN2_PLL_SELECT(REG_CLKSELECT0, 24), 14562306a36Sopenharmony_ci BERLIN2_DIV_SELECT(REG_CLKSELECT0, 27), 14662306a36Sopenharmony_ci BERLIN2_PLL_SWITCH(REG_CLKSWITCH0, 15), 14762306a36Sopenharmony_ci BERLIN2_DIV_SWITCH(REG_CLKSWITCH0, 16), 14862306a36Sopenharmony_ci BERLIN2_DIV_D3SWITCH(REG_CLKSWITCH0, 17), 14962306a36Sopenharmony_ci }, 15062306a36Sopenharmony_ci .div_flags = BERLIN2_DIV_HAS_GATE | BERLIN2_DIV_HAS_MUX, 15162306a36Sopenharmony_ci .flags = 0, 15262306a36Sopenharmony_ci }, 15362306a36Sopenharmony_ci { 15462306a36Sopenharmony_ci .name = "perif", 15562306a36Sopenharmony_ci .parent_ids = default_parent_ids, 15662306a36Sopenharmony_ci .num_parents = ARRAY_SIZE(default_parent_ids), 15762306a36Sopenharmony_ci .map = { 15862306a36Sopenharmony_ci BERLIN2_DIV_GATE(REG_CLKENABLE, 7), 15962306a36Sopenharmony_ci BERLIN2_PLL_SELECT(REG_CLKSELECT1, 0), 16062306a36Sopenharmony_ci BERLIN2_DIV_SELECT(REG_CLKSELECT1, 3), 16162306a36Sopenharmony_ci BERLIN2_PLL_SWITCH(REG_CLKSWITCH0, 18), 16262306a36Sopenharmony_ci BERLIN2_DIV_SWITCH(REG_CLKSWITCH0, 19), 16362306a36Sopenharmony_ci BERLIN2_DIV_D3SWITCH(REG_CLKSWITCH0, 20), 16462306a36Sopenharmony_ci }, 16562306a36Sopenharmony_ci .div_flags = BERLIN2_DIV_HAS_GATE | BERLIN2_DIV_HAS_MUX, 16662306a36Sopenharmony_ci .flags = CLK_IGNORE_UNUSED, 16762306a36Sopenharmony_ci }, 16862306a36Sopenharmony_ci { 16962306a36Sopenharmony_ci .name = "pcube", 17062306a36Sopenharmony_ci .parent_ids = default_parent_ids, 17162306a36Sopenharmony_ci .num_parents = ARRAY_SIZE(default_parent_ids), 17262306a36Sopenharmony_ci .map = { 17362306a36Sopenharmony_ci BERLIN2_DIV_GATE(REG_CLKENABLE, 2), 17462306a36Sopenharmony_ci BERLIN2_PLL_SELECT(REG_CLKSELECT1, 6), 17562306a36Sopenharmony_ci BERLIN2_DIV_SELECT(REG_CLKSELECT1, 9), 17662306a36Sopenharmony_ci BERLIN2_PLL_SWITCH(REG_CLKSWITCH0, 21), 17762306a36Sopenharmony_ci BERLIN2_DIV_SWITCH(REG_CLKSWITCH0, 22), 17862306a36Sopenharmony_ci BERLIN2_DIV_D3SWITCH(REG_CLKSWITCH0, 23), 17962306a36Sopenharmony_ci }, 18062306a36Sopenharmony_ci .div_flags = BERLIN2_DIV_HAS_GATE | BERLIN2_DIV_HAS_MUX, 18162306a36Sopenharmony_ci .flags = 0, 18262306a36Sopenharmony_ci }, 18362306a36Sopenharmony_ci { 18462306a36Sopenharmony_ci .name = "vscope", 18562306a36Sopenharmony_ci .parent_ids = default_parent_ids, 18662306a36Sopenharmony_ci .num_parents = ARRAY_SIZE(default_parent_ids), 18762306a36Sopenharmony_ci .map = { 18862306a36Sopenharmony_ci BERLIN2_DIV_GATE(REG_CLKENABLE, 3), 18962306a36Sopenharmony_ci BERLIN2_PLL_SELECT(REG_CLKSELECT1, 12), 19062306a36Sopenharmony_ci BERLIN2_DIV_SELECT(REG_CLKSELECT1, 15), 19162306a36Sopenharmony_ci BERLIN2_PLL_SWITCH(REG_CLKSWITCH0, 24), 19262306a36Sopenharmony_ci BERLIN2_DIV_SWITCH(REG_CLKSWITCH0, 25), 19362306a36Sopenharmony_ci BERLIN2_DIV_D3SWITCH(REG_CLKSWITCH0, 26), 19462306a36Sopenharmony_ci }, 19562306a36Sopenharmony_ci .div_flags = BERLIN2_DIV_HAS_GATE | BERLIN2_DIV_HAS_MUX, 19662306a36Sopenharmony_ci .flags = 0, 19762306a36Sopenharmony_ci }, 19862306a36Sopenharmony_ci { 19962306a36Sopenharmony_ci .name = "nfc_ecc", 20062306a36Sopenharmony_ci .parent_ids = default_parent_ids, 20162306a36Sopenharmony_ci .num_parents = ARRAY_SIZE(default_parent_ids), 20262306a36Sopenharmony_ci .map = { 20362306a36Sopenharmony_ci BERLIN2_DIV_GATE(REG_CLKENABLE, 19), 20462306a36Sopenharmony_ci BERLIN2_PLL_SELECT(REG_CLKSELECT1, 18), 20562306a36Sopenharmony_ci BERLIN2_DIV_SELECT(REG_CLKSELECT1, 21), 20662306a36Sopenharmony_ci BERLIN2_PLL_SWITCH(REG_CLKSWITCH0, 27), 20762306a36Sopenharmony_ci BERLIN2_DIV_SWITCH(REG_CLKSWITCH0, 28), 20862306a36Sopenharmony_ci BERLIN2_DIV_D3SWITCH(REG_CLKSWITCH0, 29), 20962306a36Sopenharmony_ci }, 21062306a36Sopenharmony_ci .div_flags = BERLIN2_DIV_HAS_GATE | BERLIN2_DIV_HAS_MUX, 21162306a36Sopenharmony_ci .flags = 0, 21262306a36Sopenharmony_ci }, 21362306a36Sopenharmony_ci { 21462306a36Sopenharmony_ci .name = "vpp", 21562306a36Sopenharmony_ci .parent_ids = default_parent_ids, 21662306a36Sopenharmony_ci .num_parents = ARRAY_SIZE(default_parent_ids), 21762306a36Sopenharmony_ci .map = { 21862306a36Sopenharmony_ci BERLIN2_DIV_GATE(REG_CLKENABLE, 21), 21962306a36Sopenharmony_ci BERLIN2_PLL_SELECT(REG_CLKSELECT1, 24), 22062306a36Sopenharmony_ci BERLIN2_DIV_SELECT(REG_CLKSELECT1, 27), 22162306a36Sopenharmony_ci BERLIN2_PLL_SWITCH(REG_CLKSWITCH0, 30), 22262306a36Sopenharmony_ci BERLIN2_DIV_SWITCH(REG_CLKSWITCH0, 31), 22362306a36Sopenharmony_ci BERLIN2_DIV_D3SWITCH(REG_CLKSWITCH1, 0), 22462306a36Sopenharmony_ci }, 22562306a36Sopenharmony_ci .div_flags = BERLIN2_DIV_HAS_GATE | BERLIN2_DIV_HAS_MUX, 22662306a36Sopenharmony_ci .flags = 0, 22762306a36Sopenharmony_ci }, 22862306a36Sopenharmony_ci { 22962306a36Sopenharmony_ci .name = "app", 23062306a36Sopenharmony_ci .parent_ids = default_parent_ids, 23162306a36Sopenharmony_ci .num_parents = ARRAY_SIZE(default_parent_ids), 23262306a36Sopenharmony_ci .map = { 23362306a36Sopenharmony_ci BERLIN2_DIV_GATE(REG_CLKENABLE, 20), 23462306a36Sopenharmony_ci BERLIN2_PLL_SELECT(REG_CLKSELECT2, 0), 23562306a36Sopenharmony_ci BERLIN2_DIV_SELECT(REG_CLKSELECT2, 3), 23662306a36Sopenharmony_ci BERLIN2_PLL_SWITCH(REG_CLKSWITCH1, 1), 23762306a36Sopenharmony_ci BERLIN2_DIV_SWITCH(REG_CLKSWITCH1, 2), 23862306a36Sopenharmony_ci BERLIN2_DIV_D3SWITCH(REG_CLKSWITCH1, 3), 23962306a36Sopenharmony_ci }, 24062306a36Sopenharmony_ci .div_flags = BERLIN2_DIV_HAS_GATE | BERLIN2_DIV_HAS_MUX, 24162306a36Sopenharmony_ci .flags = 0, 24262306a36Sopenharmony_ci }, 24362306a36Sopenharmony_ci { 24462306a36Sopenharmony_ci .name = "sdio0xin", 24562306a36Sopenharmony_ci .parent_ids = default_parent_ids, 24662306a36Sopenharmony_ci .num_parents = ARRAY_SIZE(default_parent_ids), 24762306a36Sopenharmony_ci .map = { 24862306a36Sopenharmony_ci BERLIN2_SINGLE_DIV(REG_SDIO0XIN_CLKCTL), 24962306a36Sopenharmony_ci }, 25062306a36Sopenharmony_ci .div_flags = BERLIN2_DIV_HAS_GATE | BERLIN2_DIV_HAS_MUX, 25162306a36Sopenharmony_ci .flags = 0, 25262306a36Sopenharmony_ci }, 25362306a36Sopenharmony_ci { 25462306a36Sopenharmony_ci .name = "sdio1xin", 25562306a36Sopenharmony_ci .parent_ids = default_parent_ids, 25662306a36Sopenharmony_ci .num_parents = ARRAY_SIZE(default_parent_ids), 25762306a36Sopenharmony_ci .map = { 25862306a36Sopenharmony_ci BERLIN2_SINGLE_DIV(REG_SDIO1XIN_CLKCTL), 25962306a36Sopenharmony_ci }, 26062306a36Sopenharmony_ci .div_flags = BERLIN2_DIV_HAS_GATE | BERLIN2_DIV_HAS_MUX, 26162306a36Sopenharmony_ci .flags = 0, 26262306a36Sopenharmony_ci }, 26362306a36Sopenharmony_ci}; 26462306a36Sopenharmony_ci 26562306a36Sopenharmony_cistatic const struct berlin2_gate_data bg2q_gates[] __initconst = { 26662306a36Sopenharmony_ci { "gfx2daxi", "perif", 5 }, 26762306a36Sopenharmony_ci { "geth0", "perif", 8 }, 26862306a36Sopenharmony_ci { "sata", "perif", 9 }, 26962306a36Sopenharmony_ci { "ahbapb", "perif", 10, CLK_IGNORE_UNUSED }, 27062306a36Sopenharmony_ci { "usb0", "perif", 11 }, 27162306a36Sopenharmony_ci { "usb1", "perif", 12 }, 27262306a36Sopenharmony_ci { "usb2", "perif", 13 }, 27362306a36Sopenharmony_ci { "usb3", "perif", 14 }, 27462306a36Sopenharmony_ci { "pbridge", "perif", 15, CLK_IGNORE_UNUSED }, 27562306a36Sopenharmony_ci { "sdio", "perif", 16 }, 27662306a36Sopenharmony_ci { "nfc", "perif", 18 }, 27762306a36Sopenharmony_ci { "pcie", "perif", 22 }, 27862306a36Sopenharmony_ci}; 27962306a36Sopenharmony_ci 28062306a36Sopenharmony_cistatic void __init berlin2q_clock_setup(struct device_node *np) 28162306a36Sopenharmony_ci{ 28262306a36Sopenharmony_ci struct device_node *parent_np = of_get_parent(np); 28362306a36Sopenharmony_ci const char *parent_names[9]; 28462306a36Sopenharmony_ci struct clk *clk; 28562306a36Sopenharmony_ci struct clk_hw **hws; 28662306a36Sopenharmony_ci int n, ret; 28762306a36Sopenharmony_ci 28862306a36Sopenharmony_ci clk_data = kzalloc(struct_size(clk_data, hws, MAX_CLKS), GFP_KERNEL); 28962306a36Sopenharmony_ci if (!clk_data) { 29062306a36Sopenharmony_ci of_node_put(parent_np); 29162306a36Sopenharmony_ci return; 29262306a36Sopenharmony_ci } 29362306a36Sopenharmony_ci clk_data->num = MAX_CLKS; 29462306a36Sopenharmony_ci hws = clk_data->hws; 29562306a36Sopenharmony_ci 29662306a36Sopenharmony_ci gbase = of_iomap(parent_np, 0); 29762306a36Sopenharmony_ci if (!gbase) { 29862306a36Sopenharmony_ci of_node_put(parent_np); 29962306a36Sopenharmony_ci pr_err("%pOF: Unable to map global base\n", np); 30062306a36Sopenharmony_ci return; 30162306a36Sopenharmony_ci } 30262306a36Sopenharmony_ci 30362306a36Sopenharmony_ci /* BG2Q CPU PLL is not part of global registers */ 30462306a36Sopenharmony_ci cpupll_base = of_iomap(parent_np, 1); 30562306a36Sopenharmony_ci of_node_put(parent_np); 30662306a36Sopenharmony_ci if (!cpupll_base) { 30762306a36Sopenharmony_ci pr_err("%pOF: Unable to map cpupll base\n", np); 30862306a36Sopenharmony_ci iounmap(gbase); 30962306a36Sopenharmony_ci return; 31062306a36Sopenharmony_ci } 31162306a36Sopenharmony_ci 31262306a36Sopenharmony_ci /* overwrite default clock names with DT provided ones */ 31362306a36Sopenharmony_ci clk = of_clk_get_by_name(np, clk_names[REFCLK]); 31462306a36Sopenharmony_ci if (!IS_ERR(clk)) { 31562306a36Sopenharmony_ci clk_names[REFCLK] = __clk_get_name(clk); 31662306a36Sopenharmony_ci clk_put(clk); 31762306a36Sopenharmony_ci } 31862306a36Sopenharmony_ci 31962306a36Sopenharmony_ci /* simple register PLLs */ 32062306a36Sopenharmony_ci ret = berlin2_pll_register(&bg2q_pll_map, gbase + REG_SYSPLLCTL0, 32162306a36Sopenharmony_ci clk_names[SYSPLL], clk_names[REFCLK], 0); 32262306a36Sopenharmony_ci if (ret) 32362306a36Sopenharmony_ci goto bg2q_fail; 32462306a36Sopenharmony_ci 32562306a36Sopenharmony_ci ret = berlin2_pll_register(&bg2q_pll_map, cpupll_base, 32662306a36Sopenharmony_ci clk_names[CPUPLL], clk_names[REFCLK], 0); 32762306a36Sopenharmony_ci if (ret) 32862306a36Sopenharmony_ci goto bg2q_fail; 32962306a36Sopenharmony_ci 33062306a36Sopenharmony_ci /* TODO: add BG2Q AVPLL */ 33162306a36Sopenharmony_ci 33262306a36Sopenharmony_ci /* 33362306a36Sopenharmony_ci * TODO: add reference clock bypass switches: 33462306a36Sopenharmony_ci * memPLLSWBypass, cpuPLLSWBypass, and sysPLLSWBypass 33562306a36Sopenharmony_ci */ 33662306a36Sopenharmony_ci 33762306a36Sopenharmony_ci /* clock divider cells */ 33862306a36Sopenharmony_ci for (n = 0; n < ARRAY_SIZE(bg2q_divs); n++) { 33962306a36Sopenharmony_ci const struct berlin2_div_data *dd = &bg2q_divs[n]; 34062306a36Sopenharmony_ci int k; 34162306a36Sopenharmony_ci 34262306a36Sopenharmony_ci for (k = 0; k < dd->num_parents; k++) 34362306a36Sopenharmony_ci parent_names[k] = clk_names[dd->parent_ids[k]]; 34462306a36Sopenharmony_ci 34562306a36Sopenharmony_ci hws[CLKID_SYS + n] = berlin2_div_register(&dd->map, gbase, 34662306a36Sopenharmony_ci dd->name, dd->div_flags, parent_names, 34762306a36Sopenharmony_ci dd->num_parents, dd->flags, &lock); 34862306a36Sopenharmony_ci } 34962306a36Sopenharmony_ci 35062306a36Sopenharmony_ci /* clock gate cells */ 35162306a36Sopenharmony_ci for (n = 0; n < ARRAY_SIZE(bg2q_gates); n++) { 35262306a36Sopenharmony_ci const struct berlin2_gate_data *gd = &bg2q_gates[n]; 35362306a36Sopenharmony_ci 35462306a36Sopenharmony_ci hws[CLKID_GFX2DAXI + n] = clk_hw_register_gate(NULL, gd->name, 35562306a36Sopenharmony_ci gd->parent_name, gd->flags, gbase + REG_CLKENABLE, 35662306a36Sopenharmony_ci gd->bit_idx, 0, &lock); 35762306a36Sopenharmony_ci } 35862306a36Sopenharmony_ci 35962306a36Sopenharmony_ci /* cpuclk divider is fixed to 1 */ 36062306a36Sopenharmony_ci hws[CLKID_CPU] = 36162306a36Sopenharmony_ci clk_hw_register_fixed_factor(NULL, "cpu", clk_names[CPUPLL], 36262306a36Sopenharmony_ci 0, 1, 1); 36362306a36Sopenharmony_ci /* twdclk is derived from cpu/3 */ 36462306a36Sopenharmony_ci hws[CLKID_TWD] = 36562306a36Sopenharmony_ci clk_hw_register_fixed_factor(NULL, "twd", "cpu", 0, 1, 3); 36662306a36Sopenharmony_ci 36762306a36Sopenharmony_ci /* check for errors on leaf clocks */ 36862306a36Sopenharmony_ci for (n = 0; n < MAX_CLKS; n++) { 36962306a36Sopenharmony_ci if (!IS_ERR(hws[n])) 37062306a36Sopenharmony_ci continue; 37162306a36Sopenharmony_ci 37262306a36Sopenharmony_ci pr_err("%pOF: Unable to register leaf clock %d\n", np, n); 37362306a36Sopenharmony_ci goto bg2q_fail; 37462306a36Sopenharmony_ci } 37562306a36Sopenharmony_ci 37662306a36Sopenharmony_ci /* register clk-provider */ 37762306a36Sopenharmony_ci of_clk_add_hw_provider(np, of_clk_hw_onecell_get, clk_data); 37862306a36Sopenharmony_ci 37962306a36Sopenharmony_ci return; 38062306a36Sopenharmony_ci 38162306a36Sopenharmony_cibg2q_fail: 38262306a36Sopenharmony_ci iounmap(cpupll_base); 38362306a36Sopenharmony_ci iounmap(gbase); 38462306a36Sopenharmony_ci} 38562306a36Sopenharmony_ciCLK_OF_DECLARE(berlin2q_clk, "marvell,berlin2q-clk", 38662306a36Sopenharmony_ci berlin2q_clock_setup); 387