xref: /linux/drivers/clk/berlin/bg2q.c (revision 4f2c0a4acffbec01079c28f839422e64ddeff004)
13504395fSJisheng Zhang // SPDX-License-Identifier: GPL-2.0
218882ac5SAlexandre Belloni /*
318882ac5SAlexandre Belloni  * Copyright (c) 2014 Marvell Technology Group Ltd.
418882ac5SAlexandre Belloni  *
518882ac5SAlexandre Belloni  * Alexandre Belloni <alexandre.belloni@free-electrons.com>
618882ac5SAlexandre Belloni  * Sebastian Hesselbarth <sebastian.hesselbarth@gmail.com>
718882ac5SAlexandre Belloni  */
818882ac5SAlexandre Belloni 
918882ac5SAlexandre Belloni #include <linux/clk.h>
1018882ac5SAlexandre Belloni #include <linux/clk-provider.h>
1162e59c4eSStephen Boyd #include <linux/io.h>
1218882ac5SAlexandre Belloni #include <linux/kernel.h>
1318882ac5SAlexandre Belloni #include <linux/of.h>
1418882ac5SAlexandre Belloni #include <linux/of_address.h>
1518882ac5SAlexandre Belloni #include <linux/slab.h>
1618882ac5SAlexandre Belloni 
1718882ac5SAlexandre Belloni #include <dt-bindings/clock/berlin2q.h>
1818882ac5SAlexandre Belloni 
1918882ac5SAlexandre Belloni #include "berlin2-div.h"
2018882ac5SAlexandre Belloni #include "berlin2-pll.h"
2118882ac5SAlexandre Belloni #include "common.h"
2218882ac5SAlexandre Belloni 
2318882ac5SAlexandre Belloni #define REG_PINMUX0		0x0018
2418882ac5SAlexandre Belloni #define REG_PINMUX5		0x002c
2518882ac5SAlexandre Belloni #define REG_SYSPLLCTL0		0x0030
2618882ac5SAlexandre Belloni #define REG_SYSPLLCTL4		0x0040
2718882ac5SAlexandre Belloni #define REG_CLKENABLE		0x00e8
2818882ac5SAlexandre Belloni #define REG_CLKSELECT0		0x00ec
2918882ac5SAlexandre Belloni #define REG_CLKSELECT1		0x00f0
3018882ac5SAlexandre Belloni #define REG_CLKSELECT2		0x00f4
3118882ac5SAlexandre Belloni #define REG_CLKSWITCH0		0x00f8
3218882ac5SAlexandre Belloni #define REG_CLKSWITCH1		0x00fc
3318882ac5SAlexandre Belloni #define REG_SW_GENERIC0		0x0110
3418882ac5SAlexandre Belloni #define REG_SW_GENERIC3		0x011c
3518882ac5SAlexandre Belloni #define REG_SDIO0XIN_CLKCTL	0x0158
3618882ac5SAlexandre Belloni #define REG_SDIO1XIN_CLKCTL	0x015c
3718882ac5SAlexandre Belloni 
38515f1a20SAntoine Tenart #define	MAX_CLKS 28
39f6475e29SStephen Boyd static struct clk_hw_onecell_data *clk_data;
4018882ac5SAlexandre Belloni static DEFINE_SPINLOCK(lock);
4118882ac5SAlexandre Belloni static void __iomem *gbase;
4218882ac5SAlexandre Belloni static void __iomem *cpupll_base;
4318882ac5SAlexandre Belloni 
4418882ac5SAlexandre Belloni enum {
4518882ac5SAlexandre Belloni 	REFCLK,
4618882ac5SAlexandre Belloni 	SYSPLL, CPUPLL,
4718882ac5SAlexandre Belloni 	AVPLL_B1, AVPLL_B2, AVPLL_B3, AVPLL_B4,
4818882ac5SAlexandre Belloni 	AVPLL_B5, AVPLL_B6, AVPLL_B7, AVPLL_B8,
4918882ac5SAlexandre Belloni };
5018882ac5SAlexandre Belloni 
5118882ac5SAlexandre Belloni static const char *clk_names[] = {
5218882ac5SAlexandre Belloni 	[REFCLK]		= "refclk",
5318882ac5SAlexandre Belloni 	[SYSPLL]		= "syspll",
5418882ac5SAlexandre Belloni 	[CPUPLL]		= "cpupll",
5518882ac5SAlexandre Belloni 	[AVPLL_B1]		= "avpll_b1",
5618882ac5SAlexandre Belloni 	[AVPLL_B2]		= "avpll_b2",
5718882ac5SAlexandre Belloni 	[AVPLL_B3]		= "avpll_b3",
5818882ac5SAlexandre Belloni 	[AVPLL_B4]		= "avpll_b4",
5918882ac5SAlexandre Belloni 	[AVPLL_B5]		= "avpll_b5",
6018882ac5SAlexandre Belloni 	[AVPLL_B6]		= "avpll_b6",
6118882ac5SAlexandre Belloni 	[AVPLL_B7]		= "avpll_b7",
6218882ac5SAlexandre Belloni 	[AVPLL_B8]		= "avpll_b8",
6318882ac5SAlexandre Belloni };
6418882ac5SAlexandre Belloni 
6518882ac5SAlexandre Belloni static const struct berlin2_pll_map bg2q_pll_map __initconst = {
6618882ac5SAlexandre Belloni 	.vcodiv		= {1, 0, 2, 0, 3, 4, 0, 6, 8},
6718882ac5SAlexandre Belloni 	.mult		= 1,
6818882ac5SAlexandre Belloni 	.fbdiv_shift	= 7,
6918882ac5SAlexandre Belloni 	.rfdiv_shift	= 2,
7018882ac5SAlexandre Belloni 	.divsel_shift	= 9,
7118882ac5SAlexandre Belloni };
7218882ac5SAlexandre Belloni 
7318882ac5SAlexandre Belloni static const u8 default_parent_ids[] = {
7418882ac5SAlexandre Belloni 	SYSPLL, AVPLL_B4, AVPLL_B5, AVPLL_B6, AVPLL_B7, SYSPLL
7518882ac5SAlexandre Belloni };
7618882ac5SAlexandre Belloni 
7718882ac5SAlexandre Belloni static const struct berlin2_div_data bg2q_divs[] __initconst = {
7818882ac5SAlexandre Belloni 	{
7918882ac5SAlexandre Belloni 		.name = "sys",
8018882ac5SAlexandre Belloni 		.parent_ids = default_parent_ids,
8118882ac5SAlexandre Belloni 		.num_parents = ARRAY_SIZE(default_parent_ids),
8218882ac5SAlexandre Belloni 		.map = {
8318882ac5SAlexandre Belloni 			BERLIN2_DIV_GATE(REG_CLKENABLE, 0),
8418882ac5SAlexandre Belloni 			BERLIN2_PLL_SELECT(REG_CLKSELECT0, 0),
8518882ac5SAlexandre Belloni 			BERLIN2_DIV_SELECT(REG_CLKSELECT0, 3),
8618882ac5SAlexandre Belloni 			BERLIN2_PLL_SWITCH(REG_CLKSWITCH0, 3),
8718882ac5SAlexandre Belloni 			BERLIN2_DIV_SWITCH(REG_CLKSWITCH0, 4),
8818882ac5SAlexandre Belloni 			BERLIN2_DIV_D3SWITCH(REG_CLKSWITCH0, 5),
8918882ac5SAlexandre Belloni 		},
9018882ac5SAlexandre Belloni 		.div_flags = BERLIN2_DIV_HAS_GATE | BERLIN2_DIV_HAS_MUX,
9118882ac5SAlexandre Belloni 		.flags = CLK_IGNORE_UNUSED,
9218882ac5SAlexandre Belloni 	},
9318882ac5SAlexandre Belloni 	{
9418882ac5SAlexandre Belloni 		.name = "drmfigo",
9518882ac5SAlexandre Belloni 		.parent_ids = default_parent_ids,
9618882ac5SAlexandre Belloni 		.num_parents = ARRAY_SIZE(default_parent_ids),
9718882ac5SAlexandre Belloni 		.map = {
9818882ac5SAlexandre Belloni 			BERLIN2_DIV_GATE(REG_CLKENABLE, 17),
9918882ac5SAlexandre Belloni 			BERLIN2_PLL_SELECT(REG_CLKSELECT0, 6),
10018882ac5SAlexandre Belloni 			BERLIN2_DIV_SELECT(REG_CLKSELECT0, 9),
10118882ac5SAlexandre Belloni 			BERLIN2_PLL_SWITCH(REG_CLKSWITCH0, 6),
10218882ac5SAlexandre Belloni 			BERLIN2_DIV_SWITCH(REG_CLKSWITCH0, 7),
10318882ac5SAlexandre Belloni 			BERLIN2_DIV_D3SWITCH(REG_CLKSWITCH0, 8),
10418882ac5SAlexandre Belloni 		},
10518882ac5SAlexandre Belloni 		.div_flags = BERLIN2_DIV_HAS_GATE | BERLIN2_DIV_HAS_MUX,
10618882ac5SAlexandre Belloni 		.flags = 0,
10718882ac5SAlexandre Belloni 	},
10818882ac5SAlexandre Belloni 	{
10918882ac5SAlexandre Belloni 		.name = "cfg",
11018882ac5SAlexandre Belloni 		.parent_ids = default_parent_ids,
11118882ac5SAlexandre Belloni 		.num_parents = ARRAY_SIZE(default_parent_ids),
11218882ac5SAlexandre Belloni 		.map = {
11318882ac5SAlexandre Belloni 			BERLIN2_DIV_GATE(REG_CLKENABLE, 1),
11418882ac5SAlexandre Belloni 			BERLIN2_PLL_SELECT(REG_CLKSELECT0, 12),
11518882ac5SAlexandre Belloni 			BERLIN2_DIV_SELECT(REG_CLKSELECT0, 15),
11618882ac5SAlexandre Belloni 			BERLIN2_PLL_SWITCH(REG_CLKSWITCH0, 9),
11718882ac5SAlexandre Belloni 			BERLIN2_DIV_SWITCH(REG_CLKSWITCH0, 10),
11818882ac5SAlexandre Belloni 			BERLIN2_DIV_D3SWITCH(REG_CLKSWITCH0, 11),
11918882ac5SAlexandre Belloni 		},
12018882ac5SAlexandre Belloni 		.div_flags = BERLIN2_DIV_HAS_GATE | BERLIN2_DIV_HAS_MUX,
12118882ac5SAlexandre Belloni 		.flags = 0,
12218882ac5SAlexandre Belloni 	},
12318882ac5SAlexandre Belloni 	{
12418882ac5SAlexandre Belloni 		.name = "gfx2d",
12518882ac5SAlexandre Belloni 		.parent_ids = default_parent_ids,
12618882ac5SAlexandre Belloni 		.num_parents = ARRAY_SIZE(default_parent_ids),
12718882ac5SAlexandre Belloni 		.map = {
12818882ac5SAlexandre Belloni 			BERLIN2_DIV_GATE(REG_CLKENABLE, 4),
12918882ac5SAlexandre Belloni 			BERLIN2_PLL_SELECT(REG_CLKSELECT0, 18),
13018882ac5SAlexandre Belloni 			BERLIN2_DIV_SELECT(REG_CLKSELECT0, 21),
13118882ac5SAlexandre Belloni 			BERLIN2_PLL_SWITCH(REG_CLKSWITCH0, 12),
13218882ac5SAlexandre Belloni 			BERLIN2_DIV_SWITCH(REG_CLKSWITCH0, 13),
13318882ac5SAlexandre Belloni 			BERLIN2_DIV_D3SWITCH(REG_CLKSWITCH0, 14),
13418882ac5SAlexandre Belloni 		},
13518882ac5SAlexandre Belloni 		.div_flags = BERLIN2_DIV_HAS_GATE | BERLIN2_DIV_HAS_MUX,
13618882ac5SAlexandre Belloni 		.flags = 0,
13718882ac5SAlexandre Belloni 	},
13818882ac5SAlexandre Belloni 	{
13918882ac5SAlexandre Belloni 		.name = "zsp",
14018882ac5SAlexandre Belloni 		.parent_ids = default_parent_ids,
14118882ac5SAlexandre Belloni 		.num_parents = ARRAY_SIZE(default_parent_ids),
14218882ac5SAlexandre Belloni 		.map = {
14318882ac5SAlexandre Belloni 			BERLIN2_DIV_GATE(REG_CLKENABLE, 6),
14418882ac5SAlexandre Belloni 			BERLIN2_PLL_SELECT(REG_CLKSELECT0, 24),
14518882ac5SAlexandre Belloni 			BERLIN2_DIV_SELECT(REG_CLKSELECT0, 27),
14618882ac5SAlexandre Belloni 			BERLIN2_PLL_SWITCH(REG_CLKSWITCH0, 15),
14718882ac5SAlexandre Belloni 			BERLIN2_DIV_SWITCH(REG_CLKSWITCH0, 16),
14818882ac5SAlexandre Belloni 			BERLIN2_DIV_D3SWITCH(REG_CLKSWITCH0, 17),
14918882ac5SAlexandre Belloni 		},
15018882ac5SAlexandre Belloni 		.div_flags = BERLIN2_DIV_HAS_GATE | BERLIN2_DIV_HAS_MUX,
15118882ac5SAlexandre Belloni 		.flags = 0,
15218882ac5SAlexandre Belloni 	},
15318882ac5SAlexandre Belloni 	{
15418882ac5SAlexandre Belloni 		.name = "perif",
15518882ac5SAlexandre Belloni 		.parent_ids = default_parent_ids,
15618882ac5SAlexandre Belloni 		.num_parents = ARRAY_SIZE(default_parent_ids),
15718882ac5SAlexandre Belloni 		.map = {
15818882ac5SAlexandre Belloni 			BERLIN2_DIV_GATE(REG_CLKENABLE, 7),
15918882ac5SAlexandre Belloni 			BERLIN2_PLL_SELECT(REG_CLKSELECT1, 0),
16018882ac5SAlexandre Belloni 			BERLIN2_DIV_SELECT(REG_CLKSELECT1, 3),
16118882ac5SAlexandre Belloni 			BERLIN2_PLL_SWITCH(REG_CLKSWITCH0, 18),
16218882ac5SAlexandre Belloni 			BERLIN2_DIV_SWITCH(REG_CLKSWITCH0, 19),
16318882ac5SAlexandre Belloni 			BERLIN2_DIV_D3SWITCH(REG_CLKSWITCH0, 20),
16418882ac5SAlexandre Belloni 		},
16518882ac5SAlexandre Belloni 		.div_flags = BERLIN2_DIV_HAS_GATE | BERLIN2_DIV_HAS_MUX,
16618882ac5SAlexandre Belloni 		.flags = CLK_IGNORE_UNUSED,
16718882ac5SAlexandre Belloni 	},
16818882ac5SAlexandre Belloni 	{
16918882ac5SAlexandre Belloni 		.name = "pcube",
17018882ac5SAlexandre Belloni 		.parent_ids = default_parent_ids,
17118882ac5SAlexandre Belloni 		.num_parents = ARRAY_SIZE(default_parent_ids),
17218882ac5SAlexandre Belloni 		.map = {
17318882ac5SAlexandre Belloni 			BERLIN2_DIV_GATE(REG_CLKENABLE, 2),
17418882ac5SAlexandre Belloni 			BERLIN2_PLL_SELECT(REG_CLKSELECT1, 6),
17518882ac5SAlexandre Belloni 			BERLIN2_DIV_SELECT(REG_CLKSELECT1, 9),
17618882ac5SAlexandre Belloni 			BERLIN2_PLL_SWITCH(REG_CLKSWITCH0, 21),
17718882ac5SAlexandre Belloni 			BERLIN2_DIV_SWITCH(REG_CLKSWITCH0, 22),
17818882ac5SAlexandre Belloni 			BERLIN2_DIV_D3SWITCH(REG_CLKSWITCH0, 23),
17918882ac5SAlexandre Belloni 		},
18018882ac5SAlexandre Belloni 		.div_flags = BERLIN2_DIV_HAS_GATE | BERLIN2_DIV_HAS_MUX,
18118882ac5SAlexandre Belloni 		.flags = 0,
18218882ac5SAlexandre Belloni 	},
18318882ac5SAlexandre Belloni 	{
18418882ac5SAlexandre Belloni 		.name = "vscope",
18518882ac5SAlexandre Belloni 		.parent_ids = default_parent_ids,
18618882ac5SAlexandre Belloni 		.num_parents = ARRAY_SIZE(default_parent_ids),
18718882ac5SAlexandre Belloni 		.map = {
18818882ac5SAlexandre Belloni 			BERLIN2_DIV_GATE(REG_CLKENABLE, 3),
18918882ac5SAlexandre Belloni 			BERLIN2_PLL_SELECT(REG_CLKSELECT1, 12),
19018882ac5SAlexandre Belloni 			BERLIN2_DIV_SELECT(REG_CLKSELECT1, 15),
19118882ac5SAlexandre Belloni 			BERLIN2_PLL_SWITCH(REG_CLKSWITCH0, 24),
19218882ac5SAlexandre Belloni 			BERLIN2_DIV_SWITCH(REG_CLKSWITCH0, 25),
19318882ac5SAlexandre Belloni 			BERLIN2_DIV_D3SWITCH(REG_CLKSWITCH0, 26),
19418882ac5SAlexandre Belloni 		},
19518882ac5SAlexandre Belloni 		.div_flags = BERLIN2_DIV_HAS_GATE | BERLIN2_DIV_HAS_MUX,
19618882ac5SAlexandre Belloni 		.flags = 0,
19718882ac5SAlexandre Belloni 	},
19818882ac5SAlexandre Belloni 	{
19918882ac5SAlexandre Belloni 		.name = "nfc_ecc",
20018882ac5SAlexandre Belloni 		.parent_ids = default_parent_ids,
20118882ac5SAlexandre Belloni 		.num_parents = ARRAY_SIZE(default_parent_ids),
20218882ac5SAlexandre Belloni 		.map = {
20318882ac5SAlexandre Belloni 			BERLIN2_DIV_GATE(REG_CLKENABLE, 19),
20418882ac5SAlexandre Belloni 			BERLIN2_PLL_SELECT(REG_CLKSELECT1, 18),
20518882ac5SAlexandre Belloni 			BERLIN2_DIV_SELECT(REG_CLKSELECT1, 21),
20618882ac5SAlexandre Belloni 			BERLIN2_PLL_SWITCH(REG_CLKSWITCH0, 27),
20718882ac5SAlexandre Belloni 			BERLIN2_DIV_SWITCH(REG_CLKSWITCH0, 28),
20818882ac5SAlexandre Belloni 			BERLIN2_DIV_D3SWITCH(REG_CLKSWITCH0, 29),
20918882ac5SAlexandre Belloni 		},
21018882ac5SAlexandre Belloni 		.div_flags = BERLIN2_DIV_HAS_GATE | BERLIN2_DIV_HAS_MUX,
21118882ac5SAlexandre Belloni 		.flags = 0,
21218882ac5SAlexandre Belloni 	},
21318882ac5SAlexandre Belloni 	{
21418882ac5SAlexandre Belloni 		.name = "vpp",
21518882ac5SAlexandre Belloni 		.parent_ids = default_parent_ids,
21618882ac5SAlexandre Belloni 		.num_parents = ARRAY_SIZE(default_parent_ids),
21718882ac5SAlexandre Belloni 		.map = {
21818882ac5SAlexandre Belloni 			BERLIN2_DIV_GATE(REG_CLKENABLE, 21),
21918882ac5SAlexandre Belloni 			BERLIN2_PLL_SELECT(REG_CLKSELECT1, 24),
22018882ac5SAlexandre Belloni 			BERLIN2_DIV_SELECT(REG_CLKSELECT1, 27),
22118882ac5SAlexandre Belloni 			BERLIN2_PLL_SWITCH(REG_CLKSWITCH0, 30),
22218882ac5SAlexandre Belloni 			BERLIN2_DIV_SWITCH(REG_CLKSWITCH0, 31),
22318882ac5SAlexandre Belloni 			BERLIN2_DIV_D3SWITCH(REG_CLKSWITCH1, 0),
22418882ac5SAlexandre Belloni 		},
22518882ac5SAlexandre Belloni 		.div_flags = BERLIN2_DIV_HAS_GATE | BERLIN2_DIV_HAS_MUX,
22618882ac5SAlexandre Belloni 		.flags = 0,
22718882ac5SAlexandre Belloni 	},
22818882ac5SAlexandre Belloni 	{
22918882ac5SAlexandre Belloni 		.name = "app",
23018882ac5SAlexandre Belloni 		.parent_ids = default_parent_ids,
23118882ac5SAlexandre Belloni 		.num_parents = ARRAY_SIZE(default_parent_ids),
23218882ac5SAlexandre Belloni 		.map = {
23318882ac5SAlexandre Belloni 			BERLIN2_DIV_GATE(REG_CLKENABLE, 20),
23418882ac5SAlexandre Belloni 			BERLIN2_PLL_SELECT(REG_CLKSELECT2, 0),
23518882ac5SAlexandre Belloni 			BERLIN2_DIV_SELECT(REG_CLKSELECT2, 3),
23618882ac5SAlexandre Belloni 			BERLIN2_PLL_SWITCH(REG_CLKSWITCH1, 1),
23718882ac5SAlexandre Belloni 			BERLIN2_DIV_SWITCH(REG_CLKSWITCH1, 2),
23818882ac5SAlexandre Belloni 			BERLIN2_DIV_D3SWITCH(REG_CLKSWITCH1, 3),
23918882ac5SAlexandre Belloni 		},
24018882ac5SAlexandre Belloni 		.div_flags = BERLIN2_DIV_HAS_GATE | BERLIN2_DIV_HAS_MUX,
24118882ac5SAlexandre Belloni 		.flags = 0,
24218882ac5SAlexandre Belloni 	},
24318882ac5SAlexandre Belloni 	{
24418882ac5SAlexandre Belloni 		.name = "sdio0xin",
24518882ac5SAlexandre Belloni 		.parent_ids = default_parent_ids,
24618882ac5SAlexandre Belloni 		.num_parents = ARRAY_SIZE(default_parent_ids),
24718882ac5SAlexandre Belloni 		.map = {
24818882ac5SAlexandre Belloni 			BERLIN2_SINGLE_DIV(REG_SDIO0XIN_CLKCTL),
24918882ac5SAlexandre Belloni 		},
25018882ac5SAlexandre Belloni 		.div_flags = BERLIN2_DIV_HAS_GATE | BERLIN2_DIV_HAS_MUX,
25118882ac5SAlexandre Belloni 		.flags = 0,
25218882ac5SAlexandre Belloni 	},
25318882ac5SAlexandre Belloni 	{
25418882ac5SAlexandre Belloni 		.name = "sdio1xin",
25518882ac5SAlexandre Belloni 		.parent_ids = default_parent_ids,
25618882ac5SAlexandre Belloni 		.num_parents = ARRAY_SIZE(default_parent_ids),
25718882ac5SAlexandre Belloni 		.map = {
25818882ac5SAlexandre Belloni 			BERLIN2_SINGLE_DIV(REG_SDIO1XIN_CLKCTL),
25918882ac5SAlexandre Belloni 		},
26018882ac5SAlexandre Belloni 		.div_flags = BERLIN2_DIV_HAS_GATE | BERLIN2_DIV_HAS_MUX,
26118882ac5SAlexandre Belloni 		.flags = 0,
26218882ac5SAlexandre Belloni 	},
26318882ac5SAlexandre Belloni };
26418882ac5SAlexandre Belloni 
26518882ac5SAlexandre Belloni static const struct berlin2_gate_data bg2q_gates[] __initconst = {
26618882ac5SAlexandre Belloni 	{ "gfx2daxi",	"perif",	5 },
26718882ac5SAlexandre Belloni 	{ "geth0",	"perif",	8 },
26818882ac5SAlexandre Belloni 	{ "sata",	"perif",	9 },
26918882ac5SAlexandre Belloni 	{ "ahbapb",	"perif",	10, CLK_IGNORE_UNUSED },
27018882ac5SAlexandre Belloni 	{ "usb0",	"perif",	11 },
27118882ac5SAlexandre Belloni 	{ "usb1",	"perif",	12 },
27218882ac5SAlexandre Belloni 	{ "usb2",	"perif",	13 },
27318882ac5SAlexandre Belloni 	{ "usb3",	"perif",	14 },
27418882ac5SAlexandre Belloni 	{ "pbridge",	"perif",	15, CLK_IGNORE_UNUSED },
275123796bbSJisheng Zhang 	{ "sdio",	"perif",	16 },
27618882ac5SAlexandre Belloni 	{ "nfc",	"perif",	18 },
27718882ac5SAlexandre Belloni 	{ "pcie",	"perif",	22 },
27818882ac5SAlexandre Belloni };
27918882ac5SAlexandre Belloni 
berlin2q_clock_setup(struct device_node * np)28018882ac5SAlexandre Belloni static void __init berlin2q_clock_setup(struct device_node *np)
28118882ac5SAlexandre Belloni {
28226b3b6b9SAntoine Tenart 	struct device_node *parent_np = of_get_parent(np);
28318882ac5SAlexandre Belloni 	const char *parent_names[9];
28418882ac5SAlexandre Belloni 	struct clk *clk;
285f6475e29SStephen Boyd 	struct clk_hw **hws;
286f6475e29SStephen Boyd 	int n, ret;
287f6475e29SStephen Boyd 
288acafe7e3SKees Cook 	clk_data = kzalloc(struct_size(clk_data, hws, MAX_CLKS), GFP_KERNEL);
289*37c381b8SLiang He 	if (!clk_data) {
290*37c381b8SLiang He 		of_node_put(parent_np);
291f6475e29SStephen Boyd 		return;
292*37c381b8SLiang He 	}
293f6475e29SStephen Boyd 	clk_data->num = MAX_CLKS;
294f6475e29SStephen Boyd 	hws = clk_data->hws;
29518882ac5SAlexandre Belloni 
296fd26031bSAntoine Tenart 	gbase = of_iomap(parent_np, 0);
29718882ac5SAlexandre Belloni 	if (!gbase) {
298*37c381b8SLiang He 		of_node_put(parent_np);
29916673931SRob Herring 		pr_err("%pOF: Unable to map global base\n", np);
30018882ac5SAlexandre Belloni 		return;
30118882ac5SAlexandre Belloni 	}
30218882ac5SAlexandre Belloni 
30318882ac5SAlexandre Belloni 	/* BG2Q CPU PLL is not part of global registers */
304fd26031bSAntoine Tenart 	cpupll_base = of_iomap(parent_np, 1);
305*37c381b8SLiang He 	of_node_put(parent_np);
30618882ac5SAlexandre Belloni 	if (!cpupll_base) {
30716673931SRob Herring 		pr_err("%pOF: Unable to map cpupll base\n", np);
30818882ac5SAlexandre Belloni 		iounmap(gbase);
30918882ac5SAlexandre Belloni 		return;
31018882ac5SAlexandre Belloni 	}
31118882ac5SAlexandre Belloni 
31218882ac5SAlexandre Belloni 	/* overwrite default clock names with DT provided ones */
31318882ac5SAlexandre Belloni 	clk = of_clk_get_by_name(np, clk_names[REFCLK]);
31418882ac5SAlexandre Belloni 	if (!IS_ERR(clk)) {
31518882ac5SAlexandre Belloni 		clk_names[REFCLK] = __clk_get_name(clk);
31618882ac5SAlexandre Belloni 		clk_put(clk);
31718882ac5SAlexandre Belloni 	}
31818882ac5SAlexandre Belloni 
31918882ac5SAlexandre Belloni 	/* simple register PLLs */
320f6475e29SStephen Boyd 	ret = berlin2_pll_register(&bg2q_pll_map, gbase + REG_SYSPLLCTL0,
32118882ac5SAlexandre Belloni 				   clk_names[SYSPLL], clk_names[REFCLK], 0);
322f6475e29SStephen Boyd 	if (ret)
32318882ac5SAlexandre Belloni 		goto bg2q_fail;
32418882ac5SAlexandre Belloni 
325f6475e29SStephen Boyd 	ret = berlin2_pll_register(&bg2q_pll_map, cpupll_base,
32618882ac5SAlexandre Belloni 				   clk_names[CPUPLL], clk_names[REFCLK], 0);
327f6475e29SStephen Boyd 	if (ret)
32818882ac5SAlexandre Belloni 		goto bg2q_fail;
32918882ac5SAlexandre Belloni 
33018882ac5SAlexandre Belloni 	/* TODO: add BG2Q AVPLL */
33118882ac5SAlexandre Belloni 
33218882ac5SAlexandre Belloni 	/*
33318882ac5SAlexandre Belloni 	 * TODO: add reference clock bypass switches:
33418882ac5SAlexandre Belloni 	 * memPLLSWBypass, cpuPLLSWBypass, and sysPLLSWBypass
33518882ac5SAlexandre Belloni 	 */
33618882ac5SAlexandre Belloni 
33718882ac5SAlexandre Belloni 	/* clock divider cells */
33818882ac5SAlexandre Belloni 	for (n = 0; n < ARRAY_SIZE(bg2q_divs); n++) {
33918882ac5SAlexandre Belloni 		const struct berlin2_div_data *dd = &bg2q_divs[n];
34018882ac5SAlexandre Belloni 		int k;
34118882ac5SAlexandre Belloni 
34218882ac5SAlexandre Belloni 		for (k = 0; k < dd->num_parents; k++)
34318882ac5SAlexandre Belloni 			parent_names[k] = clk_names[dd->parent_ids[k]];
34418882ac5SAlexandre Belloni 
345f6475e29SStephen Boyd 		hws[CLKID_SYS + n] = berlin2_div_register(&dd->map, gbase,
34618882ac5SAlexandre Belloni 				dd->name, dd->div_flags, parent_names,
34718882ac5SAlexandre Belloni 				dd->num_parents, dd->flags, &lock);
34818882ac5SAlexandre Belloni 	}
34918882ac5SAlexandre Belloni 
35018882ac5SAlexandre Belloni 	/* clock gate cells */
35118882ac5SAlexandre Belloni 	for (n = 0; n < ARRAY_SIZE(bg2q_gates); n++) {
35218882ac5SAlexandre Belloni 		const struct berlin2_gate_data *gd = &bg2q_gates[n];
35318882ac5SAlexandre Belloni 
354f6475e29SStephen Boyd 		hws[CLKID_GFX2DAXI + n] = clk_hw_register_gate(NULL, gd->name,
35518882ac5SAlexandre Belloni 			    gd->parent_name, gd->flags, gbase + REG_CLKENABLE,
35618882ac5SAlexandre Belloni 			    gd->bit_idx, 0, &lock);
35718882ac5SAlexandre Belloni 	}
35818882ac5SAlexandre Belloni 
359515f1a20SAntoine Tenart 	/* cpuclk divider is fixed to 1 */
360f6475e29SStephen Boyd 	hws[CLKID_CPU] =
361f6475e29SStephen Boyd 		clk_hw_register_fixed_factor(NULL, "cpu", clk_names[CPUPLL],
362515f1a20SAntoine Tenart 					  0, 1, 1);
363515f1a20SAntoine Tenart 	/* twdclk is derived from cpu/3 */
364f6475e29SStephen Boyd 	hws[CLKID_TWD] =
365f6475e29SStephen Boyd 		clk_hw_register_fixed_factor(NULL, "twd", "cpu", 0, 1, 3);
36618882ac5SAlexandre Belloni 
36718882ac5SAlexandre Belloni 	/* check for errors on leaf clocks */
36818882ac5SAlexandre Belloni 	for (n = 0; n < MAX_CLKS; n++) {
369f6475e29SStephen Boyd 		if (!IS_ERR(hws[n]))
37018882ac5SAlexandre Belloni 			continue;
37118882ac5SAlexandre Belloni 
37216673931SRob Herring 		pr_err("%pOF: Unable to register leaf clock %d\n", np, n);
37318882ac5SAlexandre Belloni 		goto bg2q_fail;
37418882ac5SAlexandre Belloni 	}
37518882ac5SAlexandre Belloni 
37618882ac5SAlexandre Belloni 	/* register clk-provider */
3773ca0b51dSStephen Boyd 	of_clk_add_hw_provider(np, of_clk_hw_onecell_get, clk_data);
37818882ac5SAlexandre Belloni 
37918882ac5SAlexandre Belloni 	return;
38018882ac5SAlexandre Belloni 
38118882ac5SAlexandre Belloni bg2q_fail:
38218882ac5SAlexandre Belloni 	iounmap(cpupll_base);
38318882ac5SAlexandre Belloni 	iounmap(gbase);
38418882ac5SAlexandre Belloni }
38526b3b6b9SAntoine Tenart CLK_OF_DECLARE(berlin2q_clk, "marvell,berlin2q-clk",
38626b3b6b9SAntoine Tenart 	       berlin2q_clock_setup);
387