xref: /rk3399_rockchip-uboot/drivers/clk/uniphier/clk-uniphier-core.c (revision e4adc8ed3c684f41a307fde275e683a391f2a7ce)
148264d9bSMasahiro Yamada /*
24e3d8406SMasahiro Yamada  * Copyright (C) 2016 Socionext Inc.
34e3d8406SMasahiro Yamada  *   Author: Masahiro Yamada <yamada.masahiro@socionext.com>
448264d9bSMasahiro Yamada  *
548264d9bSMasahiro Yamada  * SPDX-License-Identifier:	GPL-2.0+
648264d9bSMasahiro Yamada  */
748264d9bSMasahiro Yamada 
848264d9bSMasahiro Yamada #include <common.h>
9805dc44cSMasahiro Yamada #include <clk-uclass.h>
109d922450SSimon Glass #include <dm.h>
1148264d9bSMasahiro Yamada #include <linux/bitops.h>
1248264d9bSMasahiro Yamada #include <linux/io.h>
1345a3b1fdSMasahiro Yamada #include <linux/sizes.h>
1448264d9bSMasahiro Yamada 
1548264d9bSMasahiro Yamada #include "clk-uniphier.h"
1648264d9bSMasahiro Yamada 
17102e3187SMasahiro Yamada /**
18102e3187SMasahiro Yamada  * struct uniphier_clk_priv - private data for UniPhier clock driver
19102e3187SMasahiro Yamada  *
20102e3187SMasahiro Yamada  * @base: base address of the clock provider
21805dc44cSMasahiro Yamada  * @data: SoC specific data
22102e3187SMasahiro Yamada  */
23102e3187SMasahiro Yamada struct uniphier_clk_priv {
24102e3187SMasahiro Yamada 	void __iomem *base;
25805dc44cSMasahiro Yamada 	const struct uniphier_clk_data *data;
26102e3187SMasahiro Yamada };
27102e3187SMasahiro Yamada 
uniphier_clk_enable(struct clk * clk)28805dc44cSMasahiro Yamada static int uniphier_clk_enable(struct clk *clk)
29805dc44cSMasahiro Yamada {
30805dc44cSMasahiro Yamada 	struct uniphier_clk_priv *priv = dev_get_priv(clk->dev);
31805dc44cSMasahiro Yamada 	unsigned long id = clk->id;
32805dc44cSMasahiro Yamada 	const struct uniphier_clk_gate_data *p;
33805dc44cSMasahiro Yamada 
34805dc44cSMasahiro Yamada 	for (p = priv->data->gate; p->id != UNIPHIER_CLK_ID_END; p++) {
35805dc44cSMasahiro Yamada 		u32 val;
36805dc44cSMasahiro Yamada 
37805dc44cSMasahiro Yamada 		if (p->id != id)
38805dc44cSMasahiro Yamada 			continue;
39805dc44cSMasahiro Yamada 
40805dc44cSMasahiro Yamada 		val = readl(priv->base + p->reg);
41805dc44cSMasahiro Yamada 		val |= BIT(p->bit);
42805dc44cSMasahiro Yamada 		writel(val, priv->base + p->reg);
43805dc44cSMasahiro Yamada 
44805dc44cSMasahiro Yamada 		return 0;
45805dc44cSMasahiro Yamada 	}
46805dc44cSMasahiro Yamada 
47805dc44cSMasahiro Yamada 	dev_err(priv->dev, "clk_id=%lu was not handled\n", id);
48805dc44cSMasahiro Yamada 	return -EINVAL;
49805dc44cSMasahiro Yamada }
50805dc44cSMasahiro Yamada 
51805dc44cSMasahiro Yamada static const struct uniphier_clk_mux_data *
uniphier_clk_get_mux_data(struct uniphier_clk_priv * priv,unsigned long id)52805dc44cSMasahiro Yamada uniphier_clk_get_mux_data(struct uniphier_clk_priv *priv, unsigned long id)
53805dc44cSMasahiro Yamada {
54805dc44cSMasahiro Yamada 	const struct uniphier_clk_mux_data *p;
55805dc44cSMasahiro Yamada 
56805dc44cSMasahiro Yamada 	for (p = priv->data->mux; p->id != UNIPHIER_CLK_ID_END; p++) {
57805dc44cSMasahiro Yamada 		if (p->id == id)
58805dc44cSMasahiro Yamada 			return p;
59805dc44cSMasahiro Yamada 	}
60805dc44cSMasahiro Yamada 
61805dc44cSMasahiro Yamada 	return NULL;
62805dc44cSMasahiro Yamada }
63805dc44cSMasahiro Yamada 
uniphier_clk_get_rate(struct clk * clk)64805dc44cSMasahiro Yamada static ulong uniphier_clk_get_rate(struct clk *clk)
65805dc44cSMasahiro Yamada {
66805dc44cSMasahiro Yamada 	struct uniphier_clk_priv *priv = dev_get_priv(clk->dev);
67805dc44cSMasahiro Yamada 	const struct uniphier_clk_mux_data *mux;
68805dc44cSMasahiro Yamada 	u32 val;
69805dc44cSMasahiro Yamada 	int i;
70805dc44cSMasahiro Yamada 
71805dc44cSMasahiro Yamada 	mux = uniphier_clk_get_mux_data(priv, clk->id);
72805dc44cSMasahiro Yamada 	if (!mux)
73805dc44cSMasahiro Yamada 		return 0;
74805dc44cSMasahiro Yamada 
75805dc44cSMasahiro Yamada 	if (!mux->nr_muxs)		/* fixed-rate */
76805dc44cSMasahiro Yamada 		return mux->rates[0];
77805dc44cSMasahiro Yamada 
78805dc44cSMasahiro Yamada 	val = readl(priv->base + mux->reg);
79805dc44cSMasahiro Yamada 
80805dc44cSMasahiro Yamada 	for (i = 0; i < mux->nr_muxs; i++)
81805dc44cSMasahiro Yamada 		if ((mux->masks[i] & val) == mux->vals[i])
82805dc44cSMasahiro Yamada 			return mux->rates[i];
83805dc44cSMasahiro Yamada 
84805dc44cSMasahiro Yamada 	return -EINVAL;
85805dc44cSMasahiro Yamada }
86805dc44cSMasahiro Yamada 
uniphier_clk_set_rate(struct clk * clk,ulong rate)87805dc44cSMasahiro Yamada static ulong uniphier_clk_set_rate(struct clk *clk, ulong rate)
88805dc44cSMasahiro Yamada {
89805dc44cSMasahiro Yamada 	struct uniphier_clk_priv *priv = dev_get_priv(clk->dev);
90805dc44cSMasahiro Yamada 	const struct uniphier_clk_mux_data *mux;
91805dc44cSMasahiro Yamada 	u32 val;
92805dc44cSMasahiro Yamada 	int i, best_rate_id = -1;
93805dc44cSMasahiro Yamada 	ulong best_rate = 0;
94805dc44cSMasahiro Yamada 
95805dc44cSMasahiro Yamada 	mux = uniphier_clk_get_mux_data(priv, clk->id);
96805dc44cSMasahiro Yamada 	if (!mux)
97805dc44cSMasahiro Yamada 		return 0;
98805dc44cSMasahiro Yamada 
99805dc44cSMasahiro Yamada 	if (!mux->nr_muxs)		/* fixed-rate */
100805dc44cSMasahiro Yamada 		return mux->rates[0];
101805dc44cSMasahiro Yamada 
102805dc44cSMasahiro Yamada 	/* first, decide the best match rate */
103805dc44cSMasahiro Yamada 	for (i = 0; i < mux->nr_muxs; i++) {
104805dc44cSMasahiro Yamada 		if (mux->rates[i] > best_rate && mux->rates[i] <= rate) {
105805dc44cSMasahiro Yamada 			best_rate = mux->rates[i];
106805dc44cSMasahiro Yamada 			best_rate_id = i;
107805dc44cSMasahiro Yamada 		}
108805dc44cSMasahiro Yamada 	}
109805dc44cSMasahiro Yamada 
110805dc44cSMasahiro Yamada 	if (best_rate_id < 0)
111805dc44cSMasahiro Yamada 		return -EINVAL;
112805dc44cSMasahiro Yamada 
113805dc44cSMasahiro Yamada 	val = readl(priv->base + mux->reg);
114805dc44cSMasahiro Yamada 	val &= ~mux->masks[best_rate_id];
115805dc44cSMasahiro Yamada 	val |= mux->vals[best_rate_id];
116805dc44cSMasahiro Yamada 	writel(val, priv->base + mux->reg);
117805dc44cSMasahiro Yamada 
118805dc44cSMasahiro Yamada 	debug("%s: requested rate = %lu, set rate = %lu\n", __func__,
119805dc44cSMasahiro Yamada 	      rate, best_rate);
120805dc44cSMasahiro Yamada 
121805dc44cSMasahiro Yamada 	return best_rate;
122805dc44cSMasahiro Yamada }
123805dc44cSMasahiro Yamada 
1241d21e1b9SMasahiro Yamada static const struct clk_ops uniphier_clk_ops = {
125805dc44cSMasahiro Yamada 	.enable = uniphier_clk_enable,
126805dc44cSMasahiro Yamada 	.get_rate = uniphier_clk_get_rate,
127805dc44cSMasahiro Yamada 	.set_rate = uniphier_clk_set_rate,
128805dc44cSMasahiro Yamada };
129805dc44cSMasahiro Yamada 
uniphier_clk_probe(struct udevice * dev)130805dc44cSMasahiro Yamada static int uniphier_clk_probe(struct udevice *dev)
131102e3187SMasahiro Yamada {
132102e3187SMasahiro Yamada 	struct uniphier_clk_priv *priv = dev_get_priv(dev);
133102e3187SMasahiro Yamada 	fdt_addr_t addr;
134102e3187SMasahiro Yamada 
135a821c4afSSimon Glass 	addr = devfdt_get_addr(dev->parent);
136102e3187SMasahiro Yamada 	if (addr == FDT_ADDR_T_NONE)
137102e3187SMasahiro Yamada 		return -EINVAL;
138102e3187SMasahiro Yamada 
139102e3187SMasahiro Yamada 	priv->base = devm_ioremap(dev, addr, SZ_4K);
140102e3187SMasahiro Yamada 	if (!priv->base)
141102e3187SMasahiro Yamada 		return -ENOMEM;
142102e3187SMasahiro Yamada 
143805dc44cSMasahiro Yamada 	priv->data = (void *)dev_get_driver_data(dev);
144102e3187SMasahiro Yamada 
145102e3187SMasahiro Yamada 	return 0;
146102e3187SMasahiro Yamada }
147102e3187SMasahiro Yamada 
148102e3187SMasahiro Yamada static const struct udevice_id uniphier_clk_match[] = {
149*d7505752SMasahiro Yamada 	/* System clock */
150*d7505752SMasahiro Yamada 	{
151*d7505752SMasahiro Yamada 		.compatible = "socionext,uniphier-ld4-clock",
152*d7505752SMasahiro Yamada 		.data = (ulong)&uniphier_pxs2_sys_clk_data,
153*d7505752SMasahiro Yamada 	},
154*d7505752SMasahiro Yamada 	{
155*d7505752SMasahiro Yamada 		.compatible = "socionext,uniphier-pro4-clock",
156*d7505752SMasahiro Yamada 		.data = (ulong)&uniphier_pxs2_sys_clk_data,
157*d7505752SMasahiro Yamada 	},
158*d7505752SMasahiro Yamada 	{
159*d7505752SMasahiro Yamada 		.compatible = "socionext,uniphier-sld8-clock",
160*d7505752SMasahiro Yamada 		.data = (ulong)&uniphier_pxs2_sys_clk_data,
161*d7505752SMasahiro Yamada 	},
162*d7505752SMasahiro Yamada 	{
163*d7505752SMasahiro Yamada 		.compatible = "socionext,uniphier-pro5-clock",
164*d7505752SMasahiro Yamada 		.data = (ulong)&uniphier_pxs2_sys_clk_data,
165*d7505752SMasahiro Yamada 	},
166*d7505752SMasahiro Yamada 	{
167*d7505752SMasahiro Yamada 		.compatible = "socionext,uniphier-pxs2-clock",
168*d7505752SMasahiro Yamada 		.data = (ulong)&uniphier_pxs2_sys_clk_data,
169*d7505752SMasahiro Yamada 	},
170*d7505752SMasahiro Yamada 	{
171*d7505752SMasahiro Yamada 		.compatible = "socionext,uniphier-ld11-clock",
172*d7505752SMasahiro Yamada 		.data = (ulong)&uniphier_ld20_sys_clk_data,
173*d7505752SMasahiro Yamada 	},
174*d7505752SMasahiro Yamada 	{
175*d7505752SMasahiro Yamada 		.compatible = "socionext,uniphier-ld20-clock",
176*d7505752SMasahiro Yamada 		.data = (ulong)&uniphier_ld20_sys_clk_data,
177*d7505752SMasahiro Yamada 	},
178*d7505752SMasahiro Yamada 	/* Media I/O clock */
17948264d9bSMasahiro Yamada 	{
1806dc5b6b1SMasahiro Yamada 		.compatible = "socionext,uniphier-ld4-mio-clock",
181102e3187SMasahiro Yamada 		.data = (ulong)&uniphier_mio_clk_data,
182102e3187SMasahiro Yamada 	},
183102e3187SMasahiro Yamada 	{
1846dc5b6b1SMasahiro Yamada 		.compatible = "socionext,uniphier-pro4-mio-clock",
185102e3187SMasahiro Yamada 		.data = (ulong)&uniphier_mio_clk_data,
186102e3187SMasahiro Yamada 	},
187102e3187SMasahiro Yamada 	{
1886dc5b6b1SMasahiro Yamada 		.compatible = "socionext,uniphier-sld8-mio-clock",
189102e3187SMasahiro Yamada 		.data = (ulong)&uniphier_mio_clk_data,
190102e3187SMasahiro Yamada 	},
191102e3187SMasahiro Yamada 	{
1924c642e68SMasahiro Yamada 		.compatible = "socionext,uniphier-pro5-sd-clock",
193102e3187SMasahiro Yamada 		.data = (ulong)&uniphier_mio_clk_data,
194102e3187SMasahiro Yamada 	},
195102e3187SMasahiro Yamada 	{
1964c642e68SMasahiro Yamada 		.compatible = "socionext,uniphier-pxs2-sd-clock",
197102e3187SMasahiro Yamada 		.data = (ulong)&uniphier_mio_clk_data,
198102e3187SMasahiro Yamada 	},
199102e3187SMasahiro Yamada 	{
2006dc5b6b1SMasahiro Yamada 		.compatible = "socionext,uniphier-ld11-mio-clock",
201102e3187SMasahiro Yamada 		.data = (ulong)&uniphier_mio_clk_data,
202102e3187SMasahiro Yamada 	},
203102e3187SMasahiro Yamada 	{
2044c642e68SMasahiro Yamada 		.compatible = "socionext,uniphier-ld20-sd-clock",
205102e3187SMasahiro Yamada 		.data = (ulong)&uniphier_mio_clk_data,
206102e3187SMasahiro Yamada 	},
207102e3187SMasahiro Yamada 	{ /* sentinel */ }
208102e3187SMasahiro Yamada };
20948264d9bSMasahiro Yamada 
210102e3187SMasahiro Yamada U_BOOT_DRIVER(uniphier_clk) = {
211102e3187SMasahiro Yamada 	.name = "uniphier-clk",
212102e3187SMasahiro Yamada 	.id = UCLASS_CLK,
213102e3187SMasahiro Yamada 	.of_match = uniphier_clk_match,
214102e3187SMasahiro Yamada 	.probe = uniphier_clk_probe,
215102e3187SMasahiro Yamada 	.priv_auto_alloc_size = sizeof(struct uniphier_clk_priv),
216102e3187SMasahiro Yamada 	.ops = &uniphier_clk_ops,
217102e3187SMasahiro Yamada };
218