18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci *  Copyright 2011-2012 Calxeda, Inc.
48c2ecf20Sopenharmony_ci *  Copyright (C) 2012-2013 Altera Corporation <www.altera.com>
58c2ecf20Sopenharmony_ci *
68c2ecf20Sopenharmony_ci * Based from clk-highbank.c
78c2ecf20Sopenharmony_ci */
88c2ecf20Sopenharmony_ci#include <linux/slab.h>
98c2ecf20Sopenharmony_ci#include <linux/clk-provider.h>
108c2ecf20Sopenharmony_ci#include <linux/io.h>
118c2ecf20Sopenharmony_ci#include <linux/mfd/syscon.h>
128c2ecf20Sopenharmony_ci#include <linux/of.h>
138c2ecf20Sopenharmony_ci#include <linux/regmap.h>
148c2ecf20Sopenharmony_ci
158c2ecf20Sopenharmony_ci#include "clk.h"
168c2ecf20Sopenharmony_ci
178c2ecf20Sopenharmony_ci#define SOCFPGA_L4_MP_CLK		"l4_mp_clk"
188c2ecf20Sopenharmony_ci#define SOCFPGA_L4_SP_CLK		"l4_sp_clk"
198c2ecf20Sopenharmony_ci#define SOCFPGA_NAND_CLK		"nand_clk"
208c2ecf20Sopenharmony_ci#define SOCFPGA_NAND_X_CLK		"nand_x_clk"
218c2ecf20Sopenharmony_ci#define SOCFPGA_MMC_CLK			"sdmmc_clk"
228c2ecf20Sopenharmony_ci#define SOCFPGA_GPIO_DB_CLK_OFFSET	0xA8
238c2ecf20Sopenharmony_ci
248c2ecf20Sopenharmony_ci#define to_socfpga_gate_clk(p) container_of(p, struct socfpga_gate_clk, hw.hw)
258c2ecf20Sopenharmony_ci
268c2ecf20Sopenharmony_ci/* SDMMC Group for System Manager defines */
278c2ecf20Sopenharmony_ci#define SYSMGR_SDMMCGRP_CTRL_OFFSET    0x108
288c2ecf20Sopenharmony_ci
298c2ecf20Sopenharmony_cistatic u8 socfpga_clk_get_parent(struct clk_hw *hwclk)
308c2ecf20Sopenharmony_ci{
318c2ecf20Sopenharmony_ci	u32 l4_src;
328c2ecf20Sopenharmony_ci	u32 perpll_src;
338c2ecf20Sopenharmony_ci	const char *name = clk_hw_get_name(hwclk);
348c2ecf20Sopenharmony_ci
358c2ecf20Sopenharmony_ci	if (streq(name, SOCFPGA_L4_MP_CLK)) {
368c2ecf20Sopenharmony_ci		l4_src = readl(clk_mgr_base_addr + CLKMGR_L4SRC);
378c2ecf20Sopenharmony_ci		return l4_src &= 0x1;
388c2ecf20Sopenharmony_ci	}
398c2ecf20Sopenharmony_ci	if (streq(name, SOCFPGA_L4_SP_CLK)) {
408c2ecf20Sopenharmony_ci		l4_src = readl(clk_mgr_base_addr + CLKMGR_L4SRC);
418c2ecf20Sopenharmony_ci		return !!(l4_src & 2);
428c2ecf20Sopenharmony_ci	}
438c2ecf20Sopenharmony_ci
448c2ecf20Sopenharmony_ci	perpll_src = readl(clk_mgr_base_addr + CLKMGR_PERPLL_SRC);
458c2ecf20Sopenharmony_ci	if (streq(name, SOCFPGA_MMC_CLK))
468c2ecf20Sopenharmony_ci		return perpll_src &= 0x3;
478c2ecf20Sopenharmony_ci	if (streq(name, SOCFPGA_NAND_CLK) ||
488c2ecf20Sopenharmony_ci	    streq(name, SOCFPGA_NAND_X_CLK))
498c2ecf20Sopenharmony_ci		return (perpll_src >> 2) & 3;
508c2ecf20Sopenharmony_ci
518c2ecf20Sopenharmony_ci	/* QSPI clock */
528c2ecf20Sopenharmony_ci	return (perpll_src >> 4) & 3;
538c2ecf20Sopenharmony_ci
548c2ecf20Sopenharmony_ci}
558c2ecf20Sopenharmony_ci
568c2ecf20Sopenharmony_cistatic int socfpga_clk_set_parent(struct clk_hw *hwclk, u8 parent)
578c2ecf20Sopenharmony_ci{
588c2ecf20Sopenharmony_ci	u32 src_reg;
598c2ecf20Sopenharmony_ci	const char *name = clk_hw_get_name(hwclk);
608c2ecf20Sopenharmony_ci
618c2ecf20Sopenharmony_ci	if (streq(name, SOCFPGA_L4_MP_CLK)) {
628c2ecf20Sopenharmony_ci		src_reg = readl(clk_mgr_base_addr + CLKMGR_L4SRC);
638c2ecf20Sopenharmony_ci		src_reg &= ~0x1;
648c2ecf20Sopenharmony_ci		src_reg |= parent;
658c2ecf20Sopenharmony_ci		writel(src_reg, clk_mgr_base_addr + CLKMGR_L4SRC);
668c2ecf20Sopenharmony_ci	} else if (streq(name, SOCFPGA_L4_SP_CLK)) {
678c2ecf20Sopenharmony_ci		src_reg = readl(clk_mgr_base_addr + CLKMGR_L4SRC);
688c2ecf20Sopenharmony_ci		src_reg &= ~0x2;
698c2ecf20Sopenharmony_ci		src_reg |= (parent << 1);
708c2ecf20Sopenharmony_ci		writel(src_reg, clk_mgr_base_addr + CLKMGR_L4SRC);
718c2ecf20Sopenharmony_ci	} else {
728c2ecf20Sopenharmony_ci		src_reg = readl(clk_mgr_base_addr + CLKMGR_PERPLL_SRC);
738c2ecf20Sopenharmony_ci		if (streq(name, SOCFPGA_MMC_CLK)) {
748c2ecf20Sopenharmony_ci			src_reg &= ~0x3;
758c2ecf20Sopenharmony_ci			src_reg |= parent;
768c2ecf20Sopenharmony_ci		} else if (streq(name, SOCFPGA_NAND_CLK) ||
778c2ecf20Sopenharmony_ci			streq(name, SOCFPGA_NAND_X_CLK)) {
788c2ecf20Sopenharmony_ci			src_reg &= ~0xC;
798c2ecf20Sopenharmony_ci			src_reg |= (parent << 2);
808c2ecf20Sopenharmony_ci		} else {/* QSPI clock */
818c2ecf20Sopenharmony_ci			src_reg &= ~0x30;
828c2ecf20Sopenharmony_ci			src_reg |= (parent << 4);
838c2ecf20Sopenharmony_ci		}
848c2ecf20Sopenharmony_ci		writel(src_reg, clk_mgr_base_addr + CLKMGR_PERPLL_SRC);
858c2ecf20Sopenharmony_ci	}
868c2ecf20Sopenharmony_ci
878c2ecf20Sopenharmony_ci	return 0;
888c2ecf20Sopenharmony_ci}
898c2ecf20Sopenharmony_ci
908c2ecf20Sopenharmony_cistatic unsigned long socfpga_clk_recalc_rate(struct clk_hw *hwclk,
918c2ecf20Sopenharmony_ci	unsigned long parent_rate)
928c2ecf20Sopenharmony_ci{
938c2ecf20Sopenharmony_ci	struct socfpga_gate_clk *socfpgaclk = to_socfpga_gate_clk(hwclk);
948c2ecf20Sopenharmony_ci	u32 div = 1, val;
958c2ecf20Sopenharmony_ci
968c2ecf20Sopenharmony_ci	if (socfpgaclk->fixed_div)
978c2ecf20Sopenharmony_ci		div = socfpgaclk->fixed_div;
988c2ecf20Sopenharmony_ci	else if (socfpgaclk->div_reg) {
998c2ecf20Sopenharmony_ci		val = readl(socfpgaclk->div_reg) >> socfpgaclk->shift;
1008c2ecf20Sopenharmony_ci		val &= GENMASK(socfpgaclk->width - 1, 0);
1018c2ecf20Sopenharmony_ci		/* Check for GPIO_DB_CLK by its offset */
1028c2ecf20Sopenharmony_ci		if ((uintptr_t) socfpgaclk->div_reg & SOCFPGA_GPIO_DB_CLK_OFFSET)
1038c2ecf20Sopenharmony_ci			div = val + 1;
1048c2ecf20Sopenharmony_ci		else
1058c2ecf20Sopenharmony_ci			div = (1 << val);
1068c2ecf20Sopenharmony_ci	}
1078c2ecf20Sopenharmony_ci
1088c2ecf20Sopenharmony_ci	return parent_rate / div;
1098c2ecf20Sopenharmony_ci}
1108c2ecf20Sopenharmony_ci
1118c2ecf20Sopenharmony_cistatic int socfpga_clk_prepare(struct clk_hw *hwclk)
1128c2ecf20Sopenharmony_ci{
1138c2ecf20Sopenharmony_ci	struct socfpga_gate_clk *socfpgaclk = to_socfpga_gate_clk(hwclk);
1148c2ecf20Sopenharmony_ci	struct regmap *sys_mgr_base_addr;
1158c2ecf20Sopenharmony_ci	int i;
1168c2ecf20Sopenharmony_ci	u32 hs_timing;
1178c2ecf20Sopenharmony_ci	u32 clk_phase[2];
1188c2ecf20Sopenharmony_ci
1198c2ecf20Sopenharmony_ci	if (socfpgaclk->clk_phase[0] || socfpgaclk->clk_phase[1]) {
1208c2ecf20Sopenharmony_ci		sys_mgr_base_addr = syscon_regmap_lookup_by_compatible("altr,sys-mgr");
1218c2ecf20Sopenharmony_ci		if (IS_ERR(sys_mgr_base_addr)) {
1228c2ecf20Sopenharmony_ci			pr_err("%s: failed to find altr,sys-mgr regmap!\n", __func__);
1238c2ecf20Sopenharmony_ci			return -EINVAL;
1248c2ecf20Sopenharmony_ci		}
1258c2ecf20Sopenharmony_ci
1268c2ecf20Sopenharmony_ci		for (i = 0; i < 2; i++) {
1278c2ecf20Sopenharmony_ci			switch (socfpgaclk->clk_phase[i]) {
1288c2ecf20Sopenharmony_ci			case 0:
1298c2ecf20Sopenharmony_ci				clk_phase[i] = 0;
1308c2ecf20Sopenharmony_ci				break;
1318c2ecf20Sopenharmony_ci			case 45:
1328c2ecf20Sopenharmony_ci				clk_phase[i] = 1;
1338c2ecf20Sopenharmony_ci				break;
1348c2ecf20Sopenharmony_ci			case 90:
1358c2ecf20Sopenharmony_ci				clk_phase[i] = 2;
1368c2ecf20Sopenharmony_ci				break;
1378c2ecf20Sopenharmony_ci			case 135:
1388c2ecf20Sopenharmony_ci				clk_phase[i] = 3;
1398c2ecf20Sopenharmony_ci				break;
1408c2ecf20Sopenharmony_ci			case 180:
1418c2ecf20Sopenharmony_ci				clk_phase[i] = 4;
1428c2ecf20Sopenharmony_ci				break;
1438c2ecf20Sopenharmony_ci			case 225:
1448c2ecf20Sopenharmony_ci				clk_phase[i] = 5;
1458c2ecf20Sopenharmony_ci				break;
1468c2ecf20Sopenharmony_ci			case 270:
1478c2ecf20Sopenharmony_ci				clk_phase[i] = 6;
1488c2ecf20Sopenharmony_ci				break;
1498c2ecf20Sopenharmony_ci			case 315:
1508c2ecf20Sopenharmony_ci				clk_phase[i] = 7;
1518c2ecf20Sopenharmony_ci				break;
1528c2ecf20Sopenharmony_ci			default:
1538c2ecf20Sopenharmony_ci				clk_phase[i] = 0;
1548c2ecf20Sopenharmony_ci				break;
1558c2ecf20Sopenharmony_ci			}
1568c2ecf20Sopenharmony_ci		}
1578c2ecf20Sopenharmony_ci		hs_timing = SYSMGR_SDMMC_CTRL_SET(clk_phase[0], clk_phase[1]);
1588c2ecf20Sopenharmony_ci		regmap_write(sys_mgr_base_addr, SYSMGR_SDMMCGRP_CTRL_OFFSET,
1598c2ecf20Sopenharmony_ci			hs_timing);
1608c2ecf20Sopenharmony_ci	}
1618c2ecf20Sopenharmony_ci	return 0;
1628c2ecf20Sopenharmony_ci}
1638c2ecf20Sopenharmony_ci
1648c2ecf20Sopenharmony_cistatic struct clk_ops gateclk_ops = {
1658c2ecf20Sopenharmony_ci	.prepare = socfpga_clk_prepare,
1668c2ecf20Sopenharmony_ci	.recalc_rate = socfpga_clk_recalc_rate,
1678c2ecf20Sopenharmony_ci	.get_parent = socfpga_clk_get_parent,
1688c2ecf20Sopenharmony_ci	.set_parent = socfpga_clk_set_parent,
1698c2ecf20Sopenharmony_ci};
1708c2ecf20Sopenharmony_ci
1718c2ecf20Sopenharmony_civoid __init socfpga_gate_init(struct device_node *node)
1728c2ecf20Sopenharmony_ci{
1738c2ecf20Sopenharmony_ci	u32 clk_gate[2];
1748c2ecf20Sopenharmony_ci	u32 div_reg[3];
1758c2ecf20Sopenharmony_ci	u32 clk_phase[2];
1768c2ecf20Sopenharmony_ci	u32 fixed_div;
1778c2ecf20Sopenharmony_ci	struct clk_hw *hw_clk;
1788c2ecf20Sopenharmony_ci	struct socfpga_gate_clk *socfpga_clk;
1798c2ecf20Sopenharmony_ci	const char *clk_name = node->name;
1808c2ecf20Sopenharmony_ci	const char *parent_name[SOCFPGA_MAX_PARENTS];
1818c2ecf20Sopenharmony_ci	struct clk_init_data init;
1828c2ecf20Sopenharmony_ci	struct clk_ops *ops;
1838c2ecf20Sopenharmony_ci	int rc;
1848c2ecf20Sopenharmony_ci	int err;
1858c2ecf20Sopenharmony_ci
1868c2ecf20Sopenharmony_ci	socfpga_clk = kzalloc(sizeof(*socfpga_clk), GFP_KERNEL);
1878c2ecf20Sopenharmony_ci	if (WARN_ON(!socfpga_clk))
1888c2ecf20Sopenharmony_ci		return;
1898c2ecf20Sopenharmony_ci
1908c2ecf20Sopenharmony_ci	ops = kmemdup(&gateclk_ops, sizeof(gateclk_ops), GFP_KERNEL);
1918c2ecf20Sopenharmony_ci	if (WARN_ON(!ops)) {
1928c2ecf20Sopenharmony_ci		kfree(socfpga_clk);
1938c2ecf20Sopenharmony_ci		return;
1948c2ecf20Sopenharmony_ci	}
1958c2ecf20Sopenharmony_ci
1968c2ecf20Sopenharmony_ci	rc = of_property_read_u32_array(node, "clk-gate", clk_gate, 2);
1978c2ecf20Sopenharmony_ci	if (rc)
1988c2ecf20Sopenharmony_ci		clk_gate[0] = 0;
1998c2ecf20Sopenharmony_ci
2008c2ecf20Sopenharmony_ci	if (clk_gate[0]) {
2018c2ecf20Sopenharmony_ci		socfpga_clk->hw.reg = clk_mgr_base_addr + clk_gate[0];
2028c2ecf20Sopenharmony_ci		socfpga_clk->hw.bit_idx = clk_gate[1];
2038c2ecf20Sopenharmony_ci
2048c2ecf20Sopenharmony_ci		ops->enable = clk_gate_ops.enable;
2058c2ecf20Sopenharmony_ci		ops->disable = clk_gate_ops.disable;
2068c2ecf20Sopenharmony_ci	}
2078c2ecf20Sopenharmony_ci
2088c2ecf20Sopenharmony_ci	rc = of_property_read_u32(node, "fixed-divider", &fixed_div);
2098c2ecf20Sopenharmony_ci	if (rc)
2108c2ecf20Sopenharmony_ci		socfpga_clk->fixed_div = 0;
2118c2ecf20Sopenharmony_ci	else
2128c2ecf20Sopenharmony_ci		socfpga_clk->fixed_div = fixed_div;
2138c2ecf20Sopenharmony_ci
2148c2ecf20Sopenharmony_ci	rc = of_property_read_u32_array(node, "div-reg", div_reg, 3);
2158c2ecf20Sopenharmony_ci	if (!rc) {
2168c2ecf20Sopenharmony_ci		socfpga_clk->div_reg = clk_mgr_base_addr + div_reg[0];
2178c2ecf20Sopenharmony_ci		socfpga_clk->shift = div_reg[1];
2188c2ecf20Sopenharmony_ci		socfpga_clk->width = div_reg[2];
2198c2ecf20Sopenharmony_ci	} else {
2208c2ecf20Sopenharmony_ci		socfpga_clk->div_reg = NULL;
2218c2ecf20Sopenharmony_ci	}
2228c2ecf20Sopenharmony_ci
2238c2ecf20Sopenharmony_ci	rc = of_property_read_u32_array(node, "clk-phase", clk_phase, 2);
2248c2ecf20Sopenharmony_ci	if (!rc) {
2258c2ecf20Sopenharmony_ci		socfpga_clk->clk_phase[0] = clk_phase[0];
2268c2ecf20Sopenharmony_ci		socfpga_clk->clk_phase[1] = clk_phase[1];
2278c2ecf20Sopenharmony_ci	}
2288c2ecf20Sopenharmony_ci
2298c2ecf20Sopenharmony_ci	of_property_read_string(node, "clock-output-names", &clk_name);
2308c2ecf20Sopenharmony_ci
2318c2ecf20Sopenharmony_ci	init.name = clk_name;
2328c2ecf20Sopenharmony_ci	init.ops = ops;
2338c2ecf20Sopenharmony_ci	init.flags = 0;
2348c2ecf20Sopenharmony_ci
2358c2ecf20Sopenharmony_ci	init.num_parents = of_clk_parent_fill(node, parent_name, SOCFPGA_MAX_PARENTS);
2368c2ecf20Sopenharmony_ci	if (init.num_parents < 2) {
2378c2ecf20Sopenharmony_ci		ops->get_parent = NULL;
2388c2ecf20Sopenharmony_ci		ops->set_parent = NULL;
2398c2ecf20Sopenharmony_ci	}
2408c2ecf20Sopenharmony_ci
2418c2ecf20Sopenharmony_ci	init.parent_names = parent_name;
2428c2ecf20Sopenharmony_ci	socfpga_clk->hw.hw.init = &init;
2438c2ecf20Sopenharmony_ci
2448c2ecf20Sopenharmony_ci	hw_clk = &socfpga_clk->hw.hw;
2458c2ecf20Sopenharmony_ci
2468c2ecf20Sopenharmony_ci	err = clk_hw_register(NULL, hw_clk);
2478c2ecf20Sopenharmony_ci	if (err) {
2488c2ecf20Sopenharmony_ci		kfree(ops);
2498c2ecf20Sopenharmony_ci		kfree(socfpga_clk);
2508c2ecf20Sopenharmony_ci		return;
2518c2ecf20Sopenharmony_ci	}
2528c2ecf20Sopenharmony_ci	rc = of_clk_add_provider(node, of_clk_src_simple_get, hw_clk);
2538c2ecf20Sopenharmony_ci	if (WARN_ON(rc))
2548c2ecf20Sopenharmony_ci		return;
2558c2ecf20Sopenharmony_ci}
256