brintos

brintos / linux-shallow public Read only

0
0
Text · 10.3 KiB · dd2784b Raw
387 lines · c
1// SPDX-License-Identifier: GPL-2.02/*3 * Copyright (c) 2014 Marvell Technology Group Ltd.4 *5 * Alexandre Belloni <alexandre.belloni@free-electrons.com>6 * Sebastian Hesselbarth <sebastian.hesselbarth@gmail.com>7 */8 9#include <linux/clk.h>10#include <linux/clk-provider.h>11#include <linux/io.h>12#include <linux/kernel.h>13#include <linux/of.h>14#include <linux/of_address.h>15#include <linux/slab.h>16 17#include <dt-bindings/clock/berlin2q.h>18 19#include "berlin2-div.h"20#include "berlin2-pll.h"21#include "common.h"22 23#define REG_PINMUX0		0x001824#define REG_PINMUX5		0x002c25#define REG_SYSPLLCTL0		0x003026#define REG_SYSPLLCTL4		0x004027#define REG_CLKENABLE		0x00e828#define REG_CLKSELECT0		0x00ec29#define REG_CLKSELECT1		0x00f030#define REG_CLKSELECT2		0x00f431#define REG_CLKSWITCH0		0x00f832#define REG_CLKSWITCH1		0x00fc33#define REG_SW_GENERIC0		0x011034#define REG_SW_GENERIC3		0x011c35#define REG_SDIO0XIN_CLKCTL	0x015836#define REG_SDIO1XIN_CLKCTL	0x015c37 38#define	MAX_CLKS 2839static struct clk_hw_onecell_data *clk_data;40static DEFINE_SPINLOCK(lock);41static void __iomem *gbase;42static void __iomem *cpupll_base;43 44enum {45	REFCLK,46	SYSPLL, CPUPLL,47	AVPLL_B1, AVPLL_B2, AVPLL_B3, AVPLL_B4,48	AVPLL_B5, AVPLL_B6, AVPLL_B7, AVPLL_B8,49};50 51static const char *clk_names[] = {52	[REFCLK]		= "refclk",53	[SYSPLL]		= "syspll",54	[CPUPLL]		= "cpupll",55	[AVPLL_B1]		= "avpll_b1",56	[AVPLL_B2]		= "avpll_b2",57	[AVPLL_B3]		= "avpll_b3",58	[AVPLL_B4]		= "avpll_b4",59	[AVPLL_B5]		= "avpll_b5",60	[AVPLL_B6]		= "avpll_b6",61	[AVPLL_B7]		= "avpll_b7",62	[AVPLL_B8]		= "avpll_b8",63};64 65static const struct berlin2_pll_map bg2q_pll_map __initconst = {66	.vcodiv		= {1, 0, 2, 0, 3, 4, 0, 6, 8},67	.mult		= 1,68	.fbdiv_shift	= 7,69	.rfdiv_shift	= 2,70	.divsel_shift	= 9,71};72 73static const u8 default_parent_ids[] = {74	SYSPLL, AVPLL_B4, AVPLL_B5, AVPLL_B6, AVPLL_B7, SYSPLL75};76 77static const struct berlin2_div_data bg2q_divs[] __initconst = {78	{79		.name = "sys",80		.parent_ids = default_parent_ids,81		.num_parents = ARRAY_SIZE(default_parent_ids),82		.map = {83			BERLIN2_DIV_GATE(REG_CLKENABLE, 0),84			BERLIN2_PLL_SELECT(REG_CLKSELECT0, 0),85			BERLIN2_DIV_SELECT(REG_CLKSELECT0, 3),86			BERLIN2_PLL_SWITCH(REG_CLKSWITCH0, 3),87			BERLIN2_DIV_SWITCH(REG_CLKSWITCH0, 4),88			BERLIN2_DIV_D3SWITCH(REG_CLKSWITCH0, 5),89		},90		.div_flags = BERLIN2_DIV_HAS_GATE | BERLIN2_DIV_HAS_MUX,91		.flags = CLK_IGNORE_UNUSED,92	},93	{94		.name = "drmfigo",95		.parent_ids = default_parent_ids,96		.num_parents = ARRAY_SIZE(default_parent_ids),97		.map = {98			BERLIN2_DIV_GATE(REG_CLKENABLE, 17),99			BERLIN2_PLL_SELECT(REG_CLKSELECT0, 6),100			BERLIN2_DIV_SELECT(REG_CLKSELECT0, 9),101			BERLIN2_PLL_SWITCH(REG_CLKSWITCH0, 6),102			BERLIN2_DIV_SWITCH(REG_CLKSWITCH0, 7),103			BERLIN2_DIV_D3SWITCH(REG_CLKSWITCH0, 8),104		},105		.div_flags = BERLIN2_DIV_HAS_GATE | BERLIN2_DIV_HAS_MUX,106		.flags = 0,107	},108	{109		.name = "cfg",110		.parent_ids = default_parent_ids,111		.num_parents = ARRAY_SIZE(default_parent_ids),112		.map = {113			BERLIN2_DIV_GATE(REG_CLKENABLE, 1),114			BERLIN2_PLL_SELECT(REG_CLKSELECT0, 12),115			BERLIN2_DIV_SELECT(REG_CLKSELECT0, 15),116			BERLIN2_PLL_SWITCH(REG_CLKSWITCH0, 9),117			BERLIN2_DIV_SWITCH(REG_CLKSWITCH0, 10),118			BERLIN2_DIV_D3SWITCH(REG_CLKSWITCH0, 11),119		},120		.div_flags = BERLIN2_DIV_HAS_GATE | BERLIN2_DIV_HAS_MUX,121		.flags = 0,122	},123	{124		.name = "gfx2d",125		.parent_ids = default_parent_ids,126		.num_parents = ARRAY_SIZE(default_parent_ids),127		.map = {128			BERLIN2_DIV_GATE(REG_CLKENABLE, 4),129			BERLIN2_PLL_SELECT(REG_CLKSELECT0, 18),130			BERLIN2_DIV_SELECT(REG_CLKSELECT0, 21),131			BERLIN2_PLL_SWITCH(REG_CLKSWITCH0, 12),132			BERLIN2_DIV_SWITCH(REG_CLKSWITCH0, 13),133			BERLIN2_DIV_D3SWITCH(REG_CLKSWITCH0, 14),134		},135		.div_flags = BERLIN2_DIV_HAS_GATE | BERLIN2_DIV_HAS_MUX,136		.flags = 0,137	},138	{139		.name = "zsp",140		.parent_ids = default_parent_ids,141		.num_parents = ARRAY_SIZE(default_parent_ids),142		.map = {143			BERLIN2_DIV_GATE(REG_CLKENABLE, 6),144			BERLIN2_PLL_SELECT(REG_CLKSELECT0, 24),145			BERLIN2_DIV_SELECT(REG_CLKSELECT0, 27),146			BERLIN2_PLL_SWITCH(REG_CLKSWITCH0, 15),147			BERLIN2_DIV_SWITCH(REG_CLKSWITCH0, 16),148			BERLIN2_DIV_D3SWITCH(REG_CLKSWITCH0, 17),149		},150		.div_flags = BERLIN2_DIV_HAS_GATE | BERLIN2_DIV_HAS_MUX,151		.flags = 0,152	},153	{154		.name = "perif",155		.parent_ids = default_parent_ids,156		.num_parents = ARRAY_SIZE(default_parent_ids),157		.map = {158			BERLIN2_DIV_GATE(REG_CLKENABLE, 7),159			BERLIN2_PLL_SELECT(REG_CLKSELECT1, 0),160			BERLIN2_DIV_SELECT(REG_CLKSELECT1, 3),161			BERLIN2_PLL_SWITCH(REG_CLKSWITCH0, 18),162			BERLIN2_DIV_SWITCH(REG_CLKSWITCH0, 19),163			BERLIN2_DIV_D3SWITCH(REG_CLKSWITCH0, 20),164		},165		.div_flags = BERLIN2_DIV_HAS_GATE | BERLIN2_DIV_HAS_MUX,166		.flags = CLK_IGNORE_UNUSED,167	},168	{169		.name = "pcube",170		.parent_ids = default_parent_ids,171		.num_parents = ARRAY_SIZE(default_parent_ids),172		.map = {173			BERLIN2_DIV_GATE(REG_CLKENABLE, 2),174			BERLIN2_PLL_SELECT(REG_CLKSELECT1, 6),175			BERLIN2_DIV_SELECT(REG_CLKSELECT1, 9),176			BERLIN2_PLL_SWITCH(REG_CLKSWITCH0, 21),177			BERLIN2_DIV_SWITCH(REG_CLKSWITCH0, 22),178			BERLIN2_DIV_D3SWITCH(REG_CLKSWITCH0, 23),179		},180		.div_flags = BERLIN2_DIV_HAS_GATE | BERLIN2_DIV_HAS_MUX,181		.flags = 0,182	},183	{184		.name = "vscope",185		.parent_ids = default_parent_ids,186		.num_parents = ARRAY_SIZE(default_parent_ids),187		.map = {188			BERLIN2_DIV_GATE(REG_CLKENABLE, 3),189			BERLIN2_PLL_SELECT(REG_CLKSELECT1, 12),190			BERLIN2_DIV_SELECT(REG_CLKSELECT1, 15),191			BERLIN2_PLL_SWITCH(REG_CLKSWITCH0, 24),192			BERLIN2_DIV_SWITCH(REG_CLKSWITCH0, 25),193			BERLIN2_DIV_D3SWITCH(REG_CLKSWITCH0, 26),194		},195		.div_flags = BERLIN2_DIV_HAS_GATE | BERLIN2_DIV_HAS_MUX,196		.flags = 0,197	},198	{199		.name = "nfc_ecc",200		.parent_ids = default_parent_ids,201		.num_parents = ARRAY_SIZE(default_parent_ids),202		.map = {203			BERLIN2_DIV_GATE(REG_CLKENABLE, 19),204			BERLIN2_PLL_SELECT(REG_CLKSELECT1, 18),205			BERLIN2_DIV_SELECT(REG_CLKSELECT1, 21),206			BERLIN2_PLL_SWITCH(REG_CLKSWITCH0, 27),207			BERLIN2_DIV_SWITCH(REG_CLKSWITCH0, 28),208			BERLIN2_DIV_D3SWITCH(REG_CLKSWITCH0, 29),209		},210		.div_flags = BERLIN2_DIV_HAS_GATE | BERLIN2_DIV_HAS_MUX,211		.flags = 0,212	},213	{214		.name = "vpp",215		.parent_ids = default_parent_ids,216		.num_parents = ARRAY_SIZE(default_parent_ids),217		.map = {218			BERLIN2_DIV_GATE(REG_CLKENABLE, 21),219			BERLIN2_PLL_SELECT(REG_CLKSELECT1, 24),220			BERLIN2_DIV_SELECT(REG_CLKSELECT1, 27),221			BERLIN2_PLL_SWITCH(REG_CLKSWITCH0, 30),222			BERLIN2_DIV_SWITCH(REG_CLKSWITCH0, 31),223			BERLIN2_DIV_D3SWITCH(REG_CLKSWITCH1, 0),224		},225		.div_flags = BERLIN2_DIV_HAS_GATE | BERLIN2_DIV_HAS_MUX,226		.flags = 0,227	},228	{229		.name = "app",230		.parent_ids = default_parent_ids,231		.num_parents = ARRAY_SIZE(default_parent_ids),232		.map = {233			BERLIN2_DIV_GATE(REG_CLKENABLE, 20),234			BERLIN2_PLL_SELECT(REG_CLKSELECT2, 0),235			BERLIN2_DIV_SELECT(REG_CLKSELECT2, 3),236			BERLIN2_PLL_SWITCH(REG_CLKSWITCH1, 1),237			BERLIN2_DIV_SWITCH(REG_CLKSWITCH1, 2),238			BERLIN2_DIV_D3SWITCH(REG_CLKSWITCH1, 3),239		},240		.div_flags = BERLIN2_DIV_HAS_GATE | BERLIN2_DIV_HAS_MUX,241		.flags = 0,242	},243	{244		.name = "sdio0xin",245		.parent_ids = default_parent_ids,246		.num_parents = ARRAY_SIZE(default_parent_ids),247		.map = {248			BERLIN2_SINGLE_DIV(REG_SDIO0XIN_CLKCTL),249		},250		.div_flags = BERLIN2_DIV_HAS_GATE | BERLIN2_DIV_HAS_MUX,251		.flags = 0,252	},253	{254		.name = "sdio1xin",255		.parent_ids = default_parent_ids,256		.num_parents = ARRAY_SIZE(default_parent_ids),257		.map = {258			BERLIN2_SINGLE_DIV(REG_SDIO1XIN_CLKCTL),259		},260		.div_flags = BERLIN2_DIV_HAS_GATE | BERLIN2_DIV_HAS_MUX,261		.flags = 0,262	},263};264 265static const struct berlin2_gate_data bg2q_gates[] __initconst = {266	{ "gfx2daxi",	"perif",	5 },267	{ "geth0",	"perif",	8 },268	{ "sata",	"perif",	9 },269	{ "ahbapb",	"perif",	10, CLK_IGNORE_UNUSED },270	{ "usb0",	"perif",	11 },271	{ "usb1",	"perif",	12 },272	{ "usb2",	"perif",	13 },273	{ "usb3",	"perif",	14 },274	{ "pbridge",	"perif",	15, CLK_IGNORE_UNUSED },275	{ "sdio",	"perif",	16 },276	{ "nfc",	"perif",	18 },277	{ "pcie",	"perif",	22 },278};279 280static void __init berlin2q_clock_setup(struct device_node *np)281{282	struct device_node *parent_np = of_get_parent(np);283	const char *parent_names[9];284	struct clk *clk;285	struct clk_hw **hws;286	int n, ret;287 288	clk_data = kzalloc(struct_size(clk_data, hws, MAX_CLKS), GFP_KERNEL);289	if (!clk_data) {290		of_node_put(parent_np);291		return;292	}293	clk_data->num = MAX_CLKS;294	hws = clk_data->hws;295 296	gbase = of_iomap(parent_np, 0);297	if (!gbase) {298		of_node_put(parent_np);299		pr_err("%pOF: Unable to map global base\n", np);300		return;301	}302 303	/* BG2Q CPU PLL is not part of global registers */304	cpupll_base = of_iomap(parent_np, 1);305	of_node_put(parent_np);306	if (!cpupll_base) {307		pr_err("%pOF: Unable to map cpupll base\n", np);308		iounmap(gbase);309		return;310	}311 312	/* overwrite default clock names with DT provided ones */313	clk = of_clk_get_by_name(np, clk_names[REFCLK]);314	if (!IS_ERR(clk)) {315		clk_names[REFCLK] = __clk_get_name(clk);316		clk_put(clk);317	}318 319	/* simple register PLLs */320	ret = berlin2_pll_register(&bg2q_pll_map, gbase + REG_SYSPLLCTL0,321				   clk_names[SYSPLL], clk_names[REFCLK], 0);322	if (ret)323		goto bg2q_fail;324 325	ret = berlin2_pll_register(&bg2q_pll_map, cpupll_base,326				   clk_names[CPUPLL], clk_names[REFCLK], 0);327	if (ret)328		goto bg2q_fail;329 330	/* TODO: add BG2Q AVPLL */331 332	/*333	 * TODO: add reference clock bypass switches:334	 * memPLLSWBypass, cpuPLLSWBypass, and sysPLLSWBypass335	 */336 337	/* clock divider cells */338	for (n = 0; n < ARRAY_SIZE(bg2q_divs); n++) {339		const struct berlin2_div_data *dd = &bg2q_divs[n];340		int k;341 342		for (k = 0; k < dd->num_parents; k++)343			parent_names[k] = clk_names[dd->parent_ids[k]];344 345		hws[CLKID_SYS + n] = berlin2_div_register(&dd->map, gbase,346				dd->name, dd->div_flags, parent_names,347				dd->num_parents, dd->flags, &lock);348	}349 350	/* clock gate cells */351	for (n = 0; n < ARRAY_SIZE(bg2q_gates); n++) {352		const struct berlin2_gate_data *gd = &bg2q_gates[n];353 354		hws[CLKID_GFX2DAXI + n] = clk_hw_register_gate(NULL, gd->name,355			    gd->parent_name, gd->flags, gbase + REG_CLKENABLE,356			    gd->bit_idx, 0, &lock);357	}358 359	/* cpuclk divider is fixed to 1 */360	hws[CLKID_CPU] =361		clk_hw_register_fixed_factor(NULL, "cpu", clk_names[CPUPLL],362					  0, 1, 1);363	/* twdclk is derived from cpu/3 */364	hws[CLKID_TWD] =365		clk_hw_register_fixed_factor(NULL, "twd", "cpu", 0, 1, 3);366 367	/* check for errors on leaf clocks */368	for (n = 0; n < MAX_CLKS; n++) {369		if (!IS_ERR(hws[n]))370			continue;371 372		pr_err("%pOF: Unable to register leaf clock %d\n", np, n);373		goto bg2q_fail;374	}375 376	/* register clk-provider */377	of_clk_add_hw_provider(np, of_clk_hw_onecell_get, clk_data);378 379	return;380 381bg2q_fail:382	iounmap(cpupll_base);383	iounmap(gbase);384}385CLK_OF_DECLARE(berlin2q_clk, "marvell,berlin2q-clk",386	       berlin2q_clock_setup);387