.. | .. |
---|
1 | 1 | // SPDX-License-Identifier: GPL-2.0+ |
---|
| 2 | +// Copyright IBM Corp |
---|
2 | 3 | |
---|
3 | 4 | #define pr_fmt(fmt) "clk-aspeed: " fmt |
---|
4 | 5 | |
---|
5 | | -#include <linux/clk-provider.h> |
---|
6 | 6 | #include <linux/mfd/syscon.h> |
---|
7 | 7 | #include <linux/of_address.h> |
---|
8 | 8 | #include <linux/of_device.h> |
---|
9 | 9 | #include <linux/platform_device.h> |
---|
10 | 10 | #include <linux/regmap.h> |
---|
11 | | -#include <linux/reset-controller.h> |
---|
12 | 11 | #include <linux/slab.h> |
---|
13 | | -#include <linux/spinlock.h> |
---|
14 | 12 | |
---|
15 | 13 | #include <dt-bindings/clock/aspeed-clock.h> |
---|
16 | 14 | |
---|
17 | | -#define ASPEED_NUM_CLKS 36 |
---|
| 15 | +#include "clk-aspeed.h" |
---|
| 16 | + |
---|
| 17 | +#define ASPEED_NUM_CLKS 38 |
---|
18 | 18 | |
---|
19 | 19 | #define ASPEED_RESET2_OFFSET 32 |
---|
20 | 20 | |
---|
.. | .. |
---|
28 | 28 | #define AST2400_HPLL_BYPASS_EN BIT(17) |
---|
29 | 29 | #define ASPEED_MISC_CTRL 0x2c |
---|
30 | 30 | #define UART_DIV13_EN BIT(12) |
---|
| 31 | +#define ASPEED_MAC_CLK_DLY 0x48 |
---|
31 | 32 | #define ASPEED_STRAP 0x70 |
---|
32 | 33 | #define CLKIN_25MHZ_EN BIT(23) |
---|
33 | 34 | #define AST2400_CLK_SOURCE_SEL BIT(18) |
---|
.. | .. |
---|
42 | 43 | |
---|
43 | 44 | static void __iomem *scu_base; |
---|
44 | 45 | |
---|
45 | | -/** |
---|
46 | | - * struct aspeed_gate_data - Aspeed gated clocks |
---|
47 | | - * @clock_idx: bit used to gate this clock in the clock register |
---|
48 | | - * @reset_idx: bit used to reset this IP in the reset register. -1 if no |
---|
49 | | - * reset is required when enabling the clock |
---|
50 | | - * @name: the clock name |
---|
51 | | - * @parent_name: the name of the parent clock |
---|
52 | | - * @flags: standard clock framework flags |
---|
53 | | - */ |
---|
54 | | -struct aspeed_gate_data { |
---|
55 | | - u8 clock_idx; |
---|
56 | | - s8 reset_idx; |
---|
57 | | - const char *name; |
---|
58 | | - const char *parent_name; |
---|
59 | | - unsigned long flags; |
---|
60 | | -}; |
---|
61 | | - |
---|
62 | | -/** |
---|
63 | | - * struct aspeed_clk_gate - Aspeed specific clk_gate structure |
---|
64 | | - * @hw: handle between common and hardware-specific interfaces |
---|
65 | | - * @reg: register controlling gate |
---|
66 | | - * @clock_idx: bit used to gate this clock in the clock register |
---|
67 | | - * @reset_idx: bit used to reset this IP in the reset register. -1 if no |
---|
68 | | - * reset is required when enabling the clock |
---|
69 | | - * @flags: hardware-specific flags |
---|
70 | | - * @lock: register lock |
---|
71 | | - * |
---|
72 | | - * Some of the clocks in the Aspeed SoC must be put in reset before enabling. |
---|
73 | | - * This modified version of clk_gate allows an optional reset bit to be |
---|
74 | | - * specified. |
---|
75 | | - */ |
---|
76 | | -struct aspeed_clk_gate { |
---|
77 | | - struct clk_hw hw; |
---|
78 | | - struct regmap *map; |
---|
79 | | - u8 clock_idx; |
---|
80 | | - s8 reset_idx; |
---|
81 | | - u8 flags; |
---|
82 | | - spinlock_t *lock; |
---|
83 | | -}; |
---|
84 | | - |
---|
85 | | -#define to_aspeed_clk_gate(_hw) container_of(_hw, struct aspeed_clk_gate, hw) |
---|
86 | | - |
---|
87 | 46 | /* TODO: ask Aspeed about the actual parent data */ |
---|
88 | 47 | static const struct aspeed_gate_data aspeed_gates[] = { |
---|
89 | 48 | /* clk rst name parent flags */ |
---|
90 | | - [ASPEED_CLK_GATE_ECLK] = { 0, -1, "eclk-gate", "eclk", 0 }, /* Video Engine */ |
---|
| 49 | + [ASPEED_CLK_GATE_ECLK] = { 0, 6, "eclk-gate", "eclk", 0 }, /* Video Engine */ |
---|
91 | 50 | [ASPEED_CLK_GATE_GCLK] = { 1, 7, "gclk-gate", NULL, 0 }, /* 2D engine */ |
---|
92 | 51 | [ASPEED_CLK_GATE_MCLK] = { 2, -1, "mclk-gate", "mpll", CLK_IS_CRITICAL }, /* SDRAM */ |
---|
93 | | - [ASPEED_CLK_GATE_VCLK] = { 3, 6, "vclk-gate", NULL, 0 }, /* Video Capture */ |
---|
| 52 | + [ASPEED_CLK_GATE_VCLK] = { 3, -1, "vclk-gate", NULL, 0 }, /* Video Capture */ |
---|
94 | 53 | [ASPEED_CLK_GATE_BCLK] = { 4, 8, "bclk-gate", "bclk", CLK_IS_CRITICAL }, /* PCIe/PCI */ |
---|
95 | 54 | [ASPEED_CLK_GATE_DCLK] = { 5, -1, "dclk-gate", NULL, CLK_IS_CRITICAL }, /* DAC */ |
---|
96 | 55 | [ASPEED_CLK_GATE_REFCLK] = { 6, -1, "refclk-gate", "clkin", CLK_IS_CRITICAL }, |
---|
.. | .. |
---|
111 | 70 | [ASPEED_CLK_GATE_UART4CLK] = { 26, -1, "uart4clk-gate", "uart", 0 }, /* UART4 */ |
---|
112 | 71 | [ASPEED_CLK_GATE_SDCLK] = { 27, 16, "sdclk-gate", NULL, 0 }, /* SDIO/SD */ |
---|
113 | 72 | [ASPEED_CLK_GATE_LHCCLK] = { 28, -1, "lhclk-gate", "lhclk", 0 }, /* LPC master/LPC+ */ |
---|
| 73 | +}; |
---|
| 74 | + |
---|
| 75 | +static const char * const eclk_parent_names[] = { |
---|
| 76 | + "mpll", |
---|
| 77 | + "hpll", |
---|
| 78 | + "dpll", |
---|
| 79 | +}; |
---|
| 80 | + |
---|
| 81 | +static const struct clk_div_table ast2500_eclk_div_table[] = { |
---|
| 82 | + { 0x0, 2 }, |
---|
| 83 | + { 0x1, 2 }, |
---|
| 84 | + { 0x2, 3 }, |
---|
| 85 | + { 0x3, 4 }, |
---|
| 86 | + { 0x4, 5 }, |
---|
| 87 | + { 0x5, 6 }, |
---|
| 88 | + { 0x6, 7 }, |
---|
| 89 | + { 0x7, 8 }, |
---|
| 90 | + { 0 } |
---|
114 | 91 | }; |
---|
115 | 92 | |
---|
116 | 93 | static const struct clk_div_table ast2500_mac_div_table[] = { |
---|
.. | .. |
---|
190 | 167 | mult, div); |
---|
191 | 168 | } |
---|
192 | 169 | |
---|
193 | | -struct aspeed_clk_soc_data { |
---|
194 | | - const struct clk_div_table *div_table; |
---|
195 | | - const struct clk_div_table *mac_div_table; |
---|
196 | | - struct clk_hw *(*calc_pll)(const char *name, u32 val); |
---|
197 | | -}; |
---|
198 | | - |
---|
199 | 170 | static const struct aspeed_clk_soc_data ast2500_data = { |
---|
200 | 171 | .div_table = ast2500_div_table, |
---|
| 172 | + .eclk_div_table = ast2500_eclk_div_table, |
---|
201 | 173 | .mac_div_table = ast2500_mac_div_table, |
---|
202 | 174 | .calc_pll = aspeed_ast2500_calc_pll, |
---|
203 | 175 | }; |
---|
204 | 176 | |
---|
205 | 177 | static const struct aspeed_clk_soc_data ast2400_data = { |
---|
206 | 178 | .div_table = ast2400_div_table, |
---|
| 179 | + .eclk_div_table = ast2400_div_table, |
---|
207 | 180 | .mac_div_table = ast2400_div_table, |
---|
208 | 181 | .calc_pll = aspeed_ast2400_calc_pll, |
---|
209 | 182 | }; |
---|
.. | .. |
---|
294 | 267 | .is_enabled = aspeed_clk_is_enabled, |
---|
295 | 268 | }; |
---|
296 | 269 | |
---|
297 | | -/** |
---|
298 | | - * struct aspeed_reset - Aspeed reset controller |
---|
299 | | - * @map: regmap to access the containing system controller |
---|
300 | | - * @rcdev: reset controller device |
---|
301 | | - */ |
---|
302 | | -struct aspeed_reset { |
---|
303 | | - struct regmap *map; |
---|
304 | | - struct reset_controller_dev rcdev; |
---|
305 | | -}; |
---|
306 | | - |
---|
307 | | -#define to_aspeed_reset(p) container_of((p), struct aspeed_reset, rcdev) |
---|
308 | | - |
---|
309 | 270 | static const u8 aspeed_resets[] = { |
---|
310 | 271 | /* SCU04 resets */ |
---|
311 | 272 | [ASPEED_RESET_XDMA] = 25, |
---|
.. | .. |
---|
387 | 348 | u8 clk_gate_flags, spinlock_t *lock) |
---|
388 | 349 | { |
---|
389 | 350 | struct aspeed_clk_gate *gate; |
---|
390 | | - struct clk_init_data init = {}; |
---|
| 351 | + struct clk_init_data init; |
---|
391 | 352 | struct clk_hw *hw; |
---|
392 | 353 | int ret; |
---|
393 | 354 | |
---|
.. | .. |
---|
479 | 440 | return PTR_ERR(hw); |
---|
480 | 441 | aspeed_clk_data->hws[ASPEED_CLK_MPLL] = hw; |
---|
481 | 442 | |
---|
482 | | - /* SD/SDIO clock divider (TODO: There's a gate too) */ |
---|
483 | | - hw = clk_hw_register_divider_table(dev, "sdio", "hpll", 0, |
---|
484 | | - scu_base + ASPEED_CLK_SELECTION, 12, 3, 0, |
---|
| 443 | + /* SD/SDIO clock divider and gate */ |
---|
| 444 | + hw = clk_hw_register_gate(dev, "sd_extclk_gate", "hpll", 0, |
---|
| 445 | + scu_base + ASPEED_CLK_SELECTION, 15, 0, |
---|
| 446 | + &aspeed_clk_lock); |
---|
| 447 | + if (IS_ERR(hw)) |
---|
| 448 | + return PTR_ERR(hw); |
---|
| 449 | + hw = clk_hw_register_divider_table(dev, "sd_extclk", "sd_extclk_gate", |
---|
| 450 | + 0, scu_base + ASPEED_CLK_SELECTION, 12, 3, 0, |
---|
485 | 451 | soc_data->div_table, |
---|
486 | 452 | &aspeed_clk_lock); |
---|
487 | 453 | if (IS_ERR(hw)) |
---|
.. | .. |
---|
496 | 462 | if (IS_ERR(hw)) |
---|
497 | 463 | return PTR_ERR(hw); |
---|
498 | 464 | aspeed_clk_data->hws[ASPEED_CLK_MAC] = hw; |
---|
| 465 | + |
---|
| 466 | + if (of_device_is_compatible(pdev->dev.of_node, "aspeed,ast2500-scu")) { |
---|
| 467 | + /* RMII 50MHz RCLK */ |
---|
| 468 | + hw = clk_hw_register_fixed_rate(dev, "mac12rclk", "hpll", 0, |
---|
| 469 | + 50000000); |
---|
| 470 | + if (IS_ERR(hw)) |
---|
| 471 | + return PTR_ERR(hw); |
---|
| 472 | + |
---|
| 473 | + /* RMII1 50MHz (RCLK) output enable */ |
---|
| 474 | + hw = clk_hw_register_gate(dev, "mac1rclk", "mac12rclk", 0, |
---|
| 475 | + scu_base + ASPEED_MAC_CLK_DLY, 29, 0, |
---|
| 476 | + &aspeed_clk_lock); |
---|
| 477 | + if (IS_ERR(hw)) |
---|
| 478 | + return PTR_ERR(hw); |
---|
| 479 | + aspeed_clk_data->hws[ASPEED_CLK_MAC1RCLK] = hw; |
---|
| 480 | + |
---|
| 481 | + /* RMII2 50MHz (RCLK) output enable */ |
---|
| 482 | + hw = clk_hw_register_gate(dev, "mac2rclk", "mac12rclk", 0, |
---|
| 483 | + scu_base + ASPEED_MAC_CLK_DLY, 30, 0, |
---|
| 484 | + &aspeed_clk_lock); |
---|
| 485 | + if (IS_ERR(hw)) |
---|
| 486 | + return PTR_ERR(hw); |
---|
| 487 | + aspeed_clk_data->hws[ASPEED_CLK_MAC2RCLK] = hw; |
---|
| 488 | + } |
---|
499 | 489 | |
---|
500 | 490 | /* LPC Host (LHCLK) clock divider */ |
---|
501 | 491 | hw = clk_hw_register_divider_table(dev, "lhclk", "hpll", 0, |
---|
.. | .. |
---|
522 | 512 | return PTR_ERR(hw); |
---|
523 | 513 | aspeed_clk_data->hws[ASPEED_CLK_24M] = hw; |
---|
524 | 514 | |
---|
| 515 | + hw = clk_hw_register_mux(dev, "eclk-mux", eclk_parent_names, |
---|
| 516 | + ARRAY_SIZE(eclk_parent_names), 0, |
---|
| 517 | + scu_base + ASPEED_CLK_SELECTION, 2, 0x3, 0, |
---|
| 518 | + &aspeed_clk_lock); |
---|
| 519 | + if (IS_ERR(hw)) |
---|
| 520 | + return PTR_ERR(hw); |
---|
| 521 | + aspeed_clk_data->hws[ASPEED_CLK_ECLK_MUX] = hw; |
---|
| 522 | + |
---|
| 523 | + hw = clk_hw_register_divider_table(dev, "eclk", "eclk-mux", 0, |
---|
| 524 | + scu_base + ASPEED_CLK_SELECTION, 28, |
---|
| 525 | + 3, 0, soc_data->eclk_div_table, |
---|
| 526 | + &aspeed_clk_lock); |
---|
| 527 | + if (IS_ERR(hw)) |
---|
| 528 | + return PTR_ERR(hw); |
---|
| 529 | + aspeed_clk_data->hws[ASPEED_CLK_ECLK] = hw; |
---|
| 530 | + |
---|
525 | 531 | /* |
---|
526 | 532 | * TODO: There are a number of clocks that not included in this driver |
---|
527 | 533 | * as more information is required: |
---|
.. | .. |
---|
531 | 537 | * RGMII |
---|
532 | 538 | * RMII |
---|
533 | 539 | * UART[1..5] clock source mux |
---|
534 | | - * Video Engine (ECLK) mux and clock divider |
---|
535 | 540 | */ |
---|
536 | 541 | |
---|
537 | 542 | for (i = 0; i < ARRAY_SIZE(aspeed_gates); i++) { |
---|