xref: /rk3399_rockchip-uboot/drivers/clk/exynos/clk-exynos7420.c (revision a821c4af79e4f5ce9b629b20473863397bbe9b10)
1166097e8SThomas Abraham /*
2166097e8SThomas Abraham  * Samsung Exynos7420 clock driver.
3166097e8SThomas Abraham  * Copyright (C) 2016 Samsung Electronics
4166097e8SThomas Abraham  * Thomas Abraham <thomas.ab@samsung.com>
5166097e8SThomas Abraham  *
6166097e8SThomas Abraham  * SPDX-License-Identifier:	GPL-2.0+
7166097e8SThomas Abraham  */
8166097e8SThomas Abraham 
9166097e8SThomas Abraham #include <common.h>
10166097e8SThomas Abraham #include <dm.h>
11166097e8SThomas Abraham #include <errno.h>
12135aa950SStephen Warren #include <clk-uclass.h>
13166097e8SThomas Abraham #include <asm/io.h>
14166097e8SThomas Abraham #include <dt-bindings/clock/exynos7420-clk.h>
15166097e8SThomas Abraham #include "clk-pll.h"
16166097e8SThomas Abraham 
17166097e8SThomas Abraham DECLARE_GLOBAL_DATA_PTR;
18166097e8SThomas Abraham 
19166097e8SThomas Abraham #define DIVIDER(reg, shift, mask)	\
20166097e8SThomas Abraham 	(((readl(reg) >> shift) & mask) + 1)
21166097e8SThomas Abraham 
22166097e8SThomas Abraham /* CMU TOPC block device structure */
23166097e8SThomas Abraham struct exynos7420_clk_cmu_topc {
24166097e8SThomas Abraham 	unsigned int	rsvd1[68];
25166097e8SThomas Abraham 	unsigned int	bus0_pll_con[2];
26166097e8SThomas Abraham 	unsigned int	rsvd2[2];
27166097e8SThomas Abraham 	unsigned int	bus1_pll_con[2];
28166097e8SThomas Abraham 	unsigned int	rsvd3[54];
29166097e8SThomas Abraham 	unsigned int	mux_sel[6];
30166097e8SThomas Abraham 	unsigned int	rsvd4[250];
31166097e8SThomas Abraham 	unsigned int	div[4];
32166097e8SThomas Abraham };
33166097e8SThomas Abraham 
34166097e8SThomas Abraham /* CMU TOP0 block device structure */
35166097e8SThomas Abraham struct exynos7420_clk_cmu_top0 {
36166097e8SThomas Abraham 	unsigned int	rsvd0[128];
37166097e8SThomas Abraham 	unsigned int	mux_sel[7];
38166097e8SThomas Abraham 	unsigned int	rsvd1[261];
39166097e8SThomas Abraham 	unsigned int	div_peric[5];
40166097e8SThomas Abraham };
41166097e8SThomas Abraham 
42166097e8SThomas Abraham /**
43166097e8SThomas Abraham  * struct exynos7420_clk_topc_priv - private data for CMU topc clock driver.
44166097e8SThomas Abraham  *
45166097e8SThomas Abraham  * @topc: base address of the memory mapped CMU TOPC controller.
46166097e8SThomas Abraham  * @fin_freq: frequency of the Oscillator clock.
47166097e8SThomas Abraham  * @sclk_bus0_pll_a: frequency of sclk_bus0_pll_a clock.
48166097e8SThomas Abraham  * @sclk_bus1_pll_a: frequency of sclk_bus1_pll_a clock.
49166097e8SThomas Abraham  */
50166097e8SThomas Abraham struct exynos7420_clk_topc_priv {
51166097e8SThomas Abraham 	struct exynos7420_clk_cmu_topc *topc;
52166097e8SThomas Abraham 	unsigned long fin_freq;
53166097e8SThomas Abraham 	unsigned long sclk_bus0_pll_a;
54166097e8SThomas Abraham 	unsigned long sclk_bus1_pll_a;
55166097e8SThomas Abraham };
56166097e8SThomas Abraham 
57166097e8SThomas Abraham /**
58166097e8SThomas Abraham  * struct exynos7420_clk_top0_priv - private data for CMU top0 clock driver.
59166097e8SThomas Abraham  *
60166097e8SThomas Abraham  * @top0: base address of the memory mapped CMU TOP0 controller.
61166097e8SThomas Abraham  * @mout_top0_bus0_pll_half: frequency of mout_top0_bus0_pll_half clock
62166097e8SThomas Abraham  * @sclk_uart2: frequency of sclk_uart2 clock.
63166097e8SThomas Abraham  */
64166097e8SThomas Abraham struct exynos7420_clk_top0_priv {
65166097e8SThomas Abraham 	struct exynos7420_clk_cmu_top0 *top0;
66166097e8SThomas Abraham 	unsigned long mout_top0_bus0_pll_half;
67166097e8SThomas Abraham 	unsigned long sclk_uart2;
68166097e8SThomas Abraham };
69166097e8SThomas Abraham 
exynos7420_topc_get_rate(struct clk * clk)70135aa950SStephen Warren static ulong exynos7420_topc_get_rate(struct clk *clk)
71166097e8SThomas Abraham {
72135aa950SStephen Warren 	struct exynos7420_clk_topc_priv *priv = dev_get_priv(clk->dev);
73166097e8SThomas Abraham 
74135aa950SStephen Warren 	switch (clk->id) {
75166097e8SThomas Abraham 	case DOUT_SCLK_BUS0_PLL:
76166097e8SThomas Abraham 	case SCLK_BUS0_PLL_A:
77166097e8SThomas Abraham 	case SCLK_BUS0_PLL_B:
78166097e8SThomas Abraham 		return priv->sclk_bus0_pll_a;
79166097e8SThomas Abraham 	case DOUT_SCLK_BUS1_PLL:
80166097e8SThomas Abraham 	case SCLK_BUS1_PLL_A:
81166097e8SThomas Abraham 	case SCLK_BUS1_PLL_B:
82166097e8SThomas Abraham 		return priv->sclk_bus1_pll_a;
83166097e8SThomas Abraham 	default:
84166097e8SThomas Abraham 		return 0;
85166097e8SThomas Abraham 	}
86166097e8SThomas Abraham }
87166097e8SThomas Abraham 
88166097e8SThomas Abraham static struct clk_ops exynos7420_clk_topc_ops = {
89135aa950SStephen Warren 	.get_rate	= exynos7420_topc_get_rate,
90166097e8SThomas Abraham };
91166097e8SThomas Abraham 
exynos7420_clk_topc_probe(struct udevice * dev)92166097e8SThomas Abraham static int exynos7420_clk_topc_probe(struct udevice *dev)
93166097e8SThomas Abraham {
94166097e8SThomas Abraham 	struct exynos7420_clk_topc_priv *priv = dev_get_priv(dev);
95166097e8SThomas Abraham 	struct exynos7420_clk_cmu_topc *topc;
96135aa950SStephen Warren 	struct clk in_clk;
97166097e8SThomas Abraham 	unsigned long rate;
98166097e8SThomas Abraham 	fdt_addr_t base;
99166097e8SThomas Abraham 	int ret;
100166097e8SThomas Abraham 
101*a821c4afSSimon Glass 	base = devfdt_get_addr(dev);
102166097e8SThomas Abraham 	if (base == FDT_ADDR_T_NONE)
103166097e8SThomas Abraham 		return -EINVAL;
104166097e8SThomas Abraham 
105166097e8SThomas Abraham 	topc = (struct exynos7420_clk_cmu_topc *)base;
106166097e8SThomas Abraham 	priv->topc = topc;
107166097e8SThomas Abraham 
108135aa950SStephen Warren 	ret = clk_get_by_index(dev, 0, &in_clk);
109166097e8SThomas Abraham 	if (ret >= 0)
110135aa950SStephen Warren 		priv->fin_freq = clk_get_rate(&in_clk);
111166097e8SThomas Abraham 
112166097e8SThomas Abraham 	rate = pll145x_get_rate(&topc->bus0_pll_con[0], priv->fin_freq);
113166097e8SThomas Abraham 	if (readl(&topc->mux_sel[1]) & (1 << 16))
114166097e8SThomas Abraham 		rate >>= 1;
115166097e8SThomas Abraham 	rate /= DIVIDER(&topc->div[3], 0, 0xf);
116166097e8SThomas Abraham 	priv->sclk_bus0_pll_a = rate;
117166097e8SThomas Abraham 
118166097e8SThomas Abraham 	rate = pll145x_get_rate(&topc->bus1_pll_con[0], priv->fin_freq) /
119166097e8SThomas Abraham 			DIVIDER(&topc->div[3], 8, 0xf);
120166097e8SThomas Abraham 	priv->sclk_bus1_pll_a = rate;
121166097e8SThomas Abraham 
122166097e8SThomas Abraham 	return 0;
123166097e8SThomas Abraham }
124166097e8SThomas Abraham 
exynos7420_top0_get_rate(struct clk * clk)125135aa950SStephen Warren static ulong exynos7420_top0_get_rate(struct clk *clk)
126166097e8SThomas Abraham {
127135aa950SStephen Warren 	struct exynos7420_clk_top0_priv *priv = dev_get_priv(clk->dev);
128166097e8SThomas Abraham 	struct exynos7420_clk_cmu_top0 *top0 = priv->top0;
129166097e8SThomas Abraham 
130135aa950SStephen Warren 	switch (clk->id) {
131166097e8SThomas Abraham 	case CLK_SCLK_UART2:
132166097e8SThomas Abraham 		return priv->mout_top0_bus0_pll_half /
133166097e8SThomas Abraham 			DIVIDER(&top0->div_peric[3], 8, 0xf);
134166097e8SThomas Abraham 	default:
135166097e8SThomas Abraham 		return 0;
136166097e8SThomas Abraham 	}
137166097e8SThomas Abraham }
138166097e8SThomas Abraham 
139166097e8SThomas Abraham static struct clk_ops exynos7420_clk_top0_ops = {
140135aa950SStephen Warren 	.get_rate	= exynos7420_top0_get_rate,
141166097e8SThomas Abraham };
142166097e8SThomas Abraham 
exynos7420_clk_top0_probe(struct udevice * dev)143166097e8SThomas Abraham static int exynos7420_clk_top0_probe(struct udevice *dev)
144166097e8SThomas Abraham {
145166097e8SThomas Abraham 	struct exynos7420_clk_top0_priv *priv;
146166097e8SThomas Abraham 	struct exynos7420_clk_cmu_top0 *top0;
147135aa950SStephen Warren 	struct clk in_clk;
148166097e8SThomas Abraham 	fdt_addr_t base;
149166097e8SThomas Abraham 	int ret;
150166097e8SThomas Abraham 
151166097e8SThomas Abraham 	priv = dev_get_priv(dev);
152166097e8SThomas Abraham 	if (!priv)
153166097e8SThomas Abraham 		return -EINVAL;
154166097e8SThomas Abraham 
155*a821c4afSSimon Glass 	base = devfdt_get_addr(dev);
156166097e8SThomas Abraham 	if (base == FDT_ADDR_T_NONE)
157166097e8SThomas Abraham 		return -EINVAL;
158166097e8SThomas Abraham 
159166097e8SThomas Abraham 	top0 = (struct exynos7420_clk_cmu_top0 *)base;
160166097e8SThomas Abraham 	priv->top0 = top0;
161166097e8SThomas Abraham 
162135aa950SStephen Warren 	ret = clk_get_by_index(dev, 1, &in_clk);
163166097e8SThomas Abraham 	if (ret >= 0) {
164166097e8SThomas Abraham 		priv->mout_top0_bus0_pll_half =
165135aa950SStephen Warren 			clk_get_rate(&in_clk);
166166097e8SThomas Abraham 		if (readl(&top0->mux_sel[1]) & (1 << 16))
167166097e8SThomas Abraham 			priv->mout_top0_bus0_pll_half >>= 1;
168166097e8SThomas Abraham 	}
169166097e8SThomas Abraham 
170166097e8SThomas Abraham 	return 0;
171166097e8SThomas Abraham }
172166097e8SThomas Abraham 
exynos7420_peric1_get_rate(struct clk * clk)173135aa950SStephen Warren static ulong exynos7420_peric1_get_rate(struct clk *clk)
174166097e8SThomas Abraham {
175135aa950SStephen Warren 	struct clk in_clk;
176166097e8SThomas Abraham 	unsigned int ret;
177166097e8SThomas Abraham 	unsigned long freq = 0;
178166097e8SThomas Abraham 
179135aa950SStephen Warren 	switch (clk->id) {
180166097e8SThomas Abraham 	case SCLK_UART2:
181135aa950SStephen Warren 		ret = clk_get_by_index(clk->dev, 3, &in_clk);
182166097e8SThomas Abraham 		if (ret < 0)
183166097e8SThomas Abraham 			return ret;
184135aa950SStephen Warren 		freq = clk_get_rate(&in_clk);
185166097e8SThomas Abraham 		break;
186166097e8SThomas Abraham 	}
187166097e8SThomas Abraham 
188166097e8SThomas Abraham 	return freq;
189166097e8SThomas Abraham }
190166097e8SThomas Abraham 
191166097e8SThomas Abraham static struct clk_ops exynos7420_clk_peric1_ops = {
192135aa950SStephen Warren 	.get_rate	= exynos7420_peric1_get_rate,
193166097e8SThomas Abraham };
194166097e8SThomas Abraham 
195166097e8SThomas Abraham static const struct udevice_id exynos7420_clk_topc_compat[] = {
196166097e8SThomas Abraham 	{ .compatible = "samsung,exynos7-clock-topc" },
197166097e8SThomas Abraham 	{ }
198166097e8SThomas Abraham };
199166097e8SThomas Abraham 
200166097e8SThomas Abraham U_BOOT_DRIVER(exynos7420_clk_topc) = {
201166097e8SThomas Abraham 	.name = "exynos7420-clock-topc",
202166097e8SThomas Abraham 	.id = UCLASS_CLK,
203166097e8SThomas Abraham 	.of_match = exynos7420_clk_topc_compat,
204166097e8SThomas Abraham 	.probe = exynos7420_clk_topc_probe,
205166097e8SThomas Abraham 	.priv_auto_alloc_size = sizeof(struct exynos7420_clk_topc_priv),
206166097e8SThomas Abraham 	.ops = &exynos7420_clk_topc_ops,
207166097e8SThomas Abraham 	.flags = DM_FLAG_PRE_RELOC,
208166097e8SThomas Abraham };
209166097e8SThomas Abraham 
210166097e8SThomas Abraham static const struct udevice_id exynos7420_clk_top0_compat[] = {
211166097e8SThomas Abraham 	{ .compatible = "samsung,exynos7-clock-top0" },
212166097e8SThomas Abraham 	{ }
213166097e8SThomas Abraham };
214166097e8SThomas Abraham 
215166097e8SThomas Abraham U_BOOT_DRIVER(exynos7420_clk_top0) = {
216166097e8SThomas Abraham 	.name = "exynos7420-clock-top0",
217166097e8SThomas Abraham 	.id = UCLASS_CLK,
218166097e8SThomas Abraham 	.of_match = exynos7420_clk_top0_compat,
219166097e8SThomas Abraham 	.probe = exynos7420_clk_top0_probe,
220166097e8SThomas Abraham 	.priv_auto_alloc_size = sizeof(struct exynos7420_clk_top0_priv),
221166097e8SThomas Abraham 	.ops = &exynos7420_clk_top0_ops,
222166097e8SThomas Abraham 	.flags = DM_FLAG_PRE_RELOC,
223166097e8SThomas Abraham };
224166097e8SThomas Abraham 
225166097e8SThomas Abraham static const struct udevice_id exynos7420_clk_peric1_compat[] = {
226166097e8SThomas Abraham 	{ .compatible = "samsung,exynos7-clock-peric1" },
227166097e8SThomas Abraham 	{ }
228166097e8SThomas Abraham };
229166097e8SThomas Abraham 
230166097e8SThomas Abraham U_BOOT_DRIVER(exynos7420_clk_peric1) = {
231166097e8SThomas Abraham 	.name = "exynos7420-clock-peric1",
232166097e8SThomas Abraham 	.id = UCLASS_CLK,
233166097e8SThomas Abraham 	.of_match = exynos7420_clk_peric1_compat,
234166097e8SThomas Abraham 	.ops = &exynos7420_clk_peric1_ops,
235166097e8SThomas Abraham 	.flags = DM_FLAG_PRE_RELOC,
236166097e8SThomas Abraham };
237