162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Copyright 2011-2012 Calxeda, Inc. 462306a36Sopenharmony_ci * Copyright (C) 2012-2013 Altera Corporation <www.altera.com> 562306a36Sopenharmony_ci * 662306a36Sopenharmony_ci * Based from clk-highbank.c 762306a36Sopenharmony_ci */ 862306a36Sopenharmony_ci#include <linux/slab.h> 962306a36Sopenharmony_ci#include <linux/clk-provider.h> 1062306a36Sopenharmony_ci#include <linux/io.h> 1162306a36Sopenharmony_ci#include <linux/mfd/syscon.h> 1262306a36Sopenharmony_ci#include <linux/of.h> 1362306a36Sopenharmony_ci#include <linux/regmap.h> 1462306a36Sopenharmony_ci 1562306a36Sopenharmony_ci#include "clk.h" 1662306a36Sopenharmony_ci 1762306a36Sopenharmony_ci#define SOCFPGA_L4_MP_CLK "l4_mp_clk" 1862306a36Sopenharmony_ci#define SOCFPGA_L4_SP_CLK "l4_sp_clk" 1962306a36Sopenharmony_ci#define SOCFPGA_NAND_CLK "nand_clk" 2062306a36Sopenharmony_ci#define SOCFPGA_NAND_X_CLK "nand_x_clk" 2162306a36Sopenharmony_ci#define SOCFPGA_MMC_CLK "sdmmc_clk" 2262306a36Sopenharmony_ci#define SOCFPGA_GPIO_DB_CLK_OFFSET 0xA8 2362306a36Sopenharmony_ci 2462306a36Sopenharmony_ci#define to_socfpga_gate_clk(p) container_of(p, struct socfpga_gate_clk, hw.hw) 2562306a36Sopenharmony_ci 2662306a36Sopenharmony_ci/* SDMMC Group for System Manager defines */ 2762306a36Sopenharmony_ci#define SYSMGR_SDMMCGRP_CTRL_OFFSET 0x108 2862306a36Sopenharmony_ci 2962306a36Sopenharmony_cistatic u8 socfpga_clk_get_parent(struct clk_hw *hwclk) 3062306a36Sopenharmony_ci{ 3162306a36Sopenharmony_ci u32 l4_src; 3262306a36Sopenharmony_ci u32 perpll_src; 3362306a36Sopenharmony_ci const char *name = clk_hw_get_name(hwclk); 3462306a36Sopenharmony_ci 3562306a36Sopenharmony_ci if (streq(name, SOCFPGA_L4_MP_CLK)) { 3662306a36Sopenharmony_ci l4_src = readl(clk_mgr_base_addr + CLKMGR_L4SRC); 3762306a36Sopenharmony_ci return l4_src & 0x1; 3862306a36Sopenharmony_ci } 3962306a36Sopenharmony_ci if (streq(name, SOCFPGA_L4_SP_CLK)) { 4062306a36Sopenharmony_ci l4_src = readl(clk_mgr_base_addr + CLKMGR_L4SRC); 4162306a36Sopenharmony_ci return !!(l4_src & 2); 4262306a36Sopenharmony_ci } 4362306a36Sopenharmony_ci 4462306a36Sopenharmony_ci perpll_src = readl(clk_mgr_base_addr + CLKMGR_PERPLL_SRC); 4562306a36Sopenharmony_ci if (streq(name, SOCFPGA_MMC_CLK)) 4662306a36Sopenharmony_ci return perpll_src & 0x3; 4762306a36Sopenharmony_ci if (streq(name, SOCFPGA_NAND_CLK) || 4862306a36Sopenharmony_ci streq(name, SOCFPGA_NAND_X_CLK)) 4962306a36Sopenharmony_ci return (perpll_src >> 2) & 3; 5062306a36Sopenharmony_ci 5162306a36Sopenharmony_ci /* QSPI clock */ 5262306a36Sopenharmony_ci return (perpll_src >> 4) & 3; 5362306a36Sopenharmony_ci 5462306a36Sopenharmony_ci} 5562306a36Sopenharmony_ci 5662306a36Sopenharmony_cistatic int socfpga_clk_set_parent(struct clk_hw *hwclk, u8 parent) 5762306a36Sopenharmony_ci{ 5862306a36Sopenharmony_ci u32 src_reg; 5962306a36Sopenharmony_ci const char *name = clk_hw_get_name(hwclk); 6062306a36Sopenharmony_ci 6162306a36Sopenharmony_ci if (streq(name, SOCFPGA_L4_MP_CLK)) { 6262306a36Sopenharmony_ci src_reg = readl(clk_mgr_base_addr + CLKMGR_L4SRC); 6362306a36Sopenharmony_ci src_reg &= ~0x1; 6462306a36Sopenharmony_ci src_reg |= parent; 6562306a36Sopenharmony_ci writel(src_reg, clk_mgr_base_addr + CLKMGR_L4SRC); 6662306a36Sopenharmony_ci } else if (streq(name, SOCFPGA_L4_SP_CLK)) { 6762306a36Sopenharmony_ci src_reg = readl(clk_mgr_base_addr + CLKMGR_L4SRC); 6862306a36Sopenharmony_ci src_reg &= ~0x2; 6962306a36Sopenharmony_ci src_reg |= (parent << 1); 7062306a36Sopenharmony_ci writel(src_reg, clk_mgr_base_addr + CLKMGR_L4SRC); 7162306a36Sopenharmony_ci } else { 7262306a36Sopenharmony_ci src_reg = readl(clk_mgr_base_addr + CLKMGR_PERPLL_SRC); 7362306a36Sopenharmony_ci if (streq(name, SOCFPGA_MMC_CLK)) { 7462306a36Sopenharmony_ci src_reg &= ~0x3; 7562306a36Sopenharmony_ci src_reg |= parent; 7662306a36Sopenharmony_ci } else if (streq(name, SOCFPGA_NAND_CLK) || 7762306a36Sopenharmony_ci streq(name, SOCFPGA_NAND_X_CLK)) { 7862306a36Sopenharmony_ci src_reg &= ~0xC; 7962306a36Sopenharmony_ci src_reg |= (parent << 2); 8062306a36Sopenharmony_ci } else {/* QSPI clock */ 8162306a36Sopenharmony_ci src_reg &= ~0x30; 8262306a36Sopenharmony_ci src_reg |= (parent << 4); 8362306a36Sopenharmony_ci } 8462306a36Sopenharmony_ci writel(src_reg, clk_mgr_base_addr + CLKMGR_PERPLL_SRC); 8562306a36Sopenharmony_ci } 8662306a36Sopenharmony_ci 8762306a36Sopenharmony_ci return 0; 8862306a36Sopenharmony_ci} 8962306a36Sopenharmony_ci 9062306a36Sopenharmony_cistatic u32 socfpga_clk_get_div(struct socfpga_gate_clk *socfpgaclk) 9162306a36Sopenharmony_ci{ 9262306a36Sopenharmony_ci u32 div = 1, val; 9362306a36Sopenharmony_ci 9462306a36Sopenharmony_ci if (socfpgaclk->fixed_div) 9562306a36Sopenharmony_ci div = socfpgaclk->fixed_div; 9662306a36Sopenharmony_ci else if (socfpgaclk->div_reg) { 9762306a36Sopenharmony_ci val = readl(socfpgaclk->div_reg) >> socfpgaclk->shift; 9862306a36Sopenharmony_ci val &= GENMASK(socfpgaclk->width - 1, 0); 9962306a36Sopenharmony_ci /* Check for GPIO_DB_CLK by its offset */ 10062306a36Sopenharmony_ci if ((uintptr_t) socfpgaclk->div_reg & SOCFPGA_GPIO_DB_CLK_OFFSET) 10162306a36Sopenharmony_ci div = val + 1; 10262306a36Sopenharmony_ci else 10362306a36Sopenharmony_ci div = (1 << val); 10462306a36Sopenharmony_ci } 10562306a36Sopenharmony_ci 10662306a36Sopenharmony_ci return div; 10762306a36Sopenharmony_ci} 10862306a36Sopenharmony_ci 10962306a36Sopenharmony_cistatic unsigned long socfpga_clk_recalc_rate(struct clk_hw *hwclk, 11062306a36Sopenharmony_ci unsigned long parent_rate) 11162306a36Sopenharmony_ci{ 11262306a36Sopenharmony_ci struct socfpga_gate_clk *socfpgaclk = to_socfpga_gate_clk(hwclk); 11362306a36Sopenharmony_ci u32 div = socfpga_clk_get_div(socfpgaclk); 11462306a36Sopenharmony_ci 11562306a36Sopenharmony_ci return parent_rate / div; 11662306a36Sopenharmony_ci} 11762306a36Sopenharmony_ci 11862306a36Sopenharmony_ci 11962306a36Sopenharmony_cistatic int socfpga_clk_determine_rate(struct clk_hw *hwclk, 12062306a36Sopenharmony_ci struct clk_rate_request *req) 12162306a36Sopenharmony_ci{ 12262306a36Sopenharmony_ci struct socfpga_gate_clk *socfpgaclk = to_socfpga_gate_clk(hwclk); 12362306a36Sopenharmony_ci u32 div = socfpga_clk_get_div(socfpgaclk); 12462306a36Sopenharmony_ci 12562306a36Sopenharmony_ci req->rate = req->best_parent_rate / div; 12662306a36Sopenharmony_ci 12762306a36Sopenharmony_ci return 0; 12862306a36Sopenharmony_ci} 12962306a36Sopenharmony_ci 13062306a36Sopenharmony_cistatic struct clk_ops gateclk_ops = { 13162306a36Sopenharmony_ci .recalc_rate = socfpga_clk_recalc_rate, 13262306a36Sopenharmony_ci .determine_rate = socfpga_clk_determine_rate, 13362306a36Sopenharmony_ci .get_parent = socfpga_clk_get_parent, 13462306a36Sopenharmony_ci .set_parent = socfpga_clk_set_parent, 13562306a36Sopenharmony_ci}; 13662306a36Sopenharmony_ci 13762306a36Sopenharmony_civoid __init socfpga_gate_init(struct device_node *node) 13862306a36Sopenharmony_ci{ 13962306a36Sopenharmony_ci u32 clk_gate[2]; 14062306a36Sopenharmony_ci u32 div_reg[3]; 14162306a36Sopenharmony_ci u32 fixed_div; 14262306a36Sopenharmony_ci struct clk_hw *hw_clk; 14362306a36Sopenharmony_ci struct socfpga_gate_clk *socfpga_clk; 14462306a36Sopenharmony_ci const char *clk_name = node->name; 14562306a36Sopenharmony_ci const char *parent_name[SOCFPGA_MAX_PARENTS]; 14662306a36Sopenharmony_ci struct clk_init_data init; 14762306a36Sopenharmony_ci struct clk_ops *ops; 14862306a36Sopenharmony_ci int rc; 14962306a36Sopenharmony_ci 15062306a36Sopenharmony_ci socfpga_clk = kzalloc(sizeof(*socfpga_clk), GFP_KERNEL); 15162306a36Sopenharmony_ci if (WARN_ON(!socfpga_clk)) 15262306a36Sopenharmony_ci return; 15362306a36Sopenharmony_ci 15462306a36Sopenharmony_ci ops = kmemdup(&gateclk_ops, sizeof(gateclk_ops), GFP_KERNEL); 15562306a36Sopenharmony_ci if (WARN_ON(!ops)) 15662306a36Sopenharmony_ci goto err_kmemdup; 15762306a36Sopenharmony_ci 15862306a36Sopenharmony_ci rc = of_property_read_u32_array(node, "clk-gate", clk_gate, 2); 15962306a36Sopenharmony_ci if (rc) 16062306a36Sopenharmony_ci clk_gate[0] = 0; 16162306a36Sopenharmony_ci 16262306a36Sopenharmony_ci if (clk_gate[0]) { 16362306a36Sopenharmony_ci socfpga_clk->hw.reg = clk_mgr_base_addr + clk_gate[0]; 16462306a36Sopenharmony_ci socfpga_clk->hw.bit_idx = clk_gate[1]; 16562306a36Sopenharmony_ci 16662306a36Sopenharmony_ci ops->enable = clk_gate_ops.enable; 16762306a36Sopenharmony_ci ops->disable = clk_gate_ops.disable; 16862306a36Sopenharmony_ci } 16962306a36Sopenharmony_ci 17062306a36Sopenharmony_ci rc = of_property_read_u32(node, "fixed-divider", &fixed_div); 17162306a36Sopenharmony_ci if (rc) 17262306a36Sopenharmony_ci socfpga_clk->fixed_div = 0; 17362306a36Sopenharmony_ci else 17462306a36Sopenharmony_ci socfpga_clk->fixed_div = fixed_div; 17562306a36Sopenharmony_ci 17662306a36Sopenharmony_ci rc = of_property_read_u32_array(node, "div-reg", div_reg, 3); 17762306a36Sopenharmony_ci if (!rc) { 17862306a36Sopenharmony_ci socfpga_clk->div_reg = clk_mgr_base_addr + div_reg[0]; 17962306a36Sopenharmony_ci socfpga_clk->shift = div_reg[1]; 18062306a36Sopenharmony_ci socfpga_clk->width = div_reg[2]; 18162306a36Sopenharmony_ci } else { 18262306a36Sopenharmony_ci socfpga_clk->div_reg = NULL; 18362306a36Sopenharmony_ci } 18462306a36Sopenharmony_ci 18562306a36Sopenharmony_ci of_property_read_string(node, "clock-output-names", &clk_name); 18662306a36Sopenharmony_ci 18762306a36Sopenharmony_ci init.name = clk_name; 18862306a36Sopenharmony_ci init.ops = ops; 18962306a36Sopenharmony_ci init.flags = 0; 19062306a36Sopenharmony_ci 19162306a36Sopenharmony_ci init.num_parents = of_clk_parent_fill(node, parent_name, SOCFPGA_MAX_PARENTS); 19262306a36Sopenharmony_ci if (init.num_parents < 2) { 19362306a36Sopenharmony_ci ops->get_parent = NULL; 19462306a36Sopenharmony_ci ops->set_parent = NULL; 19562306a36Sopenharmony_ci } 19662306a36Sopenharmony_ci 19762306a36Sopenharmony_ci init.parent_names = parent_name; 19862306a36Sopenharmony_ci socfpga_clk->hw.hw.init = &init; 19962306a36Sopenharmony_ci 20062306a36Sopenharmony_ci hw_clk = &socfpga_clk->hw.hw; 20162306a36Sopenharmony_ci 20262306a36Sopenharmony_ci rc = clk_hw_register(NULL, hw_clk); 20362306a36Sopenharmony_ci if (rc) { 20462306a36Sopenharmony_ci pr_err("Could not register clock:%s\n", clk_name); 20562306a36Sopenharmony_ci goto err_clk_hw_register; 20662306a36Sopenharmony_ci } 20762306a36Sopenharmony_ci 20862306a36Sopenharmony_ci rc = of_clk_add_hw_provider(node, of_clk_hw_simple_get, hw_clk); 20962306a36Sopenharmony_ci if (rc) { 21062306a36Sopenharmony_ci pr_err("Could not register clock provider for node:%s\n", 21162306a36Sopenharmony_ci clk_name); 21262306a36Sopenharmony_ci goto err_of_clk_add_hw_provider; 21362306a36Sopenharmony_ci } 21462306a36Sopenharmony_ci 21562306a36Sopenharmony_ci return; 21662306a36Sopenharmony_ci 21762306a36Sopenharmony_cierr_of_clk_add_hw_provider: 21862306a36Sopenharmony_ci clk_hw_unregister(hw_clk); 21962306a36Sopenharmony_cierr_clk_hw_register: 22062306a36Sopenharmony_ci kfree(ops); 22162306a36Sopenharmony_cierr_kmemdup: 22262306a36Sopenharmony_ci kfree(socfpga_clk); 22362306a36Sopenharmony_ci} 224