| .. | .. |
|---|
| 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 | } |
|---|