162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * Copyright (C) 2013 DENX Software Engineering
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * Gerhard Sittig, <gsi@denx.de>
662306a36Sopenharmony_ci *
762306a36Sopenharmony_ci * common clock driver support for the MPC512x platform
862306a36Sopenharmony_ci */
962306a36Sopenharmony_ci
1062306a36Sopenharmony_ci#include <linux/bitops.h>
1162306a36Sopenharmony_ci#include <linux/clk.h>
1262306a36Sopenharmony_ci#include <linux/clk-provider.h>
1362306a36Sopenharmony_ci#include <linux/clkdev.h>
1462306a36Sopenharmony_ci#include <linux/device.h>
1562306a36Sopenharmony_ci#include <linux/errno.h>
1662306a36Sopenharmony_ci#include <linux/io.h>
1762306a36Sopenharmony_ci#include <linux/of.h>
1862306a36Sopenharmony_ci#include <linux/of_address.h>
1962306a36Sopenharmony_ci
2062306a36Sopenharmony_ci#include <asm/mpc5121.h>
2162306a36Sopenharmony_ci#include <dt-bindings/clock/mpc512x-clock.h>
2262306a36Sopenharmony_ci
2362306a36Sopenharmony_ci#include "mpc512x.h"		/* our public mpc5121_clk_init() API */
2462306a36Sopenharmony_ci
2562306a36Sopenharmony_ci/* helpers to keep the MCLK intermediates "somewhere" in our table */
2662306a36Sopenharmony_cienum {
2762306a36Sopenharmony_ci	MCLK_IDX_MUX0,
2862306a36Sopenharmony_ci	MCLK_IDX_EN0,
2962306a36Sopenharmony_ci	MCLK_IDX_DIV0,
3062306a36Sopenharmony_ci	MCLK_MAX_IDX,
3162306a36Sopenharmony_ci};
3262306a36Sopenharmony_ci
3362306a36Sopenharmony_ci#define NR_PSCS			12
3462306a36Sopenharmony_ci#define NR_MSCANS		4
3562306a36Sopenharmony_ci#define NR_SPDIFS		1
3662306a36Sopenharmony_ci#define NR_OUTCLK		4
3762306a36Sopenharmony_ci#define NR_MCLKS		(NR_PSCS + NR_MSCANS + NR_SPDIFS + NR_OUTCLK)
3862306a36Sopenharmony_ci
3962306a36Sopenharmony_ci/* extend the public set of clocks by adding internal slots for management */
4062306a36Sopenharmony_cienum {
4162306a36Sopenharmony_ci	/* arrange for adjacent numbers after the public set */
4262306a36Sopenharmony_ci	MPC512x_CLK_START_PRIVATE = MPC512x_CLK_LAST_PUBLIC,
4362306a36Sopenharmony_ci	/* clocks which aren't announced to the public */
4462306a36Sopenharmony_ci	MPC512x_CLK_DDR,
4562306a36Sopenharmony_ci	MPC512x_CLK_MEM,
4662306a36Sopenharmony_ci	MPC512x_CLK_IIM,
4762306a36Sopenharmony_ci	/* intermediates in div+gate combos or fractional dividers */
4862306a36Sopenharmony_ci	MPC512x_CLK_DDR_UG,
4962306a36Sopenharmony_ci	MPC512x_CLK_SDHC_x4,
5062306a36Sopenharmony_ci	MPC512x_CLK_SDHC_UG,
5162306a36Sopenharmony_ci	MPC512x_CLK_SDHC2_UG,
5262306a36Sopenharmony_ci	MPC512x_CLK_DIU_x4,
5362306a36Sopenharmony_ci	MPC512x_CLK_DIU_UG,
5462306a36Sopenharmony_ci	MPC512x_CLK_MBX_BUS_UG,
5562306a36Sopenharmony_ci	MPC512x_CLK_MBX_UG,
5662306a36Sopenharmony_ci	MPC512x_CLK_MBX_3D_UG,
5762306a36Sopenharmony_ci	MPC512x_CLK_PCI_UG,
5862306a36Sopenharmony_ci	MPC512x_CLK_NFC_UG,
5962306a36Sopenharmony_ci	MPC512x_CLK_LPC_UG,
6062306a36Sopenharmony_ci	MPC512x_CLK_SPDIF_TX_IN,
6162306a36Sopenharmony_ci	/* intermediates for the mux+gate+div+mux MCLK generation */
6262306a36Sopenharmony_ci	MPC512x_CLK_MCLKS_FIRST,
6362306a36Sopenharmony_ci	MPC512x_CLK_MCLKS_LAST = MPC512x_CLK_MCLKS_FIRST
6462306a36Sopenharmony_ci				+ NR_MCLKS * MCLK_MAX_IDX,
6562306a36Sopenharmony_ci	/* internal, symbolic spec for the number of slots */
6662306a36Sopenharmony_ci	MPC512x_CLK_LAST_PRIVATE,
6762306a36Sopenharmony_ci};
6862306a36Sopenharmony_ci
6962306a36Sopenharmony_ci/* data required for the OF clock provider registration */
7062306a36Sopenharmony_cistatic struct clk *clks[MPC512x_CLK_LAST_PRIVATE];
7162306a36Sopenharmony_cistatic struct clk_onecell_data clk_data;
7262306a36Sopenharmony_ci
7362306a36Sopenharmony_ci/* CCM register access */
7462306a36Sopenharmony_cistatic struct mpc512x_ccm __iomem *clkregs;
7562306a36Sopenharmony_cistatic DEFINE_SPINLOCK(clklock);
7662306a36Sopenharmony_ci
7762306a36Sopenharmony_ci/* SoC variants {{{ */
7862306a36Sopenharmony_ci
7962306a36Sopenharmony_ci/*
8062306a36Sopenharmony_ci * tell SoC variants apart as they are rather similar yet not identical,
8162306a36Sopenharmony_ci * cache the result in an enum to not repeatedly run the expensive OF test
8262306a36Sopenharmony_ci *
8362306a36Sopenharmony_ci * MPC5123 is an MPC5121 without the MBX graphics accelerator
8462306a36Sopenharmony_ci *
8562306a36Sopenharmony_ci * MPC5125 has many more differences: no MBX, no AXE, no VIU, no SPDIF,
8662306a36Sopenharmony_ci * no PATA, no SATA, no PCI, two FECs (of different compatibility name),
8762306a36Sopenharmony_ci * only 10 PSCs (of different compatibility name), two SDHCs, different
8862306a36Sopenharmony_ci * NFC IP block, output clocks, system PLL status query, different CPMF
8962306a36Sopenharmony_ci * interpretation, no CFM, different fourth PSC/CAN mux0 input -- yet
9062306a36Sopenharmony_ci * those differences can get folded into this clock provider support
9162306a36Sopenharmony_ci * code and don't warrant a separate highly redundant implementation
9262306a36Sopenharmony_ci */
9362306a36Sopenharmony_ci
9462306a36Sopenharmony_cistatic enum soc_type {
9562306a36Sopenharmony_ci	MPC512x_SOC_MPC5121,
9662306a36Sopenharmony_ci	MPC512x_SOC_MPC5123,
9762306a36Sopenharmony_ci	MPC512x_SOC_MPC5125,
9862306a36Sopenharmony_ci} soc;
9962306a36Sopenharmony_ci
10062306a36Sopenharmony_cistatic void __init mpc512x_clk_determine_soc(void)
10162306a36Sopenharmony_ci{
10262306a36Sopenharmony_ci	if (of_machine_is_compatible("fsl,mpc5121")) {
10362306a36Sopenharmony_ci		soc = MPC512x_SOC_MPC5121;
10462306a36Sopenharmony_ci		return;
10562306a36Sopenharmony_ci	}
10662306a36Sopenharmony_ci	if (of_machine_is_compatible("fsl,mpc5123")) {
10762306a36Sopenharmony_ci		soc = MPC512x_SOC_MPC5123;
10862306a36Sopenharmony_ci		return;
10962306a36Sopenharmony_ci	}
11062306a36Sopenharmony_ci	if (of_machine_is_compatible("fsl,mpc5125")) {
11162306a36Sopenharmony_ci		soc = MPC512x_SOC_MPC5125;
11262306a36Sopenharmony_ci		return;
11362306a36Sopenharmony_ci	}
11462306a36Sopenharmony_ci}
11562306a36Sopenharmony_ci
11662306a36Sopenharmony_cistatic bool __init soc_has_mbx(void)
11762306a36Sopenharmony_ci{
11862306a36Sopenharmony_ci	if (soc == MPC512x_SOC_MPC5121)
11962306a36Sopenharmony_ci		return true;
12062306a36Sopenharmony_ci	return false;
12162306a36Sopenharmony_ci}
12262306a36Sopenharmony_ci
12362306a36Sopenharmony_cistatic bool __init soc_has_axe(void)
12462306a36Sopenharmony_ci{
12562306a36Sopenharmony_ci	if (soc == MPC512x_SOC_MPC5125)
12662306a36Sopenharmony_ci		return false;
12762306a36Sopenharmony_ci	return true;
12862306a36Sopenharmony_ci}
12962306a36Sopenharmony_ci
13062306a36Sopenharmony_cistatic bool __init soc_has_viu(void)
13162306a36Sopenharmony_ci{
13262306a36Sopenharmony_ci	if (soc == MPC512x_SOC_MPC5125)
13362306a36Sopenharmony_ci		return false;
13462306a36Sopenharmony_ci	return true;
13562306a36Sopenharmony_ci}
13662306a36Sopenharmony_ci
13762306a36Sopenharmony_cistatic bool __init soc_has_spdif(void)
13862306a36Sopenharmony_ci{
13962306a36Sopenharmony_ci	if (soc == MPC512x_SOC_MPC5125)
14062306a36Sopenharmony_ci		return false;
14162306a36Sopenharmony_ci	return true;
14262306a36Sopenharmony_ci}
14362306a36Sopenharmony_ci
14462306a36Sopenharmony_cistatic bool __init soc_has_pata(void)
14562306a36Sopenharmony_ci{
14662306a36Sopenharmony_ci	if (soc == MPC512x_SOC_MPC5125)
14762306a36Sopenharmony_ci		return false;
14862306a36Sopenharmony_ci	return true;
14962306a36Sopenharmony_ci}
15062306a36Sopenharmony_ci
15162306a36Sopenharmony_cistatic bool __init soc_has_sata(void)
15262306a36Sopenharmony_ci{
15362306a36Sopenharmony_ci	if (soc == MPC512x_SOC_MPC5125)
15462306a36Sopenharmony_ci		return false;
15562306a36Sopenharmony_ci	return true;
15662306a36Sopenharmony_ci}
15762306a36Sopenharmony_ci
15862306a36Sopenharmony_cistatic bool __init soc_has_pci(void)
15962306a36Sopenharmony_ci{
16062306a36Sopenharmony_ci	if (soc == MPC512x_SOC_MPC5125)
16162306a36Sopenharmony_ci		return false;
16262306a36Sopenharmony_ci	return true;
16362306a36Sopenharmony_ci}
16462306a36Sopenharmony_ci
16562306a36Sopenharmony_cistatic bool __init soc_has_fec2(void)
16662306a36Sopenharmony_ci{
16762306a36Sopenharmony_ci	if (soc == MPC512x_SOC_MPC5125)
16862306a36Sopenharmony_ci		return true;
16962306a36Sopenharmony_ci	return false;
17062306a36Sopenharmony_ci}
17162306a36Sopenharmony_ci
17262306a36Sopenharmony_cistatic int __init soc_max_pscnum(void)
17362306a36Sopenharmony_ci{
17462306a36Sopenharmony_ci	if (soc == MPC512x_SOC_MPC5125)
17562306a36Sopenharmony_ci		return 10;
17662306a36Sopenharmony_ci	return 12;
17762306a36Sopenharmony_ci}
17862306a36Sopenharmony_ci
17962306a36Sopenharmony_cistatic bool __init soc_has_sdhc2(void)
18062306a36Sopenharmony_ci{
18162306a36Sopenharmony_ci	if (soc == MPC512x_SOC_MPC5125)
18262306a36Sopenharmony_ci		return true;
18362306a36Sopenharmony_ci	return false;
18462306a36Sopenharmony_ci}
18562306a36Sopenharmony_ci
18662306a36Sopenharmony_cistatic bool __init soc_has_nfc_5125(void)
18762306a36Sopenharmony_ci{
18862306a36Sopenharmony_ci	if (soc == MPC512x_SOC_MPC5125)
18962306a36Sopenharmony_ci		return true;
19062306a36Sopenharmony_ci	return false;
19162306a36Sopenharmony_ci}
19262306a36Sopenharmony_ci
19362306a36Sopenharmony_cistatic bool __init soc_has_outclk(void)
19462306a36Sopenharmony_ci{
19562306a36Sopenharmony_ci	if (soc == MPC512x_SOC_MPC5125)
19662306a36Sopenharmony_ci		return true;
19762306a36Sopenharmony_ci	return false;
19862306a36Sopenharmony_ci}
19962306a36Sopenharmony_ci
20062306a36Sopenharmony_cistatic bool __init soc_has_cpmf_0_bypass(void)
20162306a36Sopenharmony_ci{
20262306a36Sopenharmony_ci	if (soc == MPC512x_SOC_MPC5125)
20362306a36Sopenharmony_ci		return true;
20462306a36Sopenharmony_ci	return false;
20562306a36Sopenharmony_ci}
20662306a36Sopenharmony_ci
20762306a36Sopenharmony_cistatic bool __init soc_has_mclk_mux0_canin(void)
20862306a36Sopenharmony_ci{
20962306a36Sopenharmony_ci	if (soc == MPC512x_SOC_MPC5125)
21062306a36Sopenharmony_ci		return true;
21162306a36Sopenharmony_ci	return false;
21262306a36Sopenharmony_ci}
21362306a36Sopenharmony_ci
21462306a36Sopenharmony_ci/* }}} SoC variants */
21562306a36Sopenharmony_ci/* common clk API wrappers {{{ */
21662306a36Sopenharmony_ci
21762306a36Sopenharmony_ci/* convenience wrappers around the common clk API */
21862306a36Sopenharmony_cistatic inline struct clk *mpc512x_clk_fixed(const char *name, int rate)
21962306a36Sopenharmony_ci{
22062306a36Sopenharmony_ci	return clk_register_fixed_rate(NULL, name, NULL, 0, rate);
22162306a36Sopenharmony_ci}
22262306a36Sopenharmony_ci
22362306a36Sopenharmony_cistatic inline struct clk *mpc512x_clk_factor(
22462306a36Sopenharmony_ci	const char *name, const char *parent_name,
22562306a36Sopenharmony_ci	int mul, int div)
22662306a36Sopenharmony_ci{
22762306a36Sopenharmony_ci	int clkflags;
22862306a36Sopenharmony_ci
22962306a36Sopenharmony_ci	clkflags = CLK_SET_RATE_PARENT;
23062306a36Sopenharmony_ci	return clk_register_fixed_factor(NULL, name, parent_name, clkflags,
23162306a36Sopenharmony_ci					 mul, div);
23262306a36Sopenharmony_ci}
23362306a36Sopenharmony_ci
23462306a36Sopenharmony_cistatic inline struct clk *mpc512x_clk_divider(
23562306a36Sopenharmony_ci	const char *name, const char *parent_name, u8 clkflags,
23662306a36Sopenharmony_ci	u32 __iomem *reg, u8 pos, u8 len, int divflags)
23762306a36Sopenharmony_ci{
23862306a36Sopenharmony_ci	divflags |= CLK_DIVIDER_BIG_ENDIAN;
23962306a36Sopenharmony_ci	return clk_register_divider(NULL, name, parent_name, clkflags,
24062306a36Sopenharmony_ci				    reg, pos, len, divflags, &clklock);
24162306a36Sopenharmony_ci}
24262306a36Sopenharmony_ci
24362306a36Sopenharmony_cistatic inline struct clk *mpc512x_clk_divtable(
24462306a36Sopenharmony_ci	const char *name, const char *parent_name,
24562306a36Sopenharmony_ci	u32 __iomem *reg, u8 pos, u8 len,
24662306a36Sopenharmony_ci	const struct clk_div_table *divtab)
24762306a36Sopenharmony_ci{
24862306a36Sopenharmony_ci	u8 divflags;
24962306a36Sopenharmony_ci
25062306a36Sopenharmony_ci	divflags = CLK_DIVIDER_BIG_ENDIAN;
25162306a36Sopenharmony_ci	return clk_register_divider_table(NULL, name, parent_name, 0,
25262306a36Sopenharmony_ci					  reg, pos, len, divflags,
25362306a36Sopenharmony_ci					  divtab, &clklock);
25462306a36Sopenharmony_ci}
25562306a36Sopenharmony_ci
25662306a36Sopenharmony_cistatic inline struct clk *mpc512x_clk_gated(
25762306a36Sopenharmony_ci	const char *name, const char *parent_name,
25862306a36Sopenharmony_ci	u32 __iomem *reg, u8 pos)
25962306a36Sopenharmony_ci{
26062306a36Sopenharmony_ci	int clkflags;
26162306a36Sopenharmony_ci	u8 gateflags;
26262306a36Sopenharmony_ci
26362306a36Sopenharmony_ci	clkflags = CLK_SET_RATE_PARENT;
26462306a36Sopenharmony_ci	gateflags = CLK_GATE_BIG_ENDIAN;
26562306a36Sopenharmony_ci	return clk_register_gate(NULL, name, parent_name, clkflags,
26662306a36Sopenharmony_ci				 reg, pos, gateflags, &clklock);
26762306a36Sopenharmony_ci}
26862306a36Sopenharmony_ci
26962306a36Sopenharmony_cistatic inline struct clk *mpc512x_clk_muxed(const char *name,
27062306a36Sopenharmony_ci	const char **parent_names, int parent_count,
27162306a36Sopenharmony_ci	u32 __iomem *reg, u8 pos, u8 len)
27262306a36Sopenharmony_ci{
27362306a36Sopenharmony_ci	int clkflags;
27462306a36Sopenharmony_ci	u8 muxflags;
27562306a36Sopenharmony_ci
27662306a36Sopenharmony_ci	clkflags = CLK_SET_RATE_PARENT;
27762306a36Sopenharmony_ci	muxflags = CLK_MUX_BIG_ENDIAN;
27862306a36Sopenharmony_ci	return clk_register_mux(NULL, name,
27962306a36Sopenharmony_ci				parent_names, parent_count, clkflags,
28062306a36Sopenharmony_ci				reg, pos, len, muxflags, &clklock);
28162306a36Sopenharmony_ci}
28262306a36Sopenharmony_ci
28362306a36Sopenharmony_ci/* }}} common clk API wrappers */
28462306a36Sopenharmony_ci
28562306a36Sopenharmony_ci/* helper to isolate a bit field from a register */
28662306a36Sopenharmony_cistatic inline int get_bit_field(uint32_t __iomem *reg, uint8_t pos, uint8_t len)
28762306a36Sopenharmony_ci{
28862306a36Sopenharmony_ci	uint32_t val;
28962306a36Sopenharmony_ci
29062306a36Sopenharmony_ci	val = in_be32(reg);
29162306a36Sopenharmony_ci	val >>= pos;
29262306a36Sopenharmony_ci	val &= (1 << len) - 1;
29362306a36Sopenharmony_ci	return val;
29462306a36Sopenharmony_ci}
29562306a36Sopenharmony_ci
29662306a36Sopenharmony_ci/* get the SPMF and translate it into the "sys pll" multiplier */
29762306a36Sopenharmony_cistatic int __init get_spmf_mult(void)
29862306a36Sopenharmony_ci{
29962306a36Sopenharmony_ci	static int spmf_to_mult[] = {
30062306a36Sopenharmony_ci		68, 1, 12, 16, 20, 24, 28, 32,
30162306a36Sopenharmony_ci		36, 40, 44, 48, 52, 56, 60, 64,
30262306a36Sopenharmony_ci	};
30362306a36Sopenharmony_ci	int spmf;
30462306a36Sopenharmony_ci
30562306a36Sopenharmony_ci	spmf = get_bit_field(&clkregs->spmr, 24, 4);
30662306a36Sopenharmony_ci	return spmf_to_mult[spmf];
30762306a36Sopenharmony_ci}
30862306a36Sopenharmony_ci
30962306a36Sopenharmony_ci/*
31062306a36Sopenharmony_ci * get the SYS_DIV value and translate it into a divide factor
31162306a36Sopenharmony_ci *
31262306a36Sopenharmony_ci * values returned from here are a multiple of the real factor since the
31362306a36Sopenharmony_ci * divide ratio is fractional
31462306a36Sopenharmony_ci */
31562306a36Sopenharmony_cistatic int __init get_sys_div_x2(void)
31662306a36Sopenharmony_ci{
31762306a36Sopenharmony_ci	static int sysdiv_code_to_x2[] = {
31862306a36Sopenharmony_ci		4, 5, 6, 7, 8, 9, 10, 14,
31962306a36Sopenharmony_ci		12, 16, 18, 22, 20, 24, 26, 30,
32062306a36Sopenharmony_ci		28, 32, 34, 38, 36, 40, 42, 46,
32162306a36Sopenharmony_ci		44, 48, 50, 54, 52, 56, 58, 62,
32262306a36Sopenharmony_ci		60, 64, 66,
32362306a36Sopenharmony_ci	};
32462306a36Sopenharmony_ci	int divcode;
32562306a36Sopenharmony_ci
32662306a36Sopenharmony_ci	divcode = get_bit_field(&clkregs->scfr2, 26, 6);
32762306a36Sopenharmony_ci	return sysdiv_code_to_x2[divcode];
32862306a36Sopenharmony_ci}
32962306a36Sopenharmony_ci
33062306a36Sopenharmony_ci/*
33162306a36Sopenharmony_ci * get the CPMF value and translate it into a multiplier factor
33262306a36Sopenharmony_ci *
33362306a36Sopenharmony_ci * values returned from here are a multiple of the real factor since the
33462306a36Sopenharmony_ci * multiplier ratio is fractional
33562306a36Sopenharmony_ci */
33662306a36Sopenharmony_cistatic int __init get_cpmf_mult_x2(void)
33762306a36Sopenharmony_ci{
33862306a36Sopenharmony_ci	static int cpmf_to_mult_x36[] = {
33962306a36Sopenharmony_ci		/* 0b000 is "times 36" */
34062306a36Sopenharmony_ci		72, 2, 2, 3, 4, 5, 6, 7,
34162306a36Sopenharmony_ci	};
34262306a36Sopenharmony_ci	static int cpmf_to_mult_0by[] = {
34362306a36Sopenharmony_ci		/* 0b000 is "bypass" */
34462306a36Sopenharmony_ci		2, 2, 2, 3, 4, 5, 6, 7,
34562306a36Sopenharmony_ci	};
34662306a36Sopenharmony_ci
34762306a36Sopenharmony_ci	int *cpmf_to_mult;
34862306a36Sopenharmony_ci	int cpmf;
34962306a36Sopenharmony_ci
35062306a36Sopenharmony_ci	cpmf = get_bit_field(&clkregs->spmr, 16, 4);
35162306a36Sopenharmony_ci	if (soc_has_cpmf_0_bypass())
35262306a36Sopenharmony_ci		cpmf_to_mult = cpmf_to_mult_0by;
35362306a36Sopenharmony_ci	else
35462306a36Sopenharmony_ci		cpmf_to_mult = cpmf_to_mult_x36;
35562306a36Sopenharmony_ci	return cpmf_to_mult[cpmf];
35662306a36Sopenharmony_ci}
35762306a36Sopenharmony_ci
35862306a36Sopenharmony_ci/*
35962306a36Sopenharmony_ci * some of the clock dividers do scale in a linear way, yet not all of
36062306a36Sopenharmony_ci * their bit combinations are legal; use a divider table to get a
36162306a36Sopenharmony_ci * resulting set of applicable divider values
36262306a36Sopenharmony_ci */
36362306a36Sopenharmony_ci
36462306a36Sopenharmony_ci/* applies to the IPS_DIV, and PCI_DIV values */
36562306a36Sopenharmony_cistatic const struct clk_div_table divtab_2346[] = {
36662306a36Sopenharmony_ci	{ .val = 2, .div = 2, },
36762306a36Sopenharmony_ci	{ .val = 3, .div = 3, },
36862306a36Sopenharmony_ci	{ .val = 4, .div = 4, },
36962306a36Sopenharmony_ci	{ .val = 6, .div = 6, },
37062306a36Sopenharmony_ci	{ .div = 0, },
37162306a36Sopenharmony_ci};
37262306a36Sopenharmony_ci
37362306a36Sopenharmony_ci/* applies to the MBX_DIV, LPC_DIV, and NFC_DIV values */
37462306a36Sopenharmony_cistatic const struct clk_div_table divtab_1234[] = {
37562306a36Sopenharmony_ci	{ .val = 1, .div = 1, },
37662306a36Sopenharmony_ci	{ .val = 2, .div = 2, },
37762306a36Sopenharmony_ci	{ .val = 3, .div = 3, },
37862306a36Sopenharmony_ci	{ .val = 4, .div = 4, },
37962306a36Sopenharmony_ci	{ .div = 0, },
38062306a36Sopenharmony_ci};
38162306a36Sopenharmony_ci
38262306a36Sopenharmony_cistatic int __init get_freq_from_dt(char *propname)
38362306a36Sopenharmony_ci{
38462306a36Sopenharmony_ci	struct device_node *np;
38562306a36Sopenharmony_ci	const unsigned int *prop;
38662306a36Sopenharmony_ci	int val;
38762306a36Sopenharmony_ci
38862306a36Sopenharmony_ci	val = 0;
38962306a36Sopenharmony_ci	np = of_find_compatible_node(NULL, NULL, "fsl,mpc5121-immr");
39062306a36Sopenharmony_ci	if (np) {
39162306a36Sopenharmony_ci		prop = of_get_property(np, propname, NULL);
39262306a36Sopenharmony_ci		if (prop)
39362306a36Sopenharmony_ci			val = *prop;
39462306a36Sopenharmony_ci	    of_node_put(np);
39562306a36Sopenharmony_ci	}
39662306a36Sopenharmony_ci	return val;
39762306a36Sopenharmony_ci}
39862306a36Sopenharmony_ci
39962306a36Sopenharmony_cistatic void __init mpc512x_clk_preset_data(void)
40062306a36Sopenharmony_ci{
40162306a36Sopenharmony_ci	size_t i;
40262306a36Sopenharmony_ci
40362306a36Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(clks); i++)
40462306a36Sopenharmony_ci		clks[i] = ERR_PTR(-ENODEV);
40562306a36Sopenharmony_ci}
40662306a36Sopenharmony_ci
40762306a36Sopenharmony_ci/*
40862306a36Sopenharmony_ci * - receives the "bus frequency" from the caller (that's the IPS clock
40962306a36Sopenharmony_ci *   rate, the historical source of clock information)
41062306a36Sopenharmony_ci * - fetches the system PLL multiplier and divider values as well as the
41162306a36Sopenharmony_ci *   IPS divider value from hardware
41262306a36Sopenharmony_ci * - determines the REF clock rate either from the XTAL/OSC spec (if
41362306a36Sopenharmony_ci *   there is a device tree node describing the oscillator) or from the
41462306a36Sopenharmony_ci *   IPS bus clock (supported for backwards compatibility, such that
41562306a36Sopenharmony_ci *   setups without XTAL/OSC specs keep working)
41662306a36Sopenharmony_ci * - creates the "ref" clock item in the clock tree, such that
41762306a36Sopenharmony_ci *   subsequent code can create the remainder of the hierarchy (REF ->
41862306a36Sopenharmony_ci *   SYS -> CSB -> IPS) from the REF clock rate and the returned mul/div
41962306a36Sopenharmony_ci *   values
42062306a36Sopenharmony_ci */
42162306a36Sopenharmony_cistatic void __init mpc512x_clk_setup_ref_clock(struct device_node *np, int bus_freq,
42262306a36Sopenharmony_ci					int *sys_mul, int *sys_div,
42362306a36Sopenharmony_ci					int *ips_div)
42462306a36Sopenharmony_ci{
42562306a36Sopenharmony_ci	struct clk *osc_clk;
42662306a36Sopenharmony_ci	int calc_freq;
42762306a36Sopenharmony_ci
42862306a36Sopenharmony_ci	/* fetch mul/div factors from the hardware */
42962306a36Sopenharmony_ci	*sys_mul = get_spmf_mult();
43062306a36Sopenharmony_ci	*sys_mul *= 2;		/* compensate for the fractional divider */
43162306a36Sopenharmony_ci	*sys_div = get_sys_div_x2();
43262306a36Sopenharmony_ci	*ips_div = get_bit_field(&clkregs->scfr1, 23, 3);
43362306a36Sopenharmony_ci
43462306a36Sopenharmony_ci	/* lookup the oscillator clock for its rate */
43562306a36Sopenharmony_ci	osc_clk = of_clk_get_by_name(np, "osc");
43662306a36Sopenharmony_ci
43762306a36Sopenharmony_ci	/*
43862306a36Sopenharmony_ci	 * either descend from OSC to REF (and in bypassing verify the
43962306a36Sopenharmony_ci	 * IPS rate), or backtrack from IPS and multiplier values that
44062306a36Sopenharmony_ci	 * were fetched from hardware to REF and thus to the OSC value
44162306a36Sopenharmony_ci	 *
44262306a36Sopenharmony_ci	 * in either case the REF clock gets created here and the
44362306a36Sopenharmony_ci	 * remainder of the clock tree can get spanned from there
44462306a36Sopenharmony_ci	 */
44562306a36Sopenharmony_ci	if (!IS_ERR(osc_clk)) {
44662306a36Sopenharmony_ci		clks[MPC512x_CLK_REF] = mpc512x_clk_factor("ref", "osc", 1, 1);
44762306a36Sopenharmony_ci		calc_freq = clk_get_rate(clks[MPC512x_CLK_REF]);
44862306a36Sopenharmony_ci		calc_freq *= *sys_mul;
44962306a36Sopenharmony_ci		calc_freq /= *sys_div;
45062306a36Sopenharmony_ci		calc_freq /= 2;
45162306a36Sopenharmony_ci		calc_freq /= *ips_div;
45262306a36Sopenharmony_ci		if (bus_freq && calc_freq != bus_freq)
45362306a36Sopenharmony_ci			pr_warn("calc rate %d != OF spec %d\n",
45462306a36Sopenharmony_ci				calc_freq, bus_freq);
45562306a36Sopenharmony_ci	} else {
45662306a36Sopenharmony_ci		calc_freq = bus_freq;	/* start with IPS */
45762306a36Sopenharmony_ci		calc_freq *= *ips_div;	/* IPS -> CSB */
45862306a36Sopenharmony_ci		calc_freq *= 2;		/* CSB -> SYS */
45962306a36Sopenharmony_ci		calc_freq *= *sys_div;	/* SYS -> PLL out */
46062306a36Sopenharmony_ci		calc_freq /= *sys_mul;	/* PLL out -> REF == OSC */
46162306a36Sopenharmony_ci		clks[MPC512x_CLK_REF] = mpc512x_clk_fixed("ref", calc_freq);
46262306a36Sopenharmony_ci	}
46362306a36Sopenharmony_ci}
46462306a36Sopenharmony_ci
46562306a36Sopenharmony_ci/* MCLK helpers {{{ */
46662306a36Sopenharmony_ci
46762306a36Sopenharmony_ci/*
46862306a36Sopenharmony_ci * helper code for the MCLK subtree setup
46962306a36Sopenharmony_ci *
47062306a36Sopenharmony_ci * the overview in section 5.2.4 of the MPC5121e Reference Manual rev4
47162306a36Sopenharmony_ci * suggests that all instances of the "PSC clock generation" are equal,
47262306a36Sopenharmony_ci * and that one might re-use the PSC setup for MSCAN clock generation
47362306a36Sopenharmony_ci * (section 5.2.5) as well, at least the logic if not the data for
47462306a36Sopenharmony_ci * description
47562306a36Sopenharmony_ci *
47662306a36Sopenharmony_ci * the details (starting at page 5-20) show differences in the specific
47762306a36Sopenharmony_ci * inputs of the first mux stage ("can clk in", "spdif tx"), and the
47862306a36Sopenharmony_ci * factual non-availability of the second mux stage (it's present yet
47962306a36Sopenharmony_ci * only one input is valid)
48062306a36Sopenharmony_ci *
48162306a36Sopenharmony_ci * the MSCAN clock related registers (starting at page 5-35) all
48262306a36Sopenharmony_ci * reference "spdif clk" at the first mux stage and don't mention any
48362306a36Sopenharmony_ci * "can clk" at all, which somehow is unexpected
48462306a36Sopenharmony_ci *
48562306a36Sopenharmony_ci * TODO re-check the document, and clarify whether the RM is correct in
48662306a36Sopenharmony_ci * the overview or in the details, and whether the difference is a
48762306a36Sopenharmony_ci * clipboard induced error or results from chip revisions
48862306a36Sopenharmony_ci *
48962306a36Sopenharmony_ci * it turns out that the RM rev4 as of 2012-06 talks about "can" for the
49062306a36Sopenharmony_ci * PSCs while RM rev3 as of 2008-10 talks about "spdif", so I guess that
49162306a36Sopenharmony_ci * first a doc update is required which better reflects reality in the
49262306a36Sopenharmony_ci * SoC before the implementation should follow while no questions remain
49362306a36Sopenharmony_ci */
49462306a36Sopenharmony_ci
49562306a36Sopenharmony_ci/*
49662306a36Sopenharmony_ci * note that this declaration raises a checkpatch warning, but
49762306a36Sopenharmony_ci * it's the very data type dictated by <linux/clk-provider.h>,
49862306a36Sopenharmony_ci * "fixing" this warning will break compilation
49962306a36Sopenharmony_ci */
50062306a36Sopenharmony_cistatic const char *parent_names_mux0_spdif[] = {
50162306a36Sopenharmony_ci	"sys", "ref", "psc-mclk-in", "spdif-tx",
50262306a36Sopenharmony_ci};
50362306a36Sopenharmony_ci
50462306a36Sopenharmony_cistatic const char *parent_names_mux0_canin[] = {
50562306a36Sopenharmony_ci	"sys", "ref", "psc-mclk-in", "can-clk-in",
50662306a36Sopenharmony_ci};
50762306a36Sopenharmony_ci
50862306a36Sopenharmony_cienum mclk_type {
50962306a36Sopenharmony_ci	MCLK_TYPE_PSC,
51062306a36Sopenharmony_ci	MCLK_TYPE_MSCAN,
51162306a36Sopenharmony_ci	MCLK_TYPE_SPDIF,
51262306a36Sopenharmony_ci	MCLK_TYPE_OUTCLK,
51362306a36Sopenharmony_ci};
51462306a36Sopenharmony_ci
51562306a36Sopenharmony_cistruct mclk_setup_data {
51662306a36Sopenharmony_ci	enum mclk_type type;
51762306a36Sopenharmony_ci	bool has_mclk1;
51862306a36Sopenharmony_ci	const char *name_mux0;
51962306a36Sopenharmony_ci	const char *name_en0;
52062306a36Sopenharmony_ci	const char *name_div0;
52162306a36Sopenharmony_ci	const char *parent_names_mux1[2];
52262306a36Sopenharmony_ci	const char *name_mclk;
52362306a36Sopenharmony_ci};
52462306a36Sopenharmony_ci
52562306a36Sopenharmony_ci#define MCLK_SETUP_DATA_PSC(id) { \
52662306a36Sopenharmony_ci	MCLK_TYPE_PSC, 0, \
52762306a36Sopenharmony_ci	"psc" #id "-mux0", \
52862306a36Sopenharmony_ci	"psc" #id "-en0", \
52962306a36Sopenharmony_ci	"psc" #id "_mclk_div", \
53062306a36Sopenharmony_ci	{ "psc" #id "_mclk_div", "dummy", }, \
53162306a36Sopenharmony_ci	"psc" #id "_mclk", \
53262306a36Sopenharmony_ci}
53362306a36Sopenharmony_ci
53462306a36Sopenharmony_ci#define MCLK_SETUP_DATA_MSCAN(id) { \
53562306a36Sopenharmony_ci	MCLK_TYPE_MSCAN, 0, \
53662306a36Sopenharmony_ci	"mscan" #id "-mux0", \
53762306a36Sopenharmony_ci	"mscan" #id "-en0", \
53862306a36Sopenharmony_ci	"mscan" #id "_mclk_div", \
53962306a36Sopenharmony_ci	{ "mscan" #id "_mclk_div", "dummy", }, \
54062306a36Sopenharmony_ci	"mscan" #id "_mclk", \
54162306a36Sopenharmony_ci}
54262306a36Sopenharmony_ci
54362306a36Sopenharmony_ci#define MCLK_SETUP_DATA_SPDIF { \
54462306a36Sopenharmony_ci	MCLK_TYPE_SPDIF, 1, \
54562306a36Sopenharmony_ci	"spdif-mux0", \
54662306a36Sopenharmony_ci	"spdif-en0", \
54762306a36Sopenharmony_ci	"spdif_mclk_div", \
54862306a36Sopenharmony_ci	{ "spdif_mclk_div", "spdif-rx", }, \
54962306a36Sopenharmony_ci	"spdif_mclk", \
55062306a36Sopenharmony_ci}
55162306a36Sopenharmony_ci
55262306a36Sopenharmony_ci#define MCLK_SETUP_DATA_OUTCLK(id) { \
55362306a36Sopenharmony_ci	MCLK_TYPE_OUTCLK, 0, \
55462306a36Sopenharmony_ci	"out" #id "-mux0", \
55562306a36Sopenharmony_ci	"out" #id "-en0", \
55662306a36Sopenharmony_ci	"out" #id "_mclk_div", \
55762306a36Sopenharmony_ci	{ "out" #id "_mclk_div", "dummy", }, \
55862306a36Sopenharmony_ci	"out" #id "_clk", \
55962306a36Sopenharmony_ci}
56062306a36Sopenharmony_ci
56162306a36Sopenharmony_cistatic struct mclk_setup_data mclk_psc_data[] = {
56262306a36Sopenharmony_ci	MCLK_SETUP_DATA_PSC(0),
56362306a36Sopenharmony_ci	MCLK_SETUP_DATA_PSC(1),
56462306a36Sopenharmony_ci	MCLK_SETUP_DATA_PSC(2),
56562306a36Sopenharmony_ci	MCLK_SETUP_DATA_PSC(3),
56662306a36Sopenharmony_ci	MCLK_SETUP_DATA_PSC(4),
56762306a36Sopenharmony_ci	MCLK_SETUP_DATA_PSC(5),
56862306a36Sopenharmony_ci	MCLK_SETUP_DATA_PSC(6),
56962306a36Sopenharmony_ci	MCLK_SETUP_DATA_PSC(7),
57062306a36Sopenharmony_ci	MCLK_SETUP_DATA_PSC(8),
57162306a36Sopenharmony_ci	MCLK_SETUP_DATA_PSC(9),
57262306a36Sopenharmony_ci	MCLK_SETUP_DATA_PSC(10),
57362306a36Sopenharmony_ci	MCLK_SETUP_DATA_PSC(11),
57462306a36Sopenharmony_ci};
57562306a36Sopenharmony_ci
57662306a36Sopenharmony_cistatic struct mclk_setup_data mclk_mscan_data[] = {
57762306a36Sopenharmony_ci	MCLK_SETUP_DATA_MSCAN(0),
57862306a36Sopenharmony_ci	MCLK_SETUP_DATA_MSCAN(1),
57962306a36Sopenharmony_ci	MCLK_SETUP_DATA_MSCAN(2),
58062306a36Sopenharmony_ci	MCLK_SETUP_DATA_MSCAN(3),
58162306a36Sopenharmony_ci};
58262306a36Sopenharmony_ci
58362306a36Sopenharmony_cistatic struct mclk_setup_data mclk_spdif_data[] = {
58462306a36Sopenharmony_ci	MCLK_SETUP_DATA_SPDIF,
58562306a36Sopenharmony_ci};
58662306a36Sopenharmony_ci
58762306a36Sopenharmony_cistatic struct mclk_setup_data mclk_outclk_data[] = {
58862306a36Sopenharmony_ci	MCLK_SETUP_DATA_OUTCLK(0),
58962306a36Sopenharmony_ci	MCLK_SETUP_DATA_OUTCLK(1),
59062306a36Sopenharmony_ci	MCLK_SETUP_DATA_OUTCLK(2),
59162306a36Sopenharmony_ci	MCLK_SETUP_DATA_OUTCLK(3),
59262306a36Sopenharmony_ci};
59362306a36Sopenharmony_ci
59462306a36Sopenharmony_ci/* setup the MCLK clock subtree of an individual PSC/MSCAN/SPDIF */
59562306a36Sopenharmony_cistatic void __init mpc512x_clk_setup_mclk(struct mclk_setup_data *entry, size_t idx)
59662306a36Sopenharmony_ci{
59762306a36Sopenharmony_ci	size_t clks_idx_pub, clks_idx_int;
59862306a36Sopenharmony_ci	u32 __iomem *mccr_reg;	/* MCLK control register (mux, en, div) */
59962306a36Sopenharmony_ci	int div;
60062306a36Sopenharmony_ci
60162306a36Sopenharmony_ci	/* derive a few parameters from the component type and index */
60262306a36Sopenharmony_ci	switch (entry->type) {
60362306a36Sopenharmony_ci	case MCLK_TYPE_PSC:
60462306a36Sopenharmony_ci		clks_idx_pub = MPC512x_CLK_PSC0_MCLK + idx;
60562306a36Sopenharmony_ci		clks_idx_int = MPC512x_CLK_MCLKS_FIRST
60662306a36Sopenharmony_ci			     + (idx) * MCLK_MAX_IDX;
60762306a36Sopenharmony_ci		mccr_reg = &clkregs->psc_ccr[idx];
60862306a36Sopenharmony_ci		break;
60962306a36Sopenharmony_ci	case MCLK_TYPE_MSCAN:
61062306a36Sopenharmony_ci		clks_idx_pub = MPC512x_CLK_MSCAN0_MCLK + idx;
61162306a36Sopenharmony_ci		clks_idx_int = MPC512x_CLK_MCLKS_FIRST
61262306a36Sopenharmony_ci			     + (NR_PSCS + idx) * MCLK_MAX_IDX;
61362306a36Sopenharmony_ci		mccr_reg = &clkregs->mscan_ccr[idx];
61462306a36Sopenharmony_ci		break;
61562306a36Sopenharmony_ci	case MCLK_TYPE_SPDIF:
61662306a36Sopenharmony_ci		clks_idx_pub = MPC512x_CLK_SPDIF_MCLK;
61762306a36Sopenharmony_ci		clks_idx_int = MPC512x_CLK_MCLKS_FIRST
61862306a36Sopenharmony_ci			     + (NR_PSCS + NR_MSCANS) * MCLK_MAX_IDX;
61962306a36Sopenharmony_ci		mccr_reg = &clkregs->spccr;
62062306a36Sopenharmony_ci		break;
62162306a36Sopenharmony_ci	case MCLK_TYPE_OUTCLK:
62262306a36Sopenharmony_ci		clks_idx_pub = MPC512x_CLK_OUT0_CLK + idx;
62362306a36Sopenharmony_ci		clks_idx_int = MPC512x_CLK_MCLKS_FIRST
62462306a36Sopenharmony_ci			     + (NR_PSCS + NR_MSCANS + NR_SPDIFS + idx)
62562306a36Sopenharmony_ci			     * MCLK_MAX_IDX;
62662306a36Sopenharmony_ci		mccr_reg = &clkregs->out_ccr[idx];
62762306a36Sopenharmony_ci		break;
62862306a36Sopenharmony_ci	default:
62962306a36Sopenharmony_ci		return;
63062306a36Sopenharmony_ci	}
63162306a36Sopenharmony_ci
63262306a36Sopenharmony_ci	/*
63362306a36Sopenharmony_ci	 * this was grabbed from the PPC_CLOCK implementation, which
63462306a36Sopenharmony_ci	 * enforced a specific MCLK divider while the clock was gated
63562306a36Sopenharmony_ci	 * during setup (that's a documented hardware requirement)
63662306a36Sopenharmony_ci	 *
63762306a36Sopenharmony_ci	 * the PPC_CLOCK implementation might even have violated the
63862306a36Sopenharmony_ci	 * "MCLK <= IPS" constraint, the fixed divider value of 1
63962306a36Sopenharmony_ci	 * results in a divider of 2 and thus MCLK = SYS/2 which equals
64062306a36Sopenharmony_ci	 * CSB which is greater than IPS; the serial port setup may have
64162306a36Sopenharmony_ci	 * adjusted the divider which the clock setup might have left in
64262306a36Sopenharmony_ci	 * an undesirable state
64362306a36Sopenharmony_ci	 *
64462306a36Sopenharmony_ci	 * initial setup is:
64562306a36Sopenharmony_ci	 * - MCLK 0 from SYS
64662306a36Sopenharmony_ci	 * - MCLK DIV such to not exceed the IPS clock
64762306a36Sopenharmony_ci	 * - MCLK 0 enabled
64862306a36Sopenharmony_ci	 * - MCLK 1 from MCLK DIV
64962306a36Sopenharmony_ci	 */
65062306a36Sopenharmony_ci	div = clk_get_rate(clks[MPC512x_CLK_SYS]);
65162306a36Sopenharmony_ci	div /= clk_get_rate(clks[MPC512x_CLK_IPS]);
65262306a36Sopenharmony_ci	out_be32(mccr_reg, (0 << 16));
65362306a36Sopenharmony_ci	out_be32(mccr_reg, (0 << 16) | ((div - 1) << 17));
65462306a36Sopenharmony_ci	out_be32(mccr_reg, (1 << 16) | ((div - 1) << 17));
65562306a36Sopenharmony_ci
65662306a36Sopenharmony_ci	/*
65762306a36Sopenharmony_ci	 * create the 'struct clk' items of the MCLK's clock subtree
65862306a36Sopenharmony_ci	 *
65962306a36Sopenharmony_ci	 * note that by design we always create all nodes and won't take
66062306a36Sopenharmony_ci	 * shortcuts here, because
66162306a36Sopenharmony_ci	 * - the "internal" MCLK_DIV and MCLK_OUT signal in turn are
66262306a36Sopenharmony_ci	 *   selectable inputs to the CFM while those who "actually use"
66362306a36Sopenharmony_ci	 *   the PSC/MSCAN/SPDIF (serial drivers et al) need the MCLK
66462306a36Sopenharmony_ci	 *   for their bitrate
66562306a36Sopenharmony_ci	 * - in the absence of "aliases" for clocks we need to create
66662306a36Sopenharmony_ci	 *   individual 'struct clk' items for whatever might get
66762306a36Sopenharmony_ci	 *   referenced or looked up, even if several of those items are
66862306a36Sopenharmony_ci	 *   identical from the logical POV (their rate value)
66962306a36Sopenharmony_ci	 * - for easier future maintenance and for better reflection of
67062306a36Sopenharmony_ci	 *   the SoC's documentation, it appears appropriate to generate
67162306a36Sopenharmony_ci	 *   clock items even for those muxers which actually are NOPs
67262306a36Sopenharmony_ci	 *   (those with two inputs of which one is reserved)
67362306a36Sopenharmony_ci	 */
67462306a36Sopenharmony_ci	clks[clks_idx_int + MCLK_IDX_MUX0] = mpc512x_clk_muxed(
67562306a36Sopenharmony_ci			entry->name_mux0,
67662306a36Sopenharmony_ci			soc_has_mclk_mux0_canin()
67762306a36Sopenharmony_ci				? &parent_names_mux0_canin[0]
67862306a36Sopenharmony_ci				: &parent_names_mux0_spdif[0],
67962306a36Sopenharmony_ci			ARRAY_SIZE(parent_names_mux0_spdif),
68062306a36Sopenharmony_ci			mccr_reg, 14, 2);
68162306a36Sopenharmony_ci	clks[clks_idx_int + MCLK_IDX_EN0] = mpc512x_clk_gated(
68262306a36Sopenharmony_ci			entry->name_en0, entry->name_mux0,
68362306a36Sopenharmony_ci			mccr_reg, 16);
68462306a36Sopenharmony_ci	clks[clks_idx_int + MCLK_IDX_DIV0] = mpc512x_clk_divider(
68562306a36Sopenharmony_ci			entry->name_div0,
68662306a36Sopenharmony_ci			entry->name_en0, CLK_SET_RATE_GATE,
68762306a36Sopenharmony_ci			mccr_reg, 17, 15, 0);
68862306a36Sopenharmony_ci	if (entry->has_mclk1) {
68962306a36Sopenharmony_ci		clks[clks_idx_pub] = mpc512x_clk_muxed(
69062306a36Sopenharmony_ci				entry->name_mclk,
69162306a36Sopenharmony_ci				&entry->parent_names_mux1[0],
69262306a36Sopenharmony_ci				ARRAY_SIZE(entry->parent_names_mux1),
69362306a36Sopenharmony_ci				mccr_reg, 7, 1);
69462306a36Sopenharmony_ci	} else {
69562306a36Sopenharmony_ci		clks[clks_idx_pub] = mpc512x_clk_factor(
69662306a36Sopenharmony_ci				entry->name_mclk,
69762306a36Sopenharmony_ci				entry->parent_names_mux1[0],
69862306a36Sopenharmony_ci				1, 1);
69962306a36Sopenharmony_ci	}
70062306a36Sopenharmony_ci}
70162306a36Sopenharmony_ci
70262306a36Sopenharmony_ci/* }}} MCLK helpers */
70362306a36Sopenharmony_ci
70462306a36Sopenharmony_cistatic void __init mpc512x_clk_setup_clock_tree(struct device_node *np, int busfreq)
70562306a36Sopenharmony_ci{
70662306a36Sopenharmony_ci	int sys_mul, sys_div, ips_div;
70762306a36Sopenharmony_ci	int mul, div;
70862306a36Sopenharmony_ci	size_t mclk_idx;
70962306a36Sopenharmony_ci	int freq;
71062306a36Sopenharmony_ci
71162306a36Sopenharmony_ci	/*
71262306a36Sopenharmony_ci	 * developer's notes:
71362306a36Sopenharmony_ci	 * - consider whether to handle clocks which have both gates and
71462306a36Sopenharmony_ci	 *   dividers via intermediates or by means of composites
71562306a36Sopenharmony_ci	 * - fractional dividers appear to not map well to composites
71662306a36Sopenharmony_ci	 *   since they can be seen as a fixed multiplier and an
71762306a36Sopenharmony_ci	 *   adjustable divider, while composites can only combine at
71862306a36Sopenharmony_ci	 *   most one of a mux, div, and gate each into one 'struct clk'
71962306a36Sopenharmony_ci	 *   item
72062306a36Sopenharmony_ci	 * - PSC/MSCAN/SPDIF clock generation OTOH already is very
72162306a36Sopenharmony_ci	 *   specific and cannot get mapped to composites (at least not
72262306a36Sopenharmony_ci	 *   a single one, maybe two of them, but then some of these
72362306a36Sopenharmony_ci	 *   intermediate clock signals get referenced elsewhere (e.g.
72462306a36Sopenharmony_ci	 *   in the clock frequency measurement, CFM) and thus need
72562306a36Sopenharmony_ci	 *   publicly available names
72662306a36Sopenharmony_ci	 * - the current source layout appropriately reflects the
72762306a36Sopenharmony_ci	 *   hardware setup, and it works, so it's questionable whether
72862306a36Sopenharmony_ci	 *   further changes will result in big enough a benefit
72962306a36Sopenharmony_ci	 */
73062306a36Sopenharmony_ci
73162306a36Sopenharmony_ci	/* regardless of whether XTAL/OSC exists, have REF created */
73262306a36Sopenharmony_ci	mpc512x_clk_setup_ref_clock(np, busfreq, &sys_mul, &sys_div, &ips_div);
73362306a36Sopenharmony_ci
73462306a36Sopenharmony_ci	/* now setup the REF -> SYS -> CSB -> IPS hierarchy */
73562306a36Sopenharmony_ci	clks[MPC512x_CLK_SYS] = mpc512x_clk_factor("sys", "ref",
73662306a36Sopenharmony_ci						   sys_mul, sys_div);
73762306a36Sopenharmony_ci	clks[MPC512x_CLK_CSB] = mpc512x_clk_factor("csb", "sys", 1, 2);
73862306a36Sopenharmony_ci	clks[MPC512x_CLK_IPS] = mpc512x_clk_divtable("ips", "csb",
73962306a36Sopenharmony_ci						     &clkregs->scfr1, 23, 3,
74062306a36Sopenharmony_ci						     divtab_2346);
74162306a36Sopenharmony_ci	/* now setup anything below SYS and CSB and IPS */
74262306a36Sopenharmony_ci
74362306a36Sopenharmony_ci	clks[MPC512x_CLK_DDR_UG] = mpc512x_clk_factor("ddr-ug", "sys", 1, 2);
74462306a36Sopenharmony_ci
74562306a36Sopenharmony_ci	/*
74662306a36Sopenharmony_ci	 * the Reference Manual discusses that for SDHC only even divide
74762306a36Sopenharmony_ci	 * ratios are supported because clock domain synchronization
74862306a36Sopenharmony_ci	 * between 'per' and 'ipg' is broken;
74962306a36Sopenharmony_ci	 * keep the divider's bit 0 cleared (per reset value), and only
75062306a36Sopenharmony_ci	 * allow to setup the divider's bits 7:1, which results in that
75162306a36Sopenharmony_ci	 * only even divide ratios can get configured upon rate changes;
75262306a36Sopenharmony_ci	 * keep the "x4" name because this bit shift hack is an internal
75362306a36Sopenharmony_ci	 * implementation detail, the "fractional divider with quarters"
75462306a36Sopenharmony_ci	 * semantics remains
75562306a36Sopenharmony_ci	 */
75662306a36Sopenharmony_ci	clks[MPC512x_CLK_SDHC_x4] = mpc512x_clk_factor("sdhc-x4", "csb", 2, 1);
75762306a36Sopenharmony_ci	clks[MPC512x_CLK_SDHC_UG] = mpc512x_clk_divider("sdhc-ug", "sdhc-x4", 0,
75862306a36Sopenharmony_ci							&clkregs->scfr2, 1, 7,
75962306a36Sopenharmony_ci							CLK_DIVIDER_ONE_BASED);
76062306a36Sopenharmony_ci	if (soc_has_sdhc2()) {
76162306a36Sopenharmony_ci		clks[MPC512x_CLK_SDHC2_UG] = mpc512x_clk_divider(
76262306a36Sopenharmony_ci				"sdhc2-ug", "sdhc-x4", 0, &clkregs->scfr2,
76362306a36Sopenharmony_ci				9, 7, CLK_DIVIDER_ONE_BASED);
76462306a36Sopenharmony_ci	}
76562306a36Sopenharmony_ci
76662306a36Sopenharmony_ci	clks[MPC512x_CLK_DIU_x4] = mpc512x_clk_factor("diu-x4", "csb", 4, 1);
76762306a36Sopenharmony_ci	clks[MPC512x_CLK_DIU_UG] = mpc512x_clk_divider("diu-ug", "diu-x4", 0,
76862306a36Sopenharmony_ci						       &clkregs->scfr1, 0, 8,
76962306a36Sopenharmony_ci						       CLK_DIVIDER_ONE_BASED);
77062306a36Sopenharmony_ci
77162306a36Sopenharmony_ci	/*
77262306a36Sopenharmony_ci	 * the "power architecture PLL" was setup from data which was
77362306a36Sopenharmony_ci	 * sampled from the reset config word, at this point in time the
77462306a36Sopenharmony_ci	 * configuration can be considered fixed and read only (i.e. no
77562306a36Sopenharmony_ci	 * longer adjustable, or no longer in need of adjustment), which
77662306a36Sopenharmony_ci	 * is why we don't register a PLL here but assume fixed factors
77762306a36Sopenharmony_ci	 */
77862306a36Sopenharmony_ci	mul = get_cpmf_mult_x2();
77962306a36Sopenharmony_ci	div = 2;	/* compensate for the fractional factor */
78062306a36Sopenharmony_ci	clks[MPC512x_CLK_E300] = mpc512x_clk_factor("e300", "csb", mul, div);
78162306a36Sopenharmony_ci
78262306a36Sopenharmony_ci	if (soc_has_mbx()) {
78362306a36Sopenharmony_ci		clks[MPC512x_CLK_MBX_BUS_UG] = mpc512x_clk_factor(
78462306a36Sopenharmony_ci				"mbx-bus-ug", "csb", 1, 2);
78562306a36Sopenharmony_ci		clks[MPC512x_CLK_MBX_UG] = mpc512x_clk_divtable(
78662306a36Sopenharmony_ci				"mbx-ug", "mbx-bus-ug", &clkregs->scfr1,
78762306a36Sopenharmony_ci				14, 3, divtab_1234);
78862306a36Sopenharmony_ci		clks[MPC512x_CLK_MBX_3D_UG] = mpc512x_clk_factor(
78962306a36Sopenharmony_ci				"mbx-3d-ug", "mbx-ug", 1, 1);
79062306a36Sopenharmony_ci	}
79162306a36Sopenharmony_ci	if (soc_has_pci()) {
79262306a36Sopenharmony_ci		clks[MPC512x_CLK_PCI_UG] = mpc512x_clk_divtable(
79362306a36Sopenharmony_ci				"pci-ug", "csb", &clkregs->scfr1,
79462306a36Sopenharmony_ci				20, 3, divtab_2346);
79562306a36Sopenharmony_ci	}
79662306a36Sopenharmony_ci	if (soc_has_nfc_5125()) {
79762306a36Sopenharmony_ci		/*
79862306a36Sopenharmony_ci		 * XXX TODO implement 5125 NFC clock setup logic,
79962306a36Sopenharmony_ci		 * with high/low period counters in clkregs->scfr3,
80062306a36Sopenharmony_ci		 * currently there are no users so it's ENOIMPL
80162306a36Sopenharmony_ci		 */
80262306a36Sopenharmony_ci		clks[MPC512x_CLK_NFC_UG] = ERR_PTR(-ENOTSUPP);
80362306a36Sopenharmony_ci	} else {
80462306a36Sopenharmony_ci		clks[MPC512x_CLK_NFC_UG] = mpc512x_clk_divtable(
80562306a36Sopenharmony_ci				"nfc-ug", "ips", &clkregs->scfr1,
80662306a36Sopenharmony_ci				8, 3, divtab_1234);
80762306a36Sopenharmony_ci	}
80862306a36Sopenharmony_ci	clks[MPC512x_CLK_LPC_UG] = mpc512x_clk_divtable("lpc-ug", "ips",
80962306a36Sopenharmony_ci							&clkregs->scfr1, 11, 3,
81062306a36Sopenharmony_ci							divtab_1234);
81162306a36Sopenharmony_ci
81262306a36Sopenharmony_ci	clks[MPC512x_CLK_LPC] = mpc512x_clk_gated("lpc", "lpc-ug",
81362306a36Sopenharmony_ci						  &clkregs->sccr1, 30);
81462306a36Sopenharmony_ci	clks[MPC512x_CLK_NFC] = mpc512x_clk_gated("nfc", "nfc-ug",
81562306a36Sopenharmony_ci						  &clkregs->sccr1, 29);
81662306a36Sopenharmony_ci	if (soc_has_pata()) {
81762306a36Sopenharmony_ci		clks[MPC512x_CLK_PATA] = mpc512x_clk_gated(
81862306a36Sopenharmony_ci				"pata", "ips", &clkregs->sccr1, 28);
81962306a36Sopenharmony_ci	}
82062306a36Sopenharmony_ci	/* for PSCs there is a "registers" gate and a bitrate MCLK subtree */
82162306a36Sopenharmony_ci	for (mclk_idx = 0; mclk_idx < soc_max_pscnum(); mclk_idx++) {
82262306a36Sopenharmony_ci		char name[12];
82362306a36Sopenharmony_ci		snprintf(name, sizeof(name), "psc%d", mclk_idx);
82462306a36Sopenharmony_ci		clks[MPC512x_CLK_PSC0 + mclk_idx] = mpc512x_clk_gated(
82562306a36Sopenharmony_ci				name, "ips", &clkregs->sccr1, 27 - mclk_idx);
82662306a36Sopenharmony_ci		mpc512x_clk_setup_mclk(&mclk_psc_data[mclk_idx], mclk_idx);
82762306a36Sopenharmony_ci	}
82862306a36Sopenharmony_ci	clks[MPC512x_CLK_PSC_FIFO] = mpc512x_clk_gated("psc-fifo", "ips",
82962306a36Sopenharmony_ci						       &clkregs->sccr1, 15);
83062306a36Sopenharmony_ci	if (soc_has_sata()) {
83162306a36Sopenharmony_ci		clks[MPC512x_CLK_SATA] = mpc512x_clk_gated(
83262306a36Sopenharmony_ci				"sata", "ips", &clkregs->sccr1, 14);
83362306a36Sopenharmony_ci	}
83462306a36Sopenharmony_ci	clks[MPC512x_CLK_FEC] = mpc512x_clk_gated("fec", "ips",
83562306a36Sopenharmony_ci						  &clkregs->sccr1, 13);
83662306a36Sopenharmony_ci	if (soc_has_pci()) {
83762306a36Sopenharmony_ci		clks[MPC512x_CLK_PCI] = mpc512x_clk_gated(
83862306a36Sopenharmony_ci				"pci", "pci-ug", &clkregs->sccr1, 11);
83962306a36Sopenharmony_ci	}
84062306a36Sopenharmony_ci	clks[MPC512x_CLK_DDR] = mpc512x_clk_gated("ddr", "ddr-ug",
84162306a36Sopenharmony_ci						  &clkregs->sccr1, 10);
84262306a36Sopenharmony_ci	if (soc_has_fec2()) {
84362306a36Sopenharmony_ci		clks[MPC512x_CLK_FEC2] = mpc512x_clk_gated(
84462306a36Sopenharmony_ci				"fec2", "ips", &clkregs->sccr1, 9);
84562306a36Sopenharmony_ci	}
84662306a36Sopenharmony_ci
84762306a36Sopenharmony_ci	clks[MPC512x_CLK_DIU] = mpc512x_clk_gated("diu", "diu-ug",
84862306a36Sopenharmony_ci						  &clkregs->sccr2, 31);
84962306a36Sopenharmony_ci	if (soc_has_axe()) {
85062306a36Sopenharmony_ci		clks[MPC512x_CLK_AXE] = mpc512x_clk_gated(
85162306a36Sopenharmony_ci				"axe", "csb", &clkregs->sccr2, 30);
85262306a36Sopenharmony_ci	}
85362306a36Sopenharmony_ci	clks[MPC512x_CLK_MEM] = mpc512x_clk_gated("mem", "ips",
85462306a36Sopenharmony_ci						  &clkregs->sccr2, 29);
85562306a36Sopenharmony_ci	clks[MPC512x_CLK_USB1] = mpc512x_clk_gated("usb1", "csb",
85662306a36Sopenharmony_ci						   &clkregs->sccr2, 28);
85762306a36Sopenharmony_ci	clks[MPC512x_CLK_USB2] = mpc512x_clk_gated("usb2", "csb",
85862306a36Sopenharmony_ci						   &clkregs->sccr2, 27);
85962306a36Sopenharmony_ci	clks[MPC512x_CLK_I2C] = mpc512x_clk_gated("i2c", "ips",
86062306a36Sopenharmony_ci						  &clkregs->sccr2, 26);
86162306a36Sopenharmony_ci	/* MSCAN differs from PSC with just one gate for multiple components */
86262306a36Sopenharmony_ci	clks[MPC512x_CLK_BDLC] = mpc512x_clk_gated("bdlc", "ips",
86362306a36Sopenharmony_ci						   &clkregs->sccr2, 25);
86462306a36Sopenharmony_ci	for (mclk_idx = 0; mclk_idx < ARRAY_SIZE(mclk_mscan_data); mclk_idx++)
86562306a36Sopenharmony_ci		mpc512x_clk_setup_mclk(&mclk_mscan_data[mclk_idx], mclk_idx);
86662306a36Sopenharmony_ci	clks[MPC512x_CLK_SDHC] = mpc512x_clk_gated("sdhc", "sdhc-ug",
86762306a36Sopenharmony_ci						   &clkregs->sccr2, 24);
86862306a36Sopenharmony_ci	/* there is only one SPDIF component, which shares MCLK support code */
86962306a36Sopenharmony_ci	if (soc_has_spdif()) {
87062306a36Sopenharmony_ci		clks[MPC512x_CLK_SPDIF] = mpc512x_clk_gated(
87162306a36Sopenharmony_ci				"spdif", "ips", &clkregs->sccr2, 23);
87262306a36Sopenharmony_ci		mpc512x_clk_setup_mclk(&mclk_spdif_data[0], 0);
87362306a36Sopenharmony_ci	}
87462306a36Sopenharmony_ci	if (soc_has_mbx()) {
87562306a36Sopenharmony_ci		clks[MPC512x_CLK_MBX_BUS] = mpc512x_clk_gated(
87662306a36Sopenharmony_ci				"mbx-bus", "mbx-bus-ug", &clkregs->sccr2, 22);
87762306a36Sopenharmony_ci		clks[MPC512x_CLK_MBX] = mpc512x_clk_gated(
87862306a36Sopenharmony_ci				"mbx", "mbx-ug", &clkregs->sccr2, 21);
87962306a36Sopenharmony_ci		clks[MPC512x_CLK_MBX_3D] = mpc512x_clk_gated(
88062306a36Sopenharmony_ci				"mbx-3d", "mbx-3d-ug", &clkregs->sccr2, 20);
88162306a36Sopenharmony_ci	}
88262306a36Sopenharmony_ci	clks[MPC512x_CLK_IIM] = mpc512x_clk_gated("iim", "csb",
88362306a36Sopenharmony_ci						  &clkregs->sccr2, 19);
88462306a36Sopenharmony_ci	if (soc_has_viu()) {
88562306a36Sopenharmony_ci		clks[MPC512x_CLK_VIU] = mpc512x_clk_gated(
88662306a36Sopenharmony_ci				"viu", "csb", &clkregs->sccr2, 18);
88762306a36Sopenharmony_ci	}
88862306a36Sopenharmony_ci	if (soc_has_sdhc2()) {
88962306a36Sopenharmony_ci		clks[MPC512x_CLK_SDHC2] = mpc512x_clk_gated(
89062306a36Sopenharmony_ci				"sdhc-2", "sdhc2-ug", &clkregs->sccr2, 17);
89162306a36Sopenharmony_ci	}
89262306a36Sopenharmony_ci
89362306a36Sopenharmony_ci	if (soc_has_outclk()) {
89462306a36Sopenharmony_ci		size_t idx;	/* used as mclk_idx, just to trim line length */
89562306a36Sopenharmony_ci		for (idx = 0; idx < ARRAY_SIZE(mclk_outclk_data); idx++)
89662306a36Sopenharmony_ci			mpc512x_clk_setup_mclk(&mclk_outclk_data[idx], idx);
89762306a36Sopenharmony_ci	}
89862306a36Sopenharmony_ci
89962306a36Sopenharmony_ci	/*
90062306a36Sopenharmony_ci	 * externally provided clocks (when implemented in hardware,
90162306a36Sopenharmony_ci	 * device tree may specify values which otherwise were unknown)
90262306a36Sopenharmony_ci	 */
90362306a36Sopenharmony_ci	freq = get_freq_from_dt("psc_mclk_in");
90462306a36Sopenharmony_ci	if (!freq)
90562306a36Sopenharmony_ci		freq = 25000000;
90662306a36Sopenharmony_ci	clks[MPC512x_CLK_PSC_MCLK_IN] = mpc512x_clk_fixed("psc_mclk_in", freq);
90762306a36Sopenharmony_ci	if (soc_has_mclk_mux0_canin()) {
90862306a36Sopenharmony_ci		freq = get_freq_from_dt("can_clk_in");
90962306a36Sopenharmony_ci		clks[MPC512x_CLK_CAN_CLK_IN] = mpc512x_clk_fixed(
91062306a36Sopenharmony_ci				"can_clk_in", freq);
91162306a36Sopenharmony_ci	} else {
91262306a36Sopenharmony_ci		freq = get_freq_from_dt("spdif_tx_in");
91362306a36Sopenharmony_ci		clks[MPC512x_CLK_SPDIF_TX_IN] = mpc512x_clk_fixed(
91462306a36Sopenharmony_ci				"spdif_tx_in", freq);
91562306a36Sopenharmony_ci		freq = get_freq_from_dt("spdif_rx_in");
91662306a36Sopenharmony_ci		clks[MPC512x_CLK_SPDIF_TX_IN] = mpc512x_clk_fixed(
91762306a36Sopenharmony_ci				"spdif_rx_in", freq);
91862306a36Sopenharmony_ci	}
91962306a36Sopenharmony_ci
92062306a36Sopenharmony_ci	/* fixed frequency for AC97, always 24.567MHz */
92162306a36Sopenharmony_ci	clks[MPC512x_CLK_AC97] = mpc512x_clk_fixed("ac97", 24567000);
92262306a36Sopenharmony_ci
92362306a36Sopenharmony_ci	/*
92462306a36Sopenharmony_ci	 * pre-enable those "internal" clock items which never get
92562306a36Sopenharmony_ci	 * claimed by any peripheral driver, to not have the clock
92662306a36Sopenharmony_ci	 * subsystem disable them late at startup
92762306a36Sopenharmony_ci	 */
92862306a36Sopenharmony_ci	clk_prepare_enable(clks[MPC512x_CLK_DUMMY]);
92962306a36Sopenharmony_ci	clk_prepare_enable(clks[MPC512x_CLK_E300]);	/* PowerPC CPU */
93062306a36Sopenharmony_ci	clk_prepare_enable(clks[MPC512x_CLK_DDR]);	/* DRAM */
93162306a36Sopenharmony_ci	clk_prepare_enable(clks[MPC512x_CLK_MEM]);	/* SRAM */
93262306a36Sopenharmony_ci	clk_prepare_enable(clks[MPC512x_CLK_IPS]);	/* SoC periph */
93362306a36Sopenharmony_ci	clk_prepare_enable(clks[MPC512x_CLK_LPC]);	/* boot media */
93462306a36Sopenharmony_ci}
93562306a36Sopenharmony_ci
93662306a36Sopenharmony_ci/*
93762306a36Sopenharmony_ci * registers the set of public clocks (those listed in the dt-bindings/
93862306a36Sopenharmony_ci * header file) for OF lookups, keeps the intermediates private to us
93962306a36Sopenharmony_ci */
94062306a36Sopenharmony_cistatic void __init mpc5121_clk_register_of_provider(struct device_node *np)
94162306a36Sopenharmony_ci{
94262306a36Sopenharmony_ci	clk_data.clks = clks;
94362306a36Sopenharmony_ci	clk_data.clk_num = MPC512x_CLK_LAST_PUBLIC + 1;	/* _not_ ARRAY_SIZE() */
94462306a36Sopenharmony_ci	of_clk_add_provider(np, of_clk_src_onecell_get, &clk_data);
94562306a36Sopenharmony_ci}
94662306a36Sopenharmony_ci
94762306a36Sopenharmony_ci/*
94862306a36Sopenharmony_ci * temporary support for the period of time between introduction of CCF
94962306a36Sopenharmony_ci * support and the adjustment of peripheral drivers to OF based lookups
95062306a36Sopenharmony_ci */
95162306a36Sopenharmony_cistatic void __init mpc5121_clk_provide_migration_support(void)
95262306a36Sopenharmony_ci{
95362306a36Sopenharmony_ci	struct device_node *np;
95462306a36Sopenharmony_ci	/*
95562306a36Sopenharmony_ci	 * pre-enable those clock items which are not yet appropriately
95662306a36Sopenharmony_ci	 * acquired by their peripheral driver
95762306a36Sopenharmony_ci	 *
95862306a36Sopenharmony_ci	 * the PCI clock cannot get acquired by its peripheral driver,
95962306a36Sopenharmony_ci	 * because for this platform the driver won't probe(), instead
96062306a36Sopenharmony_ci	 * initialization is done from within the .setup_arch() routine
96162306a36Sopenharmony_ci	 * at a point in time where the clock provider has not been
96262306a36Sopenharmony_ci	 * setup yet and thus isn't available yet
96362306a36Sopenharmony_ci	 *
96462306a36Sopenharmony_ci	 * so we "pre-enable" the clock here, to not have the clock
96562306a36Sopenharmony_ci	 * subsystem automatically disable this item in a late init call
96662306a36Sopenharmony_ci	 *
96762306a36Sopenharmony_ci	 * this PCI clock pre-enable workaround only applies when there
96862306a36Sopenharmony_ci	 * are device tree nodes for PCI and thus the peripheral driver
96962306a36Sopenharmony_ci	 * has attached to bridges, otherwise the PCI clock remains
97062306a36Sopenharmony_ci	 * unused and so it gets disabled
97162306a36Sopenharmony_ci	 */
97262306a36Sopenharmony_ci	clk_prepare_enable(clks[MPC512x_CLK_PSC3_MCLK]);/* serial console */
97362306a36Sopenharmony_ci	np = of_find_compatible_node(NULL, "pci", "fsl,mpc5121-pci");
97462306a36Sopenharmony_ci	of_node_put(np);
97562306a36Sopenharmony_ci	if (np)
97662306a36Sopenharmony_ci		clk_prepare_enable(clks[MPC512x_CLK_PCI]);
97762306a36Sopenharmony_ci}
97862306a36Sopenharmony_ci
97962306a36Sopenharmony_ci/*
98062306a36Sopenharmony_ci * those macros are not exactly pretty, but they encapsulate a lot
98162306a36Sopenharmony_ci * of copy'n'paste heavy code which is even more ugly, and reduce
98262306a36Sopenharmony_ci * the potential for inconsistencies in those many code copies
98362306a36Sopenharmony_ci */
98462306a36Sopenharmony_ci#define FOR_NODES(compatname) \
98562306a36Sopenharmony_ci	for_each_compatible_node(np, NULL, compatname)
98662306a36Sopenharmony_ci
98762306a36Sopenharmony_ci#define NODE_PREP do { \
98862306a36Sopenharmony_ci	of_address_to_resource(np, 0, &res); \
98962306a36Sopenharmony_ci	snprintf(devname, sizeof(devname), "%pa.%s", &res.start, np->name); \
99062306a36Sopenharmony_ci} while (0)
99162306a36Sopenharmony_ci
99262306a36Sopenharmony_ci#define NODE_CHK(clkname, clkitem, regnode, regflag) do { \
99362306a36Sopenharmony_ci	struct clk *clk; \
99462306a36Sopenharmony_ci	clk = of_clk_get_by_name(np, clkname); \
99562306a36Sopenharmony_ci	if (IS_ERR(clk)) { \
99662306a36Sopenharmony_ci		clk = clkitem; \
99762306a36Sopenharmony_ci		clk_register_clkdev(clk, clkname, devname); \
99862306a36Sopenharmony_ci		if (regnode) \
99962306a36Sopenharmony_ci			clk_register_clkdev(clk, clkname, np->name); \
100062306a36Sopenharmony_ci		did_register |= DID_REG_ ## regflag; \
100162306a36Sopenharmony_ci		pr_debug("clock alias name '%s' for dev '%s' pointer %p\n", \
100262306a36Sopenharmony_ci			 clkname, devname, clk); \
100362306a36Sopenharmony_ci	} else { \
100462306a36Sopenharmony_ci		clk_put(clk); \
100562306a36Sopenharmony_ci	} \
100662306a36Sopenharmony_ci} while (0)
100762306a36Sopenharmony_ci
100862306a36Sopenharmony_ci/*
100962306a36Sopenharmony_ci * register source code provided fallback results for clock lookups,
101062306a36Sopenharmony_ci * these get consulted when OF based clock lookup fails (that is in the
101162306a36Sopenharmony_ci * case of not yet adjusted device tree data, where clock related specs
101262306a36Sopenharmony_ci * are missing)
101362306a36Sopenharmony_ci */
101462306a36Sopenharmony_cistatic void __init mpc5121_clk_provide_backwards_compat(void)
101562306a36Sopenharmony_ci{
101662306a36Sopenharmony_ci	enum did_reg_flags {
101762306a36Sopenharmony_ci		DID_REG_PSC	= BIT(0),
101862306a36Sopenharmony_ci		DID_REG_PSCFIFO	= BIT(1),
101962306a36Sopenharmony_ci		DID_REG_NFC	= BIT(2),
102062306a36Sopenharmony_ci		DID_REG_CAN	= BIT(3),
102162306a36Sopenharmony_ci		DID_REG_I2C	= BIT(4),
102262306a36Sopenharmony_ci		DID_REG_DIU	= BIT(5),
102362306a36Sopenharmony_ci		DID_REG_VIU	= BIT(6),
102462306a36Sopenharmony_ci		DID_REG_FEC	= BIT(7),
102562306a36Sopenharmony_ci		DID_REG_USB	= BIT(8),
102662306a36Sopenharmony_ci		DID_REG_PATA	= BIT(9),
102762306a36Sopenharmony_ci	};
102862306a36Sopenharmony_ci
102962306a36Sopenharmony_ci	int did_register;
103062306a36Sopenharmony_ci	struct device_node *np;
103162306a36Sopenharmony_ci	struct resource res;
103262306a36Sopenharmony_ci	int idx;
103362306a36Sopenharmony_ci	char devname[32];
103462306a36Sopenharmony_ci
103562306a36Sopenharmony_ci	did_register = 0;
103662306a36Sopenharmony_ci
103762306a36Sopenharmony_ci	FOR_NODES(mpc512x_select_psc_compat()) {
103862306a36Sopenharmony_ci		NODE_PREP;
103962306a36Sopenharmony_ci		idx = (res.start >> 8) & 0xf;
104062306a36Sopenharmony_ci		NODE_CHK("ipg", clks[MPC512x_CLK_PSC0 + idx], 0, PSC);
104162306a36Sopenharmony_ci		NODE_CHK("mclk", clks[MPC512x_CLK_PSC0_MCLK + idx], 0, PSC);
104262306a36Sopenharmony_ci	}
104362306a36Sopenharmony_ci
104462306a36Sopenharmony_ci	FOR_NODES("fsl,mpc5121-psc-fifo") {
104562306a36Sopenharmony_ci		NODE_PREP;
104662306a36Sopenharmony_ci		NODE_CHK("ipg", clks[MPC512x_CLK_PSC_FIFO], 1, PSCFIFO);
104762306a36Sopenharmony_ci	}
104862306a36Sopenharmony_ci
104962306a36Sopenharmony_ci	FOR_NODES("fsl,mpc5121-nfc") {
105062306a36Sopenharmony_ci		NODE_PREP;
105162306a36Sopenharmony_ci		NODE_CHK("ipg", clks[MPC512x_CLK_NFC], 0, NFC);
105262306a36Sopenharmony_ci	}
105362306a36Sopenharmony_ci
105462306a36Sopenharmony_ci	FOR_NODES("fsl,mpc5121-mscan") {
105562306a36Sopenharmony_ci		NODE_PREP;
105662306a36Sopenharmony_ci		idx = 0;
105762306a36Sopenharmony_ci		idx += (res.start & 0x2000) ? 2 : 0;
105862306a36Sopenharmony_ci		idx += (res.start & 0x0080) ? 1 : 0;
105962306a36Sopenharmony_ci		NODE_CHK("ipg", clks[MPC512x_CLK_BDLC], 0, CAN);
106062306a36Sopenharmony_ci		NODE_CHK("mclk", clks[MPC512x_CLK_MSCAN0_MCLK + idx], 0, CAN);
106162306a36Sopenharmony_ci	}
106262306a36Sopenharmony_ci
106362306a36Sopenharmony_ci	/*
106462306a36Sopenharmony_ci	 * do register the 'ips', 'sys', and 'ref' names globally
106562306a36Sopenharmony_ci	 * instead of inside each individual CAN node, as there is no
106662306a36Sopenharmony_ci	 * potential for a name conflict (in contrast to 'ipg' and 'mclk')
106762306a36Sopenharmony_ci	 */
106862306a36Sopenharmony_ci	if (did_register & DID_REG_CAN) {
106962306a36Sopenharmony_ci		clk_register_clkdev(clks[MPC512x_CLK_IPS], "ips", NULL);
107062306a36Sopenharmony_ci		clk_register_clkdev(clks[MPC512x_CLK_SYS], "sys", NULL);
107162306a36Sopenharmony_ci		clk_register_clkdev(clks[MPC512x_CLK_REF], "ref", NULL);
107262306a36Sopenharmony_ci	}
107362306a36Sopenharmony_ci
107462306a36Sopenharmony_ci	FOR_NODES("fsl,mpc5121-i2c") {
107562306a36Sopenharmony_ci		NODE_PREP;
107662306a36Sopenharmony_ci		NODE_CHK("ipg", clks[MPC512x_CLK_I2C], 0, I2C);
107762306a36Sopenharmony_ci	}
107862306a36Sopenharmony_ci
107962306a36Sopenharmony_ci	/*
108062306a36Sopenharmony_ci	 * workaround for the fact that the I2C driver does an "anonymous"
108162306a36Sopenharmony_ci	 * lookup (NULL name spec, which yields the first clock spec) for
108262306a36Sopenharmony_ci	 * which we cannot register an alias -- a _global_ 'ipg' alias that
108362306a36Sopenharmony_ci	 * is not bound to any device name and returns the I2C clock item
108462306a36Sopenharmony_ci	 * is not a good idea
108562306a36Sopenharmony_ci	 *
108662306a36Sopenharmony_ci	 * so we have the lookup in the peripheral driver fail, which is
108762306a36Sopenharmony_ci	 * silent and non-fatal, and pre-enable the clock item here such
108862306a36Sopenharmony_ci	 * that register access is possible
108962306a36Sopenharmony_ci	 *
109062306a36Sopenharmony_ci	 * see commit b3bfce2b "i2c: mpc: cleanup clock API use" for
109162306a36Sopenharmony_ci	 * details, adjusting s/NULL/"ipg"/ in i2c-mpc.c would make this
109262306a36Sopenharmony_ci	 * workaround obsolete
109362306a36Sopenharmony_ci	 */
109462306a36Sopenharmony_ci	if (did_register & DID_REG_I2C)
109562306a36Sopenharmony_ci		clk_prepare_enable(clks[MPC512x_CLK_I2C]);
109662306a36Sopenharmony_ci
109762306a36Sopenharmony_ci	FOR_NODES("fsl,mpc5121-diu") {
109862306a36Sopenharmony_ci		NODE_PREP;
109962306a36Sopenharmony_ci		NODE_CHK("ipg", clks[MPC512x_CLK_DIU], 1, DIU);
110062306a36Sopenharmony_ci	}
110162306a36Sopenharmony_ci
110262306a36Sopenharmony_ci	FOR_NODES("fsl,mpc5121-viu") {
110362306a36Sopenharmony_ci		NODE_PREP;
110462306a36Sopenharmony_ci		NODE_CHK("ipg", clks[MPC512x_CLK_VIU], 0, VIU);
110562306a36Sopenharmony_ci	}
110662306a36Sopenharmony_ci
110762306a36Sopenharmony_ci	/*
110862306a36Sopenharmony_ci	 * note that 2771399a "fs_enet: cleanup clock API use" did use the
110962306a36Sopenharmony_ci	 * "per" string for the clock lookup in contrast to the "ipg" name
111062306a36Sopenharmony_ci	 * which most other nodes are using -- this is not a fatal thing
111162306a36Sopenharmony_ci	 * but just something to keep in mind when doing compatibility
111262306a36Sopenharmony_ci	 * registration, it's a non-issue with up-to-date device tree data
111362306a36Sopenharmony_ci	 */
111462306a36Sopenharmony_ci	FOR_NODES("fsl,mpc5121-fec") {
111562306a36Sopenharmony_ci		NODE_PREP;
111662306a36Sopenharmony_ci		NODE_CHK("per", clks[MPC512x_CLK_FEC], 0, FEC);
111762306a36Sopenharmony_ci	}
111862306a36Sopenharmony_ci	FOR_NODES("fsl,mpc5121-fec-mdio") {
111962306a36Sopenharmony_ci		NODE_PREP;
112062306a36Sopenharmony_ci		NODE_CHK("per", clks[MPC512x_CLK_FEC], 0, FEC);
112162306a36Sopenharmony_ci	}
112262306a36Sopenharmony_ci	/*
112362306a36Sopenharmony_ci	 * MPC5125 has two FECs: FEC1 at 0x2800, FEC2 at 0x4800;
112462306a36Sopenharmony_ci	 * the clock items don't "form an array" since FEC2 was
112562306a36Sopenharmony_ci	 * added only later and was not allowed to shift all other
112662306a36Sopenharmony_ci	 * clock item indices, so the numbers aren't adjacent
112762306a36Sopenharmony_ci	 */
112862306a36Sopenharmony_ci	FOR_NODES("fsl,mpc5125-fec") {
112962306a36Sopenharmony_ci		NODE_PREP;
113062306a36Sopenharmony_ci		if (res.start & 0x4000)
113162306a36Sopenharmony_ci			idx = MPC512x_CLK_FEC2;
113262306a36Sopenharmony_ci		else
113362306a36Sopenharmony_ci			idx = MPC512x_CLK_FEC;
113462306a36Sopenharmony_ci		NODE_CHK("per", clks[idx], 0, FEC);
113562306a36Sopenharmony_ci	}
113662306a36Sopenharmony_ci
113762306a36Sopenharmony_ci	FOR_NODES("fsl,mpc5121-usb2-dr") {
113862306a36Sopenharmony_ci		NODE_PREP;
113962306a36Sopenharmony_ci		idx = (res.start & 0x4000) ? 1 : 0;
114062306a36Sopenharmony_ci		NODE_CHK("ipg", clks[MPC512x_CLK_USB1 + idx], 0, USB);
114162306a36Sopenharmony_ci	}
114262306a36Sopenharmony_ci
114362306a36Sopenharmony_ci	FOR_NODES("fsl,mpc5121-pata") {
114462306a36Sopenharmony_ci		NODE_PREP;
114562306a36Sopenharmony_ci		NODE_CHK("ipg", clks[MPC512x_CLK_PATA], 0, PATA);
114662306a36Sopenharmony_ci	}
114762306a36Sopenharmony_ci
114862306a36Sopenharmony_ci	/*
114962306a36Sopenharmony_ci	 * try to collapse diagnostics into a single line of output yet
115062306a36Sopenharmony_ci	 * provide a full list of what is missing, to avoid noise in the
115162306a36Sopenharmony_ci	 * absence of up-to-date device tree data -- backwards
115262306a36Sopenharmony_ci	 * compatibility to old DTBs is a requirement, updates may be
115362306a36Sopenharmony_ci	 * desirable or preferrable but are not at all mandatory
115462306a36Sopenharmony_ci	 */
115562306a36Sopenharmony_ci	if (did_register) {
115662306a36Sopenharmony_ci		pr_notice("device tree lacks clock specs, adding fallbacks (0x%x,%s%s%s%s%s%s%s%s%s%s)\n",
115762306a36Sopenharmony_ci			  did_register,
115862306a36Sopenharmony_ci			  (did_register & DID_REG_PSC) ? " PSC" : "",
115962306a36Sopenharmony_ci			  (did_register & DID_REG_PSCFIFO) ? " PSCFIFO" : "",
116062306a36Sopenharmony_ci			  (did_register & DID_REG_NFC) ? " NFC" : "",
116162306a36Sopenharmony_ci			  (did_register & DID_REG_CAN) ? " CAN" : "",
116262306a36Sopenharmony_ci			  (did_register & DID_REG_I2C) ? " I2C" : "",
116362306a36Sopenharmony_ci			  (did_register & DID_REG_DIU) ? " DIU" : "",
116462306a36Sopenharmony_ci			  (did_register & DID_REG_VIU) ? " VIU" : "",
116562306a36Sopenharmony_ci			  (did_register & DID_REG_FEC) ? " FEC" : "",
116662306a36Sopenharmony_ci			  (did_register & DID_REG_USB) ? " USB" : "",
116762306a36Sopenharmony_ci			  (did_register & DID_REG_PATA) ? " PATA" : "");
116862306a36Sopenharmony_ci	} else {
116962306a36Sopenharmony_ci		pr_debug("device tree has clock specs, no fallbacks added\n");
117062306a36Sopenharmony_ci	}
117162306a36Sopenharmony_ci}
117262306a36Sopenharmony_ci
117362306a36Sopenharmony_ci/*
117462306a36Sopenharmony_ci * The "fixed-clock" nodes (which includes the oscillator node if the board's
117562306a36Sopenharmony_ci * DT provides one) has already been scanned by the of_clk_init() in
117662306a36Sopenharmony_ci * time_init().
117762306a36Sopenharmony_ci */
117862306a36Sopenharmony_ciint __init mpc5121_clk_init(void)
117962306a36Sopenharmony_ci{
118062306a36Sopenharmony_ci	struct device_node *clk_np;
118162306a36Sopenharmony_ci	int busfreq;
118262306a36Sopenharmony_ci
118362306a36Sopenharmony_ci	/* map the clock control registers */
118462306a36Sopenharmony_ci	clk_np = of_find_compatible_node(NULL, NULL, "fsl,mpc5121-clock");
118562306a36Sopenharmony_ci	if (!clk_np)
118662306a36Sopenharmony_ci		return -ENODEV;
118762306a36Sopenharmony_ci	clkregs = of_iomap(clk_np, 0);
118862306a36Sopenharmony_ci	WARN_ON(!clkregs);
118962306a36Sopenharmony_ci
119062306a36Sopenharmony_ci	/* determine the SoC variant we run on */
119162306a36Sopenharmony_ci	mpc512x_clk_determine_soc();
119262306a36Sopenharmony_ci
119362306a36Sopenharmony_ci	/* invalidate all not yet registered clock slots */
119462306a36Sopenharmony_ci	mpc512x_clk_preset_data();
119562306a36Sopenharmony_ci
119662306a36Sopenharmony_ci	/*
119762306a36Sopenharmony_ci	 * add a dummy clock for those situations where a clock spec is
119862306a36Sopenharmony_ci	 * required yet no real clock is involved
119962306a36Sopenharmony_ci	 */
120062306a36Sopenharmony_ci	clks[MPC512x_CLK_DUMMY] = mpc512x_clk_fixed("dummy", 0);
120162306a36Sopenharmony_ci
120262306a36Sopenharmony_ci	/*
120362306a36Sopenharmony_ci	 * have all the real nodes in the clock tree populated from REF
120462306a36Sopenharmony_ci	 * down to all leaves, either starting from the OSC node or from
120562306a36Sopenharmony_ci	 * a REF root that was created from the IPS bus clock input
120662306a36Sopenharmony_ci	 */
120762306a36Sopenharmony_ci	busfreq = get_freq_from_dt("bus-frequency");
120862306a36Sopenharmony_ci	mpc512x_clk_setup_clock_tree(clk_np, busfreq);
120962306a36Sopenharmony_ci
121062306a36Sopenharmony_ci	/* register as an OF clock provider */
121162306a36Sopenharmony_ci	mpc5121_clk_register_of_provider(clk_np);
121262306a36Sopenharmony_ci
121362306a36Sopenharmony_ci	of_node_put(clk_np);
121462306a36Sopenharmony_ci
121562306a36Sopenharmony_ci	/*
121662306a36Sopenharmony_ci	 * unbreak not yet adjusted peripheral drivers during migration
121762306a36Sopenharmony_ci	 * towards fully operational common clock support, and allow
121862306a36Sopenharmony_ci	 * operation in the absence of clock related device tree specs
121962306a36Sopenharmony_ci	 */
122062306a36Sopenharmony_ci	mpc5121_clk_provide_migration_support();
122162306a36Sopenharmony_ci	mpc5121_clk_provide_backwards_compat();
122262306a36Sopenharmony_ci
122362306a36Sopenharmony_ci	return 0;
122462306a36Sopenharmony_ci}
1225