blob: 678fdd5a45406377e97e1406001ab242f03be6cc [file] [log] [blame]
Manivannan Sadhasivamae485b52018-06-14 23:38:35 +05301// SPDX-License-Identifier: GPL-2.0+
2/*
Amit Singh Tomar8b520ac2020-04-19 19:28:30 +05303 * Common clock driver for Actions Semi SoCs.
Manivannan Sadhasivamae485b52018-06-14 23:38:35 +05304 *
5 * Copyright (C) 2015 Actions Semi Co., Ltd.
6 * Copyright (C) 2018 Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org>
7 */
8
9#include <common.h>
10#include <dm.h>
Amit Singh Tomar8b520ac2020-04-19 19:28:30 +053011#include "clk_owl.h"
Manivannan Sadhasivamae485b52018-06-14 23:38:35 +053012#include <asm/io.h>
Amit Singh Tomar8b520ac2020-04-19 19:28:30 +053013#if defined(CONFIG_MACH_S900)
14#include <asm/arch-owl/regs_s900.h>
Amit Singh Tomar4939bee2020-04-19 19:28:28 +053015#include <dt-bindings/clock/actions,s900-cmu.h>
Amit Singh Tomar8b520ac2020-04-19 19:28:30 +053016#elif defined(CONFIG_MACH_S700)
17#include <asm/arch-owl/regs_s700.h>
18#include <dt-bindings/clock/actions,s700-cmu.h>
19#endif
Simon Glasscd93d622020-05-10 11:40:13 -060020#include <linux/bitops.h>
Simon Glassc05ed002020-05-10 11:40:11 -060021#include <linux/delay.h>
Manivannan Sadhasivamae485b52018-06-14 23:38:35 +053022
Amit Singh Tomar05c2ff72021-11-28 17:02:21 +053023#define CMU_DEVCLKEN0_SD0 BIT(22)
24
Manivannan Sadhasivamae485b52018-06-14 23:38:35 +053025void owl_clk_init(struct owl_clk_priv *priv)
26{
27 u32 bus_clk = 0, core_pll, dev_pll;
28
Amit Singh Tomar8b520ac2020-04-19 19:28:30 +053029#if defined(CONFIG_MACH_S900)
Manivannan Sadhasivamae485b52018-06-14 23:38:35 +053030 /* Enable ASSIST_PLL */
31 setbits_le32(priv->base + CMU_ASSISTPLL, BIT(0));
Manivannan Sadhasivamae485b52018-06-14 23:38:35 +053032 udelay(PLL_STABILITY_WAIT_US);
Amit Singh Tomar8b520ac2020-04-19 19:28:30 +053033#endif
Manivannan Sadhasivamae485b52018-06-14 23:38:35 +053034
35 /* Source HOSC to DEV_CLK */
36 clrbits_le32(priv->base + CMU_DEVPLL, CMU_DEVPLL_CLK);
37
38 /* Configure BUS_CLK */
39 bus_clk |= (CMU_PDBGDIV_DIV | CMU_PERDIV_DIV | CMU_NOCDIV_DIV |
40 CMU_DMMCLK_SRC | CMU_APBCLK_DIV | CMU_AHBCLK_DIV |
41 CMU_NOCCLK_SRC | CMU_CORECLK_HOSC);
42 writel(bus_clk, priv->base + CMU_BUSCLK);
43
44 udelay(PLL_STABILITY_WAIT_US);
45
46 /* Configure CORE_PLL */
47 core_pll = readl(priv->base + CMU_COREPLL);
48 core_pll |= (CMU_COREPLL_EN | CMU_COREPLL_HOSC_EN | CMU_COREPLL_OUT);
49 writel(core_pll, priv->base + CMU_COREPLL);
50
51 udelay(PLL_STABILITY_WAIT_US);
52
53 /* Configure DEV_PLL */
54 dev_pll = readl(priv->base + CMU_DEVPLL);
55 dev_pll |= (CMU_DEVPLL_EN | CMU_DEVPLL_OUT);
56 writel(dev_pll, priv->base + CMU_DEVPLL);
57
58 udelay(PLL_STABILITY_WAIT_US);
59
60 /* Source CORE_PLL for CORE_CLK */
61 clrsetbits_le32(priv->base + CMU_BUSCLK, CMU_CORECLK_MASK,
62 CMU_CORECLK_CPLL);
63
64 /* Source DEV_PLL for DEV_CLK */
65 setbits_le32(priv->base + CMU_DEVPLL, CMU_DEVPLL_CLK);
66
67 udelay(PLL_STABILITY_WAIT_US);
68}
69
Manivannan Sadhasivamae485b52018-06-14 23:38:35 +053070int owl_clk_enable(struct clk *clk)
71{
72 struct owl_clk_priv *priv = dev_get_priv(clk->dev);
Amit Singh Tomar8b520ac2020-04-19 19:28:30 +053073 enum owl_soc model = dev_get_driver_data(clk->dev);
Manivannan Sadhasivamae485b52018-06-14 23:38:35 +053074
75 switch (clk->id) {
Amit Singh Tomar4939bee2020-04-19 19:28:28 +053076 case CLK_UART5:
Amit Singh Tomar8b520ac2020-04-19 19:28:30 +053077 if (model != S900)
78 return -EINVAL;
79 /* Source HOSC for UART5 interface */
80 clrbits_le32(priv->base + CMU_UART5CLK, CMU_UARTCLK_SRC_DEVPLL);
81 /* Enable UART5 interface clock */
82 setbits_le32(priv->base + CMU_DEVCLKEN1, CMU_DEVCLKEN1_UART5);
83 break;
84 case CLK_UART3:
85 if (model != S700)
86 return -EINVAL;
87 /* Source HOSC for UART3 interface */
88 clrbits_le32(priv->base + CMU_UART3CLK, CMU_UARTCLK_SRC_DEVPLL);
89 /* Enable UART3 interface clock */
90 setbits_le32(priv->base + CMU_DEVCLKEN1, CMU_DEVCLKEN1_UART3);
Manivannan Sadhasivamae485b52018-06-14 23:38:35 +053091 break;
Amit Singh Tomar3a217342020-05-09 19:55:09 +053092 case CLK_RMII_REF:
93 case CLK_ETHERNET:
94 setbits_le32(priv->base + CMU_DEVCLKEN1, CMU_DEVCLKEN1_ETH);
95 setbits_le32(priv->base + CMU_ETHERNETPLL, 5);
96 break;
Amit Singh Tomar05c2ff72021-11-28 17:02:21 +053097 case CLK_SD0:
98 setbits_le32(priv->base + CMU_DEVCLKEN0, CMU_DEVCLKEN0_SD0);
99 break;
Manivannan Sadhasivamae485b52018-06-14 23:38:35 +0530100 default:
Amit Singh Tomar8b520ac2020-04-19 19:28:30 +0530101 return -EINVAL;
Manivannan Sadhasivamae485b52018-06-14 23:38:35 +0530102 }
103
104 return 0;
105}
106
107int owl_clk_disable(struct clk *clk)
108{
109 struct owl_clk_priv *priv = dev_get_priv(clk->dev);
Amit Singh Tomar8b520ac2020-04-19 19:28:30 +0530110 enum owl_soc model = dev_get_driver_data(clk->dev);
Manivannan Sadhasivamae485b52018-06-14 23:38:35 +0530111
112 switch (clk->id) {
Amit Singh Tomar4939bee2020-04-19 19:28:28 +0530113 case CLK_UART5:
Amit Singh Tomar8b520ac2020-04-19 19:28:30 +0530114 if (model != S900)
115 return -EINVAL;
116 /* Disable UART5 interface clock */
117 clrbits_le32(priv->base + CMU_DEVCLKEN1, CMU_DEVCLKEN1_UART5);
118 break;
119 case CLK_UART3:
120 if (model != S700)
121 return -EINVAL;
122 /* Disable UART3 interface clock */
123 clrbits_le32(priv->base + CMU_DEVCLKEN1, CMU_DEVCLKEN1_UART3);
Manivannan Sadhasivamae485b52018-06-14 23:38:35 +0530124 break;
Amit Singh Tomar3a217342020-05-09 19:55:09 +0530125 case CLK_RMII_REF:
126 case CLK_ETHERNET:
127 clrbits_le32(priv->base + CMU_DEVCLKEN1, CMU_DEVCLKEN1_ETH);
128 break;
Amit Singh Tomar05c2ff72021-11-28 17:02:21 +0530129 case CLK_SD0:
130 clrbits_le32(priv->base + CMU_DEVCLKEN0, CMU_DEVCLKEN0_SD0);
131 break;
Manivannan Sadhasivamae485b52018-06-14 23:38:35 +0530132 default:
Amit Singh Tomar8b520ac2020-04-19 19:28:30 +0530133 return -EINVAL;
Manivannan Sadhasivamae485b52018-06-14 23:38:35 +0530134 }
135
136 return 0;
137}
138
Amit Singh Tomar05c2ff72021-11-28 17:02:21 +0530139static ulong get_sd_parent_rate(struct owl_clk_priv *priv, u32 dev_index)
140{
141 ulong rate;
142 u32 reg;
143
144 reg = readl(priv->base + (CMU_SD0CLK + dev_index * 0x4));
145 /* Clock output of DEV/NAND_PLL
146 * Range: 48M ~ 756M
147 * Frequency= PLLCLK * 6
148 */
149 if (reg & 0x200)
150 rate = readl(priv->base + CMU_NANDPLL) & 0x7f;
151 else
152 rate = readl(priv->base + CMU_DEVPLL) & 0x7f;
153
154 rate *= 6000000;
155
156 return rate;
157}
158
159static ulong owl_get_sd_clk_rate(struct owl_clk_priv *priv, int sd_index)
160{
161 uint div, val;
162 ulong parent_rate = get_sd_parent_rate(priv, sd_index);
163
164 val = readl(priv->base + (CMU_SD0CLK + sd_index * 0x4));
165 div = (val & 0x1f) + 1;
166
167 return (parent_rate / div);
168}
169
170static ulong owl_set_sd_clk_rate(struct owl_clk_priv *priv, ulong rate,
171 int sd_index)
172{
173 uint div, val;
174 ulong parent_rate = get_sd_parent_rate(priv, sd_index);
175
176 if (rate == 0)
177 return rate;
178
179 div = (parent_rate / rate);
180
181 val = readl(priv->base + (CMU_SD0CLK + sd_index * 0x4));
182 /* Bits 4..0 is used to program div value and bit 8 to enable
183 * divide by 128 circuit
184 */
185 val &= ~0x11f;
186 if (div >= 128) {
187 div = div / 128;
188 val |= 0x100; /* enable divide by 128 circuit */
189 }
190 val |= ((div - 1) & 0x1f);
191 writel(val, priv->base + (CMU_SD0CLK + sd_index * 0x4));
192
193 return owl_get_sd_clk_rate(priv, 0);
194}
195
Amit Singh Tomar234c1672021-11-28 17:02:20 +0530196static ulong owl_clk_get_rate(struct clk *clk)
197{
Amit Singh Tomar05c2ff72021-11-28 17:02:21 +0530198 struct owl_clk_priv *priv = dev_get_priv(clk->dev);
Amit Singh Tomar234c1672021-11-28 17:02:20 +0530199 ulong rate;
200
201 switch (clk->id) {
Amit Singh Tomar05c2ff72021-11-28 17:02:21 +0530202 case CLK_SD0:
203 rate = owl_get_sd_clk_rate(priv, 0);
204 break;
Amit Singh Tomar234c1672021-11-28 17:02:20 +0530205 default:
206 return -ENOENT;
207 }
208
209 return rate;
210}
211
212static ulong owl_clk_set_rate(struct clk *clk, ulong rate)
213{
Amit Singh Tomar05c2ff72021-11-28 17:02:21 +0530214 struct owl_clk_priv *priv = dev_get_priv(clk->dev);
Amit Singh Tomar234c1672021-11-28 17:02:20 +0530215 ulong new_rate;
216
217 switch (clk->id) {
Amit Singh Tomar05c2ff72021-11-28 17:02:21 +0530218 case CLK_SD0:
219 new_rate = owl_set_sd_clk_rate(priv, rate, 0);
220 break;
Amit Singh Tomar234c1672021-11-28 17:02:20 +0530221 default:
222 return -ENOENT;
223 }
224
225 return new_rate;
226}
227
Manivannan Sadhasivamae485b52018-06-14 23:38:35 +0530228static int owl_clk_probe(struct udevice *dev)
229{
230 struct owl_clk_priv *priv = dev_get_priv(dev);
231
232 priv->base = dev_read_addr(dev);
233 if (priv->base == FDT_ADDR_T_NONE)
234 return -EINVAL;
235
236 /* setup necessary clocks */
237 owl_clk_init(priv);
238
239 return 0;
240}
241
Amit Singh Tomar8b520ac2020-04-19 19:28:30 +0530242static const struct clk_ops owl_clk_ops = {
Manivannan Sadhasivamae485b52018-06-14 23:38:35 +0530243 .enable = owl_clk_enable,
244 .disable = owl_clk_disable,
Amit Singh Tomar234c1672021-11-28 17:02:20 +0530245 .get_rate = owl_clk_get_rate,
246 .set_rate = owl_clk_set_rate,
Manivannan Sadhasivamae485b52018-06-14 23:38:35 +0530247};
248
249static const struct udevice_id owl_clk_ids[] = {
Amit Singh Tomar8b520ac2020-04-19 19:28:30 +0530250#if defined(CONFIG_MACH_S900)
251 { .compatible = "actions,s900-cmu", .data = S900 },
252#elif defined(CONFIG_MACH_S700)
253 { .compatible = "actions,s700-cmu", .data = S700 },
254#endif
Manivannan Sadhasivamae485b52018-06-14 23:38:35 +0530255 { }
256};
257
258U_BOOT_DRIVER(clk_owl) = {
Amit Singh Tomar8b520ac2020-04-19 19:28:30 +0530259 .name = "clk_owl",
Manivannan Sadhasivamae485b52018-06-14 23:38:35 +0530260 .id = UCLASS_CLK,
261 .of_match = owl_clk_ids,
262 .ops = &owl_clk_ops,
Simon Glass41575d82020-12-03 16:55:17 -0700263 .priv_auto = sizeof(struct owl_clk_priv),
Manivannan Sadhasivamae485b52018-06-14 23:38:35 +0530264 .probe = owl_clk_probe,
Manivannan Sadhasivamae485b52018-06-14 23:38:35 +0530265};