brintos

brintos / linux-shallow public Read only

0
0
Text · 18.6 KiB · 67a9edb Raw
688 lines · c
1// SPDX-License-Identifier: GPL-2.02/*3 * Copyright (c) 2014 Marvell Technology Group Ltd.4 *5 * Sebastian Hesselbarth <sebastian.hesselbarth@gmail.com>6 * Alexandre Belloni <alexandre.belloni@free-electrons.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/berlin2.h>18 19#include "berlin2-avpll.h"20#include "berlin2-div.h"21#include "berlin2-pll.h"22#include "common.h"23 24#define REG_PINMUX0		0x000025#define REG_PINMUX1		0x000426#define REG_SYSPLLCTL0		0x001427#define REG_SYSPLLCTL4		0x002428#define REG_MEMPLLCTL0		0x002829#define REG_MEMPLLCTL4		0x003830#define REG_CPUPLLCTL0		0x003c31#define REG_CPUPLLCTL4		0x004c32#define REG_AVPLLCTL0		0x005033#define REG_AVPLLCTL31		0x00cc34#define REG_AVPLLCTL62		0x014835#define REG_PLLSTATUS		0x014c36#define REG_CLKENABLE		0x015037#define REG_CLKSELECT0		0x015438#define REG_CLKSELECT1		0x015839#define REG_CLKSELECT2		0x015c40#define REG_CLKSELECT3		0x016041#define REG_CLKSWITCH0		0x016442#define REG_CLKSWITCH1		0x016843#define REG_RESET_TRIGGER	0x017844#define REG_RESET_STATUS0	0x017c45#define REG_RESET_STATUS1	0x018046#define REG_SW_GENERIC0		0x018447#define REG_SW_GENERIC3		0x019048#define REG_PRODUCTID		0x01cc49#define REG_PRODUCTID_EXT	0x01d050#define REG_GFX3DCORE_CLKCTL	0x022c51#define REG_GFX3DSYS_CLKCTL	0x023052#define REG_ARC_CLKCTL		0x023453#define REG_VIP_CLKCTL		0x023854#define REG_SDIO0XIN_CLKCTL	0x023c55#define REG_SDIO1XIN_CLKCTL	0x024056#define REG_GFX3DEXTRA_CLKCTL	0x024457#define REG_GFX3D_RESET		0x024858#define REG_GC360_CLKCTL	0x024c59#define REG_SDIO_DLLMST_CLKCTL	0x025060 61/*62 * BG2/BG2CD SoCs have the following audio/video I/O units:63 *64 * audiohd: HDMI TX audio65 * audio0:  7.1ch TX66 * audio1:  2ch TX67 * audio2:  2ch RX68 * audio3:  SPDIF TX69 * video0:  HDMI video70 * video1:  Secondary video71 * video2:  SD auxiliary video72 *73 * There are no external audio clocks (ACLKI0, ACLKI1) and74 * only one external video clock (VCLKI0).75 *76 * Currently missing bits and pieces:77 * - audio_fast_pll is unknown78 * - audiohd_pll is unknown79 * - video0_pll is unknown80 * - audio[023], audiohd parent pll is assumed to be audio_fast_pll81 *82 */83 84#define	MAX_CLKS 4185static struct clk_hw_onecell_data *clk_data;86static DEFINE_SPINLOCK(lock);87static void __iomem *gbase;88 89enum {90	REFCLK, VIDEO_EXT0,91	SYSPLL, MEMPLL, CPUPLL,92	AVPLL_A1, AVPLL_A2, AVPLL_A3, AVPLL_A4,93	AVPLL_A5, AVPLL_A6, AVPLL_A7, AVPLL_A8,94	AVPLL_B1, AVPLL_B2, AVPLL_B3, AVPLL_B4,95	AVPLL_B5, AVPLL_B6, AVPLL_B7, AVPLL_B8,96	AUDIO1_PLL, AUDIO_FAST_PLL,97	VIDEO0_PLL, VIDEO0_IN,98	VIDEO1_PLL, VIDEO1_IN,99	VIDEO2_PLL, VIDEO2_IN,100};101 102static const char *clk_names[] = {103	[REFCLK]		= "refclk",104	[VIDEO_EXT0]		= "video_ext0",105	[SYSPLL]		= "syspll",106	[MEMPLL]		= "mempll",107	[CPUPLL]		= "cpupll",108	[AVPLL_A1]		= "avpll_a1",109	[AVPLL_A2]		= "avpll_a2",110	[AVPLL_A3]		= "avpll_a3",111	[AVPLL_A4]		= "avpll_a4",112	[AVPLL_A5]		= "avpll_a5",113	[AVPLL_A6]		= "avpll_a6",114	[AVPLL_A7]		= "avpll_a7",115	[AVPLL_A8]		= "avpll_a8",116	[AVPLL_B1]		= "avpll_b1",117	[AVPLL_B2]		= "avpll_b2",118	[AVPLL_B3]		= "avpll_b3",119	[AVPLL_B4]		= "avpll_b4",120	[AVPLL_B5]		= "avpll_b5",121	[AVPLL_B6]		= "avpll_b6",122	[AVPLL_B7]		= "avpll_b7",123	[AVPLL_B8]		= "avpll_b8",124	[AUDIO1_PLL]		= "audio1_pll",125	[AUDIO_FAST_PLL]	= "audio_fast_pll",126	[VIDEO0_PLL]		= "video0_pll",127	[VIDEO0_IN]		= "video0_in",128	[VIDEO1_PLL]		= "video1_pll",129	[VIDEO1_IN]		= "video1_in",130	[VIDEO2_PLL]		= "video2_pll",131	[VIDEO2_IN]		= "video2_in",132};133 134static const struct berlin2_pll_map bg2_pll_map __initconst = {135	.vcodiv		= {10, 15, 20, 25, 30, 40, 50, 60, 80},136	.mult		= 10,137	.fbdiv_shift	= 6,138	.rfdiv_shift	= 1,139	.divsel_shift	= 7,140};141 142static const u8 default_parent_ids[] = {143	SYSPLL, AVPLL_B4, AVPLL_A5, AVPLL_B6, AVPLL_B7, SYSPLL144};145 146static const struct berlin2_div_data bg2_divs[] __initconst = {147	{148		.name = "sys",149		.parent_ids = (const u8 []){150			SYSPLL, AVPLL_B4, AVPLL_B5, AVPLL_B6, AVPLL_B7, SYSPLL151		},152		.num_parents = 6,153		.map = {154			BERLIN2_DIV_GATE(REG_CLKENABLE, 0),155			BERLIN2_PLL_SELECT(REG_CLKSELECT0, 0),156			BERLIN2_DIV_SELECT(REG_CLKSELECT0, 3),157			BERLIN2_PLL_SWITCH(REG_CLKSWITCH0, 3),158			BERLIN2_DIV_SWITCH(REG_CLKSWITCH0, 4),159			BERLIN2_DIV_D3SWITCH(REG_CLKSWITCH0, 5),160		},161		.div_flags = BERLIN2_DIV_HAS_GATE | BERLIN2_DIV_HAS_MUX,162		.flags = CLK_IGNORE_UNUSED,163	},164	{165		.name = "cpu",166		.parent_ids = (const u8 []){167			CPUPLL, MEMPLL, MEMPLL, MEMPLL, MEMPLL168		},169		.num_parents = 5,170		.map = {171			BERLIN2_PLL_SELECT(REG_CLKSELECT0, 6),172			BERLIN2_DIV_SELECT(REG_CLKSELECT0, 9),173			BERLIN2_PLL_SWITCH(REG_CLKSWITCH0, 6),174			BERLIN2_DIV_SWITCH(REG_CLKSWITCH0, 7),175			BERLIN2_DIV_D3SWITCH(REG_CLKSWITCH0, 8),176		},177		.div_flags = BERLIN2_DIV_HAS_MUX,178		.flags = 0,179	},180	{181		.name = "drmfigo",182		.parent_ids = default_parent_ids,183		.num_parents = ARRAY_SIZE(default_parent_ids),184		.map = {185			BERLIN2_DIV_GATE(REG_CLKENABLE, 16),186			BERLIN2_PLL_SELECT(REG_CLKSELECT0, 17),187			BERLIN2_DIV_SELECT(REG_CLKSELECT0, 20),188			BERLIN2_PLL_SWITCH(REG_CLKSWITCH0, 12),189			BERLIN2_DIV_SWITCH(REG_CLKSWITCH0, 13),190			BERLIN2_DIV_D3SWITCH(REG_CLKSWITCH0, 14),191		},192		.div_flags = BERLIN2_DIV_HAS_GATE | BERLIN2_DIV_HAS_MUX,193		.flags = 0,194	},195	{196		.name = "cfg",197		.parent_ids = default_parent_ids,198		.num_parents = ARRAY_SIZE(default_parent_ids),199		.map = {200			BERLIN2_DIV_GATE(REG_CLKENABLE, 1),201			BERLIN2_PLL_SELECT(REG_CLKSELECT0, 23),202			BERLIN2_DIV_SELECT(REG_CLKSELECT0, 26),203			BERLIN2_PLL_SWITCH(REG_CLKSWITCH0, 15),204			BERLIN2_DIV_SWITCH(REG_CLKSWITCH0, 16),205			BERLIN2_DIV_D3SWITCH(REG_CLKSWITCH0, 17),206		},207		.div_flags = BERLIN2_DIV_HAS_GATE | BERLIN2_DIV_HAS_MUX,208		.flags = 0,209	},210	{211		.name = "gfx",212		.parent_ids = default_parent_ids,213		.num_parents = ARRAY_SIZE(default_parent_ids),214		.map = {215			BERLIN2_DIV_GATE(REG_CLKENABLE, 4),216			BERLIN2_PLL_SELECT(REG_CLKSELECT0, 29),217			BERLIN2_DIV_SELECT(REG_CLKSELECT1, 0),218			BERLIN2_PLL_SWITCH(REG_CLKSWITCH0, 18),219			BERLIN2_DIV_SWITCH(REG_CLKSWITCH0, 19),220			BERLIN2_DIV_D3SWITCH(REG_CLKSWITCH0, 20),221		},222		.div_flags = BERLIN2_DIV_HAS_GATE | BERLIN2_DIV_HAS_MUX,223		.flags = 0,224	},225	{226		.name = "zsp",227		.parent_ids = default_parent_ids,228		.num_parents = ARRAY_SIZE(default_parent_ids),229		.map = {230			BERLIN2_DIV_GATE(REG_CLKENABLE, 5),231			BERLIN2_PLL_SELECT(REG_CLKSELECT1, 3),232			BERLIN2_DIV_SELECT(REG_CLKSELECT1, 6),233			BERLIN2_PLL_SWITCH(REG_CLKSWITCH0, 21),234			BERLIN2_DIV_SWITCH(REG_CLKSWITCH0, 22),235			BERLIN2_DIV_D3SWITCH(REG_CLKSWITCH0, 23),236		},237		.div_flags = BERLIN2_DIV_HAS_GATE | BERLIN2_DIV_HAS_MUX,238		.flags = 0,239	},240	{241		.name = "perif",242		.parent_ids = default_parent_ids,243		.num_parents = ARRAY_SIZE(default_parent_ids),244		.map = {245			BERLIN2_DIV_GATE(REG_CLKENABLE, 6),246			BERLIN2_PLL_SELECT(REG_CLKSELECT1, 9),247			BERLIN2_DIV_SELECT(REG_CLKSELECT1, 12),248			BERLIN2_PLL_SWITCH(REG_CLKSWITCH0, 24),249			BERLIN2_DIV_SWITCH(REG_CLKSWITCH0, 25),250			BERLIN2_DIV_D3SWITCH(REG_CLKSWITCH0, 26),251		},252		.div_flags = BERLIN2_DIV_HAS_GATE | BERLIN2_DIV_HAS_MUX,253		.flags = CLK_IGNORE_UNUSED,254	},255	{256		.name = "pcube",257		.parent_ids = default_parent_ids,258		.num_parents = ARRAY_SIZE(default_parent_ids),259		.map = {260			BERLIN2_DIV_GATE(REG_CLKENABLE, 2),261			BERLIN2_PLL_SELECT(REG_CLKSELECT1, 15),262			BERLIN2_DIV_SELECT(REG_CLKSELECT1, 18),263			BERLIN2_PLL_SWITCH(REG_CLKSWITCH0, 27),264			BERLIN2_DIV_SWITCH(REG_CLKSWITCH0, 28),265			BERLIN2_DIV_D3SWITCH(REG_CLKSWITCH0, 29),266		},267		.div_flags = BERLIN2_DIV_HAS_GATE | BERLIN2_DIV_HAS_MUX,268		.flags = 0,269	},270	{271		.name = "vscope",272		.parent_ids = default_parent_ids,273		.num_parents = ARRAY_SIZE(default_parent_ids),274		.map = {275			BERLIN2_DIV_GATE(REG_CLKENABLE, 3),276			BERLIN2_PLL_SELECT(REG_CLKSELECT1, 21),277			BERLIN2_DIV_SELECT(REG_CLKSELECT1, 24),278			BERLIN2_PLL_SWITCH(REG_CLKSWITCH0, 30),279			BERLIN2_DIV_SWITCH(REG_CLKSWITCH0, 31),280			BERLIN2_DIV_D3SWITCH(REG_CLKSWITCH1, 0),281		},282		.div_flags = BERLIN2_DIV_HAS_GATE | BERLIN2_DIV_HAS_MUX,283		.flags = 0,284	},285	{286		.name = "nfc_ecc",287		.parent_ids = default_parent_ids,288		.num_parents = ARRAY_SIZE(default_parent_ids),289		.map = {290			BERLIN2_DIV_GATE(REG_CLKENABLE, 18),291			BERLIN2_PLL_SELECT(REG_CLKSELECT1, 27),292			BERLIN2_DIV_SELECT(REG_CLKSELECT2, 0),293			BERLIN2_PLL_SWITCH(REG_CLKSWITCH1, 1),294			BERLIN2_DIV_SWITCH(REG_CLKSWITCH1, 2),295			BERLIN2_DIV_D3SWITCH(REG_CLKSWITCH1, 3),296		},297		.div_flags = BERLIN2_DIV_HAS_GATE | BERLIN2_DIV_HAS_MUX,298		.flags = 0,299	},300	{301		.name = "vpp",302		.parent_ids = default_parent_ids,303		.num_parents = ARRAY_SIZE(default_parent_ids),304		.map = {305			BERLIN2_DIV_GATE(REG_CLKENABLE, 21),306			BERLIN2_PLL_SELECT(REG_CLKSELECT2, 3),307			BERLIN2_DIV_SELECT(REG_CLKSELECT2, 6),308			BERLIN2_PLL_SWITCH(REG_CLKSWITCH1, 4),309			BERLIN2_DIV_SWITCH(REG_CLKSWITCH1, 5),310			BERLIN2_DIV_D3SWITCH(REG_CLKSWITCH1, 6),311		},312		.div_flags = BERLIN2_DIV_HAS_GATE | BERLIN2_DIV_HAS_MUX,313		.flags = 0,314	},315	{316		.name = "app",317		.parent_ids = default_parent_ids,318		.num_parents = ARRAY_SIZE(default_parent_ids),319		.map = {320			BERLIN2_DIV_GATE(REG_CLKENABLE, 20),321			BERLIN2_PLL_SELECT(REG_CLKSELECT2, 9),322			BERLIN2_DIV_SELECT(REG_CLKSELECT2, 12),323			BERLIN2_PLL_SWITCH(REG_CLKSWITCH1, 7),324			BERLIN2_DIV_SWITCH(REG_CLKSWITCH1, 8),325			BERLIN2_DIV_D3SWITCH(REG_CLKSWITCH1, 9),326		},327		.div_flags = BERLIN2_DIV_HAS_GATE | BERLIN2_DIV_HAS_MUX,328		.flags = 0,329	},330	{331		.name = "audio0",332		.parent_ids = (const u8 []){ AUDIO_FAST_PLL },333		.num_parents = 1,334		.map = {335			BERLIN2_DIV_GATE(REG_CLKENABLE, 22),336			BERLIN2_DIV_SELECT(REG_CLKSELECT2, 17),337			BERLIN2_DIV_SWITCH(REG_CLKSWITCH1, 10),338			BERLIN2_DIV_D3SWITCH(REG_CLKSWITCH1, 11),339		},340		.div_flags = BERLIN2_DIV_HAS_GATE,341		.flags = 0,342	},343	{344		.name = "audio2",345		.parent_ids = (const u8 []){ AUDIO_FAST_PLL },346		.num_parents = 1,347		.map = {348			BERLIN2_DIV_GATE(REG_CLKENABLE, 24),349			BERLIN2_DIV_SELECT(REG_CLKSELECT2, 20),350			BERLIN2_DIV_SWITCH(REG_CLKSWITCH1, 14),351			BERLIN2_DIV_D3SWITCH(REG_CLKSWITCH1, 15),352		},353		.div_flags = BERLIN2_DIV_HAS_GATE,354		.flags = 0,355	},356	{357		.name = "audio3",358		.parent_ids = (const u8 []){ AUDIO_FAST_PLL },359		.num_parents = 1,360		.map = {361			BERLIN2_DIV_GATE(REG_CLKENABLE, 25),362			BERLIN2_DIV_SELECT(REG_CLKSELECT2, 23),363			BERLIN2_DIV_SWITCH(REG_CLKSWITCH1, 16),364			BERLIN2_DIV_D3SWITCH(REG_CLKSWITCH1, 17),365		},366		.div_flags = BERLIN2_DIV_HAS_GATE,367		.flags = 0,368	},369	{370		.name = "audio1",371		.parent_ids = (const u8 []){ AUDIO1_PLL },372		.num_parents = 1,373		.map = {374			BERLIN2_DIV_GATE(REG_CLKENABLE, 23),375			BERLIN2_DIV_SELECT(REG_CLKSELECT3, 0),376			BERLIN2_DIV_SWITCH(REG_CLKSWITCH1, 12),377			BERLIN2_DIV_D3SWITCH(REG_CLKSWITCH1, 13),378		},379		.div_flags = BERLIN2_DIV_HAS_GATE,380		.flags = 0,381	},382	{383		.name = "gfx3d_core",384		.parent_ids = default_parent_ids,385		.num_parents = ARRAY_SIZE(default_parent_ids),386		.map = {387			BERLIN2_SINGLE_DIV(REG_GFX3DCORE_CLKCTL),388		},389		.div_flags = BERLIN2_DIV_HAS_GATE | BERLIN2_DIV_HAS_MUX,390		.flags = 0,391	},392	{393		.name = "gfx3d_sys",394		.parent_ids = default_parent_ids,395		.num_parents = ARRAY_SIZE(default_parent_ids),396		.map = {397			BERLIN2_SINGLE_DIV(REG_GFX3DSYS_CLKCTL),398		},399		.div_flags = BERLIN2_DIV_HAS_GATE | BERLIN2_DIV_HAS_MUX,400		.flags = 0,401	},402	{403		.name = "arc",404		.parent_ids = default_parent_ids,405		.num_parents = ARRAY_SIZE(default_parent_ids),406		.map = {407			BERLIN2_SINGLE_DIV(REG_ARC_CLKCTL),408		},409		.div_flags = BERLIN2_DIV_HAS_GATE | BERLIN2_DIV_HAS_MUX,410		.flags = 0,411	},412	{413		.name = "vip",414		.parent_ids = default_parent_ids,415		.num_parents = ARRAY_SIZE(default_parent_ids),416		.map = {417			BERLIN2_SINGLE_DIV(REG_VIP_CLKCTL),418		},419		.div_flags = BERLIN2_DIV_HAS_GATE | BERLIN2_DIV_HAS_MUX,420		.flags = 0,421	},422	{423		.name = "sdio0xin",424		.parent_ids = default_parent_ids,425		.num_parents = ARRAY_SIZE(default_parent_ids),426		.map = {427			BERLIN2_SINGLE_DIV(REG_SDIO0XIN_CLKCTL),428		},429		.div_flags = BERLIN2_DIV_HAS_GATE | BERLIN2_DIV_HAS_MUX,430		.flags = 0,431	},432	{433		.name = "sdio1xin",434		.parent_ids = default_parent_ids,435		.num_parents = ARRAY_SIZE(default_parent_ids),436		.map = {437			BERLIN2_SINGLE_DIV(REG_SDIO1XIN_CLKCTL),438		},439		.div_flags = BERLIN2_DIV_HAS_GATE | BERLIN2_DIV_HAS_MUX,440		.flags = 0,441	},442	{443		.name = "gfx3d_extra",444		.parent_ids = default_parent_ids,445		.num_parents = ARRAY_SIZE(default_parent_ids),446		.map = {447			BERLIN2_SINGLE_DIV(REG_GFX3DEXTRA_CLKCTL),448		},449		.div_flags = BERLIN2_DIV_HAS_GATE | BERLIN2_DIV_HAS_MUX,450		.flags = 0,451	},452	{453		.name = "gc360",454		.parent_ids = default_parent_ids,455		.num_parents = ARRAY_SIZE(default_parent_ids),456		.map = {457			BERLIN2_SINGLE_DIV(REG_GC360_CLKCTL),458		},459		.div_flags = BERLIN2_DIV_HAS_GATE | BERLIN2_DIV_HAS_MUX,460		.flags = 0,461	},462	{463		.name = "sdio_dllmst",464		.parent_ids = default_parent_ids,465		.num_parents = ARRAY_SIZE(default_parent_ids),466		.map = {467			BERLIN2_SINGLE_DIV(REG_SDIO_DLLMST_CLKCTL),468		},469		.div_flags = BERLIN2_DIV_HAS_GATE | BERLIN2_DIV_HAS_MUX,470		.flags = 0,471	},472};473 474static const struct berlin2_gate_data bg2_gates[] __initconst = {475	{ "geth0",	"perif",	7 },476	{ "geth1",	"perif",	8 },477	{ "sata",	"perif",	9 },478	{ "ahbapb",	"perif",	10, CLK_IGNORE_UNUSED },479	{ "usb0",	"perif",	11 },480	{ "usb1",	"perif",	12 },481	{ "pbridge",	"perif",	13, CLK_IGNORE_UNUSED },482	{ "sdio0",	"perif",	14 },483	{ "sdio1",	"perif",	15 },484	{ "nfc",	"perif",	17 },485	{ "smemc",	"perif",	19 },486	{ "audiohd",	"audiohd_pll",	26 },487	{ "video0",	"video0_in",	27 },488	{ "video1",	"video1_in",	28 },489	{ "video2",	"video2_in",	29 },490};491 492static void __init berlin2_clock_setup(struct device_node *np)493{494	struct device_node *parent_np = of_get_parent(np);495	const char *parent_names[9];496	struct clk *clk;497	struct clk_hw *hw;498	struct clk_hw **hws;499	u8 avpll_flags = 0;500	int n, ret;501 502	clk_data = kzalloc(struct_size(clk_data, hws, MAX_CLKS), GFP_KERNEL);503	if (!clk_data) {504		of_node_put(parent_np);505		return;506	}507	clk_data->num = MAX_CLKS;508	hws = clk_data->hws;509 510	gbase = of_iomap(parent_np, 0);511	of_node_put(parent_np);512	if (!gbase)513		return;514 515	/* overwrite default clock names with DT provided ones */516	clk = of_clk_get_by_name(np, clk_names[REFCLK]);517	if (!IS_ERR(clk)) {518		clk_names[REFCLK] = __clk_get_name(clk);519		clk_put(clk);520	}521 522	clk = of_clk_get_by_name(np, clk_names[VIDEO_EXT0]);523	if (!IS_ERR(clk)) {524		clk_names[VIDEO_EXT0] = __clk_get_name(clk);525		clk_put(clk);526	}527 528	/* simple register PLLs */529	ret = berlin2_pll_register(&bg2_pll_map, gbase + REG_SYSPLLCTL0,530				   clk_names[SYSPLL], clk_names[REFCLK], 0);531	if (ret)532		goto bg2_fail;533 534	ret = berlin2_pll_register(&bg2_pll_map, gbase + REG_MEMPLLCTL0,535				   clk_names[MEMPLL], clk_names[REFCLK], 0);536	if (ret)537		goto bg2_fail;538 539	ret = berlin2_pll_register(&bg2_pll_map, gbase + REG_CPUPLLCTL0,540				   clk_names[CPUPLL], clk_names[REFCLK], 0);541	if (ret)542		goto bg2_fail;543 544	if (of_device_is_compatible(np, "marvell,berlin2-global-register"))545		avpll_flags |= BERLIN2_AVPLL_SCRAMBLE_QUIRK;546 547	/* audio/video VCOs */548	ret = berlin2_avpll_vco_register(gbase + REG_AVPLLCTL0, "avpll_vcoA",549			 clk_names[REFCLK], avpll_flags, 0);550	if (ret)551		goto bg2_fail;552 553	for (n = 0; n < 8; n++) {554		ret = berlin2_avpll_channel_register(gbase + REG_AVPLLCTL0,555			     clk_names[AVPLL_A1 + n], n, "avpll_vcoA",556			     avpll_flags, 0);557		if (ret)558			goto bg2_fail;559	}560 561	ret = berlin2_avpll_vco_register(gbase + REG_AVPLLCTL31, "avpll_vcoB",562				 clk_names[REFCLK], BERLIN2_AVPLL_BIT_QUIRK |563				 avpll_flags, 0);564	if (ret)565		goto bg2_fail;566 567	for (n = 0; n < 8; n++) {568		ret = berlin2_avpll_channel_register(gbase + REG_AVPLLCTL31,569			     clk_names[AVPLL_B1 + n], n, "avpll_vcoB",570			     BERLIN2_AVPLL_BIT_QUIRK | avpll_flags, 0);571		if (ret)572			goto bg2_fail;573	}574 575	/* reference clock bypass switches */576	parent_names[0] = clk_names[SYSPLL];577	parent_names[1] = clk_names[REFCLK];578	hw = clk_hw_register_mux(NULL, "syspll_byp", parent_names, 2,579			       0, gbase + REG_CLKSWITCH0, 0, 1, 0, &lock);580	if (IS_ERR(hw))581		goto bg2_fail;582	clk_names[SYSPLL] = clk_hw_get_name(hw);583 584	parent_names[0] = clk_names[MEMPLL];585	parent_names[1] = clk_names[REFCLK];586	hw = clk_hw_register_mux(NULL, "mempll_byp", parent_names, 2,587			       0, gbase + REG_CLKSWITCH0, 1, 1, 0, &lock);588	if (IS_ERR(hw))589		goto bg2_fail;590	clk_names[MEMPLL] = clk_hw_get_name(hw);591 592	parent_names[0] = clk_names[CPUPLL];593	parent_names[1] = clk_names[REFCLK];594	hw = clk_hw_register_mux(NULL, "cpupll_byp", parent_names, 2,595			       0, gbase + REG_CLKSWITCH0, 2, 1, 0, &lock);596	if (IS_ERR(hw))597		goto bg2_fail;598	clk_names[CPUPLL] = clk_hw_get_name(hw);599 600	/* clock muxes */601	parent_names[0] = clk_names[AVPLL_B3];602	parent_names[1] = clk_names[AVPLL_A3];603	hw = clk_hw_register_mux(NULL, clk_names[AUDIO1_PLL], parent_names, 2,604			       0, gbase + REG_CLKSELECT2, 29, 1, 0, &lock);605	if (IS_ERR(hw))606		goto bg2_fail;607 608	parent_names[0] = clk_names[VIDEO0_PLL];609	parent_names[1] = clk_names[VIDEO_EXT0];610	hw = clk_hw_register_mux(NULL, clk_names[VIDEO0_IN], parent_names, 2,611			       0, gbase + REG_CLKSELECT3, 4, 1, 0, &lock);612	if (IS_ERR(hw))613		goto bg2_fail;614 615	parent_names[0] = clk_names[VIDEO1_PLL];616	parent_names[1] = clk_names[VIDEO_EXT0];617	hw = clk_hw_register_mux(NULL, clk_names[VIDEO1_IN], parent_names, 2,618			       0, gbase + REG_CLKSELECT3, 6, 1, 0, &lock);619	if (IS_ERR(hw))620		goto bg2_fail;621 622	parent_names[0] = clk_names[AVPLL_A2];623	parent_names[1] = clk_names[AVPLL_B2];624	hw = clk_hw_register_mux(NULL, clk_names[VIDEO1_PLL], parent_names, 2,625			       0, gbase + REG_CLKSELECT3, 7, 1, 0, &lock);626	if (IS_ERR(hw))627		goto bg2_fail;628 629	parent_names[0] = clk_names[VIDEO2_PLL];630	parent_names[1] = clk_names[VIDEO_EXT0];631	hw = clk_hw_register_mux(NULL, clk_names[VIDEO2_IN], parent_names, 2,632			       0, gbase + REG_CLKSELECT3, 9, 1, 0, &lock);633	if (IS_ERR(hw))634		goto bg2_fail;635 636	parent_names[0] = clk_names[AVPLL_B1];637	parent_names[1] = clk_names[AVPLL_A5];638	hw = clk_hw_register_mux(NULL, clk_names[VIDEO2_PLL], parent_names, 2,639			       0, gbase + REG_CLKSELECT3, 10, 1, 0, &lock);640	if (IS_ERR(hw))641		goto bg2_fail;642 643	/* clock divider cells */644	for (n = 0; n < ARRAY_SIZE(bg2_divs); n++) {645		const struct berlin2_div_data *dd = &bg2_divs[n];646		int k;647 648		for (k = 0; k < dd->num_parents; k++)649			parent_names[k] = clk_names[dd->parent_ids[k]];650 651		hws[CLKID_SYS + n] = berlin2_div_register(&dd->map, gbase,652				dd->name, dd->div_flags, parent_names,653				dd->num_parents, dd->flags, &lock);654	}655 656	/* clock gate cells */657	for (n = 0; n < ARRAY_SIZE(bg2_gates); n++) {658		const struct berlin2_gate_data *gd = &bg2_gates[n];659 660		hws[CLKID_GETH0 + n] = clk_hw_register_gate(NULL, gd->name,661			    gd->parent_name, gd->flags, gbase + REG_CLKENABLE,662			    gd->bit_idx, 0, &lock);663	}664 665	/* twdclk is derived from cpu/3 */666	hws[CLKID_TWD] =667		clk_hw_register_fixed_factor(NULL, "twd", "cpu", 0, 1, 3);668 669	/* check for errors on leaf clocks */670	for (n = 0; n < MAX_CLKS; n++) {671		if (!IS_ERR(hws[n]))672			continue;673 674		pr_err("%pOF: Unable to register leaf clock %d\n", np, n);675		goto bg2_fail;676	}677 678	/* register clk-provider */679	of_clk_add_hw_provider(np, of_clk_hw_onecell_get, clk_data);680 681	return;682 683bg2_fail:684	iounmap(gbase);685}686CLK_OF_DECLARE(berlin2_clk, "marvell,berlin2-clk",687	       berlin2_clock_setup);688