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