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