xref: /rk3399_rockchip-uboot/drivers/clk/uniphier/clk-uniphier-core.c (revision 805dc44cc8afc357f7cdca8b183d0b641768bdb2)
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>
9*805dc44cSMasahiro Yamada #include <clk-uclass.h>
10*805dc44cSMasahiro Yamada #include <dm/device.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
21*805dc44cSMasahiro Yamada  * @data: SoC specific data
22102e3187SMasahiro Yamada  */
23102e3187SMasahiro Yamada struct uniphier_clk_priv {
24102e3187SMasahiro Yamada 	void __iomem *base;
25*805dc44cSMasahiro Yamada 	const struct uniphier_clk_data *data;
26102e3187SMasahiro Yamada };
27102e3187SMasahiro Yamada 
28*805dc44cSMasahiro Yamada static int uniphier_clk_enable(struct clk *clk)
29*805dc44cSMasahiro Yamada {
30*805dc44cSMasahiro Yamada 	struct uniphier_clk_priv *priv = dev_get_priv(clk->dev);
31*805dc44cSMasahiro Yamada 	unsigned long id = clk->id;
32*805dc44cSMasahiro Yamada 	const struct uniphier_clk_gate_data *p;
33*805dc44cSMasahiro Yamada 
34*805dc44cSMasahiro Yamada 	for (p = priv->data->gate; p->id != UNIPHIER_CLK_ID_END; p++) {
35*805dc44cSMasahiro Yamada 		u32 val;
36*805dc44cSMasahiro Yamada 
37*805dc44cSMasahiro Yamada 		if (p->id != id)
38*805dc44cSMasahiro Yamada 			continue;
39*805dc44cSMasahiro Yamada 
40*805dc44cSMasahiro Yamada 		val = readl(priv->base + p->reg);
41*805dc44cSMasahiro Yamada 		val |= BIT(p->bit);
42*805dc44cSMasahiro Yamada 		writel(val, priv->base + p->reg);
43*805dc44cSMasahiro Yamada 
44*805dc44cSMasahiro Yamada 		return 0;
45*805dc44cSMasahiro Yamada 	}
46*805dc44cSMasahiro Yamada 
47*805dc44cSMasahiro Yamada 	dev_err(priv->dev, "clk_id=%lu was not handled\n", id);
48*805dc44cSMasahiro Yamada 	return -EINVAL;
49*805dc44cSMasahiro Yamada }
50*805dc44cSMasahiro Yamada 
51*805dc44cSMasahiro Yamada static const struct uniphier_clk_mux_data *
52*805dc44cSMasahiro Yamada uniphier_clk_get_mux_data(struct uniphier_clk_priv *priv, unsigned long id)
53*805dc44cSMasahiro Yamada {
54*805dc44cSMasahiro Yamada 	const struct uniphier_clk_mux_data *p;
55*805dc44cSMasahiro Yamada 
56*805dc44cSMasahiro Yamada 	for (p = priv->data->mux; p->id != UNIPHIER_CLK_ID_END; p++) {
57*805dc44cSMasahiro Yamada 		if (p->id == id)
58*805dc44cSMasahiro Yamada 			return p;
59*805dc44cSMasahiro Yamada 	}
60*805dc44cSMasahiro Yamada 
61*805dc44cSMasahiro Yamada 	return NULL;
62*805dc44cSMasahiro Yamada }
63*805dc44cSMasahiro Yamada 
64*805dc44cSMasahiro Yamada static ulong uniphier_clk_get_rate(struct clk *clk)
65*805dc44cSMasahiro Yamada {
66*805dc44cSMasahiro Yamada 	struct uniphier_clk_priv *priv = dev_get_priv(clk->dev);
67*805dc44cSMasahiro Yamada 	const struct uniphier_clk_mux_data *mux;
68*805dc44cSMasahiro Yamada 	u32 val;
69*805dc44cSMasahiro Yamada 	int i;
70*805dc44cSMasahiro Yamada 
71*805dc44cSMasahiro Yamada 	mux = uniphier_clk_get_mux_data(priv, clk->id);
72*805dc44cSMasahiro Yamada 	if (!mux)
73*805dc44cSMasahiro Yamada 		return 0;
74*805dc44cSMasahiro Yamada 
75*805dc44cSMasahiro Yamada 	if (!mux->nr_muxs)		/* fixed-rate */
76*805dc44cSMasahiro Yamada 		return mux->rates[0];
77*805dc44cSMasahiro Yamada 
78*805dc44cSMasahiro Yamada 	val = readl(priv->base + mux->reg);
79*805dc44cSMasahiro Yamada 
80*805dc44cSMasahiro Yamada 	for (i = 0; i < mux->nr_muxs; i++)
81*805dc44cSMasahiro Yamada 		if ((mux->masks[i] & val) == mux->vals[i])
82*805dc44cSMasahiro Yamada 			return mux->rates[i];
83*805dc44cSMasahiro Yamada 
84*805dc44cSMasahiro Yamada 	return -EINVAL;
85*805dc44cSMasahiro Yamada }
86*805dc44cSMasahiro Yamada 
87*805dc44cSMasahiro Yamada static ulong uniphier_clk_set_rate(struct clk *clk, ulong rate)
88*805dc44cSMasahiro Yamada {
89*805dc44cSMasahiro Yamada 	struct uniphier_clk_priv *priv = dev_get_priv(clk->dev);
90*805dc44cSMasahiro Yamada 	const struct uniphier_clk_mux_data *mux;
91*805dc44cSMasahiro Yamada 	u32 val;
92*805dc44cSMasahiro Yamada 	int i, best_rate_id = -1;
93*805dc44cSMasahiro Yamada 	ulong best_rate = 0;
94*805dc44cSMasahiro Yamada 
95*805dc44cSMasahiro Yamada 	mux = uniphier_clk_get_mux_data(priv, clk->id);
96*805dc44cSMasahiro Yamada 	if (!mux)
97*805dc44cSMasahiro Yamada 		return 0;
98*805dc44cSMasahiro Yamada 
99*805dc44cSMasahiro Yamada 	if (!mux->nr_muxs)		/* fixed-rate */
100*805dc44cSMasahiro Yamada 		return mux->rates[0];
101*805dc44cSMasahiro Yamada 
102*805dc44cSMasahiro Yamada 	/* first, decide the best match rate */
103*805dc44cSMasahiro Yamada 	for (i = 0; i < mux->nr_muxs; i++) {
104*805dc44cSMasahiro Yamada 		if (mux->rates[i] > best_rate && mux->rates[i] <= rate) {
105*805dc44cSMasahiro Yamada 			best_rate = mux->rates[i];
106*805dc44cSMasahiro Yamada 			best_rate_id = i;
107*805dc44cSMasahiro Yamada 		}
108*805dc44cSMasahiro Yamada 	}
109*805dc44cSMasahiro Yamada 
110*805dc44cSMasahiro Yamada 	if (best_rate_id < 0)
111*805dc44cSMasahiro Yamada 		return -EINVAL;
112*805dc44cSMasahiro Yamada 
113*805dc44cSMasahiro Yamada 	val = readl(priv->base + mux->reg);
114*805dc44cSMasahiro Yamada 	val &= ~mux->masks[best_rate_id];
115*805dc44cSMasahiro Yamada 	val |= mux->vals[best_rate_id];
116*805dc44cSMasahiro Yamada 	writel(val, priv->base + mux->reg);
117*805dc44cSMasahiro Yamada 
118*805dc44cSMasahiro Yamada 	debug("%s: requested rate = %lu, set rate = %lu\n", __func__,
119*805dc44cSMasahiro Yamada 	      rate, best_rate);
120*805dc44cSMasahiro Yamada 
121*805dc44cSMasahiro Yamada 	return best_rate;
122*805dc44cSMasahiro Yamada }
123*805dc44cSMasahiro Yamada 
124*805dc44cSMasahiro Yamada const struct clk_ops uniphier_clk_ops = {
125*805dc44cSMasahiro Yamada 	.enable = uniphier_clk_enable,
126*805dc44cSMasahiro Yamada 	.get_rate = uniphier_clk_get_rate,
127*805dc44cSMasahiro Yamada 	.set_rate = uniphier_clk_set_rate,
128*805dc44cSMasahiro Yamada };
129*805dc44cSMasahiro Yamada 
130*805dc44cSMasahiro 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 
1356dc5b6b1SMasahiro Yamada 	addr = dev_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 
143*805dc44cSMasahiro 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[] = {
14948264d9bSMasahiro Yamada 	{
1506dc5b6b1SMasahiro Yamada 		.compatible = "socionext,uniphier-sld3-mio-clock",
151102e3187SMasahiro Yamada 		.data = (ulong)&uniphier_mio_clk_data,
152102e3187SMasahiro Yamada 	},
153102e3187SMasahiro Yamada 	{
1546dc5b6b1SMasahiro Yamada 		.compatible = "socionext,uniphier-ld4-mio-clock",
155102e3187SMasahiro Yamada 		.data = (ulong)&uniphier_mio_clk_data,
156102e3187SMasahiro Yamada 	},
157102e3187SMasahiro Yamada 	{
1586dc5b6b1SMasahiro Yamada 		.compatible = "socionext,uniphier-pro4-mio-clock",
159102e3187SMasahiro Yamada 		.data = (ulong)&uniphier_mio_clk_data,
160102e3187SMasahiro Yamada 	},
161102e3187SMasahiro Yamada 	{
1626dc5b6b1SMasahiro Yamada 		.compatible = "socionext,uniphier-sld8-mio-clock",
163102e3187SMasahiro Yamada 		.data = (ulong)&uniphier_mio_clk_data,
164102e3187SMasahiro Yamada 	},
165102e3187SMasahiro Yamada 	{
1666dc5b6b1SMasahiro Yamada 		.compatible = "socionext,uniphier-pro5-mio-clock",
167102e3187SMasahiro Yamada 		.data = (ulong)&uniphier_mio_clk_data,
168102e3187SMasahiro Yamada 	},
169102e3187SMasahiro Yamada 	{
1706dc5b6b1SMasahiro Yamada 		.compatible = "socionext,uniphier-pxs2-mio-clock",
171102e3187SMasahiro Yamada 		.data = (ulong)&uniphier_mio_clk_data,
172102e3187SMasahiro Yamada 	},
173102e3187SMasahiro Yamada 	{
1746dc5b6b1SMasahiro Yamada 		.compatible = "socionext,uniphier-ld11-mio-clock",
175102e3187SMasahiro Yamada 		.data = (ulong)&uniphier_mio_clk_data,
176102e3187SMasahiro Yamada 	},
177102e3187SMasahiro Yamada 	{
1786dc5b6b1SMasahiro Yamada 		.compatible = "socionext,uniphier-ld20-mio-clock",
179102e3187SMasahiro Yamada 		.data = (ulong)&uniphier_mio_clk_data,
180102e3187SMasahiro Yamada 	},
181102e3187SMasahiro Yamada 	{ /* sentinel */ }
182102e3187SMasahiro Yamada };
18348264d9bSMasahiro Yamada 
184102e3187SMasahiro Yamada U_BOOT_DRIVER(uniphier_clk) = {
185102e3187SMasahiro Yamada 	.name = "uniphier-clk",
186102e3187SMasahiro Yamada 	.id = UCLASS_CLK,
187102e3187SMasahiro Yamada 	.of_match = uniphier_clk_match,
188102e3187SMasahiro Yamada 	.probe = uniphier_clk_probe,
189102e3187SMasahiro Yamada 	.priv_auto_alloc_size = sizeof(struct uniphier_clk_priv),
190102e3187SMasahiro Yamada 	.ops = &uniphier_clk_ops,
191102e3187SMasahiro Yamada };
192