xref: /openbmc/linux/drivers/clk/clk-qoriq.c (revision c900529f3d9161bfde5cca0754f83b4d3c3e0220)
1d2912cb1SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
293a17c05STang Yuantian /*
393a17c05STang Yuantian  * Copyright 2013 Freescale Semiconductor, Inc.
4fa4dd53eSWasim Khan  * Copyright 2021 NXP
593a17c05STang Yuantian  *
693a17c05STang Yuantian  * clock driver for Freescale QorIQ SoCs.
793a17c05STang Yuantian  */
8c88b2b66SEmil Medve 
9c88b2b66SEmil Medve #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
10c88b2b66SEmil Medve 
114cb15934SMichael Walle #include <dt-bindings/clock/fsl,qoriq-clockgen.h>
120dfc86b3SScott Wood #include <linux/clk.h>
1393a17c05STang Yuantian #include <linux/clk-provider.h>
1445899dc5SYuantian Tang #include <linux/clkdev.h>
150dfc86b3SScott Wood #include <linux/fsl/guts.h>
1693a17c05STang Yuantian #include <linux/io.h>
1793a17c05STang Yuantian #include <linux/kernel.h>
1893a17c05STang Yuantian #include <linux/module.h>
1993a17c05STang Yuantian #include <linux/of_address.h>
2093a17c05STang Yuantian #include <linux/of.h>
21*a96cbb14SRob Herring #include <linux/platform_device.h>
2293a17c05STang Yuantian #include <linux/slab.h>
2393a17c05STang Yuantian 
240dfc86b3SScott Wood #define PLL_DIV1	0
250dfc86b3SScott Wood #define PLL_DIV2	1
260dfc86b3SScott Wood #define PLL_DIV3	2
270dfc86b3SScott Wood #define PLL_DIV4	3
280dfc86b3SScott Wood 
290dfc86b3SScott Wood #define PLATFORM_PLL	0
300dfc86b3SScott Wood #define CGA_PLL1	1
310dfc86b3SScott Wood #define CGA_PLL2	2
320dfc86b3SScott Wood #define CGA_PLL3	3
330dfc86b3SScott Wood #define CGA_PLL4	4	/* only on clockgen-1.0, which lacks CGB */
340dfc86b3SScott Wood #define CGB_PLL1	4
350dfc86b3SScott Wood #define CGB_PLL2	5
36e9501b97SZhao Qiang #define MAX_PLL_DIV	32
370dfc86b3SScott Wood 
380dfc86b3SScott Wood struct clockgen_pll_div {
390dfc86b3SScott Wood 	struct clk *clk;
400dfc86b3SScott Wood 	char name[32];
4193a17c05STang Yuantian };
4293a17c05STang Yuantian 
430dfc86b3SScott Wood struct clockgen_pll {
44cc61ab9bSYuantian Tang 	struct clockgen_pll_div div[MAX_PLL_DIV];
450dfc86b3SScott Wood };
4693a17c05STang Yuantian 
470dfc86b3SScott Wood #define CLKSEL_VALID	1
480dfc86b3SScott Wood #define CLKSEL_80PCT	2	/* Only allowed if PLL <= 80% of max cpu freq */
490dfc86b3SScott Wood 
500dfc86b3SScott Wood struct clockgen_sourceinfo {
510dfc86b3SScott Wood 	u32 flags;	/* CLKSEL_xxx */
520dfc86b3SScott Wood 	int pll;	/* CGx_PLLn */
530dfc86b3SScott Wood 	int div;	/* PLL_DIVn */
540dfc86b3SScott Wood };
550dfc86b3SScott Wood 
560dfc86b3SScott Wood #define NUM_MUX_PARENTS	16
570dfc86b3SScott Wood 
580dfc86b3SScott Wood struct clockgen_muxinfo {
590dfc86b3SScott Wood 	struct clockgen_sourceinfo clksel[NUM_MUX_PARENTS];
600dfc86b3SScott Wood };
610dfc86b3SScott Wood 
620dfc86b3SScott Wood #define NUM_HWACCEL	5
630dfc86b3SScott Wood #define NUM_CMUX	8
640dfc86b3SScott Wood 
650dfc86b3SScott Wood struct clockgen;
660dfc86b3SScott Wood 
670dfc86b3SScott Wood /*
680dfc86b3SScott Wood  * cmux freq must be >= platform pll.
690dfc86b3SScott Wood  * If not set, cmux freq must be >= platform pll/2
700dfc86b3SScott Wood  */
710dfc86b3SScott Wood #define CG_CMUX_GE_PLAT		1
729e19ca2fSScott Wood 
730dfc86b3SScott Wood #define CG_PLL_8BIT		2	/* PLLCnGSR[CFG] is 8 bits, not 6 */
749e19ca2fSScott Wood #define CG_VER3			4	/* version 3 cg: reg layout different */
759e19ca2fSScott Wood #define CG_LITTLE_ENDIAN	8
760dfc86b3SScott Wood 
770dfc86b3SScott Wood struct clockgen_chipinfo {
780dfc86b3SScott Wood 	const char *compat, *guts_compat;
790dfc86b3SScott Wood 	const struct clockgen_muxinfo *cmux_groups[2];
800dfc86b3SScott Wood 	const struct clockgen_muxinfo *hwaccel[NUM_HWACCEL];
810dfc86b3SScott Wood 	void (*init_periph)(struct clockgen *cg);
8242614b5bSYogesh Gaur 	int cmux_to_group[NUM_CMUX + 1]; /* array should be -1 terminated */
830dfc86b3SScott Wood 	u32 pll_mask;	/* 1 << n bit set if PLL n is valid */
840dfc86b3SScott Wood 	u32 flags;	/* CG_xxx */
850dfc86b3SScott Wood };
860dfc86b3SScott Wood 
870dfc86b3SScott Wood struct clockgen {
880dfc86b3SScott Wood 	struct device_node *node;
890dfc86b3SScott Wood 	void __iomem *regs;
900dfc86b3SScott Wood 	struct clockgen_chipinfo info; /* mutable copy */
9180b4ae7aSScott Wood 	struct clk *sysclk, *coreclk;
920dfc86b3SScott Wood 	struct clockgen_pll pll[6];
930dfc86b3SScott Wood 	struct clk *cmux[NUM_CMUX];
940dfc86b3SScott Wood 	struct clk *hwaccel[NUM_HWACCEL];
950dfc86b3SScott Wood 	struct clk *fman[2];
960dfc86b3SScott Wood 	struct ccsr_guts __iomem *guts;
970dfc86b3SScott Wood };
980dfc86b3SScott Wood 
990dfc86b3SScott Wood static struct clockgen clockgen;
100cf1e0449SMian Yousaf Kaukab static bool add_cpufreq_dev __initdata;
1010dfc86b3SScott Wood 
cg_out(struct clockgen * cg,u32 val,u32 __iomem * reg)1029e19ca2fSScott Wood static void cg_out(struct clockgen *cg, u32 val, u32 __iomem *reg)
1039e19ca2fSScott Wood {
1049e19ca2fSScott Wood 	if (cg->info.flags & CG_LITTLE_ENDIAN)
1059e19ca2fSScott Wood 		iowrite32(val, reg);
1069e19ca2fSScott Wood 	else
1079e19ca2fSScott Wood 		iowrite32be(val, reg);
1089e19ca2fSScott Wood }
1099e19ca2fSScott Wood 
cg_in(struct clockgen * cg,u32 __iomem * reg)1109e19ca2fSScott Wood static u32 cg_in(struct clockgen *cg, u32 __iomem *reg)
1119e19ca2fSScott Wood {
1129e19ca2fSScott Wood 	u32 val;
1139e19ca2fSScott Wood 
1149e19ca2fSScott Wood 	if (cg->info.flags & CG_LITTLE_ENDIAN)
1159e19ca2fSScott Wood 		val = ioread32(reg);
1169e19ca2fSScott Wood 	else
1179e19ca2fSScott Wood 		val = ioread32be(reg);
1189e19ca2fSScott Wood 
1199e19ca2fSScott Wood 	return val;
1209e19ca2fSScott Wood }
1219e19ca2fSScott Wood 
1220dfc86b3SScott Wood static const struct clockgen_muxinfo p2041_cmux_grp1 = {
12393a17c05STang Yuantian 	{
1240dfc86b3SScott Wood 		[0] = { CLKSEL_VALID, CGA_PLL1, PLL_DIV1 },
1250dfc86b3SScott Wood 		[1] = { CLKSEL_VALID, CGA_PLL1, PLL_DIV2 },
1260dfc86b3SScott Wood 		[4] = { CLKSEL_VALID, CGA_PLL2, PLL_DIV1 },
1270dfc86b3SScott Wood 	}
1280dfc86b3SScott Wood };
1290dfc86b3SScott Wood 
1300dfc86b3SScott Wood static const struct clockgen_muxinfo p2041_cmux_grp2 = {
1310dfc86b3SScott Wood 	{
1320dfc86b3SScott Wood 		[0] = { CLKSEL_VALID, CGA_PLL1, PLL_DIV1 },
1332c7693e0SScott Wood 		[4] = { CLKSEL_VALID, CGA_PLL2, PLL_DIV1 },
1342c7693e0SScott Wood 		[5] = { CLKSEL_VALID, CGA_PLL2, PLL_DIV2 },
1350dfc86b3SScott Wood 	}
1360dfc86b3SScott Wood };
1370dfc86b3SScott Wood 
1380dfc86b3SScott Wood static const struct clockgen_muxinfo p5020_cmux_grp1 = {
1390dfc86b3SScott Wood 	{
1400dfc86b3SScott Wood 		[0] = { CLKSEL_VALID, CGA_PLL1, PLL_DIV1 },
1410dfc86b3SScott Wood 		[1] = { CLKSEL_VALID, CGA_PLL1, PLL_DIV2 },
1420dfc86b3SScott Wood 		[4] = { CLKSEL_VALID | CLKSEL_80PCT, CGA_PLL2, PLL_DIV1 },
1430dfc86b3SScott Wood 	}
1440dfc86b3SScott Wood };
1450dfc86b3SScott Wood 
1460dfc86b3SScott Wood static const struct clockgen_muxinfo p5020_cmux_grp2 = {
1470dfc86b3SScott Wood 	{
1480dfc86b3SScott Wood 		[0] = { CLKSEL_VALID | CLKSEL_80PCT, CGA_PLL1, PLL_DIV1 },
1490dfc86b3SScott Wood 		[4] = { CLKSEL_VALID, CGA_PLL2, PLL_DIV1 },
1500dfc86b3SScott Wood 		[5] = { CLKSEL_VALID, CGA_PLL2, PLL_DIV2 },
1510dfc86b3SScott Wood 	}
1520dfc86b3SScott Wood };
1530dfc86b3SScott Wood 
1540dfc86b3SScott Wood static const struct clockgen_muxinfo p5040_cmux_grp1 = {
1550dfc86b3SScott Wood 	{
1560dfc86b3SScott Wood 		[0] = { CLKSEL_VALID, CGA_PLL1, PLL_DIV1 },
1570dfc86b3SScott Wood 		[1] = { CLKSEL_VALID, CGA_PLL1, PLL_DIV2 },
1580dfc86b3SScott Wood 		[4] = { CLKSEL_VALID | CLKSEL_80PCT, CGA_PLL2, PLL_DIV1 },
1590dfc86b3SScott Wood 		[5] = { CLKSEL_VALID | CLKSEL_80PCT, CGA_PLL2, PLL_DIV2 },
1600dfc86b3SScott Wood 	}
1610dfc86b3SScott Wood };
1620dfc86b3SScott Wood 
1630dfc86b3SScott Wood static const struct clockgen_muxinfo p5040_cmux_grp2 = {
1640dfc86b3SScott Wood 	{
1650dfc86b3SScott Wood 		[0] = { CLKSEL_VALID | CLKSEL_80PCT, CGA_PLL1, PLL_DIV1 },
1660dfc86b3SScott Wood 		[1] = { CLKSEL_VALID | CLKSEL_80PCT, CGA_PLL1, PLL_DIV2 },
1670dfc86b3SScott Wood 		[4] = { CLKSEL_VALID, CGA_PLL2, PLL_DIV1 },
1680dfc86b3SScott Wood 		[5] = { CLKSEL_VALID, CGA_PLL2, PLL_DIV2 },
1690dfc86b3SScott Wood 	}
1700dfc86b3SScott Wood };
1710dfc86b3SScott Wood 
1720dfc86b3SScott Wood static const struct clockgen_muxinfo p4080_cmux_grp1 = {
1730dfc86b3SScott Wood 	{
1740dfc86b3SScott Wood 		[0] = { CLKSEL_VALID, CGA_PLL1, PLL_DIV1 },
1750dfc86b3SScott Wood 		[1] = { CLKSEL_VALID, CGA_PLL1, PLL_DIV2 },
1760dfc86b3SScott Wood 		[4] = { CLKSEL_VALID, CGA_PLL2, PLL_DIV1 },
1770dfc86b3SScott Wood 		[5] = { CLKSEL_VALID, CGA_PLL2, PLL_DIV2 },
1780dfc86b3SScott Wood 		[8] = { CLKSEL_VALID | CLKSEL_80PCT, CGA_PLL3, PLL_DIV1 },
1790dfc86b3SScott Wood 	}
1800dfc86b3SScott Wood };
1810dfc86b3SScott Wood 
1820dfc86b3SScott Wood static const struct clockgen_muxinfo p4080_cmux_grp2 = {
1830dfc86b3SScott Wood 	{
1840dfc86b3SScott Wood 		[0] = { CLKSEL_VALID | CLKSEL_80PCT, CGA_PLL1, PLL_DIV1 },
1850dfc86b3SScott Wood 		[8] = { CLKSEL_VALID, CGA_PLL3, PLL_DIV1 },
1860dfc86b3SScott Wood 		[9] = { CLKSEL_VALID, CGA_PLL3, PLL_DIV2 },
1870dfc86b3SScott Wood 		[12] = { CLKSEL_VALID, CGA_PLL4, PLL_DIV1 },
1880dfc86b3SScott Wood 		[13] = { CLKSEL_VALID, CGA_PLL4, PLL_DIV2 },
1890dfc86b3SScott Wood 	}
1900dfc86b3SScott Wood };
1910dfc86b3SScott Wood 
1920dfc86b3SScott Wood static const struct clockgen_muxinfo t1023_cmux = {
1930dfc86b3SScott Wood 	{
1940dfc86b3SScott Wood 		[0] = { CLKSEL_VALID, CGA_PLL1, PLL_DIV1 },
1950dfc86b3SScott Wood 		[1] = { CLKSEL_VALID, CGA_PLL1, PLL_DIV2 },
1960dfc86b3SScott Wood 	}
1970dfc86b3SScott Wood };
1980dfc86b3SScott Wood 
1990dfc86b3SScott Wood static const struct clockgen_muxinfo t1040_cmux = {
2000dfc86b3SScott Wood 	{
2010dfc86b3SScott Wood 		[0] = { CLKSEL_VALID, CGA_PLL1, PLL_DIV1 },
2020dfc86b3SScott Wood 		[1] = { CLKSEL_VALID, CGA_PLL1, PLL_DIV2 },
2030dfc86b3SScott Wood 		[4] = { CLKSEL_VALID, CGA_PLL2, PLL_DIV1 },
2040dfc86b3SScott Wood 		[5] = { CLKSEL_VALID, CGA_PLL2, PLL_DIV2 },
2050dfc86b3SScott Wood 	}
2060dfc86b3SScott Wood };
2070dfc86b3SScott Wood 
2080dfc86b3SScott Wood 
2090dfc86b3SScott Wood static const struct clockgen_muxinfo clockgen2_cmux_cga = {
2100dfc86b3SScott Wood 	{
2110dfc86b3SScott Wood 		{ CLKSEL_VALID, CGA_PLL1, PLL_DIV1 },
2120dfc86b3SScott Wood 		{ CLKSEL_VALID, CGA_PLL1, PLL_DIV2 },
2130dfc86b3SScott Wood 		{ CLKSEL_VALID, CGA_PLL1, PLL_DIV4 },
2140dfc86b3SScott Wood 		{},
2150dfc86b3SScott Wood 		{ CLKSEL_VALID, CGA_PLL2, PLL_DIV1 },
2160dfc86b3SScott Wood 		{ CLKSEL_VALID, CGA_PLL2, PLL_DIV2 },
2170dfc86b3SScott Wood 		{ CLKSEL_VALID, CGA_PLL2, PLL_DIV4 },
2180dfc86b3SScott Wood 		{},
2190dfc86b3SScott Wood 		{ CLKSEL_VALID, CGA_PLL3, PLL_DIV1 },
2200dfc86b3SScott Wood 		{ CLKSEL_VALID, CGA_PLL3, PLL_DIV2 },
2210dfc86b3SScott Wood 		{ CLKSEL_VALID, CGA_PLL3, PLL_DIV4 },
2220dfc86b3SScott Wood 	},
2230dfc86b3SScott Wood };
2240dfc86b3SScott Wood 
2250dfc86b3SScott Wood static const struct clockgen_muxinfo clockgen2_cmux_cga12 = {
2260dfc86b3SScott Wood 	{
2270dfc86b3SScott Wood 		{ CLKSEL_VALID, CGA_PLL1, PLL_DIV1 },
2280dfc86b3SScott Wood 		{ CLKSEL_VALID, CGA_PLL1, PLL_DIV2 },
2290dfc86b3SScott Wood 		{ CLKSEL_VALID, CGA_PLL1, PLL_DIV4 },
2300dfc86b3SScott Wood 		{},
2310dfc86b3SScott Wood 		{ CLKSEL_VALID, CGA_PLL2, PLL_DIV1 },
2320dfc86b3SScott Wood 		{ CLKSEL_VALID, CGA_PLL2, PLL_DIV2 },
2330dfc86b3SScott Wood 		{ CLKSEL_VALID, CGA_PLL2, PLL_DIV4 },
2340dfc86b3SScott Wood 	},
2350dfc86b3SScott Wood };
2360dfc86b3SScott Wood 
2370dfc86b3SScott Wood static const struct clockgen_muxinfo clockgen2_cmux_cgb = {
2380dfc86b3SScott Wood 	{
2390dfc86b3SScott Wood 		{ CLKSEL_VALID, CGB_PLL1, PLL_DIV1 },
2400dfc86b3SScott Wood 		{ CLKSEL_VALID, CGB_PLL1, PLL_DIV2 },
2410dfc86b3SScott Wood 		{ CLKSEL_VALID, CGB_PLL1, PLL_DIV4 },
2420dfc86b3SScott Wood 		{},
2430dfc86b3SScott Wood 		{ CLKSEL_VALID, CGB_PLL2, PLL_DIV1 },
2440dfc86b3SScott Wood 		{ CLKSEL_VALID, CGB_PLL2, PLL_DIV2 },
2450dfc86b3SScott Wood 		{ CLKSEL_VALID, CGB_PLL2, PLL_DIV4 },
2460dfc86b3SScott Wood 	},
2470dfc86b3SScott Wood };
2480dfc86b3SScott Wood 
24992df3a9bSMichael Krummsdorf static const struct clockgen_muxinfo ls1021a_cmux = {
25092df3a9bSMichael Krummsdorf 	{
25192df3a9bSMichael Krummsdorf 		{ CLKSEL_VALID, CGA_PLL1, PLL_DIV1 },
25292df3a9bSMichael Krummsdorf 		{ CLKSEL_VALID, CGA_PLL1, PLL_DIV2 },
25392df3a9bSMichael Krummsdorf 		{ CLKSEL_VALID, CGA_PLL1, PLL_DIV4 },
25492df3a9bSMichael Krummsdorf 	}
25592df3a9bSMichael Krummsdorf };
25692df3a9bSMichael Krummsdorf 
25795089f6aSYuantian Tang static const struct clockgen_muxinfo ls1028a_hwa1 = {
25895089f6aSYuantian Tang 	{
25995089f6aSYuantian Tang 		{ CLKSEL_VALID, PLATFORM_PLL, PLL_DIV1 },
26095089f6aSYuantian Tang 		{ CLKSEL_VALID, CGA_PLL1, PLL_DIV1 },
26195089f6aSYuantian Tang 		{ CLKSEL_VALID, CGA_PLL1, PLL_DIV2 },
26295089f6aSYuantian Tang 		{ CLKSEL_VALID, CGA_PLL1, PLL_DIV3 },
26395089f6aSYuantian Tang 		{ CLKSEL_VALID, CGA_PLL1, PLL_DIV4 },
26495089f6aSYuantian Tang 		{},
26595089f6aSYuantian Tang 		{ CLKSEL_VALID, CGA_PLL2, PLL_DIV2 },
26695089f6aSYuantian Tang 		{ CLKSEL_VALID, CGA_PLL2, PLL_DIV3 },
26795089f6aSYuantian Tang 	},
26895089f6aSYuantian Tang };
26995089f6aSYuantian Tang 
27095089f6aSYuantian Tang static const struct clockgen_muxinfo ls1028a_hwa2 = {
27195089f6aSYuantian Tang 	{
27295089f6aSYuantian Tang 		{ CLKSEL_VALID, PLATFORM_PLL, PLL_DIV1 },
27395089f6aSYuantian Tang 		{ CLKSEL_VALID, CGA_PLL2, PLL_DIV1 },
27495089f6aSYuantian Tang 		{ CLKSEL_VALID, CGA_PLL2, PLL_DIV2 },
27595089f6aSYuantian Tang 		{ CLKSEL_VALID, CGA_PLL2, PLL_DIV3 },
27695089f6aSYuantian Tang 		{ CLKSEL_VALID, CGA_PLL2, PLL_DIV4 },
27795089f6aSYuantian Tang 		{},
27895089f6aSYuantian Tang 		{ CLKSEL_VALID, CGA_PLL1, PLL_DIV2 },
27995089f6aSYuantian Tang 		{ CLKSEL_VALID, CGA_PLL1, PLL_DIV3 },
28095089f6aSYuantian Tang 	},
28195089f6aSYuantian Tang };
28295089f6aSYuantian Tang 
28395089f6aSYuantian Tang static const struct clockgen_muxinfo ls1028a_hwa3 = {
28495089f6aSYuantian Tang 	{
28595089f6aSYuantian Tang 		{ CLKSEL_VALID, PLATFORM_PLL, PLL_DIV1 },
28695089f6aSYuantian Tang 		{ CLKSEL_VALID, CGA_PLL1, PLL_DIV1 },
28795089f6aSYuantian Tang 		{ CLKSEL_VALID, CGA_PLL1, PLL_DIV2 },
28895089f6aSYuantian Tang 		{ CLKSEL_VALID, CGA_PLL1, PLL_DIV3 },
28995089f6aSYuantian Tang 		{ CLKSEL_VALID, CGA_PLL1, PLL_DIV4 },
29095089f6aSYuantian Tang 		{},
29195089f6aSYuantian Tang 		{ CLKSEL_VALID, CGA_PLL2, PLL_DIV2 },
29295089f6aSYuantian Tang 		{ CLKSEL_VALID, CGA_PLL2, PLL_DIV3 },
29395089f6aSYuantian Tang 	},
29495089f6aSYuantian Tang };
29595089f6aSYuantian Tang 
29695089f6aSYuantian Tang static const struct clockgen_muxinfo ls1028a_hwa4 = {
29795089f6aSYuantian Tang 	{
29895089f6aSYuantian Tang 		{ CLKSEL_VALID, PLATFORM_PLL, PLL_DIV1 },
29995089f6aSYuantian Tang 		{ CLKSEL_VALID, CGA_PLL2, PLL_DIV1 },
30095089f6aSYuantian Tang 		{ CLKSEL_VALID, CGA_PLL2, PLL_DIV2 },
30195089f6aSYuantian Tang 		{ CLKSEL_VALID, CGA_PLL2, PLL_DIV3 },
30295089f6aSYuantian Tang 		{ CLKSEL_VALID, CGA_PLL2, PLL_DIV4 },
30395089f6aSYuantian Tang 		{},
30495089f6aSYuantian Tang 		{ CLKSEL_VALID, CGA_PLL1, PLL_DIV2 },
30595089f6aSYuantian Tang 		{ CLKSEL_VALID, CGA_PLL1, PLL_DIV3 },
30695089f6aSYuantian Tang 	},
30795089f6aSYuantian Tang };
30895089f6aSYuantian Tang 
309e994412cSHou Zhiqiang static const struct clockgen_muxinfo ls1043a_hwa1 = {
310e994412cSHou Zhiqiang 	{
311e994412cSHou Zhiqiang 		{},
312e994412cSHou Zhiqiang 		{},
313e994412cSHou Zhiqiang 		{ CLKSEL_VALID, CGA_PLL1, PLL_DIV2 },
314e994412cSHou Zhiqiang 		{ CLKSEL_VALID, CGA_PLL1, PLL_DIV3 },
315e994412cSHou Zhiqiang 		{},
316e994412cSHou Zhiqiang 		{},
317e994412cSHou Zhiqiang 		{ CLKSEL_VALID, CGA_PLL2, PLL_DIV2 },
318e994412cSHou Zhiqiang 		{ CLKSEL_VALID, CGA_PLL2, PLL_DIV3 },
319e994412cSHou Zhiqiang 	},
320e994412cSHou Zhiqiang };
321e994412cSHou Zhiqiang 
322e994412cSHou Zhiqiang static const struct clockgen_muxinfo ls1043a_hwa2 = {
323e994412cSHou Zhiqiang 	{
324e994412cSHou Zhiqiang 		{},
325e994412cSHou Zhiqiang 		{ CLKSEL_VALID, CGA_PLL2, PLL_DIV1 },
326e994412cSHou Zhiqiang 		{},
327e994412cSHou Zhiqiang 		{ CLKSEL_VALID, CGA_PLL2, PLL_DIV3 },
328e994412cSHou Zhiqiang 	},
329e994412cSHou Zhiqiang };
330e994412cSHou Zhiqiang 
33180e52198SMingkai Hu static const struct clockgen_muxinfo ls1046a_hwa1 = {
33280e52198SMingkai Hu 	{
33380e52198SMingkai Hu 		{},
33480e52198SMingkai Hu 		{},
33580e52198SMingkai Hu 		{ CLKSEL_VALID, CGA_PLL1, PLL_DIV2 },
33680e52198SMingkai Hu 		{ CLKSEL_VALID, CGA_PLL1, PLL_DIV3 },
33780e52198SMingkai Hu 		{ CLKSEL_VALID, CGA_PLL1, PLL_DIV4 },
33880e52198SMingkai Hu 		{ CLKSEL_VALID, PLATFORM_PLL, PLL_DIV1 },
33980e52198SMingkai Hu 		{ CLKSEL_VALID, CGA_PLL2, PLL_DIV2 },
34080e52198SMingkai Hu 		{ CLKSEL_VALID, CGA_PLL2, PLL_DIV3 },
34180e52198SMingkai Hu 	},
34280e52198SMingkai Hu };
34380e52198SMingkai Hu 
34480e52198SMingkai Hu static const struct clockgen_muxinfo ls1046a_hwa2 = {
34580e52198SMingkai Hu 	{
34680e52198SMingkai Hu 		{},
34780e52198SMingkai Hu 		{ CLKSEL_VALID, CGA_PLL2, PLL_DIV1 },
34880e52198SMingkai Hu 		{ CLKSEL_VALID, CGA_PLL2, PLL_DIV2 },
34980e52198SMingkai Hu 		{ CLKSEL_VALID, CGA_PLL2, PLL_DIV3 },
35080e52198SMingkai Hu 		{},
35180e52198SMingkai Hu 		{},
35280e52198SMingkai Hu 		{ CLKSEL_VALID, CGA_PLL1, PLL_DIV2 },
35380e52198SMingkai Hu 	},
35480e52198SMingkai Hu };
35580e52198SMingkai Hu 
356a932872fSYangbo Lu static const struct clockgen_muxinfo ls1088a_hwa1 = {
357a932872fSYangbo Lu 	{
358a932872fSYangbo Lu 		{},
359a932872fSYangbo Lu 		{ CLKSEL_VALID, CGA_PLL1, PLL_DIV1 },
360a932872fSYangbo Lu 		{ CLKSEL_VALID, CGA_PLL1, PLL_DIV2 },
361a932872fSYangbo Lu 		{ CLKSEL_VALID, CGA_PLL1, PLL_DIV3 },
362a932872fSYangbo Lu 		{ CLKSEL_VALID, CGA_PLL1, PLL_DIV4 },
363a932872fSYangbo Lu 		{},
364a932872fSYangbo Lu 		{ CLKSEL_VALID, CGA_PLL2, PLL_DIV2 },
365a932872fSYangbo Lu 		{ CLKSEL_VALID, CGA_PLL2, PLL_DIV3 },
366a932872fSYangbo Lu 	},
367a932872fSYangbo Lu };
368a932872fSYangbo Lu 
369a932872fSYangbo Lu static const struct clockgen_muxinfo ls1088a_hwa2 = {
370a932872fSYangbo Lu 	{
371a932872fSYangbo Lu 		{},
372a932872fSYangbo Lu 		{ CLKSEL_VALID, CGA_PLL2, PLL_DIV1 },
373a932872fSYangbo Lu 		{ CLKSEL_VALID, CGA_PLL2, PLL_DIV2 },
374a932872fSYangbo Lu 		{ CLKSEL_VALID, CGA_PLL2, PLL_DIV3 },
375a932872fSYangbo Lu 		{ CLKSEL_VALID, CGA_PLL2, PLL_DIV4 },
376a932872fSYangbo Lu 		{},
377a932872fSYangbo Lu 		{ CLKSEL_VALID, CGA_PLL1, PLL_DIV2 },
378a932872fSYangbo Lu 		{ CLKSEL_VALID, CGA_PLL1, PLL_DIV3 },
379a932872fSYangbo Lu 	},
380a932872fSYangbo Lu };
381a932872fSYangbo Lu 
38244709358STang Yuantian static const struct clockgen_muxinfo ls1012a_cmux = {
38344709358STang Yuantian 	{
38444709358STang Yuantian 		[0] = { CLKSEL_VALID, CGA_PLL1, PLL_DIV1 },
38544709358STang Yuantian 		{},
38644709358STang Yuantian 		[2] = { CLKSEL_VALID, CGA_PLL1, PLL_DIV2 },
38744709358STang Yuantian 	}
38844709358STang Yuantian };
38944709358STang Yuantian 
3900dfc86b3SScott Wood static const struct clockgen_muxinfo t1023_hwa1 = {
3910dfc86b3SScott Wood 	{
3920dfc86b3SScott Wood 		{},
3930dfc86b3SScott Wood 		{ CLKSEL_VALID, CGA_PLL1, PLL_DIV1 },
3940dfc86b3SScott Wood 		{ CLKSEL_VALID, CGA_PLL1, PLL_DIV2 },
3950dfc86b3SScott Wood 		{ CLKSEL_VALID, CGA_PLL1, PLL_DIV3 },
3960dfc86b3SScott Wood 	},
3970dfc86b3SScott Wood };
3980dfc86b3SScott Wood 
3990dfc86b3SScott Wood static const struct clockgen_muxinfo t1023_hwa2 = {
4000dfc86b3SScott Wood 	{
4010dfc86b3SScott Wood 		[6] = { CLKSEL_VALID, CGA_PLL1, PLL_DIV2 },
4020dfc86b3SScott Wood 	},
4030dfc86b3SScott Wood };
4040dfc86b3SScott Wood 
4050dfc86b3SScott Wood static const struct clockgen_muxinfo t2080_hwa1 = {
4060dfc86b3SScott Wood 	{
4070dfc86b3SScott Wood 		{},
4080dfc86b3SScott Wood 		{ CLKSEL_VALID, CGA_PLL1, PLL_DIV1 },
4090dfc86b3SScott Wood 		{ CLKSEL_VALID, CGA_PLL1, PLL_DIV2 },
4100dfc86b3SScott Wood 		{ CLKSEL_VALID, CGA_PLL1, PLL_DIV3 },
4110dfc86b3SScott Wood 		{ CLKSEL_VALID, CGA_PLL1, PLL_DIV4 },
4120dfc86b3SScott Wood 		{ CLKSEL_VALID, PLATFORM_PLL, PLL_DIV1 },
4130dfc86b3SScott Wood 		{ CLKSEL_VALID, CGA_PLL2, PLL_DIV2 },
4140dfc86b3SScott Wood 		{ CLKSEL_VALID, CGA_PLL2, PLL_DIV3 },
4150dfc86b3SScott Wood 	},
4160dfc86b3SScott Wood };
4170dfc86b3SScott Wood 
4180dfc86b3SScott Wood static const struct clockgen_muxinfo t2080_hwa2 = {
4190dfc86b3SScott Wood 	{
4200dfc86b3SScott Wood 		{},
4210dfc86b3SScott Wood 		{ CLKSEL_VALID, CGA_PLL2, PLL_DIV1 },
4220dfc86b3SScott Wood 		{ CLKSEL_VALID, CGA_PLL2, PLL_DIV2 },
4230dfc86b3SScott Wood 		{ CLKSEL_VALID, CGA_PLL2, PLL_DIV3 },
4240dfc86b3SScott Wood 		{ CLKSEL_VALID, CGA_PLL2, PLL_DIV4 },
4250dfc86b3SScott Wood 		{ CLKSEL_VALID, PLATFORM_PLL, PLL_DIV1 },
4260dfc86b3SScott Wood 		{ CLKSEL_VALID, CGA_PLL1, PLL_DIV2 },
4270dfc86b3SScott Wood 		{ CLKSEL_VALID, CGA_PLL1, PLL_DIV3 },
4280dfc86b3SScott Wood 	},
4290dfc86b3SScott Wood };
4300dfc86b3SScott Wood 
4310dfc86b3SScott Wood static const struct clockgen_muxinfo t4240_hwa1 = {
4320dfc86b3SScott Wood 	{
4330dfc86b3SScott Wood 		{ CLKSEL_VALID, PLATFORM_PLL, PLL_DIV2 },
4340dfc86b3SScott Wood 		{ CLKSEL_VALID, CGA_PLL1, PLL_DIV1 },
4350dfc86b3SScott Wood 		{ CLKSEL_VALID, CGA_PLL1, PLL_DIV2 },
4360dfc86b3SScott Wood 		{ CLKSEL_VALID, CGA_PLL1, PLL_DIV3 },
4370dfc86b3SScott Wood 		{ CLKSEL_VALID, CGA_PLL1, PLL_DIV4 },
4380dfc86b3SScott Wood 		{},
4390dfc86b3SScott Wood 		{ CLKSEL_VALID, CGA_PLL2, PLL_DIV2 },
4400dfc86b3SScott Wood 		{ CLKSEL_VALID, CGA_PLL2, PLL_DIV3 },
4410dfc86b3SScott Wood 	},
4420dfc86b3SScott Wood };
4430dfc86b3SScott Wood 
4440dfc86b3SScott Wood static const struct clockgen_muxinfo t4240_hwa4 = {
4450dfc86b3SScott Wood 	{
4460dfc86b3SScott Wood 		[2] = { CLKSEL_VALID, CGB_PLL1, PLL_DIV2 },
4470dfc86b3SScott Wood 		[3] = { CLKSEL_VALID, CGB_PLL1, PLL_DIV3 },
4480dfc86b3SScott Wood 		[4] = { CLKSEL_VALID, CGB_PLL1, PLL_DIV4 },
4490dfc86b3SScott Wood 		[5] = { CLKSEL_VALID, PLATFORM_PLL, PLL_DIV1 },
4500dfc86b3SScott Wood 		[6] = { CLKSEL_VALID, CGB_PLL2, PLL_DIV2 },
4510dfc86b3SScott Wood 	},
4520dfc86b3SScott Wood };
4530dfc86b3SScott Wood 
4540dfc86b3SScott Wood static const struct clockgen_muxinfo t4240_hwa5 = {
4550dfc86b3SScott Wood 	{
4560dfc86b3SScott Wood 		[2] = { CLKSEL_VALID, CGB_PLL2, PLL_DIV2 },
4570dfc86b3SScott Wood 		[3] = { CLKSEL_VALID, CGB_PLL2, PLL_DIV3 },
4580dfc86b3SScott Wood 		[4] = { CLKSEL_VALID, CGB_PLL2, PLL_DIV4 },
4590dfc86b3SScott Wood 		[5] = { CLKSEL_VALID, PLATFORM_PLL, PLL_DIV1 },
4600dfc86b3SScott Wood 		[6] = { CLKSEL_VALID, CGB_PLL1, PLL_DIV2 },
4610dfc86b3SScott Wood 		[7] = { CLKSEL_VALID, CGB_PLL1, PLL_DIV3 },
4620dfc86b3SScott Wood 	},
4630dfc86b3SScott Wood };
4640dfc86b3SScott Wood 
4650dfc86b3SScott Wood #define RCWSR7_FM1_CLK_SEL	0x40000000
4660dfc86b3SScott Wood #define RCWSR7_FM2_CLK_SEL	0x20000000
4670dfc86b3SScott Wood #define RCWSR7_HWA_ASYNC_DIV	0x04000000
4680dfc86b3SScott Wood 
p2041_init_periph(struct clockgen * cg)4690dfc86b3SScott Wood static void __init p2041_init_periph(struct clockgen *cg)
4700dfc86b3SScott Wood {
4710dfc86b3SScott Wood 	u32 reg;
4720dfc86b3SScott Wood 
4730dfc86b3SScott Wood 	reg = ioread32be(&cg->guts->rcwsr[7]);
4740dfc86b3SScott Wood 
4750dfc86b3SScott Wood 	if (reg & RCWSR7_FM1_CLK_SEL)
4760dfc86b3SScott Wood 		cg->fman[0] = cg->pll[CGA_PLL2].div[PLL_DIV2].clk;
4770dfc86b3SScott Wood 	else
4780dfc86b3SScott Wood 		cg->fman[0] = cg->pll[PLATFORM_PLL].div[PLL_DIV2].clk;
4790dfc86b3SScott Wood }
4800dfc86b3SScott Wood 
p4080_init_periph(struct clockgen * cg)4810dfc86b3SScott Wood static void __init p4080_init_periph(struct clockgen *cg)
4820dfc86b3SScott Wood {
4830dfc86b3SScott Wood 	u32 reg;
4840dfc86b3SScott Wood 
4850dfc86b3SScott Wood 	reg = ioread32be(&cg->guts->rcwsr[7]);
4860dfc86b3SScott Wood 
4870dfc86b3SScott Wood 	if (reg & RCWSR7_FM1_CLK_SEL)
4880dfc86b3SScott Wood 		cg->fman[0] = cg->pll[CGA_PLL3].div[PLL_DIV2].clk;
4890dfc86b3SScott Wood 	else
4900dfc86b3SScott Wood 		cg->fman[0] = cg->pll[PLATFORM_PLL].div[PLL_DIV2].clk;
4910dfc86b3SScott Wood 
4920dfc86b3SScott Wood 	if (reg & RCWSR7_FM2_CLK_SEL)
4930dfc86b3SScott Wood 		cg->fman[1] = cg->pll[CGA_PLL3].div[PLL_DIV2].clk;
4940dfc86b3SScott Wood 	else
4950dfc86b3SScott Wood 		cg->fman[1] = cg->pll[PLATFORM_PLL].div[PLL_DIV2].clk;
4960dfc86b3SScott Wood }
4970dfc86b3SScott Wood 
p5020_init_periph(struct clockgen * cg)4980dfc86b3SScott Wood static void __init p5020_init_periph(struct clockgen *cg)
4990dfc86b3SScott Wood {
5000dfc86b3SScott Wood 	u32 reg;
5010dfc86b3SScott Wood 	int div = PLL_DIV2;
5020dfc86b3SScott Wood 
5030dfc86b3SScott Wood 	reg = ioread32be(&cg->guts->rcwsr[7]);
5040dfc86b3SScott Wood 	if (reg & RCWSR7_HWA_ASYNC_DIV)
5050dfc86b3SScott Wood 		div = PLL_DIV4;
5060dfc86b3SScott Wood 
5070dfc86b3SScott Wood 	if (reg & RCWSR7_FM1_CLK_SEL)
5080dfc86b3SScott Wood 		cg->fman[0] = cg->pll[CGA_PLL2].div[div].clk;
5090dfc86b3SScott Wood 	else
5100dfc86b3SScott Wood 		cg->fman[0] = cg->pll[PLATFORM_PLL].div[PLL_DIV2].clk;
5110dfc86b3SScott Wood }
5120dfc86b3SScott Wood 
p5040_init_periph(struct clockgen * cg)5130dfc86b3SScott Wood static void __init p5040_init_periph(struct clockgen *cg)
5140dfc86b3SScott Wood {
5150dfc86b3SScott Wood 	u32 reg;
5160dfc86b3SScott Wood 	int div = PLL_DIV2;
5170dfc86b3SScott Wood 
5180dfc86b3SScott Wood 	reg = ioread32be(&cg->guts->rcwsr[7]);
5190dfc86b3SScott Wood 	if (reg & RCWSR7_HWA_ASYNC_DIV)
5200dfc86b3SScott Wood 		div = PLL_DIV4;
5210dfc86b3SScott Wood 
5220dfc86b3SScott Wood 	if (reg & RCWSR7_FM1_CLK_SEL)
5230dfc86b3SScott Wood 		cg->fman[0] = cg->pll[CGA_PLL3].div[div].clk;
5240dfc86b3SScott Wood 	else
5250dfc86b3SScott Wood 		cg->fman[0] = cg->pll[PLATFORM_PLL].div[PLL_DIV2].clk;
5260dfc86b3SScott Wood 
5270dfc86b3SScott Wood 	if (reg & RCWSR7_FM2_CLK_SEL)
5280dfc86b3SScott Wood 		cg->fman[1] = cg->pll[CGA_PLL3].div[div].clk;
5290dfc86b3SScott Wood 	else
5300dfc86b3SScott Wood 		cg->fman[1] = cg->pll[PLATFORM_PLL].div[PLL_DIV2].clk;
5310dfc86b3SScott Wood }
5320dfc86b3SScott Wood 
t1023_init_periph(struct clockgen * cg)5330dfc86b3SScott Wood static void __init t1023_init_periph(struct clockgen *cg)
5340dfc86b3SScott Wood {
5350dfc86b3SScott Wood 	cg->fman[0] = cg->hwaccel[1];
5360dfc86b3SScott Wood }
5370dfc86b3SScott Wood 
t1040_init_periph(struct clockgen * cg)5380dfc86b3SScott Wood static void __init t1040_init_periph(struct clockgen *cg)
5390dfc86b3SScott Wood {
5400dfc86b3SScott Wood 	cg->fman[0] = cg->pll[PLATFORM_PLL].div[PLL_DIV1].clk;
5410dfc86b3SScott Wood }
5420dfc86b3SScott Wood 
t2080_init_periph(struct clockgen * cg)5430dfc86b3SScott Wood static void __init t2080_init_periph(struct clockgen *cg)
5440dfc86b3SScott Wood {
5450dfc86b3SScott Wood 	cg->fman[0] = cg->hwaccel[0];
5460dfc86b3SScott Wood }
5470dfc86b3SScott Wood 
t4240_init_periph(struct clockgen * cg)5480dfc86b3SScott Wood static void __init t4240_init_periph(struct clockgen *cg)
5490dfc86b3SScott Wood {
5500dfc86b3SScott Wood 	cg->fman[0] = cg->hwaccel[3];
5510dfc86b3SScott Wood 	cg->fman[1] = cg->hwaccel[4];
5520dfc86b3SScott Wood }
5530dfc86b3SScott Wood 
5540dfc86b3SScott Wood static const struct clockgen_chipinfo chipinfo[] = {
5550dfc86b3SScott Wood 	{
5560dfc86b3SScott Wood 		.compat = "fsl,b4420-clockgen",
5570dfc86b3SScott Wood 		.guts_compat = "fsl,b4860-device-config",
5580dfc86b3SScott Wood 		.init_periph = t2080_init_periph,
5590dfc86b3SScott Wood 		.cmux_groups = {
5600dfc86b3SScott Wood 			&clockgen2_cmux_cga12, &clockgen2_cmux_cgb
5610dfc86b3SScott Wood 		},
5620dfc86b3SScott Wood 		.hwaccel = {
5630dfc86b3SScott Wood 			&t2080_hwa1
5640dfc86b3SScott Wood 		},
5650dfc86b3SScott Wood 		.cmux_to_group = {
5660dfc86b3SScott Wood 			0, 1, 1, 1, -1
5670dfc86b3SScott Wood 		},
568fa4dd53eSWasim Khan 		.pll_mask = BIT(PLATFORM_PLL) |
569fa4dd53eSWasim Khan 			    BIT(CGA_PLL1) | BIT(CGA_PLL2) | BIT(CGA_PLL3) |
570fa4dd53eSWasim Khan 			    BIT(CGB_PLL1) | BIT(CGB_PLL2),
5710dfc86b3SScott Wood 		.flags = CG_PLL_8BIT,
5720dfc86b3SScott Wood 	},
5730dfc86b3SScott Wood 	{
5740dfc86b3SScott Wood 		.compat = "fsl,b4860-clockgen",
5750dfc86b3SScott Wood 		.guts_compat = "fsl,b4860-device-config",
5760dfc86b3SScott Wood 		.init_periph = t2080_init_periph,
5770dfc86b3SScott Wood 		.cmux_groups = {
5780dfc86b3SScott Wood 			&clockgen2_cmux_cga12, &clockgen2_cmux_cgb
5790dfc86b3SScott Wood 		},
5800dfc86b3SScott Wood 		.hwaccel = {
5810dfc86b3SScott Wood 			&t2080_hwa1
5820dfc86b3SScott Wood 		},
5830dfc86b3SScott Wood 		.cmux_to_group = {
5840dfc86b3SScott Wood 			0, 1, 1, 1, -1
5850dfc86b3SScott Wood 		},
586fa4dd53eSWasim Khan 		.pll_mask = BIT(PLATFORM_PLL) |
587fa4dd53eSWasim Khan 			    BIT(CGA_PLL1) | BIT(CGA_PLL2) | BIT(CGA_PLL3) |
588fa4dd53eSWasim Khan 			    BIT(CGB_PLL1) | BIT(CGB_PLL2),
5890dfc86b3SScott Wood 		.flags = CG_PLL_8BIT,
5900dfc86b3SScott Wood 	},
5910dfc86b3SScott Wood 	{
5920dfc86b3SScott Wood 		.compat = "fsl,ls1021a-clockgen",
5930dfc86b3SScott Wood 		.cmux_groups = {
59492df3a9bSMichael Krummsdorf 			&ls1021a_cmux
5950dfc86b3SScott Wood 		},
5960dfc86b3SScott Wood 		.cmux_to_group = {
5970dfc86b3SScott Wood 			0, -1
5980dfc86b3SScott Wood 		},
599fa4dd53eSWasim Khan 		.pll_mask = BIT(PLATFORM_PLL) |
600fa4dd53eSWasim Khan 			    BIT(CGA_PLL1) | BIT(CGA_PLL2),
6010dfc86b3SScott Wood 	},
6020dfc86b3SScott Wood 	{
60395089f6aSYuantian Tang 		.compat = "fsl,ls1028a-clockgen",
60495089f6aSYuantian Tang 		.cmux_groups = {
60595089f6aSYuantian Tang 			&clockgen2_cmux_cga12
60695089f6aSYuantian Tang 		},
60795089f6aSYuantian Tang 		.hwaccel = {
60895089f6aSYuantian Tang 			&ls1028a_hwa1, &ls1028a_hwa2,
60995089f6aSYuantian Tang 			&ls1028a_hwa3, &ls1028a_hwa4
61095089f6aSYuantian Tang 		},
61195089f6aSYuantian Tang 		.cmux_to_group = {
61295089f6aSYuantian Tang 			0, 0, 0, 0, -1
61395089f6aSYuantian Tang 		},
614fa4dd53eSWasim Khan 		.pll_mask = BIT(PLATFORM_PLL) |
615fa4dd53eSWasim Khan 			    BIT(CGA_PLL1) | BIT(CGA_PLL2),
61695089f6aSYuantian Tang 		.flags = CG_VER3 | CG_LITTLE_ENDIAN,
61795089f6aSYuantian Tang 	},
61895089f6aSYuantian Tang 	{
619e994412cSHou Zhiqiang 		.compat = "fsl,ls1043a-clockgen",
620e994412cSHou Zhiqiang 		.init_periph = t2080_init_periph,
621e994412cSHou Zhiqiang 		.cmux_groups = {
622e994412cSHou Zhiqiang 			&t1040_cmux
623e994412cSHou Zhiqiang 		},
624e994412cSHou Zhiqiang 		.hwaccel = {
625e994412cSHou Zhiqiang 			&ls1043a_hwa1, &ls1043a_hwa2
626e994412cSHou Zhiqiang 		},
627e994412cSHou Zhiqiang 		.cmux_to_group = {
628e994412cSHou Zhiqiang 			0, -1
629e994412cSHou Zhiqiang 		},
630fa4dd53eSWasim Khan 		.pll_mask = BIT(PLATFORM_PLL) |
631fa4dd53eSWasim Khan 			    BIT(CGA_PLL1) | BIT(CGA_PLL2),
632e994412cSHou Zhiqiang 		.flags = CG_PLL_8BIT,
633e994412cSHou Zhiqiang 	},
634e994412cSHou Zhiqiang 	{
63580e52198SMingkai Hu 		.compat = "fsl,ls1046a-clockgen",
63680e52198SMingkai Hu 		.init_periph = t2080_init_periph,
63780e52198SMingkai Hu 		.cmux_groups = {
63880e52198SMingkai Hu 			&t1040_cmux
63980e52198SMingkai Hu 		},
64080e52198SMingkai Hu 		.hwaccel = {
64180e52198SMingkai Hu 			&ls1046a_hwa1, &ls1046a_hwa2
64280e52198SMingkai Hu 		},
64380e52198SMingkai Hu 		.cmux_to_group = {
64480e52198SMingkai Hu 			0, -1
64580e52198SMingkai Hu 		},
646fa4dd53eSWasim Khan 		.pll_mask = BIT(PLATFORM_PLL) |
647fa4dd53eSWasim Khan 			    BIT(CGA_PLL1) | BIT(CGA_PLL2),
64880e52198SMingkai Hu 		.flags = CG_PLL_8BIT,
64980e52198SMingkai Hu 	},
65080e52198SMingkai Hu 	{
651e0c888c4SYuantian Tang 		.compat = "fsl,ls1088a-clockgen",
652e0c888c4SYuantian Tang 		.cmux_groups = {
653e0c888c4SYuantian Tang 			&clockgen2_cmux_cga12
654e0c888c4SYuantian Tang 		},
655a932872fSYangbo Lu 		.hwaccel = {
656a932872fSYangbo Lu 			&ls1088a_hwa1, &ls1088a_hwa2
657a932872fSYangbo Lu 		},
658e0c888c4SYuantian Tang 		.cmux_to_group = {
659e0c888c4SYuantian Tang 			0, 0, -1
660e0c888c4SYuantian Tang 		},
661fa4dd53eSWasim Khan 		.pll_mask = BIT(PLATFORM_PLL) |
662fa4dd53eSWasim Khan 			    BIT(CGA_PLL1) | BIT(CGA_PLL2),
663e0c888c4SYuantian Tang 		.flags = CG_VER3 | CG_LITTLE_ENDIAN,
664e0c888c4SYuantian Tang 	},
665e0c888c4SYuantian Tang 	{
66644709358STang Yuantian 		.compat = "fsl,ls1012a-clockgen",
66744709358STang Yuantian 		.cmux_groups = {
66844709358STang Yuantian 			&ls1012a_cmux
66944709358STang Yuantian 		},
67044709358STang Yuantian 		.cmux_to_group = {
67144709358STang Yuantian 			0, -1
67244709358STang Yuantian 		},
673fa4dd53eSWasim Khan 		.pll_mask = BIT(PLATFORM_PLL) | BIT(CGA_PLL1),
67444709358STang Yuantian 	},
67544709358STang Yuantian 	{
6769e19ca2fSScott Wood 		.compat = "fsl,ls2080a-clockgen",
6779e19ca2fSScott Wood 		.cmux_groups = {
6789e19ca2fSScott Wood 			&clockgen2_cmux_cga12, &clockgen2_cmux_cgb
6799e19ca2fSScott Wood 		},
6809e19ca2fSScott Wood 		.cmux_to_group = {
6819e19ca2fSScott Wood 			0, 0, 1, 1, -1
6829e19ca2fSScott Wood 		},
683fa4dd53eSWasim Khan 		.pll_mask = BIT(PLATFORM_PLL) |
684fa4dd53eSWasim Khan 			    BIT(CGA_PLL1) | BIT(CGA_PLL2) |
685fa4dd53eSWasim Khan 			    BIT(CGB_PLL1) | BIT(CGB_PLL2),
6869e19ca2fSScott Wood 		.flags = CG_VER3 | CG_LITTLE_ENDIAN,
6879e19ca2fSScott Wood 	},
6889e19ca2fSScott Wood 	{
68978a5ba8fSVabhav Sharma 		.compat = "fsl,lx2160a-clockgen",
69078a5ba8fSVabhav Sharma 		.cmux_groups = {
69178a5ba8fSVabhav Sharma 			&clockgen2_cmux_cga12, &clockgen2_cmux_cgb
69278a5ba8fSVabhav Sharma 		},
69378a5ba8fSVabhav Sharma 		.cmux_to_group = {
69478a5ba8fSVabhav Sharma 			0, 0, 0, 0, 1, 1, 1, 1, -1
69578a5ba8fSVabhav Sharma 		},
696fa4dd53eSWasim Khan 		.pll_mask = BIT(PLATFORM_PLL) |
697fa4dd53eSWasim Khan 			    BIT(CGA_PLL1) | BIT(CGA_PLL2) |
698fa4dd53eSWasim Khan 			    BIT(CGB_PLL1) | BIT(CGB_PLL2),
69978a5ba8fSVabhav Sharma 		.flags = CG_VER3 | CG_LITTLE_ENDIAN,
70078a5ba8fSVabhav Sharma 	},
70178a5ba8fSVabhav Sharma 	{
7020dfc86b3SScott Wood 		.compat = "fsl,p2041-clockgen",
7030dfc86b3SScott Wood 		.guts_compat = "fsl,qoriq-device-config-1.0",
7040dfc86b3SScott Wood 		.init_periph = p2041_init_periph,
7050dfc86b3SScott Wood 		.cmux_groups = {
7060dfc86b3SScott Wood 			&p2041_cmux_grp1, &p2041_cmux_grp2
7070dfc86b3SScott Wood 		},
7080dfc86b3SScott Wood 		.cmux_to_group = {
7090dfc86b3SScott Wood 			0, 0, 1, 1, -1
7100dfc86b3SScott Wood 		},
711fa4dd53eSWasim Khan 		.pll_mask = BIT(PLATFORM_PLL) |
712fa4dd53eSWasim Khan 			    BIT(CGA_PLL1) | BIT(CGA_PLL2),
7130dfc86b3SScott Wood 	},
7140dfc86b3SScott Wood 	{
7150dfc86b3SScott Wood 		.compat = "fsl,p3041-clockgen",
7160dfc86b3SScott Wood 		.guts_compat = "fsl,qoriq-device-config-1.0",
7170dfc86b3SScott Wood 		.init_periph = p2041_init_periph,
7180dfc86b3SScott Wood 		.cmux_groups = {
7190dfc86b3SScott Wood 			&p2041_cmux_grp1, &p2041_cmux_grp2
7200dfc86b3SScott Wood 		},
7210dfc86b3SScott Wood 		.cmux_to_group = {
7220dfc86b3SScott Wood 			0, 0, 1, 1, -1
7230dfc86b3SScott Wood 		},
724fa4dd53eSWasim Khan 		.pll_mask = BIT(PLATFORM_PLL) |
725fa4dd53eSWasim Khan 			    BIT(CGA_PLL1) | BIT(CGA_PLL2),
7260dfc86b3SScott Wood 	},
7270dfc86b3SScott Wood 	{
7280dfc86b3SScott Wood 		.compat = "fsl,p4080-clockgen",
7290dfc86b3SScott Wood 		.guts_compat = "fsl,qoriq-device-config-1.0",
7300dfc86b3SScott Wood 		.init_periph = p4080_init_periph,
7310dfc86b3SScott Wood 		.cmux_groups = {
7320dfc86b3SScott Wood 			&p4080_cmux_grp1, &p4080_cmux_grp2
7330dfc86b3SScott Wood 		},
7340dfc86b3SScott Wood 		.cmux_to_group = {
73542614b5bSYogesh Gaur 			0, 0, 0, 0, 1, 1, 1, 1, -1
7360dfc86b3SScott Wood 		},
737fa4dd53eSWasim Khan 		.pll_mask = BIT(PLATFORM_PLL) |
738fa4dd53eSWasim Khan 			    BIT(CGA_PLL1) | BIT(CGA_PLL2) |
739fa4dd53eSWasim Khan 			    BIT(CGA_PLL3) | BIT(CGA_PLL4),
7400dfc86b3SScott Wood 	},
7410dfc86b3SScott Wood 	{
7420dfc86b3SScott Wood 		.compat = "fsl,p5020-clockgen",
7430dfc86b3SScott Wood 		.guts_compat = "fsl,qoriq-device-config-1.0",
7440dfc86b3SScott Wood 		.init_periph = p5020_init_periph,
7450dfc86b3SScott Wood 		.cmux_groups = {
746a95fb581SNathan Huckleberry 			&p5020_cmux_grp1, &p5020_cmux_grp2
7470dfc86b3SScott Wood 		},
7480dfc86b3SScott Wood 		.cmux_to_group = {
7490dfc86b3SScott Wood 			0, 1, -1
7500dfc86b3SScott Wood 		},
751fa4dd53eSWasim Khan 		.pll_mask = BIT(PLATFORM_PLL) |
752fa4dd53eSWasim Khan 			    BIT(CGA_PLL1) | BIT(CGA_PLL2),
7530dfc86b3SScott Wood 	},
7540dfc86b3SScott Wood 	{
7550dfc86b3SScott Wood 		.compat = "fsl,p5040-clockgen",
7560dfc86b3SScott Wood 		.guts_compat = "fsl,p5040-device-config",
7570dfc86b3SScott Wood 		.init_periph = p5040_init_periph,
7580dfc86b3SScott Wood 		.cmux_groups = {
7590dfc86b3SScott Wood 			&p5040_cmux_grp1, &p5040_cmux_grp2
7600dfc86b3SScott Wood 		},
7610dfc86b3SScott Wood 		.cmux_to_group = {
7620dfc86b3SScott Wood 			0, 0, 1, 1, -1
7630dfc86b3SScott Wood 		},
764fa4dd53eSWasim Khan 		.pll_mask = BIT(PLATFORM_PLL) |
765fa4dd53eSWasim Khan 			    BIT(CGA_PLL1) | BIT(CGA_PLL2) | BIT(CGA_PLL3),
7660dfc86b3SScott Wood 	},
7670dfc86b3SScott Wood 	{
7680dfc86b3SScott Wood 		.compat = "fsl,t1023-clockgen",
7690dfc86b3SScott Wood 		.guts_compat = "fsl,t1023-device-config",
7700dfc86b3SScott Wood 		.init_periph = t1023_init_periph,
7710dfc86b3SScott Wood 		.cmux_groups = {
7720dfc86b3SScott Wood 			&t1023_cmux
7730dfc86b3SScott Wood 		},
7740dfc86b3SScott Wood 		.hwaccel = {
7750dfc86b3SScott Wood 			&t1023_hwa1, &t1023_hwa2
7760dfc86b3SScott Wood 		},
7770dfc86b3SScott Wood 		.cmux_to_group = {
7780dfc86b3SScott Wood 			0, 0, -1
7790dfc86b3SScott Wood 		},
780fa4dd53eSWasim Khan 		.pll_mask = BIT(PLATFORM_PLL) | BIT(CGA_PLL1),
7810dfc86b3SScott Wood 		.flags = CG_PLL_8BIT,
7820dfc86b3SScott Wood 	},
7830dfc86b3SScott Wood 	{
7840dfc86b3SScott Wood 		.compat = "fsl,t1040-clockgen",
7850dfc86b3SScott Wood 		.guts_compat = "fsl,t1040-device-config",
7860dfc86b3SScott Wood 		.init_periph = t1040_init_periph,
7870dfc86b3SScott Wood 		.cmux_groups = {
7880dfc86b3SScott Wood 			&t1040_cmux
7890dfc86b3SScott Wood 		},
7900dfc86b3SScott Wood 		.cmux_to_group = {
7910dfc86b3SScott Wood 			0, 0, 0, 0, -1
7920dfc86b3SScott Wood 		},
793fa4dd53eSWasim Khan 		.pll_mask = BIT(PLATFORM_PLL) |
794fa4dd53eSWasim Khan 			    BIT(CGA_PLL1) | BIT(CGA_PLL2),
7950dfc86b3SScott Wood 		.flags = CG_PLL_8BIT,
7960dfc86b3SScott Wood 	},
7970dfc86b3SScott Wood 	{
7980dfc86b3SScott Wood 		.compat = "fsl,t2080-clockgen",
7990dfc86b3SScott Wood 		.guts_compat = "fsl,t2080-device-config",
8000dfc86b3SScott Wood 		.init_periph = t2080_init_periph,
8010dfc86b3SScott Wood 		.cmux_groups = {
8020dfc86b3SScott Wood 			&clockgen2_cmux_cga12
8030dfc86b3SScott Wood 		},
8040dfc86b3SScott Wood 		.hwaccel = {
8050dfc86b3SScott Wood 			&t2080_hwa1, &t2080_hwa2
8060dfc86b3SScott Wood 		},
8070dfc86b3SScott Wood 		.cmux_to_group = {
8080dfc86b3SScott Wood 			0, -1
8090dfc86b3SScott Wood 		},
810fa4dd53eSWasim Khan 		.pll_mask = BIT(PLATFORM_PLL) |
811fa4dd53eSWasim Khan 			    BIT(CGA_PLL1) | BIT(CGA_PLL2),
8120dfc86b3SScott Wood 		.flags = CG_PLL_8BIT,
8130dfc86b3SScott Wood 	},
8140dfc86b3SScott Wood 	{
8150dfc86b3SScott Wood 		.compat = "fsl,t4240-clockgen",
8160dfc86b3SScott Wood 		.guts_compat = "fsl,t4240-device-config",
8170dfc86b3SScott Wood 		.init_periph = t4240_init_periph,
8180dfc86b3SScott Wood 		.cmux_groups = {
8190dfc86b3SScott Wood 			&clockgen2_cmux_cga, &clockgen2_cmux_cgb
8200dfc86b3SScott Wood 		},
8210dfc86b3SScott Wood 		.hwaccel = {
8220dfc86b3SScott Wood 			&t4240_hwa1, NULL, NULL, &t4240_hwa4, &t4240_hwa5
8230dfc86b3SScott Wood 		},
8240dfc86b3SScott Wood 		.cmux_to_group = {
8250dfc86b3SScott Wood 			0, 0, 1, -1
8260dfc86b3SScott Wood 		},
827fa4dd53eSWasim Khan 		.pll_mask = BIT(PLATFORM_PLL) |
828fa4dd53eSWasim Khan 			    BIT(CGA_PLL1) | BIT(CGA_PLL2) | BIT(CGA_PLL3) |
829fa4dd53eSWasim Khan 			    BIT(CGB_PLL1) | BIT(CGB_PLL2),
8300dfc86b3SScott Wood 		.flags = CG_PLL_8BIT,
8310dfc86b3SScott Wood 	},
8320dfc86b3SScott Wood 	{},
8330dfc86b3SScott Wood };
8340dfc86b3SScott Wood 
8350dfc86b3SScott Wood struct mux_hwclock {
8360dfc86b3SScott Wood 	struct clk_hw hw;
8370dfc86b3SScott Wood 	struct clockgen *cg;
8380dfc86b3SScott Wood 	const struct clockgen_muxinfo *info;
8390dfc86b3SScott Wood 	u32 __iomem *reg;
8400dfc86b3SScott Wood 	u8 parent_to_clksel[NUM_MUX_PARENTS];
8410dfc86b3SScott Wood 	s8 clksel_to_parent[NUM_MUX_PARENTS];
8420dfc86b3SScott Wood 	int num_parents;
8430dfc86b3SScott Wood };
8440dfc86b3SScott Wood 
8450dfc86b3SScott Wood #define to_mux_hwclock(p)	container_of(p, struct mux_hwclock, hw)
8460dfc86b3SScott Wood #define CLKSEL_MASK		0x78000000
8470dfc86b3SScott Wood #define	CLKSEL_SHIFT		27
8480dfc86b3SScott Wood 
mux_set_parent(struct clk_hw * hw,u8 idx)8490dfc86b3SScott Wood static int mux_set_parent(struct clk_hw *hw, u8 idx)
8500dfc86b3SScott Wood {
8510dfc86b3SScott Wood 	struct mux_hwclock *hwc = to_mux_hwclock(hw);
85293a17c05STang Yuantian 	u32 clksel;
85393a17c05STang Yuantian 
8540dfc86b3SScott Wood 	if (idx >= hwc->num_parents)
8550dfc86b3SScott Wood 		return -EINVAL;
8560dfc86b3SScott Wood 
8570dfc86b3SScott Wood 	clksel = hwc->parent_to_clksel[idx];
8589e19ca2fSScott Wood 	cg_out(hwc->cg, (clksel << CLKSEL_SHIFT) & CLKSEL_MASK, hwc->reg);
85993a17c05STang Yuantian 
86093a17c05STang Yuantian 	return 0;
86193a17c05STang Yuantian }
86293a17c05STang Yuantian 
mux_get_parent(struct clk_hw * hw)8630dfc86b3SScott Wood static u8 mux_get_parent(struct clk_hw *hw)
86493a17c05STang Yuantian {
8650dfc86b3SScott Wood 	struct mux_hwclock *hwc = to_mux_hwclock(hw);
86693a17c05STang Yuantian 	u32 clksel;
8670dfc86b3SScott Wood 	s8 ret;
86893a17c05STang Yuantian 
8699e19ca2fSScott Wood 	clksel = (cg_in(hwc->cg, hwc->reg) & CLKSEL_MASK) >> CLKSEL_SHIFT;
87093a17c05STang Yuantian 
8710dfc86b3SScott Wood 	ret = hwc->clksel_to_parent[clksel];
8720dfc86b3SScott Wood 	if (ret < 0) {
8730dfc86b3SScott Wood 		pr_err("%s: mux at %p has bad clksel\n", __func__, hwc->reg);
8740dfc86b3SScott Wood 		return 0;
8750dfc86b3SScott Wood 	}
8760dfc86b3SScott Wood 
8770dfc86b3SScott Wood 	return ret;
87893a17c05STang Yuantian }
87993a17c05STang Yuantian 
880334680ddSEmil Medve static const struct clk_ops cmux_ops = {
8814cbe6428SMaxime Ripard 	.determine_rate = clk_hw_determine_rate_no_reparent,
8820dfc86b3SScott Wood 	.get_parent = mux_get_parent,
8830dfc86b3SScott Wood 	.set_parent = mux_set_parent,
88493a17c05STang Yuantian };
88593a17c05STang Yuantian 
8860dfc86b3SScott Wood /*
8870dfc86b3SScott Wood  * Don't allow setting for now, as the clock options haven't been
8880dfc86b3SScott Wood  * sanitized for additional restrictions.
8890dfc86b3SScott Wood  */
8900dfc86b3SScott Wood static const struct clk_ops hwaccel_ops = {
8910dfc86b3SScott Wood 	.get_parent = mux_get_parent,
8920dfc86b3SScott Wood };
8930dfc86b3SScott Wood 
get_pll_div(struct clockgen * cg,struct mux_hwclock * hwc,int idx)8940dfc86b3SScott Wood static const struct clockgen_pll_div *get_pll_div(struct clockgen *cg,
8950dfc86b3SScott Wood 						  struct mux_hwclock *hwc,
8960dfc86b3SScott Wood 						  int idx)
8970dfc86b3SScott Wood {
8980dfc86b3SScott Wood 	int pll, div;
8990dfc86b3SScott Wood 
9000dfc86b3SScott Wood 	if (!(hwc->info->clksel[idx].flags & CLKSEL_VALID))
9010dfc86b3SScott Wood 		return NULL;
9020dfc86b3SScott Wood 
9030dfc86b3SScott Wood 	pll = hwc->info->clksel[idx].pll;
9040dfc86b3SScott Wood 	div = hwc->info->clksel[idx].div;
9050dfc86b3SScott Wood 
9060dfc86b3SScott Wood 	return &cg->pll[pll].div[div];
9070dfc86b3SScott Wood }
9080dfc86b3SScott Wood 
create_mux_common(struct clockgen * cg,struct mux_hwclock * hwc,const struct clk_ops * ops,unsigned long min_rate,unsigned long max_rate,unsigned long pct80_rate,const char * fmt,int idx)9090dfc86b3SScott Wood static struct clk * __init create_mux_common(struct clockgen *cg,
9100dfc86b3SScott Wood 					     struct mux_hwclock *hwc,
9110dfc86b3SScott Wood 					     const struct clk_ops *ops,
9120dfc86b3SScott Wood 					     unsigned long min_rate,
9137c1c5413SScott Wood 					     unsigned long max_rate,
9140dfc86b3SScott Wood 					     unsigned long pct80_rate,
9150dfc86b3SScott Wood 					     const char *fmt, int idx)
9160dfc86b3SScott Wood {
9170dfc86b3SScott Wood 	struct clk_init_data init = {};
9180dfc86b3SScott Wood 	struct clk *clk;
9190dfc86b3SScott Wood 	const struct clockgen_pll_div *div;
9200dfc86b3SScott Wood 	const char *parent_names[NUM_MUX_PARENTS];
9210dfc86b3SScott Wood 	char name[32];
9220dfc86b3SScott Wood 	int i, j;
9230dfc86b3SScott Wood 
9240dfc86b3SScott Wood 	snprintf(name, sizeof(name), fmt, idx);
9250dfc86b3SScott Wood 
9260dfc86b3SScott Wood 	for (i = 0, j = 0; i < NUM_MUX_PARENTS; i++) {
9270dfc86b3SScott Wood 		unsigned long rate;
9280dfc86b3SScott Wood 
9290dfc86b3SScott Wood 		hwc->clksel_to_parent[i] = -1;
9300dfc86b3SScott Wood 
9310dfc86b3SScott Wood 		div = get_pll_div(cg, hwc, i);
9320dfc86b3SScott Wood 		if (!div)
9330dfc86b3SScott Wood 			continue;
9340dfc86b3SScott Wood 
9350dfc86b3SScott Wood 		rate = clk_get_rate(div->clk);
9360dfc86b3SScott Wood 
9370dfc86b3SScott Wood 		if (hwc->info->clksel[i].flags & CLKSEL_80PCT &&
9380dfc86b3SScott Wood 		    rate > pct80_rate)
9390dfc86b3SScott Wood 			continue;
9400dfc86b3SScott Wood 		if (rate < min_rate)
9410dfc86b3SScott Wood 			continue;
9427c1c5413SScott Wood 		if (rate > max_rate)
9437c1c5413SScott Wood 			continue;
9440dfc86b3SScott Wood 
9450dfc86b3SScott Wood 		parent_names[j] = div->name;
9460dfc86b3SScott Wood 		hwc->parent_to_clksel[j] = i;
9470dfc86b3SScott Wood 		hwc->clksel_to_parent[i] = j;
9480dfc86b3SScott Wood 		j++;
9490dfc86b3SScott Wood 	}
9500dfc86b3SScott Wood 
9510dfc86b3SScott Wood 	init.name = name;
9520dfc86b3SScott Wood 	init.ops = ops;
9530dfc86b3SScott Wood 	init.parent_names = parent_names;
9540dfc86b3SScott Wood 	init.num_parents = hwc->num_parents = j;
9550dfc86b3SScott Wood 	init.flags = 0;
9560dfc86b3SScott Wood 	hwc->hw.init = &init;
9570dfc86b3SScott Wood 	hwc->cg = cg;
9580dfc86b3SScott Wood 
9590dfc86b3SScott Wood 	clk = clk_register(NULL, &hwc->hw);
9600dfc86b3SScott Wood 	if (IS_ERR(clk)) {
9610dfc86b3SScott Wood 		pr_err("%s: Couldn't register %s: %ld\n", __func__, name,
9620dfc86b3SScott Wood 		       PTR_ERR(clk));
9630dfc86b3SScott Wood 		kfree(hwc);
9640dfc86b3SScott Wood 		return NULL;
9650dfc86b3SScott Wood 	}
9660dfc86b3SScott Wood 
9670dfc86b3SScott Wood 	return clk;
9680dfc86b3SScott Wood }
9690dfc86b3SScott Wood 
create_one_cmux(struct clockgen * cg,int idx)9700dfc86b3SScott Wood static struct clk * __init create_one_cmux(struct clockgen *cg, int idx)
9710dfc86b3SScott Wood {
9720dfc86b3SScott Wood 	struct mux_hwclock *hwc;
9730dfc86b3SScott Wood 	const struct clockgen_pll_div *div;
9740dfc86b3SScott Wood 	unsigned long plat_rate, min_rate;
9757c1c5413SScott Wood 	u64 max_rate, pct80_rate;
9760dfc86b3SScott Wood 	u32 clksel;
9770dfc86b3SScott Wood 
9780dfc86b3SScott Wood 	hwc = kzalloc(sizeof(*hwc), GFP_KERNEL);
9790dfc86b3SScott Wood 	if (!hwc)
9800dfc86b3SScott Wood 		return NULL;
9810dfc86b3SScott Wood 
9828964193fSTang Yuantian 	if (cg->info.flags & CG_VER3)
9838964193fSTang Yuantian 		hwc->reg = cg->regs + 0x70000 + 0x20 * idx;
9848964193fSTang Yuantian 	else
9850dfc86b3SScott Wood 		hwc->reg = cg->regs + 0x20 * idx;
9868964193fSTang Yuantian 
9870dfc86b3SScott Wood 	hwc->info = cg->info.cmux_groups[cg->info.cmux_to_group[idx]];
9880dfc86b3SScott Wood 
9890dfc86b3SScott Wood 	/*
9900dfc86b3SScott Wood 	 * Find the rate for the default clksel, and treat it as the
9910dfc86b3SScott Wood 	 * maximum rated core frequency.  If this is an incorrect
9920dfc86b3SScott Wood 	 * assumption, certain clock options (possibly including the
9930dfc86b3SScott Wood 	 * default clksel) may be inappropriately excluded on certain
9940dfc86b3SScott Wood 	 * chips.
9950dfc86b3SScott Wood 	 */
9969e19ca2fSScott Wood 	clksel = (cg_in(cg, hwc->reg) & CLKSEL_MASK) >> CLKSEL_SHIFT;
9970dfc86b3SScott Wood 	div = get_pll_div(cg, hwc, clksel);
998279104e3SSudip Mukherjee 	if (!div) {
999279104e3SSudip Mukherjee 		kfree(hwc);
10000dfc86b3SScott Wood 		return NULL;
1001279104e3SSudip Mukherjee 	}
10020dfc86b3SScott Wood 
10037c1c5413SScott Wood 	max_rate = clk_get_rate(div->clk);
10047c1c5413SScott Wood 	pct80_rate = max_rate * 8;
10050dfc86b3SScott Wood 	do_div(pct80_rate, 10);
10060dfc86b3SScott Wood 
10070dfc86b3SScott Wood 	plat_rate = clk_get_rate(cg->pll[PLATFORM_PLL].div[PLL_DIV1].clk);
10080dfc86b3SScott Wood 
10090dfc86b3SScott Wood 	if (cg->info.flags & CG_CMUX_GE_PLAT)
10100dfc86b3SScott Wood 		min_rate = plat_rate;
10110dfc86b3SScott Wood 	else
10120dfc86b3SScott Wood 		min_rate = plat_rate / 2;
10130dfc86b3SScott Wood 
10147c1c5413SScott Wood 	return create_mux_common(cg, hwc, &cmux_ops, min_rate, max_rate,
10150dfc86b3SScott Wood 				 pct80_rate, "cg-cmux%d", idx);
10160dfc86b3SScott Wood }
10170dfc86b3SScott Wood 
create_one_hwaccel(struct clockgen * cg,int idx)10180dfc86b3SScott Wood static struct clk * __init create_one_hwaccel(struct clockgen *cg, int idx)
10190dfc86b3SScott Wood {
10200dfc86b3SScott Wood 	struct mux_hwclock *hwc;
10210dfc86b3SScott Wood 
10220dfc86b3SScott Wood 	hwc = kzalloc(sizeof(*hwc), GFP_KERNEL);
10230dfc86b3SScott Wood 	if (!hwc)
10240dfc86b3SScott Wood 		return NULL;
10250dfc86b3SScott Wood 
10260dfc86b3SScott Wood 	hwc->reg = cg->regs + 0x20 * idx + 0x10;
10270dfc86b3SScott Wood 	hwc->info = cg->info.hwaccel[idx];
10280dfc86b3SScott Wood 
10297c1c5413SScott Wood 	return create_mux_common(cg, hwc, &hwaccel_ops, 0, ULONG_MAX, 0,
10300dfc86b3SScott Wood 				 "cg-hwaccel%d", idx);
10310dfc86b3SScott Wood }
10320dfc86b3SScott Wood 
create_muxes(struct clockgen * cg)10330dfc86b3SScott Wood static void __init create_muxes(struct clockgen *cg)
10340dfc86b3SScott Wood {
10350dfc86b3SScott Wood 	int i;
10360dfc86b3SScott Wood 
10370dfc86b3SScott Wood 	for (i = 0; i < ARRAY_SIZE(cg->cmux); i++) {
10380dfc86b3SScott Wood 		if (cg->info.cmux_to_group[i] < 0)
10390dfc86b3SScott Wood 			break;
10400dfc86b3SScott Wood 		if (cg->info.cmux_to_group[i] >=
10410dfc86b3SScott Wood 		    ARRAY_SIZE(cg->info.cmux_groups)) {
10420dfc86b3SScott Wood 			WARN_ON_ONCE(1);
10430dfc86b3SScott Wood 			continue;
10440dfc86b3SScott Wood 		}
10450dfc86b3SScott Wood 
10460dfc86b3SScott Wood 		cg->cmux[i] = create_one_cmux(cg, i);
10470dfc86b3SScott Wood 	}
10480dfc86b3SScott Wood 
10490dfc86b3SScott Wood 	for (i = 0; i < ARRAY_SIZE(cg->hwaccel); i++) {
10500dfc86b3SScott Wood 		if (!cg->info.hwaccel[i])
10510dfc86b3SScott Wood 			continue;
10520dfc86b3SScott Wood 
10530dfc86b3SScott Wood 		cg->hwaccel[i] = create_one_hwaccel(cg, i);
10540dfc86b3SScott Wood 	}
10550dfc86b3SScott Wood }
10560dfc86b3SScott Wood 
1057cf1e0449SMian Yousaf Kaukab static void __init _clockgen_init(struct device_node *np, bool legacy);
10580dfc86b3SScott Wood 
105980b4ae7aSScott Wood /*
106080b4ae7aSScott Wood  * Legacy nodes may get probed before the parent clockgen node.
106180b4ae7aSScott Wood  * It is assumed that device trees with legacy nodes will not
106280b4ae7aSScott Wood  * contain a "clocks" property -- otherwise the input clocks may
106380b4ae7aSScott Wood  * not be initialized at this point.
106480b4ae7aSScott Wood  */
legacy_init_clockgen(struct device_node * np)10650dfc86b3SScott Wood static void __init legacy_init_clockgen(struct device_node *np)
10660dfc86b3SScott Wood {
1067a8ea4273SLiang He 	if (!clockgen.node) {
1068a8ea4273SLiang He 		struct device_node *parent_np;
1069a8ea4273SLiang He 
1070a8ea4273SLiang He 		parent_np = of_get_parent(np);
1071a8ea4273SLiang He 		_clockgen_init(parent_np, true);
1072a8ea4273SLiang He 		of_node_put(parent_np);
1073a8ea4273SLiang He 	}
10740dfc86b3SScott Wood }
10750dfc86b3SScott Wood 
10760dfc86b3SScott Wood /* Legacy node */
core_mux_init(struct device_node * np)107793a17c05STang Yuantian static void __init core_mux_init(struct device_node *np)
107893a17c05STang Yuantian {
107993a17c05STang Yuantian 	struct clk *clk;
10800dfc86b3SScott Wood 	struct resource res;
10810dfc86b3SScott Wood 	int idx, rc;
108293a17c05STang Yuantian 
10830dfc86b3SScott Wood 	legacy_init_clockgen(np);
108493a17c05STang Yuantian 
10850dfc86b3SScott Wood 	if (of_address_to_resource(np, 0, &res))
108693a17c05STang Yuantian 		return;
108793a17c05STang Yuantian 
10880dfc86b3SScott Wood 	idx = (res.start & 0xf0) >> 5;
10890dfc86b3SScott Wood 	clk = clockgen.cmux[idx];
109093a17c05STang Yuantian 
109193a17c05STang Yuantian 	rc = of_clk_add_provider(np, of_clk_src_simple_get, clk);
109293a17c05STang Yuantian 	if (rc) {
1093e665f029SRob Herring 		pr_err("%s: Couldn't register clk provider for node %pOFn: %d\n",
1094e665f029SRob Herring 		       __func__, np, rc);
10950dfc86b3SScott Wood 		return;
109693a17c05STang Yuantian 	}
109793a17c05STang Yuantian }
109893a17c05STang Yuantian 
10993432a2e3SJulia Lawall static struct clk __init
sysclk_from_fixed(struct device_node * node,const char * name)11003432a2e3SJulia Lawall *sysclk_from_fixed(struct device_node *node, const char *name)
110193a17c05STang Yuantian {
11020dfc86b3SScott Wood 	u32 rate;
110393a17c05STang Yuantian 
11040dfc86b3SScott Wood 	if (of_property_read_u32(node, "clock-frequency", &rate))
11050dfc86b3SScott Wood 		return ERR_PTR(-ENODEV);
11060dfc86b3SScott Wood 
1107ec3f2fcbSStephen Boyd 	return clk_register_fixed_rate(NULL, name, NULL, 0, rate);
11080dfc86b3SScott Wood }
11090dfc86b3SScott Wood 
input_clock(const char * name,struct clk * clk)111080b4ae7aSScott Wood static struct clk __init *input_clock(const char *name, struct clk *clk)
11110dfc86b3SScott Wood {
111280b4ae7aSScott Wood 	const char *input_name;
11130dfc86b3SScott Wood 
11140dfc86b3SScott Wood 	/* Register the input clock under the desired name. */
111580b4ae7aSScott Wood 	input_name = __clk_get_name(clk);
111680b4ae7aSScott Wood 	clk = clk_register_fixed_factor(NULL, name, input_name,
11170dfc86b3SScott Wood 					0, 1, 1);
11180dfc86b3SScott Wood 	if (IS_ERR(clk))
11190dfc86b3SScott Wood 		pr_err("%s: Couldn't register %s: %ld\n", __func__, name,
11200dfc86b3SScott Wood 		       PTR_ERR(clk));
11210dfc86b3SScott Wood 
11220dfc86b3SScott Wood 	return clk;
11230dfc86b3SScott Wood }
11240dfc86b3SScott Wood 
input_clock_by_name(const char * name,const char * dtname)112580b4ae7aSScott Wood static struct clk __init *input_clock_by_name(const char *name,
112680b4ae7aSScott Wood 					      const char *dtname)
112780b4ae7aSScott Wood {
112880b4ae7aSScott Wood 	struct clk *clk;
112980b4ae7aSScott Wood 
113080b4ae7aSScott Wood 	clk = of_clk_get_by_name(clockgen.node, dtname);
113180b4ae7aSScott Wood 	if (IS_ERR(clk))
113280b4ae7aSScott Wood 		return clk;
113380b4ae7aSScott Wood 
113480b4ae7aSScott Wood 	return input_clock(name, clk);
113580b4ae7aSScott Wood }
113680b4ae7aSScott Wood 
input_clock_by_index(const char * name,int idx)113780b4ae7aSScott Wood static struct clk __init *input_clock_by_index(const char *name, int idx)
113880b4ae7aSScott Wood {
113980b4ae7aSScott Wood 	struct clk *clk;
114080b4ae7aSScott Wood 
114180b4ae7aSScott Wood 	clk = of_clk_get(clockgen.node, 0);
114280b4ae7aSScott Wood 	if (IS_ERR(clk))
114380b4ae7aSScott Wood 		return clk;
114480b4ae7aSScott Wood 
114580b4ae7aSScott Wood 	return input_clock(name, clk);
114680b4ae7aSScott Wood }
114780b4ae7aSScott Wood 
create_sysclk(const char * name)11480dfc86b3SScott Wood static struct clk * __init create_sysclk(const char *name)
11490dfc86b3SScott Wood {
11500dfc86b3SScott Wood 	struct device_node *sysclk;
11510dfc86b3SScott Wood 	struct clk *clk;
11520dfc86b3SScott Wood 
11530dfc86b3SScott Wood 	clk = sysclk_from_fixed(clockgen.node, name);
11540dfc86b3SScott Wood 	if (!IS_ERR(clk))
11550dfc86b3SScott Wood 		return clk;
11560dfc86b3SScott Wood 
115780b4ae7aSScott Wood 	clk = input_clock_by_name(name, "sysclk");
115880b4ae7aSScott Wood 	if (!IS_ERR(clk))
115980b4ae7aSScott Wood 		return clk;
116080b4ae7aSScott Wood 
116180b4ae7aSScott Wood 	clk = input_clock_by_index(name, 0);
11620dfc86b3SScott Wood 	if (!IS_ERR(clk))
11630dfc86b3SScott Wood 		return clk;
11640dfc86b3SScott Wood 
11650dfc86b3SScott Wood 	sysclk = of_get_child_by_name(clockgen.node, "sysclk");
11660dfc86b3SScott Wood 	if (sysclk) {
11670dfc86b3SScott Wood 		clk = sysclk_from_fixed(sysclk, name);
1168a8ea4273SLiang He 		of_node_put(sysclk);
11690dfc86b3SScott Wood 		if (!IS_ERR(clk))
11700dfc86b3SScott Wood 			return clk;
11710dfc86b3SScott Wood 	}
11720dfc86b3SScott Wood 
117380b4ae7aSScott Wood 	pr_err("%s: No input sysclk\n", __func__);
117480b4ae7aSScott Wood 	return NULL;
117580b4ae7aSScott Wood }
117680b4ae7aSScott Wood 
create_coreclk(const char * name)117780b4ae7aSScott Wood static struct clk * __init create_coreclk(const char *name)
117880b4ae7aSScott Wood {
117980b4ae7aSScott Wood 	struct clk *clk;
118080b4ae7aSScott Wood 
118180b4ae7aSScott Wood 	clk = input_clock_by_name(name, "coreclk");
118280b4ae7aSScott Wood 	if (!IS_ERR(clk))
118380b4ae7aSScott Wood 		return clk;
118480b4ae7aSScott Wood 
118580b4ae7aSScott Wood 	/*
118680b4ae7aSScott Wood 	 * This indicates a mix of legacy nodes with the new coreclk
118780b4ae7aSScott Wood 	 * mechanism, which should never happen.  If this error occurs,
118880b4ae7aSScott Wood 	 * don't use the wrong input clock just because coreclk isn't
118980b4ae7aSScott Wood 	 * ready yet.
119080b4ae7aSScott Wood 	 */
119180b4ae7aSScott Wood 	if (WARN_ON(PTR_ERR(clk) == -EPROBE_DEFER))
119280b4ae7aSScott Wood 		return clk;
119380b4ae7aSScott Wood 
11940dfc86b3SScott Wood 	return NULL;
11950dfc86b3SScott Wood }
11960dfc86b3SScott Wood 
11970dfc86b3SScott Wood /* Legacy node */
sysclk_init(struct device_node * node)11980dfc86b3SScott Wood static void __init sysclk_init(struct device_node *node)
11990dfc86b3SScott Wood {
12000dfc86b3SScott Wood 	struct clk *clk;
12010dfc86b3SScott Wood 
12020dfc86b3SScott Wood 	legacy_init_clockgen(node);
12030dfc86b3SScott Wood 
12040dfc86b3SScott Wood 	clk = clockgen.sysclk;
12050dfc86b3SScott Wood 	if (clk)
12060dfc86b3SScott Wood 		of_clk_add_provider(node, of_clk_src_simple_get, clk);
12070dfc86b3SScott Wood }
12080dfc86b3SScott Wood 
12090dfc86b3SScott Wood #define PLL_KILL BIT(31)
12100dfc86b3SScott Wood 
create_one_pll(struct clockgen * cg,int idx)12110dfc86b3SScott Wood static void __init create_one_pll(struct clockgen *cg, int idx)
12120dfc86b3SScott Wood {
12130dfc86b3SScott Wood 	u32 __iomem *reg;
12140dfc86b3SScott Wood 	u32 mult;
12150dfc86b3SScott Wood 	struct clockgen_pll *pll = &cg->pll[idx];
121680b4ae7aSScott Wood 	const char *input = "cg-sysclk";
12170dfc86b3SScott Wood 	int i;
12180dfc86b3SScott Wood 
12190dfc86b3SScott Wood 	if (!(cg->info.pll_mask & (1 << idx)))
12200dfc86b3SScott Wood 		return;
12210dfc86b3SScott Wood 
122280b4ae7aSScott Wood 	if (cg->coreclk && idx != PLATFORM_PLL) {
122380b4ae7aSScott Wood 		if (IS_ERR(cg->coreclk))
122480b4ae7aSScott Wood 			return;
122580b4ae7aSScott Wood 
122680b4ae7aSScott Wood 		input = "cg-coreclk";
122780b4ae7aSScott Wood 	}
122880b4ae7aSScott Wood 
12299e19ca2fSScott Wood 	if (cg->info.flags & CG_VER3) {
12309e19ca2fSScott Wood 		switch (idx) {
12319e19ca2fSScott Wood 		case PLATFORM_PLL:
12329e19ca2fSScott Wood 			reg = cg->regs + 0x60080;
12339e19ca2fSScott Wood 			break;
12349e19ca2fSScott Wood 		case CGA_PLL1:
12359e19ca2fSScott Wood 			reg = cg->regs + 0x80;
12369e19ca2fSScott Wood 			break;
12379e19ca2fSScott Wood 		case CGA_PLL2:
12389e19ca2fSScott Wood 			reg = cg->regs + 0xa0;
12399e19ca2fSScott Wood 			break;
12409e19ca2fSScott Wood 		case CGB_PLL1:
12419e19ca2fSScott Wood 			reg = cg->regs + 0x10080;
12429e19ca2fSScott Wood 			break;
12439e19ca2fSScott Wood 		case CGB_PLL2:
12449e19ca2fSScott Wood 			reg = cg->regs + 0x100a0;
12459e19ca2fSScott Wood 			break;
12469e19ca2fSScott Wood 		default:
12479e19ca2fSScott Wood 			WARN_ONCE(1, "index %d\n", idx);
12489e19ca2fSScott Wood 			return;
12499e19ca2fSScott Wood 		}
12509e19ca2fSScott Wood 	} else {
12510dfc86b3SScott Wood 		if (idx == PLATFORM_PLL)
12520dfc86b3SScott Wood 			reg = cg->regs + 0xc00;
12530dfc86b3SScott Wood 		else
12540dfc86b3SScott Wood 			reg = cg->regs + 0x800 + 0x20 * (idx - 1);
12559e19ca2fSScott Wood 	}
12560dfc86b3SScott Wood 
12570dfc86b3SScott Wood 	/* Get the multiple of PLL */
12589e19ca2fSScott Wood 	mult = cg_in(cg, reg);
12590dfc86b3SScott Wood 
12600dfc86b3SScott Wood 	/* Check if this PLL is disabled */
12610dfc86b3SScott Wood 	if (mult & PLL_KILL) {
12620dfc86b3SScott Wood 		pr_debug("%s(): pll %p disabled\n", __func__, reg);
126393a17c05STang Yuantian 		return;
126493a17c05STang Yuantian 	}
126593a17c05STang Yuantian 
12669e19ca2fSScott Wood 	if ((cg->info.flags & CG_VER3) ||
12679e19ca2fSScott Wood 	    ((cg->info.flags & CG_PLL_8BIT) && idx != PLATFORM_PLL))
12680dfc86b3SScott Wood 		mult = (mult & GENMASK(8, 1)) >> 1;
12690dfc86b3SScott Wood 	else
12700dfc86b3SScott Wood 		mult = (mult & GENMASK(6, 1)) >> 1;
127193a17c05STang Yuantian 
12720dfc86b3SScott Wood 	for (i = 0; i < ARRAY_SIZE(pll->div); i++) {
12730dfc86b3SScott Wood 		struct clk *clk;
127445899dc5SYuantian Tang 		int ret;
127593a17c05STang Yuantian 
127636ab0467SYuantian Tang 		/*
1277cc61ab9bSYuantian Tang 		 * For platform PLL, there are MAX_PLL_DIV divider clocks.
127836ab0467SYuantian Tang 		 * For core PLL, there are 4 divider clocks at most.
127936ab0467SYuantian Tang 		 */
128036ab0467SYuantian Tang 		if (idx != PLATFORM_PLL && i >= 4)
128136ab0467SYuantian Tang 			break;
128236ab0467SYuantian Tang 
12830dfc86b3SScott Wood 		snprintf(pll->div[i].name, sizeof(pll->div[i].name),
12840dfc86b3SScott Wood 			 "cg-pll%d-div%d", idx, i + 1);
12850dfc86b3SScott Wood 
12860dfc86b3SScott Wood 		clk = clk_register_fixed_factor(NULL,
128780b4ae7aSScott Wood 				pll->div[i].name, input, 0, mult, i + 1);
12880dfc86b3SScott Wood 		if (IS_ERR(clk)) {
12890dfc86b3SScott Wood 			pr_err("%s: %s: register failed %ld\n",
12900dfc86b3SScott Wood 			       __func__, pll->div[i].name, PTR_ERR(clk));
12910dfc86b3SScott Wood 			continue;
129293a17c05STang Yuantian 		}
129393a17c05STang Yuantian 
12940dfc86b3SScott Wood 		pll->div[i].clk = clk;
129545899dc5SYuantian Tang 		ret = clk_register_clkdev(clk, pll->div[i].name, NULL);
129645899dc5SYuantian Tang 		if (ret != 0)
12978f99f5eaSDan Carpenter 			pr_err("%s: %s: register to lookup table failed %d\n",
12988f99f5eaSDan Carpenter 			       __func__, pll->div[i].name, ret);
129945899dc5SYuantian Tang 
13000dfc86b3SScott Wood 	}
13010dfc86b3SScott Wood }
13020dfc86b3SScott Wood 
create_plls(struct clockgen * cg)13030dfc86b3SScott Wood static void __init create_plls(struct clockgen *cg)
13040dfc86b3SScott Wood {
13050dfc86b3SScott Wood 	int i;
13060dfc86b3SScott Wood 
13070dfc86b3SScott Wood 	for (i = 0; i < ARRAY_SIZE(cg->pll); i++)
13080dfc86b3SScott Wood 		create_one_pll(cg, i);
13090dfc86b3SScott Wood }
13100dfc86b3SScott Wood 
legacy_pll_init(struct device_node * np,int idx)13110dfc86b3SScott Wood static void __init legacy_pll_init(struct device_node *np, int idx)
13120dfc86b3SScott Wood {
13130dfc86b3SScott Wood 	struct clockgen_pll *pll;
13140dfc86b3SScott Wood 	struct clk_onecell_data *onecell_data;
13150dfc86b3SScott Wood 	struct clk **subclks;
13160dfc86b3SScott Wood 	int count, rc;
13170dfc86b3SScott Wood 
13180dfc86b3SScott Wood 	legacy_init_clockgen(np);
13190dfc86b3SScott Wood 
13200dfc86b3SScott Wood 	pll = &clockgen.pll[idx];
132193a17c05STang Yuantian 	count = of_property_count_strings(np, "clock-output-names");
132293a17c05STang Yuantian 
13230dfc86b3SScott Wood 	BUILD_BUG_ON(ARRAY_SIZE(pll->div) < 4);
13240dfc86b3SScott Wood 	subclks = kcalloc(4, sizeof(struct clk *), GFP_KERNEL);
13258002cab6SEmil Medve 	if (!subclks)
13260dfc86b3SScott Wood 		return;
132793a17c05STang Yuantian 
13286ef1ccacSEmil Medve 	onecell_data = kmalloc(sizeof(*onecell_data), GFP_KERNEL);
13298002cab6SEmil Medve 	if (!onecell_data)
133093a17c05STang Yuantian 		goto err_clks;
133193a17c05STang Yuantian 
13320dfc86b3SScott Wood 	if (count <= 3) {
13330dfc86b3SScott Wood 		subclks[0] = pll->div[0].clk;
13340dfc86b3SScott Wood 		subclks[1] = pll->div[1].clk;
13350dfc86b3SScott Wood 		subclks[2] = pll->div[3].clk;
13360dfc86b3SScott Wood 	} else {
13370dfc86b3SScott Wood 		subclks[0] = pll->div[0].clk;
13380dfc86b3SScott Wood 		subclks[1] = pll->div[1].clk;
13390dfc86b3SScott Wood 		subclks[2] = pll->div[2].clk;
13400dfc86b3SScott Wood 		subclks[3] = pll->div[3].clk;
134193a17c05STang Yuantian 	}
134293a17c05STang Yuantian 
134393a17c05STang Yuantian 	onecell_data->clks = subclks;
134493a17c05STang Yuantian 	onecell_data->clk_num = count;
134593a17c05STang Yuantian 
134693a17c05STang Yuantian 	rc = of_clk_add_provider(np, of_clk_src_onecell_get, onecell_data);
134793a17c05STang Yuantian 	if (rc) {
1348e665f029SRob Herring 		pr_err("%s: Couldn't register clk provider for node %pOFn: %d\n",
1349e665f029SRob Herring 		       __func__, np, rc);
135093a17c05STang Yuantian 		goto err_cell;
135193a17c05STang Yuantian 	}
135293a17c05STang Yuantian 
135393a17c05STang Yuantian 	return;
135493a17c05STang Yuantian err_cell:
135593a17c05STang Yuantian 	kfree(onecell_data);
135693a17c05STang Yuantian err_clks:
135793a17c05STang Yuantian 	kfree(subclks);
135893a17c05STang Yuantian }
135993a17c05STang Yuantian 
13600dfc86b3SScott Wood /* Legacy node */
pltfrm_pll_init(struct device_node * np)1361a513b72cSEmil Medve static void __init pltfrm_pll_init(struct device_node *np)
1362a513b72cSEmil Medve {
13630dfc86b3SScott Wood 	legacy_pll_init(np, PLATFORM_PLL);
13640dfc86b3SScott Wood }
1365a513b72cSEmil Medve 
13660dfc86b3SScott Wood /* Legacy node */
core_pll_init(struct device_node * np)13670dfc86b3SScott Wood static void __init core_pll_init(struct device_node *np)
13680dfc86b3SScott Wood {
13690dfc86b3SScott Wood 	struct resource res;
13700dfc86b3SScott Wood 	int idx;
13710dfc86b3SScott Wood 
13720dfc86b3SScott Wood 	if (of_address_to_resource(np, 0, &res))
13730dfc86b3SScott Wood 		return;
13740dfc86b3SScott Wood 
13750dfc86b3SScott Wood 	if ((res.start & 0xfff) == 0xc00) {
13760dfc86b3SScott Wood 		/*
13770dfc86b3SScott Wood 		 * ls1021a devtree labels the platform PLL
13780dfc86b3SScott Wood 		 * with the core PLL compatible
13790dfc86b3SScott Wood 		 */
13800dfc86b3SScott Wood 		pltfrm_pll_init(np);
13810dfc86b3SScott Wood 	} else {
13820dfc86b3SScott Wood 		idx = (res.start & 0xf0) >> 5;
13830dfc86b3SScott Wood 		legacy_pll_init(np, CGA_PLL1 + idx);
13840dfc86b3SScott Wood 	}
13850dfc86b3SScott Wood }
13860dfc86b3SScott Wood 
clockgen_clk_get(struct of_phandle_args * clkspec,void * data)13870dfc86b3SScott Wood static struct clk *clockgen_clk_get(struct of_phandle_args *clkspec, void *data)
13880dfc86b3SScott Wood {
13890dfc86b3SScott Wood 	struct clockgen *cg = data;
13900dfc86b3SScott Wood 	struct clk *clk;
13910dfc86b3SScott Wood 	struct clockgen_pll *pll;
13920dfc86b3SScott Wood 	u32 type, idx;
13930dfc86b3SScott Wood 
13940dfc86b3SScott Wood 	if (clkspec->args_count < 2) {
13950dfc86b3SScott Wood 		pr_err("%s: insufficient phandle args\n", __func__);
13960dfc86b3SScott Wood 		return ERR_PTR(-EINVAL);
13970dfc86b3SScott Wood 	}
13980dfc86b3SScott Wood 
13990dfc86b3SScott Wood 	type = clkspec->args[0];
14000dfc86b3SScott Wood 	idx = clkspec->args[1];
14010dfc86b3SScott Wood 
14020dfc86b3SScott Wood 	switch (type) {
14034cb15934SMichael Walle 	case QORIQ_CLK_SYSCLK:
14040dfc86b3SScott Wood 		if (idx != 0)
14050dfc86b3SScott Wood 			goto bad_args;
14060dfc86b3SScott Wood 		clk = cg->sysclk;
14070dfc86b3SScott Wood 		break;
14084cb15934SMichael Walle 	case QORIQ_CLK_CMUX:
14090dfc86b3SScott Wood 		if (idx >= ARRAY_SIZE(cg->cmux))
14100dfc86b3SScott Wood 			goto bad_args;
14110dfc86b3SScott Wood 		clk = cg->cmux[idx];
14120dfc86b3SScott Wood 		break;
14134cb15934SMichael Walle 	case QORIQ_CLK_HWACCEL:
14140dfc86b3SScott Wood 		if (idx >= ARRAY_SIZE(cg->hwaccel))
14150dfc86b3SScott Wood 			goto bad_args;
14160dfc86b3SScott Wood 		clk = cg->hwaccel[idx];
14170dfc86b3SScott Wood 		break;
14184cb15934SMichael Walle 	case QORIQ_CLK_FMAN:
14190dfc86b3SScott Wood 		if (idx >= ARRAY_SIZE(cg->fman))
14200dfc86b3SScott Wood 			goto bad_args;
14210dfc86b3SScott Wood 		clk = cg->fman[idx];
14220dfc86b3SScott Wood 		break;
14234cb15934SMichael Walle 	case QORIQ_CLK_PLATFORM_PLL:
14240dfc86b3SScott Wood 		pll = &cg->pll[PLATFORM_PLL];
14250dfc86b3SScott Wood 		if (idx >= ARRAY_SIZE(pll->div))
14260dfc86b3SScott Wood 			goto bad_args;
14270dfc86b3SScott Wood 		clk = pll->div[idx].clk;
14280dfc86b3SScott Wood 		break;
14294cb15934SMichael Walle 	case QORIQ_CLK_CORECLK:
143080b4ae7aSScott Wood 		if (idx != 0)
143180b4ae7aSScott Wood 			goto bad_args;
143280b4ae7aSScott Wood 		clk = cg->coreclk;
143380b4ae7aSScott Wood 		if (IS_ERR(clk))
143480b4ae7aSScott Wood 			clk = NULL;
143580b4ae7aSScott Wood 		break;
14360dfc86b3SScott Wood 	default:
14370dfc86b3SScott Wood 		goto bad_args;
14380dfc86b3SScott Wood 	}
14390dfc86b3SScott Wood 
14400dfc86b3SScott Wood 	if (!clk)
14410dfc86b3SScott Wood 		return ERR_PTR(-ENOENT);
14420dfc86b3SScott Wood 	return clk;
14430dfc86b3SScott Wood 
14440dfc86b3SScott Wood bad_args:
14450dfc86b3SScott Wood 	pr_err("%s: Bad phandle args %u %u\n", __func__, type, idx);
14460dfc86b3SScott Wood 	return ERR_PTR(-EINVAL);
14470dfc86b3SScott Wood }
14480dfc86b3SScott Wood 
14490dfc86b3SScott Wood #ifdef CONFIG_PPC
14500dfc86b3SScott Wood #include <asm/mpc85xx.h>
14510dfc86b3SScott Wood 
14520dfc86b3SScott Wood static const u32 a4510_svrs[] __initconst = {
14530dfc86b3SScott Wood 	(SVR_P2040 << 8) | 0x10,	/* P2040 1.0 */
14540dfc86b3SScott Wood 	(SVR_P2040 << 8) | 0x11,	/* P2040 1.1 */
14550dfc86b3SScott Wood 	(SVR_P2041 << 8) | 0x10,	/* P2041 1.0 */
14560dfc86b3SScott Wood 	(SVR_P2041 << 8) | 0x11,	/* P2041 1.1 */
14570dfc86b3SScott Wood 	(SVR_P3041 << 8) | 0x10,	/* P3041 1.0 */
14580dfc86b3SScott Wood 	(SVR_P3041 << 8) | 0x11,	/* P3041 1.1 */
14590dfc86b3SScott Wood 	(SVR_P4040 << 8) | 0x20,	/* P4040 2.0 */
14600dfc86b3SScott Wood 	(SVR_P4080 << 8) | 0x20,	/* P4080 2.0 */
14610dfc86b3SScott Wood 	(SVR_P5010 << 8) | 0x10,	/* P5010 1.0 */
14620dfc86b3SScott Wood 	(SVR_P5010 << 8) | 0x20,	/* P5010 2.0 */
14630dfc86b3SScott Wood 	(SVR_P5020 << 8) | 0x10,	/* P5020 1.0 */
14640dfc86b3SScott Wood 	(SVR_P5021 << 8) | 0x10,	/* P5021 1.0 */
14650dfc86b3SScott Wood 	(SVR_P5040 << 8) | 0x10,	/* P5040 1.0 */
14660dfc86b3SScott Wood };
14670dfc86b3SScott Wood 
14680dfc86b3SScott Wood #define SVR_SECURITY	0x80000	/* The Security (E) bit */
14690dfc86b3SScott Wood 
has_erratum_a4510(void)14700dfc86b3SScott Wood static bool __init has_erratum_a4510(void)
14710dfc86b3SScott Wood {
14720dfc86b3SScott Wood 	u32 svr = mfspr(SPRN_SVR);
14730dfc86b3SScott Wood 	int i;
14740dfc86b3SScott Wood 
14750dfc86b3SScott Wood 	svr &= ~SVR_SECURITY;
14760dfc86b3SScott Wood 
14770dfc86b3SScott Wood 	for (i = 0; i < ARRAY_SIZE(a4510_svrs); i++) {
14780dfc86b3SScott Wood 		if (svr == a4510_svrs[i])
14790dfc86b3SScott Wood 			return true;
14800dfc86b3SScott Wood 	}
14810dfc86b3SScott Wood 
14820dfc86b3SScott Wood 	return false;
14830dfc86b3SScott Wood }
14840dfc86b3SScott Wood #else
has_erratum_a4510(void)14850dfc86b3SScott Wood static bool __init has_erratum_a4510(void)
14860dfc86b3SScott Wood {
14870dfc86b3SScott Wood 	return false;
14880dfc86b3SScott Wood }
14890dfc86b3SScott Wood #endif
14900dfc86b3SScott Wood 
_clockgen_init(struct device_node * np,bool legacy)1491cf1e0449SMian Yousaf Kaukab static void __init _clockgen_init(struct device_node *np, bool legacy)
14920dfc86b3SScott Wood {
14930dfc86b3SScott Wood 	int i, ret;
14940dfc86b3SScott Wood 	bool is_old_ls1021a = false;
14950dfc86b3SScott Wood 
14960dfc86b3SScott Wood 	/* May have already been called by a legacy probe */
14970dfc86b3SScott Wood 	if (clockgen.node)
14980dfc86b3SScott Wood 		return;
14990dfc86b3SScott Wood 
15000dfc86b3SScott Wood 	clockgen.node = np;
15010dfc86b3SScott Wood 	clockgen.regs = of_iomap(np, 0);
15020dfc86b3SScott Wood 	if (!clockgen.regs &&
15030dfc86b3SScott Wood 	    of_device_is_compatible(of_root, "fsl,ls1021a")) {
15040dfc86b3SScott Wood 		/* Compatibility hack for old, broken device trees */
15050dfc86b3SScott Wood 		clockgen.regs = ioremap(0x1ee1000, 0x1000);
15060dfc86b3SScott Wood 		is_old_ls1021a = true;
15070dfc86b3SScott Wood 	}
15080dfc86b3SScott Wood 	if (!clockgen.regs) {
1509e665f029SRob Herring 		pr_err("%s(): %pOFn: of_iomap() failed\n", __func__, np);
1510a513b72cSEmil Medve 		return;
1511a513b72cSEmil Medve 	}
1512a513b72cSEmil Medve 
15130dfc86b3SScott Wood 	for (i = 0; i < ARRAY_SIZE(chipinfo); i++) {
15140dfc86b3SScott Wood 		if (of_device_is_compatible(np, chipinfo[i].compat))
15150dfc86b3SScott Wood 			break;
15160dfc86b3SScott Wood 		if (is_old_ls1021a &&
15170dfc86b3SScott Wood 		    !strcmp(chipinfo[i].compat, "fsl,ls1021a-clockgen"))
15180dfc86b3SScott Wood 			break;
1519a513b72cSEmil Medve 	}
1520a513b72cSEmil Medve 
15210dfc86b3SScott Wood 	if (i == ARRAY_SIZE(chipinfo)) {
152216673931SRob Herring 		pr_err("%s: unknown clockgen node %pOF\n", __func__, np);
15230dfc86b3SScott Wood 		goto err;
1524a513b72cSEmil Medve 	}
15250dfc86b3SScott Wood 	clockgen.info = chipinfo[i];
1526a513b72cSEmil Medve 
15270dfc86b3SScott Wood 	if (clockgen.info.guts_compat) {
15280dfc86b3SScott Wood 		struct device_node *guts;
1529a513b72cSEmil Medve 
15300dfc86b3SScott Wood 		guts = of_find_compatible_node(NULL, NULL,
15310dfc86b3SScott Wood 					       clockgen.info.guts_compat);
15320dfc86b3SScott Wood 		if (guts) {
15330dfc86b3SScott Wood 			clockgen.guts = of_iomap(guts, 0);
15340dfc86b3SScott Wood 			if (!clockgen.guts) {
153516673931SRob Herring 				pr_err("%s: Couldn't map %pOF regs\n", __func__,
153616673931SRob Herring 				       guts);
1537a513b72cSEmil Medve 			}
153870af6c5bSYangtao Li 			of_node_put(guts);
1539a513b72cSEmil Medve 		}
1540a513b72cSEmil Medve 
15410dfc86b3SScott Wood 	}
15420dfc86b3SScott Wood 
15430dfc86b3SScott Wood 	if (has_erratum_a4510())
15440dfc86b3SScott Wood 		clockgen.info.flags |= CG_CMUX_GE_PLAT;
15450dfc86b3SScott Wood 
15460dfc86b3SScott Wood 	clockgen.sysclk = create_sysclk("cg-sysclk");
154780b4ae7aSScott Wood 	clockgen.coreclk = create_coreclk("cg-coreclk");
15480dfc86b3SScott Wood 	create_plls(&clockgen);
15490dfc86b3SScott Wood 	create_muxes(&clockgen);
15500dfc86b3SScott Wood 
15510dfc86b3SScott Wood 	if (clockgen.info.init_periph)
15520dfc86b3SScott Wood 		clockgen.info.init_periph(&clockgen);
15530dfc86b3SScott Wood 
15540dfc86b3SScott Wood 	ret = of_clk_add_provider(np, clockgen_clk_get, &clockgen);
15550dfc86b3SScott Wood 	if (ret) {
1556e665f029SRob Herring 		pr_err("%s: Couldn't register clk provider for node %pOFn: %d\n",
1557e665f029SRob Herring 		       __func__, np, ret);
1558a513b72cSEmil Medve 	}
1559a513b72cSEmil Medve 
1560cf1e0449SMian Yousaf Kaukab 	/* Don't create cpufreq device for legacy clockgen blocks */
1561cf1e0449SMian Yousaf Kaukab 	add_cpufreq_dev = !legacy;
1562cf1e0449SMian Yousaf Kaukab 
1563a513b72cSEmil Medve 	return;
15640dfc86b3SScott Wood err:
15650dfc86b3SScott Wood 	iounmap(clockgen.regs);
15660dfc86b3SScott Wood 	clockgen.regs = NULL;
1567a513b72cSEmil Medve }
1568a513b72cSEmil Medve 
clockgen_init(struct device_node * np)1569cf1e0449SMian Yousaf Kaukab static void __init clockgen_init(struct device_node *np)
1570cf1e0449SMian Yousaf Kaukab {
1571cf1e0449SMian Yousaf Kaukab 	_clockgen_init(np, false);
1572cf1e0449SMian Yousaf Kaukab }
1573cf1e0449SMian Yousaf Kaukab 
clockgen_cpufreq_init(void)1574cf1e0449SMian Yousaf Kaukab static int __init clockgen_cpufreq_init(void)
1575cf1e0449SMian Yousaf Kaukab {
1576cf1e0449SMian Yousaf Kaukab 	struct platform_device *pdev;
1577cf1e0449SMian Yousaf Kaukab 
1578cf1e0449SMian Yousaf Kaukab 	if (add_cpufreq_dev) {
1579cf1e0449SMian Yousaf Kaukab 		pdev = platform_device_register_simple("qoriq-cpufreq", -1,
1580cf1e0449SMian Yousaf Kaukab 				NULL, 0);
1581cf1e0449SMian Yousaf Kaukab 		if (IS_ERR(pdev))
1582cf1e0449SMian Yousaf Kaukab 			pr_err("Couldn't register qoriq-cpufreq err=%ld\n",
1583cf1e0449SMian Yousaf Kaukab 				PTR_ERR(pdev));
1584cf1e0449SMian Yousaf Kaukab 	}
1585cf1e0449SMian Yousaf Kaukab 	return 0;
1586cf1e0449SMian Yousaf Kaukab }
1587cf1e0449SMian Yousaf Kaukab device_initcall(clockgen_cpufreq_init);
1588cf1e0449SMian Yousaf Kaukab 
15890dfc86b3SScott Wood CLK_OF_DECLARE(qoriq_clockgen_1, "fsl,qoriq-clockgen-1.0", clockgen_init);
15900dfc86b3SScott Wood CLK_OF_DECLARE(qoriq_clockgen_2, "fsl,qoriq-clockgen-2.0", clockgen_init);
1591b8b211caSYuantian Tang CLK_OF_DECLARE(qoriq_clockgen_b4420, "fsl,b4420-clockgen", clockgen_init);
1592b8b211caSYuantian Tang CLK_OF_DECLARE(qoriq_clockgen_b4860, "fsl,b4860-clockgen", clockgen_init);
159344709358STang Yuantian CLK_OF_DECLARE(qoriq_clockgen_ls1012a, "fsl,ls1012a-clockgen", clockgen_init);
15940dfc86b3SScott Wood CLK_OF_DECLARE(qoriq_clockgen_ls1021a, "fsl,ls1021a-clockgen", clockgen_init);
159595089f6aSYuantian Tang CLK_OF_DECLARE(qoriq_clockgen_ls1028a, "fsl,ls1028a-clockgen", clockgen_init);
1596e994412cSHou Zhiqiang CLK_OF_DECLARE(qoriq_clockgen_ls1043a, "fsl,ls1043a-clockgen", clockgen_init);
159780e52198SMingkai Hu CLK_OF_DECLARE(qoriq_clockgen_ls1046a, "fsl,ls1046a-clockgen", clockgen_init);
1598e0c888c4SYuantian Tang CLK_OF_DECLARE(qoriq_clockgen_ls1088a, "fsl,ls1088a-clockgen", clockgen_init);
15999e19ca2fSScott Wood CLK_OF_DECLARE(qoriq_clockgen_ls2080a, "fsl,ls2080a-clockgen", clockgen_init);
160078a5ba8fSVabhav Sharma CLK_OF_DECLARE(qoriq_clockgen_lx2160a, "fsl,lx2160a-clockgen", clockgen_init);
1601b8b211caSYuantian Tang CLK_OF_DECLARE(qoriq_clockgen_p2041, "fsl,p2041-clockgen", clockgen_init);
1602b8b211caSYuantian Tang CLK_OF_DECLARE(qoriq_clockgen_p3041, "fsl,p3041-clockgen", clockgen_init);
1603b8b211caSYuantian Tang CLK_OF_DECLARE(qoriq_clockgen_p4080, "fsl,p4080-clockgen", clockgen_init);
1604b8b211caSYuantian Tang CLK_OF_DECLARE(qoriq_clockgen_p5020, "fsl,p5020-clockgen", clockgen_init);
1605b8b211caSYuantian Tang CLK_OF_DECLARE(qoriq_clockgen_p5040, "fsl,p5040-clockgen", clockgen_init);
1606b8b211caSYuantian Tang CLK_OF_DECLARE(qoriq_clockgen_t1023, "fsl,t1023-clockgen", clockgen_init);
1607b8b211caSYuantian Tang CLK_OF_DECLARE(qoriq_clockgen_t1040, "fsl,t1040-clockgen", clockgen_init);
1608b8b211caSYuantian Tang CLK_OF_DECLARE(qoriq_clockgen_t2080, "fsl,t2080-clockgen", clockgen_init);
1609b8b211caSYuantian Tang CLK_OF_DECLARE(qoriq_clockgen_t4240, "fsl,t4240-clockgen", clockgen_init);
16100dfc86b3SScott Wood 
16110dfc86b3SScott Wood /* Legacy nodes */
161293a17c05STang Yuantian CLK_OF_DECLARE(qoriq_sysclk_1, "fsl,qoriq-sysclk-1.0", sysclk_init);
161393a17c05STang Yuantian CLK_OF_DECLARE(qoriq_sysclk_2, "fsl,qoriq-sysclk-2.0", sysclk_init);
161493a17c05STang Yuantian CLK_OF_DECLARE(qoriq_core_pll_1, "fsl,qoriq-core-pll-1.0", core_pll_init);
161593a17c05STang Yuantian CLK_OF_DECLARE(qoriq_core_pll_2, "fsl,qoriq-core-pll-2.0", core_pll_init);
161693a17c05STang Yuantian CLK_OF_DECLARE(qoriq_core_mux_1, "fsl,qoriq-core-mux-1.0", core_mux_init);
161793a17c05STang Yuantian CLK_OF_DECLARE(qoriq_core_mux_2, "fsl,qoriq-core-mux-2.0", core_mux_init);
1618a513b72cSEmil Medve CLK_OF_DECLARE(qoriq_pltfrm_pll_1, "fsl,qoriq-platform-pll-1.0", pltfrm_pll_init);
1619a513b72cSEmil Medve CLK_OF_DECLARE(qoriq_pltfrm_pll_2, "fsl,qoriq-platform-pll-2.0", pltfrm_pll_init);
1620