.. | .. |
---|
| 1 | +// SPDX-License-Identifier: GPL-2.0 |
---|
1 | 2 | /* |
---|
2 | 3 | * R-Car Gen3 Clock Pulse Generator |
---|
3 | 4 | * |
---|
4 | | - * Copyright (C) 2015-2016 Glider bvba |
---|
| 5 | + * Copyright (C) 2015-2018 Glider bvba |
---|
| 6 | + * Copyright (C) 2019 Renesas Electronics Corp. |
---|
5 | 7 | * |
---|
6 | 8 | * Based on clk-rcar-gen3.c |
---|
7 | 9 | * |
---|
8 | 10 | * Copyright (C) 2015 Renesas Electronics Corp. |
---|
9 | | - * |
---|
10 | | - * This program is free software; you can redistribute it and/or modify |
---|
11 | | - * it under the terms of the GNU General Public License as published by |
---|
12 | | - * the Free Software Foundation; version 2 of the License. |
---|
13 | 11 | */ |
---|
14 | 12 | |
---|
15 | 13 | #include <linux/bug.h> |
---|
.. | .. |
---|
30 | 28 | #define CPG_PLL0CR 0x00d8 |
---|
31 | 29 | #define CPG_PLL2CR 0x002c |
---|
32 | 30 | #define CPG_PLL4CR 0x01f4 |
---|
| 31 | + |
---|
| 32 | +#define CPG_RCKCR_CKSEL BIT(15) /* RCLK Clock Source Select */ |
---|
| 33 | + |
---|
| 34 | +static spinlock_t cpg_lock; |
---|
| 35 | + |
---|
| 36 | +static void cpg_reg_modify(void __iomem *reg, u32 clear, u32 set) |
---|
| 37 | +{ |
---|
| 38 | + unsigned long flags; |
---|
| 39 | + u32 val; |
---|
| 40 | + |
---|
| 41 | + spin_lock_irqsave(&cpg_lock, flags); |
---|
| 42 | + val = readl(reg); |
---|
| 43 | + val &= ~clear; |
---|
| 44 | + val |= set; |
---|
| 45 | + writel(val, reg); |
---|
| 46 | + spin_unlock_irqrestore(&cpg_lock, flags); |
---|
| 47 | +}; |
---|
33 | 48 | |
---|
34 | 49 | struct cpg_simple_notifier { |
---|
35 | 50 | struct notifier_block nb; |
---|
.. | .. |
---|
74 | 89 | #define CPG_FRQCRB 0x00000004 |
---|
75 | 90 | #define CPG_FRQCRB_KICK BIT(31) |
---|
76 | 91 | #define CPG_FRQCRC 0x000000e0 |
---|
77 | | -#define CPG_FRQCRC_ZFC_MASK GENMASK(12, 8) |
---|
78 | | -#define CPG_FRQCRC_Z2FC_MASK GENMASK(4, 0) |
---|
79 | 92 | |
---|
80 | 93 | struct cpg_z_clk { |
---|
81 | 94 | struct clk_hw hw; |
---|
82 | 95 | void __iomem *reg; |
---|
83 | 96 | void __iomem *kick_reg; |
---|
84 | 97 | unsigned long mask; |
---|
| 98 | + unsigned int fixed_div; |
---|
85 | 99 | }; |
---|
86 | 100 | |
---|
87 | 101 | #define to_z_clk(_hw) container_of(_hw, struct cpg_z_clk, hw) |
---|
.. | .. |
---|
96 | 110 | val = readl(zclk->reg) & zclk->mask; |
---|
97 | 111 | mult = 32 - (val >> __ffs(zclk->mask)); |
---|
98 | 112 | |
---|
99 | | - /* Factor of 2 is for fixed divider */ |
---|
100 | | - return DIV_ROUND_CLOSEST_ULL((u64)parent_rate * mult, 32 * 2); |
---|
| 113 | + return DIV_ROUND_CLOSEST_ULL((u64)parent_rate * mult, |
---|
| 114 | + 32 * zclk->fixed_div); |
---|
101 | 115 | } |
---|
102 | 116 | |
---|
103 | | -static long cpg_z_clk_round_rate(struct clk_hw *hw, unsigned long rate, |
---|
104 | | - unsigned long *parent_rate) |
---|
| 117 | +static int cpg_z_clk_determine_rate(struct clk_hw *hw, |
---|
| 118 | + struct clk_rate_request *req) |
---|
105 | 119 | { |
---|
106 | | - /* Factor of 2 is for fixed divider */ |
---|
107 | | - unsigned long prate = *parent_rate / 2; |
---|
108 | | - unsigned int mult; |
---|
| 120 | + struct cpg_z_clk *zclk = to_z_clk(hw); |
---|
| 121 | + unsigned int min_mult, max_mult, mult; |
---|
| 122 | + unsigned long prate; |
---|
109 | 123 | |
---|
110 | | - mult = div_u64(rate * 32ULL, prate); |
---|
111 | | - mult = clamp(mult, 1U, 32U); |
---|
| 124 | + prate = req->best_parent_rate / zclk->fixed_div; |
---|
| 125 | + min_mult = max(div64_ul(req->min_rate * 32ULL, prate), 1ULL); |
---|
| 126 | + max_mult = min(div64_ul(req->max_rate * 32ULL, prate), 32ULL); |
---|
| 127 | + if (max_mult < min_mult) |
---|
| 128 | + return -EINVAL; |
---|
112 | 129 | |
---|
113 | | - return (u64)prate * mult / 32; |
---|
| 130 | + mult = div64_ul(req->rate * 32ULL, prate); |
---|
| 131 | + mult = clamp(mult, min_mult, max_mult); |
---|
| 132 | + |
---|
| 133 | + req->rate = div_u64((u64)prate * mult, 32); |
---|
| 134 | + return 0; |
---|
114 | 135 | } |
---|
115 | 136 | |
---|
116 | 137 | static int cpg_z_clk_set_rate(struct clk_hw *hw, unsigned long rate, |
---|
.. | .. |
---|
119 | 140 | struct cpg_z_clk *zclk = to_z_clk(hw); |
---|
120 | 141 | unsigned int mult; |
---|
121 | 142 | unsigned int i; |
---|
122 | | - u32 val, kick; |
---|
123 | 143 | |
---|
124 | | - /* Factor of 2 is for fixed divider */ |
---|
125 | | - mult = DIV_ROUND_CLOSEST_ULL(rate * 32ULL * 2, parent_rate); |
---|
| 144 | + mult = DIV64_U64_ROUND_CLOSEST(rate * 32ULL * zclk->fixed_div, |
---|
| 145 | + parent_rate); |
---|
126 | 146 | mult = clamp(mult, 1U, 32U); |
---|
127 | 147 | |
---|
128 | 148 | if (readl(zclk->kick_reg) & CPG_FRQCRB_KICK) |
---|
129 | 149 | return -EBUSY; |
---|
130 | 150 | |
---|
131 | | - val = readl(zclk->reg) & ~zclk->mask; |
---|
132 | | - val |= ((32 - mult) << __ffs(zclk->mask)) & zclk->mask; |
---|
133 | | - writel(val, zclk->reg); |
---|
| 151 | + cpg_reg_modify(zclk->reg, zclk->mask, |
---|
| 152 | + ((32 - mult) << __ffs(zclk->mask)) & zclk->mask); |
---|
134 | 153 | |
---|
135 | 154 | /* |
---|
136 | 155 | * Set KICK bit in FRQCRB to update hardware setting and wait for |
---|
137 | 156 | * clock change completion. |
---|
138 | 157 | */ |
---|
139 | | - kick = readl(zclk->kick_reg); |
---|
140 | | - kick |= CPG_FRQCRB_KICK; |
---|
141 | | - writel(kick, zclk->kick_reg); |
---|
| 158 | + cpg_reg_modify(zclk->kick_reg, 0, CPG_FRQCRB_KICK); |
---|
142 | 159 | |
---|
143 | 160 | /* |
---|
144 | 161 | * Note: There is no HW information about the worst case latency. |
---|
.. | .. |
---|
161 | 178 | |
---|
162 | 179 | static const struct clk_ops cpg_z_clk_ops = { |
---|
163 | 180 | .recalc_rate = cpg_z_clk_recalc_rate, |
---|
164 | | - .round_rate = cpg_z_clk_round_rate, |
---|
| 181 | + .determine_rate = cpg_z_clk_determine_rate, |
---|
165 | 182 | .set_rate = cpg_z_clk_set_rate, |
---|
166 | 183 | }; |
---|
167 | 184 | |
---|
168 | 185 | static struct clk * __init cpg_z_clk_register(const char *name, |
---|
169 | 186 | const char *parent_name, |
---|
170 | 187 | void __iomem *reg, |
---|
171 | | - unsigned long mask) |
---|
| 188 | + unsigned int div, |
---|
| 189 | + unsigned int offset) |
---|
172 | 190 | { |
---|
173 | | - struct clk_init_data init = {}; |
---|
| 191 | + struct clk_init_data init; |
---|
174 | 192 | struct cpg_z_clk *zclk; |
---|
175 | 193 | struct clk *clk; |
---|
176 | 194 | |
---|
.. | .. |
---|
187 | 205 | zclk->reg = reg + CPG_FRQCRC; |
---|
188 | 206 | zclk->kick_reg = reg + CPG_FRQCRB; |
---|
189 | 207 | zclk->hw.init = &init; |
---|
190 | | - zclk->mask = mask; |
---|
| 208 | + zclk->mask = GENMASK(offset + 4, offset); |
---|
| 209 | + zclk->fixed_div = div; /* PLLVCO x 1/div x SYS-CPU divider */ |
---|
191 | 210 | |
---|
192 | 211 | clk = clk_register(NULL, &zclk->hw); |
---|
193 | 212 | if (IS_ERR(clk)) |
---|
.. | .. |
---|
224 | 243 | const struct sd_div_table *div_table; |
---|
225 | 244 | struct cpg_simple_notifier csn; |
---|
226 | 245 | unsigned int div_num; |
---|
227 | | - unsigned int div_min; |
---|
228 | | - unsigned int div_max; |
---|
229 | 246 | unsigned int cur_div_idx; |
---|
230 | 247 | }; |
---|
231 | 248 | |
---|
.. | .. |
---|
233 | 250 | * sd_srcfc sd_fc div |
---|
234 | 251 | * stp_hck stp_ck (div) (div) = sd_srcfc x sd_fc |
---|
235 | 252 | *------------------------------------------------------------------- |
---|
236 | | - * 0 0 0 (1) 1 (4) 4 |
---|
237 | | - * 0 0 1 (2) 1 (4) 8 |
---|
238 | | - * 1 0 2 (4) 1 (4) 16 |
---|
239 | | - * 1 0 3 (8) 1 (4) 32 |
---|
| 253 | + * 0 0 0 (1) 1 (4) 4 : SDR104 / HS200 / HS400 (8 TAP) |
---|
| 254 | + * 0 0 1 (2) 1 (4) 8 : SDR50 |
---|
| 255 | + * 1 0 2 (4) 1 (4) 16 : HS / SDR25 |
---|
| 256 | + * 1 0 3 (8) 1 (4) 32 : NS / SDR12 |
---|
240 | 257 | * 1 0 4 (16) 1 (4) 64 |
---|
241 | 258 | * 0 0 0 (1) 0 (2) 2 |
---|
242 | | - * 0 0 1 (2) 0 (2) 4 |
---|
| 259 | + * 0 0 1 (2) 0 (2) 4 : SDR104 / HS200 / HS400 (4 TAP) |
---|
243 | 260 | * 1 0 2 (4) 0 (2) 8 |
---|
244 | 261 | * 1 0 3 (8) 0 (2) 16 |
---|
245 | 262 | * 1 0 4 (16) 0 (2) 32 |
---|
| 263 | + * |
---|
| 264 | + * NOTE: There is a quirk option to ignore the first row of the dividers |
---|
| 265 | + * table when searching for suitable settings. This is because HS400 on |
---|
| 266 | + * early ES versions of H3 and M3-W requires a specific setting to work. |
---|
246 | 267 | */ |
---|
247 | 268 | static const struct sd_div_table cpg_sd_div_table[] = { |
---|
248 | 269 | /* CPG_SD_DIV_TABLE_DATA(stp_hck, stp_ck, sd_srcfc, sd_fc, sd_div) */ |
---|
.. | .. |
---|
263 | 284 | static int cpg_sd_clock_enable(struct clk_hw *hw) |
---|
264 | 285 | { |
---|
265 | 286 | struct sd_clock *clock = to_sd_clock(hw); |
---|
266 | | - u32 val = readl(clock->csn.reg); |
---|
267 | 287 | |
---|
268 | | - val &= ~(CPG_SD_STP_MASK); |
---|
269 | | - val |= clock->div_table[clock->cur_div_idx].val & CPG_SD_STP_MASK; |
---|
270 | | - |
---|
271 | | - writel(val, clock->csn.reg); |
---|
| 288 | + cpg_reg_modify(clock->csn.reg, CPG_SD_STP_MASK, |
---|
| 289 | + clock->div_table[clock->cur_div_idx].val & |
---|
| 290 | + CPG_SD_STP_MASK); |
---|
272 | 291 | |
---|
273 | 292 | return 0; |
---|
274 | 293 | } |
---|
.. | .. |
---|
277 | 296 | { |
---|
278 | 297 | struct sd_clock *clock = to_sd_clock(hw); |
---|
279 | 298 | |
---|
280 | | - writel(readl(clock->csn.reg) | CPG_SD_STP_MASK, clock->csn.reg); |
---|
| 299 | + cpg_reg_modify(clock->csn.reg, 0, CPG_SD_STP_MASK); |
---|
281 | 300 | } |
---|
282 | 301 | |
---|
283 | 302 | static int cpg_sd_clock_is_enabled(struct clk_hw *hw) |
---|
.. | .. |
---|
296 | 315 | clock->div_table[clock->cur_div_idx].div); |
---|
297 | 316 | } |
---|
298 | 317 | |
---|
299 | | -static unsigned int cpg_sd_clock_calc_div(struct sd_clock *clock, |
---|
300 | | - unsigned long rate, |
---|
301 | | - unsigned long parent_rate) |
---|
| 318 | +static int cpg_sd_clock_determine_rate(struct clk_hw *hw, |
---|
| 319 | + struct clk_rate_request *req) |
---|
302 | 320 | { |
---|
303 | | - unsigned int div; |
---|
304 | | - |
---|
305 | | - if (!rate) |
---|
306 | | - rate = 1; |
---|
307 | | - |
---|
308 | | - div = DIV_ROUND_CLOSEST(parent_rate, rate); |
---|
309 | | - |
---|
310 | | - return clamp_t(unsigned int, div, clock->div_min, clock->div_max); |
---|
311 | | -} |
---|
312 | | - |
---|
313 | | -static long cpg_sd_clock_round_rate(struct clk_hw *hw, unsigned long rate, |
---|
314 | | - unsigned long *parent_rate) |
---|
315 | | -{ |
---|
| 321 | + unsigned long best_rate = ULONG_MAX, diff_min = ULONG_MAX; |
---|
316 | 322 | struct sd_clock *clock = to_sd_clock(hw); |
---|
317 | | - unsigned int div = cpg_sd_clock_calc_div(clock, rate, *parent_rate); |
---|
| 323 | + unsigned long calc_rate, diff; |
---|
| 324 | + unsigned int i; |
---|
318 | 325 | |
---|
319 | | - return DIV_ROUND_CLOSEST(*parent_rate, div); |
---|
| 326 | + for (i = 0; i < clock->div_num; i++) { |
---|
| 327 | + calc_rate = DIV_ROUND_CLOSEST(req->best_parent_rate, |
---|
| 328 | + clock->div_table[i].div); |
---|
| 329 | + if (calc_rate < req->min_rate || calc_rate > req->max_rate) |
---|
| 330 | + continue; |
---|
| 331 | + |
---|
| 332 | + diff = calc_rate > req->rate ? calc_rate - req->rate |
---|
| 333 | + : req->rate - calc_rate; |
---|
| 334 | + if (diff < diff_min) { |
---|
| 335 | + best_rate = calc_rate; |
---|
| 336 | + diff_min = diff; |
---|
| 337 | + } |
---|
| 338 | + } |
---|
| 339 | + |
---|
| 340 | + if (best_rate == ULONG_MAX) |
---|
| 341 | + return -EINVAL; |
---|
| 342 | + |
---|
| 343 | + req->rate = best_rate; |
---|
| 344 | + return 0; |
---|
320 | 345 | } |
---|
321 | 346 | |
---|
322 | 347 | static int cpg_sd_clock_set_rate(struct clk_hw *hw, unsigned long rate, |
---|
323 | | - unsigned long parent_rate) |
---|
| 348 | + unsigned long parent_rate) |
---|
324 | 349 | { |
---|
325 | 350 | struct sd_clock *clock = to_sd_clock(hw); |
---|
326 | | - unsigned int div = cpg_sd_clock_calc_div(clock, rate, parent_rate); |
---|
327 | | - u32 val; |
---|
328 | 351 | unsigned int i; |
---|
329 | 352 | |
---|
330 | 353 | for (i = 0; i < clock->div_num; i++) |
---|
331 | | - if (div == clock->div_table[i].div) |
---|
| 354 | + if (rate == DIV_ROUND_CLOSEST(parent_rate, |
---|
| 355 | + clock->div_table[i].div)) |
---|
332 | 356 | break; |
---|
333 | 357 | |
---|
334 | 358 | if (i >= clock->div_num) |
---|
.. | .. |
---|
336 | 360 | |
---|
337 | 361 | clock->cur_div_idx = i; |
---|
338 | 362 | |
---|
339 | | - val = readl(clock->csn.reg); |
---|
340 | | - val &= ~(CPG_SD_STP_MASK | CPG_SD_FC_MASK); |
---|
341 | | - val |= clock->div_table[i].val & (CPG_SD_STP_MASK | CPG_SD_FC_MASK); |
---|
342 | | - writel(val, clock->csn.reg); |
---|
| 363 | + cpg_reg_modify(clock->csn.reg, CPG_SD_STP_MASK | CPG_SD_FC_MASK, |
---|
| 364 | + clock->div_table[i].val & |
---|
| 365 | + (CPG_SD_STP_MASK | CPG_SD_FC_MASK)); |
---|
343 | 366 | |
---|
344 | 367 | return 0; |
---|
345 | 368 | } |
---|
.. | .. |
---|
349 | 372 | .disable = cpg_sd_clock_disable, |
---|
350 | 373 | .is_enabled = cpg_sd_clock_is_enabled, |
---|
351 | 374 | .recalc_rate = cpg_sd_clock_recalc_rate, |
---|
352 | | - .round_rate = cpg_sd_clock_round_rate, |
---|
| 375 | + .determine_rate = cpg_sd_clock_determine_rate, |
---|
353 | 376 | .set_rate = cpg_sd_clock_set_rate, |
---|
354 | 377 | }; |
---|
355 | 378 | |
---|
356 | | -static struct clk * __init cpg_sd_clk_register(const struct cpg_core_clk *core, |
---|
357 | | - void __iomem *base, const char *parent_name, |
---|
| 379 | +static u32 cpg_quirks __initdata; |
---|
| 380 | + |
---|
| 381 | +#define PLL_ERRATA BIT(0) /* Missing PLL0/2/4 post-divider */ |
---|
| 382 | +#define RCKCR_CKSEL BIT(1) /* Manual RCLK parent selection */ |
---|
| 383 | +#define SD_SKIP_FIRST BIT(2) /* Skip first clock in SD table */ |
---|
| 384 | + |
---|
| 385 | +static struct clk * __init cpg_sd_clk_register(const char *name, |
---|
| 386 | + void __iomem *base, unsigned int offset, const char *parent_name, |
---|
358 | 387 | struct raw_notifier_head *notifiers) |
---|
359 | 388 | { |
---|
360 | | - struct clk_init_data init = {}; |
---|
| 389 | + struct clk_init_data init; |
---|
361 | 390 | struct sd_clock *clock; |
---|
362 | 391 | struct clk *clk; |
---|
363 | | - unsigned int i; |
---|
364 | 392 | u32 val; |
---|
365 | 393 | |
---|
366 | 394 | clock = kzalloc(sizeof(*clock), GFP_KERNEL); |
---|
367 | 395 | if (!clock) |
---|
368 | 396 | return ERR_PTR(-ENOMEM); |
---|
369 | 397 | |
---|
370 | | - init.name = core->name; |
---|
| 398 | + init.name = name; |
---|
371 | 399 | init.ops = &cpg_sd_clock_ops; |
---|
372 | | - init.flags = CLK_IS_BASIC | CLK_SET_RATE_PARENT; |
---|
| 400 | + init.flags = CLK_SET_RATE_PARENT; |
---|
373 | 401 | init.parent_names = &parent_name; |
---|
374 | 402 | init.num_parents = 1; |
---|
375 | 403 | |
---|
376 | | - clock->csn.reg = base + core->offset; |
---|
| 404 | + clock->csn.reg = base + offset; |
---|
377 | 405 | clock->hw.init = &init; |
---|
378 | 406 | clock->div_table = cpg_sd_div_table; |
---|
379 | 407 | clock->div_num = ARRAY_SIZE(cpg_sd_div_table); |
---|
380 | 408 | |
---|
| 409 | + if (cpg_quirks & SD_SKIP_FIRST) { |
---|
| 410 | + clock->div_table++; |
---|
| 411 | + clock->div_num--; |
---|
| 412 | + } |
---|
| 413 | + |
---|
381 | 414 | val = readl(clock->csn.reg) & ~CPG_SD_FC_MASK; |
---|
382 | 415 | val |= CPG_SD_STP_MASK | (clock->div_table[0].val & CPG_SD_FC_MASK); |
---|
383 | 416 | writel(val, clock->csn.reg); |
---|
384 | | - |
---|
385 | | - clock->div_max = clock->div_table[0].div; |
---|
386 | | - clock->div_min = clock->div_max; |
---|
387 | | - for (i = 1; i < clock->div_num; i++) { |
---|
388 | | - clock->div_max = max(clock->div_max, clock->div_table[i].div); |
---|
389 | | - clock->div_min = min(clock->div_min, clock->div_table[i].div); |
---|
390 | | - } |
---|
391 | 417 | |
---|
392 | 418 | clk = clk_register(NULL, &clock->hw); |
---|
393 | 419 | if (IS_ERR(clk)) |
---|
.. | .. |
---|
401 | 427 | return clk; |
---|
402 | 428 | } |
---|
403 | 429 | |
---|
| 430 | +struct rpc_clock { |
---|
| 431 | + struct clk_divider div; |
---|
| 432 | + struct clk_gate gate; |
---|
| 433 | + /* |
---|
| 434 | + * One notifier covers both RPC and RPCD2 clocks as they are both |
---|
| 435 | + * controlled by the same RPCCKCR register... |
---|
| 436 | + */ |
---|
| 437 | + struct cpg_simple_notifier csn; |
---|
| 438 | +}; |
---|
| 439 | + |
---|
| 440 | +static const struct clk_div_table cpg_rpcsrc_div_table[] = { |
---|
| 441 | + { 2, 5 }, { 3, 6 }, { 0, 0 }, |
---|
| 442 | +}; |
---|
| 443 | + |
---|
| 444 | +static const struct clk_div_table cpg_rpc_div_table[] = { |
---|
| 445 | + { 1, 2 }, { 3, 4 }, { 5, 6 }, { 7, 8 }, { 0, 0 }, |
---|
| 446 | +}; |
---|
| 447 | + |
---|
| 448 | +static struct clk * __init cpg_rpc_clk_register(const char *name, |
---|
| 449 | + void __iomem *base, const char *parent_name, |
---|
| 450 | + struct raw_notifier_head *notifiers) |
---|
| 451 | +{ |
---|
| 452 | + struct rpc_clock *rpc; |
---|
| 453 | + struct clk *clk; |
---|
| 454 | + |
---|
| 455 | + rpc = kzalloc(sizeof(*rpc), GFP_KERNEL); |
---|
| 456 | + if (!rpc) |
---|
| 457 | + return ERR_PTR(-ENOMEM); |
---|
| 458 | + |
---|
| 459 | + rpc->div.reg = base + CPG_RPCCKCR; |
---|
| 460 | + rpc->div.width = 3; |
---|
| 461 | + rpc->div.table = cpg_rpc_div_table; |
---|
| 462 | + rpc->div.lock = &cpg_lock; |
---|
| 463 | + |
---|
| 464 | + rpc->gate.reg = base + CPG_RPCCKCR; |
---|
| 465 | + rpc->gate.bit_idx = 8; |
---|
| 466 | + rpc->gate.flags = CLK_GATE_SET_TO_DISABLE; |
---|
| 467 | + rpc->gate.lock = &cpg_lock; |
---|
| 468 | + |
---|
| 469 | + rpc->csn.reg = base + CPG_RPCCKCR; |
---|
| 470 | + |
---|
| 471 | + clk = clk_register_composite(NULL, name, &parent_name, 1, NULL, NULL, |
---|
| 472 | + &rpc->div.hw, &clk_divider_ops, |
---|
| 473 | + &rpc->gate.hw, &clk_gate_ops, |
---|
| 474 | + CLK_SET_RATE_PARENT); |
---|
| 475 | + if (IS_ERR(clk)) { |
---|
| 476 | + kfree(rpc); |
---|
| 477 | + return clk; |
---|
| 478 | + } |
---|
| 479 | + |
---|
| 480 | + cpg_simple_notifier_register(notifiers, &rpc->csn); |
---|
| 481 | + return clk; |
---|
| 482 | +} |
---|
| 483 | + |
---|
| 484 | +struct rpcd2_clock { |
---|
| 485 | + struct clk_fixed_factor fixed; |
---|
| 486 | + struct clk_gate gate; |
---|
| 487 | +}; |
---|
| 488 | + |
---|
| 489 | +static struct clk * __init cpg_rpcd2_clk_register(const char *name, |
---|
| 490 | + void __iomem *base, |
---|
| 491 | + const char *parent_name) |
---|
| 492 | +{ |
---|
| 493 | + struct rpcd2_clock *rpcd2; |
---|
| 494 | + struct clk *clk; |
---|
| 495 | + |
---|
| 496 | + rpcd2 = kzalloc(sizeof(*rpcd2), GFP_KERNEL); |
---|
| 497 | + if (!rpcd2) |
---|
| 498 | + return ERR_PTR(-ENOMEM); |
---|
| 499 | + |
---|
| 500 | + rpcd2->fixed.mult = 1; |
---|
| 501 | + rpcd2->fixed.div = 2; |
---|
| 502 | + |
---|
| 503 | + rpcd2->gate.reg = base + CPG_RPCCKCR; |
---|
| 504 | + rpcd2->gate.bit_idx = 9; |
---|
| 505 | + rpcd2->gate.flags = CLK_GATE_SET_TO_DISABLE; |
---|
| 506 | + rpcd2->gate.lock = &cpg_lock; |
---|
| 507 | + |
---|
| 508 | + clk = clk_register_composite(NULL, name, &parent_name, 1, NULL, NULL, |
---|
| 509 | + &rpcd2->fixed.hw, &clk_fixed_factor_ops, |
---|
| 510 | + &rpcd2->gate.hw, &clk_gate_ops, |
---|
| 511 | + CLK_SET_RATE_PARENT); |
---|
| 512 | + if (IS_ERR(clk)) |
---|
| 513 | + kfree(rpcd2); |
---|
| 514 | + |
---|
| 515 | + return clk; |
---|
| 516 | +} |
---|
| 517 | + |
---|
404 | 518 | |
---|
405 | 519 | static const struct rcar_gen3_cpg_pll_config *cpg_pll_config __initdata; |
---|
406 | 520 | static unsigned int cpg_clk_extalr __initdata; |
---|
407 | 521 | static u32 cpg_mode __initdata; |
---|
408 | | -static u32 cpg_quirks __initdata; |
---|
409 | | - |
---|
410 | | -#define PLL_ERRATA BIT(0) /* Missing PLL0/2/4 post-divider */ |
---|
411 | | -#define RCKCR_CKSEL BIT(1) /* Manual RCLK parent selection */ |
---|
412 | 522 | |
---|
413 | 523 | static const struct soc_device_attribute cpg_quirks_match[] __initconst = { |
---|
414 | 524 | { |
---|
415 | 525 | .soc_id = "r8a7795", .revision = "ES1.0", |
---|
416 | | - .data = (void *)(PLL_ERRATA | RCKCR_CKSEL), |
---|
| 526 | + .data = (void *)(PLL_ERRATA | RCKCR_CKSEL | SD_SKIP_FIRST), |
---|
417 | 527 | }, |
---|
418 | 528 | { |
---|
419 | 529 | .soc_id = "r8a7795", .revision = "ES1.*", |
---|
420 | | - .data = (void *)RCKCR_CKSEL, |
---|
| 530 | + .data = (void *)(RCKCR_CKSEL | SD_SKIP_FIRST), |
---|
| 531 | + }, |
---|
| 532 | + { |
---|
| 533 | + .soc_id = "r8a7795", .revision = "ES2.0", |
---|
| 534 | + .data = (void *)SD_SKIP_FIRST, |
---|
421 | 535 | }, |
---|
422 | 536 | { |
---|
423 | 537 | .soc_id = "r8a7796", .revision = "ES1.0", |
---|
424 | | - .data = (void *)RCKCR_CKSEL, |
---|
| 538 | + .data = (void *)(RCKCR_CKSEL | SD_SKIP_FIRST), |
---|
| 539 | + }, |
---|
| 540 | + { |
---|
| 541 | + .soc_id = "r8a7796", .revision = "ES1.1", |
---|
| 542 | + .data = (void *)SD_SKIP_FIRST, |
---|
425 | 543 | }, |
---|
426 | 544 | { /* sentinel */ } |
---|
427 | 545 | }; |
---|
.. | .. |
---|
436 | 554 | unsigned int div = 1; |
---|
437 | 555 | u32 value; |
---|
438 | 556 | |
---|
439 | | - parent = clks[core->parent & 0xffff]; /* CLK_TYPE_PE uses high bits */ |
---|
| 557 | + parent = clks[core->parent & 0xffff]; /* some types use high bits */ |
---|
440 | 558 | if (IS_ERR(parent)) |
---|
441 | 559 | return ERR_CAST(parent); |
---|
442 | 560 | |
---|
.. | .. |
---|
495 | 613 | break; |
---|
496 | 614 | |
---|
497 | 615 | case CLK_TYPE_GEN3_SD: |
---|
498 | | - return cpg_sd_clk_register(core, base, __clk_get_name(parent), |
---|
499 | | - notifiers); |
---|
| 616 | + return cpg_sd_clk_register(core->name, base, core->offset, |
---|
| 617 | + __clk_get_name(parent), notifiers); |
---|
500 | 618 | |
---|
501 | 619 | case CLK_TYPE_GEN3_R: |
---|
502 | 620 | if (cpg_quirks & RCKCR_CKSEL) { |
---|
.. | .. |
---|
516 | 634 | |
---|
517 | 635 | if (clk_get_rate(clks[cpg_clk_extalr])) { |
---|
518 | 636 | parent = clks[cpg_clk_extalr]; |
---|
519 | | - value |= BIT(15); |
---|
| 637 | + value |= CPG_RCKCR_CKSEL; |
---|
520 | 638 | } |
---|
521 | 639 | |
---|
522 | 640 | writel(value, csn->reg); |
---|
.. | .. |
---|
529 | 647 | parent = clks[cpg_clk_extalr]; |
---|
530 | 648 | break; |
---|
531 | 649 | |
---|
532 | | - case CLK_TYPE_GEN3_PE: |
---|
| 650 | + case CLK_TYPE_GEN3_MDSEL: |
---|
533 | 651 | /* |
---|
534 | | - * Peripheral clock with a fixed divider, selectable between |
---|
535 | | - * clean and spread spectrum parents using MD12 |
---|
| 652 | + * Clock selectable between two parents and two fixed dividers |
---|
| 653 | + * using a mode pin |
---|
536 | 654 | */ |
---|
537 | | - if (cpg_mode & BIT(12)) { |
---|
538 | | - /* Clean */ |
---|
| 655 | + if (cpg_mode & BIT(core->offset)) { |
---|
539 | 656 | div = core->div & 0xffff; |
---|
540 | 657 | } else { |
---|
541 | | - /* SCCG */ |
---|
542 | 658 | parent = clks[core->parent >> 16]; |
---|
543 | 659 | if (IS_ERR(parent)) |
---|
544 | 660 | return ERR_CAST(parent); |
---|
.. | .. |
---|
549 | 665 | |
---|
550 | 666 | case CLK_TYPE_GEN3_Z: |
---|
551 | 667 | return cpg_z_clk_register(core->name, __clk_get_name(parent), |
---|
552 | | - base, CPG_FRQCRC_ZFC_MASK); |
---|
| 668 | + base, core->div, core->offset); |
---|
553 | 669 | |
---|
554 | | - case CLK_TYPE_GEN3_Z2: |
---|
555 | | - return cpg_z_clk_register(core->name, __clk_get_name(parent), |
---|
556 | | - base, CPG_FRQCRC_Z2FC_MASK); |
---|
| 670 | + case CLK_TYPE_GEN3_OSC: |
---|
| 671 | + /* |
---|
| 672 | + * Clock combining OSC EXTAL predivider and a fixed divider |
---|
| 673 | + */ |
---|
| 674 | + div = cpg_pll_config->osc_prediv * core->div; |
---|
| 675 | + break; |
---|
| 676 | + |
---|
| 677 | + case CLK_TYPE_GEN3_RCKSEL: |
---|
| 678 | + /* |
---|
| 679 | + * Clock selectable between two parents and two fixed dividers |
---|
| 680 | + * using RCKCR.CKSEL |
---|
| 681 | + */ |
---|
| 682 | + if (readl(base + CPG_RCKCR) & CPG_RCKCR_CKSEL) { |
---|
| 683 | + div = core->div & 0xffff; |
---|
| 684 | + } else { |
---|
| 685 | + parent = clks[core->parent >> 16]; |
---|
| 686 | + if (IS_ERR(parent)) |
---|
| 687 | + return ERR_CAST(parent); |
---|
| 688 | + div = core->div >> 16; |
---|
| 689 | + } |
---|
| 690 | + break; |
---|
| 691 | + |
---|
| 692 | + case CLK_TYPE_GEN3_RPCSRC: |
---|
| 693 | + return clk_register_divider_table(NULL, core->name, |
---|
| 694 | + __clk_get_name(parent), 0, |
---|
| 695 | + base + CPG_RPCCKCR, 3, 2, 0, |
---|
| 696 | + cpg_rpcsrc_div_table, |
---|
| 697 | + &cpg_lock); |
---|
| 698 | + |
---|
| 699 | + case CLK_TYPE_GEN3_RPC: |
---|
| 700 | + return cpg_rpc_clk_register(core->name, base, |
---|
| 701 | + __clk_get_name(parent), notifiers); |
---|
| 702 | + |
---|
| 703 | + case CLK_TYPE_GEN3_RPCD2: |
---|
| 704 | + return cpg_rpcd2_clk_register(core->name, base, |
---|
| 705 | + __clk_get_name(parent)); |
---|
557 | 706 | |
---|
558 | 707 | default: |
---|
559 | 708 | return ERR_PTR(-EINVAL); |
---|
.. | .. |
---|
575 | 724 | if (attr) |
---|
576 | 725 | cpg_quirks = (uintptr_t)attr->data; |
---|
577 | 726 | pr_debug("%s: mode = 0x%x quirks = 0x%x\n", __func__, mode, cpg_quirks); |
---|
| 727 | + |
---|
| 728 | + spin_lock_init(&cpg_lock); |
---|
| 729 | + |
---|
578 | 730 | return 0; |
---|
579 | 731 | } |
---|