brintos

brintos / linux-shallow public Read only

0
0
Text · 10.6 KiB · 03c59bf Raw
435 lines · c
1// SPDX-License-Identifier: GPL-2.02/*3 * Marvell Armada CP110 System Controller4 *5 * Copyright (C) 2016 Marvell6 *7 * Thomas Petazzoni <thomas.petazzoni@free-electrons.com>8 *9 */10 11/*12 * CP110 has 6 core clocks:13 *14 *  - PLL0		(1 Ghz)15 *    - PPv2 core	(1/3 PLL0)16 *    - x2 Core		(1/2 PLL0)17 *	- Core		(1/2 x2 Core)18 *    - SDIO		(2/5 PLL0)19 *20 *  - NAND clock, which is either:21 *    - Equal to SDIO clock22 *    - 2/5 PLL023 *24 * CP110 has 32 gateable clocks, for the various peripherals in the IP.25 */26 27#define pr_fmt(fmt) "cp110-system-controller: " fmt28 29#include "armada_ap_cp_helper.h"30#include <linux/clk-provider.h>31#include <linux/mfd/syscon.h>32#include <linux/init.h>33#include <linux/of.h>34#include <linux/platform_device.h>35#include <linux/regmap.h>36#include <linux/slab.h>37 38#define CP110_PM_CLOCK_GATING_REG	0x22039#define CP110_NAND_FLASH_CLK_CTRL_REG	0x70040#define    NF_CLOCK_SEL_400_MASK	BIT(0)41 42enum {43	CP110_CLK_TYPE_CORE,44	CP110_CLK_TYPE_GATABLE,45};46 47#define CP110_MAX_CORE_CLOCKS		648#define CP110_MAX_GATABLE_CLOCKS	3249 50#define CP110_CLK_NUM \51	(CP110_MAX_CORE_CLOCKS + CP110_MAX_GATABLE_CLOCKS)52 53#define CP110_CORE_PLL0			054#define CP110_CORE_PPV2			155#define CP110_CORE_X2CORE		256#define CP110_CORE_CORE			357#define CP110_CORE_NAND			458#define CP110_CORE_SDIO			559 60/* A number of gateable clocks need special handling */61#define CP110_GATE_AUDIO		062#define CP110_GATE_COMM_UNIT		163#define CP110_GATE_NAND			264#define CP110_GATE_PPV2			365#define CP110_GATE_SDIO			466#define CP110_GATE_MG			567#define CP110_GATE_MG_CORE		668#define CP110_GATE_XOR1			769#define CP110_GATE_XOR0			870#define CP110_GATE_GOP_DP		971#define CP110_GATE_PCIE_X1_0		1172#define CP110_GATE_PCIE_X1_1		1273#define CP110_GATE_PCIE_X4		1374#define CP110_GATE_PCIE_XOR		1475#define CP110_GATE_SATA			1576#define CP110_GATE_SATA_USB		1677#define CP110_GATE_MAIN			1778#define CP110_GATE_SDMMC_GOP		1879#define CP110_GATE_SLOW_IO		2180#define CP110_GATE_USB3H0		2281#define CP110_GATE_USB3H1		2382#define CP110_GATE_USB3DEV		2483#define CP110_GATE_EIP150		2584#define CP110_GATE_EIP197		2685 86static const char * const gate_base_names[] = {87	[CP110_GATE_AUDIO]	= "audio",88	[CP110_GATE_COMM_UNIT]	= "communit",89	[CP110_GATE_NAND]	= "nand",90	[CP110_GATE_PPV2]	= "ppv2",91	[CP110_GATE_SDIO]	= "sdio",92	[CP110_GATE_MG]		= "mg-domain",93	[CP110_GATE_MG_CORE]	= "mg-core",94	[CP110_GATE_XOR1]	= "xor1",95	[CP110_GATE_XOR0]	= "xor0",96	[CP110_GATE_GOP_DP]	= "gop-dp",97	[CP110_GATE_PCIE_X1_0]	= "pcie_x10",98	[CP110_GATE_PCIE_X1_1]	= "pcie_x11",99	[CP110_GATE_PCIE_X4]	= "pcie_x4",100	[CP110_GATE_PCIE_XOR]	= "pcie-xor",101	[CP110_GATE_SATA]	= "sata",102	[CP110_GATE_SATA_USB]	= "sata-usb",103	[CP110_GATE_MAIN]	= "main",104	[CP110_GATE_SDMMC_GOP]	= "sd-mmc-gop",105	[CP110_GATE_SLOW_IO]	= "slow-io",106	[CP110_GATE_USB3H0]	= "usb3h0",107	[CP110_GATE_USB3H1]	= "usb3h1",108	[CP110_GATE_USB3DEV]	= "usb3dev",109	[CP110_GATE_EIP150]	= "eip150",110	[CP110_GATE_EIP197]	= "eip197"111};112 113struct cp110_gate_clk {114	struct clk_hw hw;115	struct regmap *regmap;116	u8 bit_idx;117};118 119#define to_cp110_gate_clk(hw) container_of(hw, struct cp110_gate_clk, hw)120 121static int cp110_gate_enable(struct clk_hw *hw)122{123	struct cp110_gate_clk *gate = to_cp110_gate_clk(hw);124 125	regmap_update_bits(gate->regmap, CP110_PM_CLOCK_GATING_REG,126			   BIT(gate->bit_idx), BIT(gate->bit_idx));127 128	return 0;129}130 131static void cp110_gate_disable(struct clk_hw *hw)132{133	struct cp110_gate_clk *gate = to_cp110_gate_clk(hw);134 135	regmap_update_bits(gate->regmap, CP110_PM_CLOCK_GATING_REG,136			   BIT(gate->bit_idx), 0);137}138 139static int cp110_gate_is_enabled(struct clk_hw *hw)140{141	struct cp110_gate_clk *gate = to_cp110_gate_clk(hw);142	u32 val;143 144	regmap_read(gate->regmap, CP110_PM_CLOCK_GATING_REG, &val);145 146	return val & BIT(gate->bit_idx);147}148 149static const struct clk_ops cp110_gate_ops = {150	.enable = cp110_gate_enable,151	.disable = cp110_gate_disable,152	.is_enabled = cp110_gate_is_enabled,153};154 155static struct clk_hw *cp110_register_gate(const char *name,156					  const char *parent_name,157					  struct regmap *regmap, u8 bit_idx)158{159	struct cp110_gate_clk *gate;160	struct clk_hw *hw;161	struct clk_init_data init;162	int ret;163 164	gate = kzalloc(sizeof(*gate), GFP_KERNEL);165	if (!gate)166		return ERR_PTR(-ENOMEM);167 168	memset(&init, 0, sizeof(init));169 170	init.name = name;171	init.ops = &cp110_gate_ops;172	init.parent_names = &parent_name;173	init.num_parents = 1;174 175	gate->regmap = regmap;176	gate->bit_idx = bit_idx;177	gate->hw.init = &init;178 179	hw = &gate->hw;180	ret = clk_hw_register(NULL, hw);181	if (ret) {182		kfree(gate);183		hw = ERR_PTR(ret);184	}185 186	return hw;187}188 189static void cp110_unregister_gate(struct clk_hw *hw)190{191	clk_hw_unregister(hw);192	kfree(to_cp110_gate_clk(hw));193}194 195static struct clk_hw *cp110_of_clk_get(struct of_phandle_args *clkspec,196				       void *data)197{198	struct clk_hw_onecell_data *clk_data = data;199	unsigned int type = clkspec->args[0];200	unsigned int idx = clkspec->args[1];201 202	if (type == CP110_CLK_TYPE_CORE) {203		if (idx >= CP110_MAX_CORE_CLOCKS)204			return ERR_PTR(-EINVAL);205		return clk_data->hws[idx];206	} else if (type == CP110_CLK_TYPE_GATABLE) {207		if (idx >= CP110_MAX_GATABLE_CLOCKS)208			return ERR_PTR(-EINVAL);209		return clk_data->hws[CP110_MAX_CORE_CLOCKS + idx];210	}211 212	return ERR_PTR(-EINVAL);213}214 215static int cp110_syscon_common_probe(struct platform_device *pdev,216				     struct device_node *syscon_node)217{218	struct regmap *regmap;219	struct device *dev = &pdev->dev;220	struct device_node *np = dev->of_node;221	const char *ppv2_name, *pll0_name, *core_name, *x2core_name, *nand_name,222		*sdio_name;223	struct clk_hw_onecell_data *cp110_clk_data;224	struct clk_hw *hw, **cp110_clks;225	u32 nand_clk_ctrl;226	int i, ret;227	char *gate_name[ARRAY_SIZE(gate_base_names)];228 229	regmap = syscon_node_to_regmap(syscon_node);230	if (IS_ERR(regmap))231		return PTR_ERR(regmap);232 233	ret = regmap_read(regmap, CP110_NAND_FLASH_CLK_CTRL_REG,234			  &nand_clk_ctrl);235	if (ret)236		return ret;237 238	cp110_clk_data = devm_kzalloc(dev, struct_size(cp110_clk_data, hws,239						       CP110_CLK_NUM),240				      GFP_KERNEL);241	if (!cp110_clk_data)242		return -ENOMEM;243	cp110_clk_data->num = CP110_CLK_NUM;244 245	cp110_clks = cp110_clk_data->hws;246 247	/* Register the PLL0 which is the root of the hw tree */248	pll0_name = ap_cp_unique_name(dev, syscon_node, "pll0");249	hw = clk_hw_register_fixed_rate(NULL, pll0_name, NULL, 0,250					1000 * 1000 * 1000);251	if (IS_ERR(hw)) {252		ret = PTR_ERR(hw);253		goto fail_pll0;254	}255 256	cp110_clks[CP110_CORE_PLL0] = hw;257 258	/* PPv2 is PLL0/3 */259	ppv2_name = ap_cp_unique_name(dev, syscon_node, "ppv2-core");260	hw = clk_hw_register_fixed_factor(NULL, ppv2_name, pll0_name, 0, 1, 3);261	if (IS_ERR(hw)) {262		ret = PTR_ERR(hw);263		goto fail_ppv2;264	}265 266	cp110_clks[CP110_CORE_PPV2] = hw;267 268	/* X2CORE clock is PLL0/2 */269	x2core_name = ap_cp_unique_name(dev, syscon_node, "x2core");270	hw = clk_hw_register_fixed_factor(NULL, x2core_name, pll0_name,271					  0, 1, 2);272	if (IS_ERR(hw)) {273		ret = PTR_ERR(hw);274		goto fail_eip;275	}276 277	cp110_clks[CP110_CORE_X2CORE] = hw;278 279	/* Core clock is X2CORE/2 */280	core_name = ap_cp_unique_name(dev, syscon_node, "core");281	hw = clk_hw_register_fixed_factor(NULL, core_name, x2core_name,282					  0, 1, 2);283	if (IS_ERR(hw)) {284		ret = PTR_ERR(hw);285		goto fail_core;286	}287 288	cp110_clks[CP110_CORE_CORE] = hw;289	/* NAND can be either PLL0/2.5 or core clock */290	nand_name = ap_cp_unique_name(dev, syscon_node, "nand-core");291	if (nand_clk_ctrl & NF_CLOCK_SEL_400_MASK)292		hw = clk_hw_register_fixed_factor(NULL, nand_name,293						   pll0_name, 0, 2, 5);294	else295		hw = clk_hw_register_fixed_factor(NULL, nand_name,296						   core_name, 0, 1, 1);297	if (IS_ERR(hw)) {298		ret = PTR_ERR(hw);299		goto fail_nand;300	}301 302	cp110_clks[CP110_CORE_NAND] = hw;303 304	/* SDIO clock is PLL0/2.5 */305	sdio_name = ap_cp_unique_name(dev, syscon_node, "sdio-core");306	hw = clk_hw_register_fixed_factor(NULL, sdio_name,307					  pll0_name, 0, 2, 5);308	if (IS_ERR(hw)) {309		ret = PTR_ERR(hw);310		goto fail_sdio;311	}312 313	cp110_clks[CP110_CORE_SDIO] = hw;314 315	/* create the unique name for all the gate clocks */316	for (i = 0; i < ARRAY_SIZE(gate_base_names); i++)317		gate_name[i] =	ap_cp_unique_name(dev, syscon_node,318						  gate_base_names[i]);319 320	for (i = 0; i < ARRAY_SIZE(gate_base_names); i++) {321		const char *parent;322 323		if (gate_name[i] == NULL)324			continue;325 326		switch (i) {327		case CP110_GATE_NAND:328			parent = nand_name;329			break;330		case CP110_GATE_MG:331		case CP110_GATE_GOP_DP:332		case CP110_GATE_PPV2:333			parent = ppv2_name;334			break;335		case CP110_GATE_SDIO:336			parent = sdio_name;337			break;338		case CP110_GATE_MAIN:339		case CP110_GATE_PCIE_XOR:340		case CP110_GATE_PCIE_X4:341		case CP110_GATE_EIP150:342		case CP110_GATE_EIP197:343			parent = x2core_name;344			break;345		default:346			parent = core_name;347			break;348		}349		hw = cp110_register_gate(gate_name[i], parent, regmap, i);350 351		if (IS_ERR(hw)) {352			ret = PTR_ERR(hw);353			goto fail_gate;354		}355 356		cp110_clks[CP110_MAX_CORE_CLOCKS + i] = hw;357	}358 359	ret = of_clk_add_hw_provider(np, cp110_of_clk_get, cp110_clk_data);360	if (ret)361		goto fail_clk_add;362 363	platform_set_drvdata(pdev, cp110_clks);364 365	return 0;366 367fail_clk_add:368fail_gate:369	for (i = 0; i < CP110_MAX_GATABLE_CLOCKS; i++) {370		hw = cp110_clks[CP110_MAX_CORE_CLOCKS + i];371 372		if (hw)373			cp110_unregister_gate(hw);374	}375 376	clk_hw_unregister_fixed_factor(cp110_clks[CP110_CORE_SDIO]);377fail_sdio:378	clk_hw_unregister_fixed_factor(cp110_clks[CP110_CORE_NAND]);379fail_nand:380	clk_hw_unregister_fixed_factor(cp110_clks[CP110_CORE_CORE]);381fail_core:382	clk_hw_unregister_fixed_factor(cp110_clks[CP110_CORE_X2CORE]);383fail_eip:384	clk_hw_unregister_fixed_factor(cp110_clks[CP110_CORE_PPV2]);385fail_ppv2:386	clk_hw_unregister_fixed_rate(cp110_clks[CP110_CORE_PLL0]);387fail_pll0:388	return ret;389}390 391static int cp110_syscon_legacy_clk_probe(struct platform_device *pdev)392{393	dev_warn(&pdev->dev, FW_WARN "Using legacy device tree binding\n");394	dev_warn(&pdev->dev, FW_WARN "Update your device tree:\n");395	dev_warn(&pdev->dev, FW_WARN396		 "This binding won't be supported in future kernels\n");397 398	return cp110_syscon_common_probe(pdev, pdev->dev.of_node);399}400 401static int cp110_clk_probe(struct platform_device *pdev)402{403	return cp110_syscon_common_probe(pdev, pdev->dev.of_node->parent);404}405 406static const struct of_device_id cp110_syscon_legacy_of_match[] = {407	{ .compatible = "marvell,cp110-system-controller0", },408	{ }409};410 411static struct platform_driver cp110_syscon_legacy_driver = {412	.probe = cp110_syscon_legacy_clk_probe,413	.driver		= {414		.name	= "marvell-cp110-system-controller0",415		.of_match_table = cp110_syscon_legacy_of_match,416		.suppress_bind_attrs = true,417	},418};419builtin_platform_driver(cp110_syscon_legacy_driver);420 421static const struct of_device_id cp110_clock_of_match[] = {422	{ .compatible = "marvell,cp110-clock", },423	{ }424};425 426static struct platform_driver cp110_clock_driver = {427	.probe = cp110_clk_probe,428	.driver		= {429		.name	= "marvell-cp110-clock",430		.of_match_table = cp110_clock_of_match,431		.suppress_bind_attrs = true,432	},433};434builtin_platform_driver(cp110_clock_driver);435