]>
Commit | Line | Data |
---|---|---|
f94859c2 LP |
1 | /* |
2 | * R-Car MSTP clocks | |
3 | * | |
4 | * Copyright (C) 2013 Ideas On Board SPRL | |
752b5ed5 | 5 | * Copyright (C) 2015 Glider bvba |
f94859c2 LP |
6 | * |
7 | * Contact: Laurent Pinchart <laurent.pinchart@ideasonboard.com> | |
8 | * | |
9 | * This program is free software; you can redistribute it and/or modify | |
10 | * it under the terms of the GNU General Public License as published by | |
11 | * the Free Software Foundation; version 2 of the License. | |
12 | */ | |
13 | ||
752b5ed5 | 14 | #include <linux/clk.h> |
f94859c2 LP |
15 | #include <linux/clk-provider.h> |
16 | #include <linux/clkdev.h> | |
09c32427 | 17 | #include <linux/clk/renesas.h> |
752b5ed5 | 18 | #include <linux/device.h> |
f94859c2 LP |
19 | #include <linux/io.h> |
20 | #include <linux/of.h> | |
21 | #include <linux/of_address.h> | |
752b5ed5 GU |
22 | #include <linux/pm_clock.h> |
23 | #include <linux/pm_domain.h> | |
f94859c2 LP |
24 | #include <linux/spinlock.h> |
25 | ||
26 | /* | |
27 | * MSTP clocks. We can't use standard gate clocks as we need to poll on the | |
28 | * status register when enabling the clock. | |
29 | */ | |
30 | ||
31 | #define MSTP_MAX_CLOCKS 32 | |
32 | ||
33 | /** | |
34 | * struct mstp_clock_group - MSTP gating clocks group | |
35 | * | |
36 | * @data: clocks in this group | |
37 | * @smstpcr: module stop control register | |
38 | * @mstpsr: module stop status register (optional) | |
39 | * @lock: protects writes to SMSTPCR | |
e2a33c34 | 40 | * @width_8bit: registers are 8-bit, not 32-bit |
f94859c2 LP |
41 | */ |
42 | struct mstp_clock_group { | |
43 | struct clk_onecell_data data; | |
44 | void __iomem *smstpcr; | |
45 | void __iomem *mstpsr; | |
46 | spinlock_t lock; | |
e2a33c34 | 47 | bool width_8bit; |
f94859c2 LP |
48 | }; |
49 | ||
50 | /** | |
51 | * struct mstp_clock - MSTP gating clock | |
52 | * @hw: handle between common and hardware-specific interfaces | |
53 | * @bit_index: control bit index | |
54 | * @group: MSTP clocks group | |
55 | */ | |
56 | struct mstp_clock { | |
57 | struct clk_hw hw; | |
58 | u32 bit_index; | |
59 | struct mstp_clock_group *group; | |
60 | }; | |
61 | ||
62 | #define to_mstp_clock(_hw) container_of(_hw, struct mstp_clock, hw) | |
63 | ||
e2a33c34 CB |
64 | static inline u32 cpg_mstp_read(struct mstp_clock_group *group, |
65 | u32 __iomem *reg) | |
66 | { | |
67 | return group->width_8bit ? readb(reg) : clk_readl(reg); | |
68 | } | |
69 | ||
70 | static inline void cpg_mstp_write(struct mstp_clock_group *group, u32 val, | |
71 | u32 __iomem *reg) | |
72 | { | |
73 | group->width_8bit ? writeb(val, reg) : clk_writel(val, reg); | |
74 | } | |
75 | ||
f94859c2 LP |
76 | static int cpg_mstp_clock_endisable(struct clk_hw *hw, bool enable) |
77 | { | |
78 | struct mstp_clock *clock = to_mstp_clock(hw); | |
79 | struct mstp_clock_group *group = clock->group; | |
80 | u32 bitmask = BIT(clock->bit_index); | |
81 | unsigned long flags; | |
82 | unsigned int i; | |
83 | u32 value; | |
84 | ||
85 | spin_lock_irqsave(&group->lock, flags); | |
86 | ||
e2a33c34 | 87 | value = cpg_mstp_read(group, group->smstpcr); |
f94859c2 LP |
88 | if (enable) |
89 | value &= ~bitmask; | |
90 | else | |
91 | value |= bitmask; | |
e2a33c34 | 92 | cpg_mstp_write(group, value, group->smstpcr); |
f94859c2 | 93 | |
f59de563 CB |
94 | if (!group->mstpsr) { |
95 | /* dummy read to ensure write has completed */ | |
96 | cpg_mstp_read(group, group->smstpcr); | |
97 | barrier_data(group->smstpcr); | |
98 | } | |
99 | ||
f94859c2 LP |
100 | spin_unlock_irqrestore(&group->lock, flags); |
101 | ||
102 | if (!enable || !group->mstpsr) | |
103 | return 0; | |
104 | ||
105 | for (i = 1000; i > 0; --i) { | |
e2a33c34 | 106 | if (!(cpg_mstp_read(group, group->mstpsr) & bitmask)) |
f94859c2 LP |
107 | break; |
108 | cpu_relax(); | |
109 | } | |
110 | ||
111 | if (!i) { | |
112 | pr_err("%s: failed to enable %p[%d]\n", __func__, | |
113 | group->smstpcr, clock->bit_index); | |
114 | return -ETIMEDOUT; | |
115 | } | |
116 | ||
117 | return 0; | |
118 | } | |
119 | ||
120 | static int cpg_mstp_clock_enable(struct clk_hw *hw) | |
121 | { | |
122 | return cpg_mstp_clock_endisable(hw, true); | |
123 | } | |
124 | ||
125 | static void cpg_mstp_clock_disable(struct clk_hw *hw) | |
126 | { | |
127 | cpg_mstp_clock_endisable(hw, false); | |
128 | } | |
129 | ||
130 | static int cpg_mstp_clock_is_enabled(struct clk_hw *hw) | |
131 | { | |
132 | struct mstp_clock *clock = to_mstp_clock(hw); | |
133 | struct mstp_clock_group *group = clock->group; | |
134 | u32 value; | |
135 | ||
136 | if (group->mstpsr) | |
e2a33c34 | 137 | value = cpg_mstp_read(group, group->mstpsr); |
f94859c2 | 138 | else |
e2a33c34 | 139 | value = cpg_mstp_read(group, group->smstpcr); |
f94859c2 | 140 | |
bb178da7 | 141 | return !(value & BIT(clock->bit_index)); |
f94859c2 LP |
142 | } |
143 | ||
144 | static const struct clk_ops cpg_mstp_clock_ops = { | |
145 | .enable = cpg_mstp_clock_enable, | |
146 | .disable = cpg_mstp_clock_disable, | |
147 | .is_enabled = cpg_mstp_clock_is_enabled, | |
148 | }; | |
149 | ||
1ce87dd2 GU |
150 | static struct clk * __init cpg_mstp_clock_register(const char *name, |
151 | const char *parent_name, unsigned int index, | |
152 | struct mstp_clock_group *group) | |
f94859c2 LP |
153 | { |
154 | struct clk_init_data init; | |
155 | struct mstp_clock *clock; | |
156 | struct clk *clk; | |
157 | ||
158 | clock = kzalloc(sizeof(*clock), GFP_KERNEL); | |
159 | if (!clock) { | |
160 | pr_err("%s: failed to allocate MSTP clock.\n", __func__); | |
161 | return ERR_PTR(-ENOMEM); | |
162 | } | |
163 | ||
164 | init.name = name; | |
165 | init.ops = &cpg_mstp_clock_ops; | |
e44df332 | 166 | init.flags = CLK_IS_BASIC | CLK_SET_RATE_PARENT; |
e34084fb GU |
167 | /* INTC-SYS is the module clock of the GIC, and must not be disabled */ |
168 | if (!strcmp(name, "intc-sys")) { | |
169 | pr_debug("MSTP %s setting CLK_IS_CRITICAL\n", name); | |
170 | init.flags |= CLK_IS_CRITICAL; | |
171 | } | |
f94859c2 LP |
172 | init.parent_names = &parent_name; |
173 | init.num_parents = 1; | |
174 | ||
175 | clock->bit_index = index; | |
176 | clock->group = group; | |
177 | clock->hw.init = &init; | |
178 | ||
179 | clk = clk_register(NULL, &clock->hw); | |
180 | ||
181 | if (IS_ERR(clk)) | |
182 | kfree(clock); | |
183 | ||
184 | return clk; | |
185 | } | |
186 | ||
187 | static void __init cpg_mstp_clocks_init(struct device_node *np) | |
188 | { | |
189 | struct mstp_clock_group *group; | |
8e33f91a | 190 | const char *idxname; |
f94859c2 LP |
191 | struct clk **clks; |
192 | unsigned int i; | |
193 | ||
194 | group = kzalloc(sizeof(*group), GFP_KERNEL); | |
0637a4c7 | 195 | clks = kmalloc_array(MSTP_MAX_CLOCKS, sizeof(*clks), GFP_KERNEL); |
f94859c2 LP |
196 | if (group == NULL || clks == NULL) { |
197 | kfree(group); | |
198 | kfree(clks); | |
199 | pr_err("%s: failed to allocate group\n", __func__); | |
200 | return; | |
201 | } | |
202 | ||
203 | spin_lock_init(&group->lock); | |
204 | group->data.clks = clks; | |
205 | ||
206 | group->smstpcr = of_iomap(np, 0); | |
207 | group->mstpsr = of_iomap(np, 1); | |
208 | ||
209 | if (group->smstpcr == NULL) { | |
210 | pr_err("%s: failed to remap SMSTPCR\n", __func__); | |
211 | kfree(group); | |
212 | kfree(clks); | |
213 | return; | |
214 | } | |
215 | ||
e2a33c34 CB |
216 | if (of_device_is_compatible(np, "renesas,r7s72100-mstp-clocks")) |
217 | group->width_8bit = true; | |
218 | ||
209f4fed VB |
219 | for (i = 0; i < MSTP_MAX_CLOCKS; ++i) |
220 | clks[i] = ERR_PTR(-ENOENT); | |
221 | ||
8e33f91a BD |
222 | if (of_find_property(np, "clock-indices", &i)) |
223 | idxname = "clock-indices"; | |
224 | else | |
225 | idxname = "renesas,clock-indices"; | |
226 | ||
f94859c2 LP |
227 | for (i = 0; i < MSTP_MAX_CLOCKS; ++i) { |
228 | const char *parent_name; | |
229 | const char *name; | |
230 | u32 clkidx; | |
231 | int ret; | |
232 | ||
233 | /* Skip clocks with no name. */ | |
234 | ret = of_property_read_string_index(np, "clock-output-names", | |
235 | i, &name); | |
236 | if (ret < 0 || strlen(name) == 0) | |
237 | continue; | |
238 | ||
239 | parent_name = of_clk_get_parent_name(np, i); | |
8e33f91a | 240 | ret = of_property_read_u32_index(np, idxname, i, &clkidx); |
f94859c2 LP |
241 | if (parent_name == NULL || ret < 0) |
242 | break; | |
243 | ||
244 | if (clkidx >= MSTP_MAX_CLOCKS) { | |
08ebdf80 | 245 | pr_err("%s: invalid clock %s %s index %u\n", |
f94859c2 LP |
246 | __func__, np->name, name, clkidx); |
247 | continue; | |
248 | } | |
249 | ||
6413b090 VB |
250 | clks[clkidx] = cpg_mstp_clock_register(name, parent_name, |
251 | clkidx, group); | |
f94859c2 | 252 | if (!IS_ERR(clks[clkidx])) { |
209f4fed VB |
253 | group->data.clk_num = max(group->data.clk_num, |
254 | clkidx + 1); | |
f94859c2 LP |
255 | /* |
256 | * Register a clkdev to let board code retrieve the | |
257 | * clock by name and register aliases for non-DT | |
258 | * devices. | |
259 | * | |
260 | * FIXME: Remove this when all devices that require a | |
261 | * clock will be instantiated from DT. | |
262 | */ | |
263 | clk_register_clkdev(clks[clkidx], name, NULL); | |
264 | } else { | |
265 | pr_err("%s: failed to register %s %s clock (%ld)\n", | |
266 | __func__, np->name, name, PTR_ERR(clks[clkidx])); | |
267 | } | |
268 | } | |
269 | ||
270 | of_clk_add_provider(np, of_clk_src_onecell_get, &group->data); | |
271 | } | |
272 | CLK_OF_DECLARE(cpg_mstp_clks, "renesas,cpg-mstp-clocks", cpg_mstp_clocks_init); | |
752b5ed5 | 273 | |
12a56817 | 274 | int cpg_mstp_attach_dev(struct generic_pm_domain *unused, struct device *dev) |
752b5ed5 GU |
275 | { |
276 | struct device_node *np = dev->of_node; | |
277 | struct of_phandle_args clkspec; | |
278 | struct clk *clk; | |
279 | int i = 0; | |
280 | int error; | |
281 | ||
282 | while (!of_parse_phandle_with_args(np, "clocks", "#clock-cells", i, | |
283 | &clkspec)) { | |
284 | if (of_device_is_compatible(clkspec.np, | |
285 | "renesas,cpg-mstp-clocks")) | |
286 | goto found; | |
287 | ||
e233d74c GU |
288 | /* BSC on r8a73a4/sh73a0 uses zb_clk instead of an mstp clock */ |
289 | if (!strcmp(clkspec.np->name, "zb_clk")) | |
290 | goto found; | |
291 | ||
752b5ed5 GU |
292 | of_node_put(clkspec.np); |
293 | i++; | |
294 | } | |
295 | ||
296 | return 0; | |
297 | ||
298 | found: | |
299 | clk = of_clk_get_from_provider(&clkspec); | |
300 | of_node_put(clkspec.np); | |
301 | ||
302 | if (IS_ERR(clk)) | |
303 | return PTR_ERR(clk); | |
304 | ||
305 | error = pm_clk_create(dev); | |
306 | if (error) { | |
307 | dev_err(dev, "pm_clk_create failed %d\n", error); | |
308 | goto fail_put; | |
309 | } | |
310 | ||
311 | error = pm_clk_add_clk(dev, clk); | |
312 | if (error) { | |
313 | dev_err(dev, "pm_clk_add_clk %pC failed %d\n", clk, error); | |
314 | goto fail_destroy; | |
315 | } | |
316 | ||
317 | return 0; | |
318 | ||
319 | fail_destroy: | |
320 | pm_clk_destroy(dev); | |
321 | fail_put: | |
322 | clk_put(clk); | |
323 | return error; | |
324 | } | |
325 | ||
12a56817 | 326 | void cpg_mstp_detach_dev(struct generic_pm_domain *unused, struct device *dev) |
752b5ed5 | 327 | { |
e05e853e | 328 | if (!pm_clk_no_clocks(dev)) |
752b5ed5 GU |
329 | pm_clk_destroy(dev); |
330 | } | |
331 | ||
332 | void __init cpg_mstp_add_clk_domain(struct device_node *np) | |
333 | { | |
334 | struct generic_pm_domain *pd; | |
335 | u32 ncells; | |
336 | ||
337 | if (of_property_read_u32(np, "#power-domain-cells", &ncells)) { | |
16673931 | 338 | pr_warn("%pOF lacks #power-domain-cells\n", np); |
752b5ed5 GU |
339 | return; |
340 | } | |
341 | ||
342 | pd = kzalloc(sizeof(*pd), GFP_KERNEL); | |
343 | if (!pd) | |
344 | return; | |
345 | ||
346 | pd->name = np->name; | |
752b5ed5 | 347 | pd->flags = GENPD_FLAG_PM_CLK; |
752b5ed5 GU |
348 | pd->attach_dev = cpg_mstp_attach_dev; |
349 | pd->detach_dev = cpg_mstp_detach_dev; | |
20729300 | 350 | pm_genpd_init(pd, &pm_domain_always_on_gov, false); |
752b5ed5 GU |
351 | |
352 | of_genpd_add_provider_simple(np, pd); | |
353 | } |