diff options
Diffstat (limited to 'drivers/clk/clk-aspeed.c')
-rw-r--r-- | drivers/clk/clk-aspeed.c | 105 |
1 files changed, 37 insertions, 68 deletions
diff --git a/drivers/clk/clk-aspeed.c b/drivers/clk/clk-aspeed.c index 42b4df6ba249..411ff5fb2c07 100644 --- a/drivers/clk/clk-aspeed.c +++ b/drivers/clk/clk-aspeed.c @@ -1,20 +1,20 @@ // SPDX-License-Identifier: GPL-2.0+ +// Copyright IBM Corp #define pr_fmt(fmt) "clk-aspeed: " fmt -#include <linux/clk-provider.h> #include <linux/mfd/syscon.h> #include <linux/of_address.h> #include <linux/of_device.h> #include <linux/platform_device.h> #include <linux/regmap.h> -#include <linux/reset-controller.h> #include <linux/slab.h> -#include <linux/spinlock.h> #include <dt-bindings/clock/aspeed-clock.h> -#define ASPEED_NUM_CLKS 36 +#include "clk-aspeed.h" + +#define ASPEED_NUM_CLKS 38 #define ASPEED_RESET2_OFFSET 32 @@ -28,6 +28,7 @@ #define AST2400_HPLL_BYPASS_EN BIT(17) #define ASPEED_MISC_CTRL 0x2c #define UART_DIV13_EN BIT(12) +#define ASPEED_MAC_CLK_DLY 0x48 #define ASPEED_STRAP 0x70 #define CLKIN_25MHZ_EN BIT(23) #define AST2400_CLK_SOURCE_SEL BIT(18) @@ -42,48 +43,6 @@ static struct clk_hw_onecell_data *aspeed_clk_data; static void __iomem *scu_base; -/** - * struct aspeed_gate_data - Aspeed gated clocks - * @clock_idx: bit used to gate this clock in the clock register - * @reset_idx: bit used to reset this IP in the reset register. -1 if no - * reset is required when enabling the clock - * @name: the clock name - * @parent_name: the name of the parent clock - * @flags: standard clock framework flags - */ -struct aspeed_gate_data { - u8 clock_idx; - s8 reset_idx; - const char *name; - const char *parent_name; - unsigned long flags; -}; - -/** - * struct aspeed_clk_gate - Aspeed specific clk_gate structure - * @hw: handle between common and hardware-specific interfaces - * @reg: register controlling gate - * @clock_idx: bit used to gate this clock in the clock register - * @reset_idx: bit used to reset this IP in the reset register. -1 if no - * reset is required when enabling the clock - * @flags: hardware-specific flags - * @lock: register lock - * - * Some of the clocks in the Aspeed SoC must be put in reset before enabling. - * This modified version of clk_gate allows an optional reset bit to be - * specified. - */ -struct aspeed_clk_gate { - struct clk_hw hw; - struct regmap *map; - u8 clock_idx; - s8 reset_idx; - u8 flags; - spinlock_t *lock; -}; - -#define to_aspeed_clk_gate(_hw) container_of(_hw, struct aspeed_clk_gate, hw) - /* TODO: ask Aspeed about the actual parent data */ static const struct aspeed_gate_data aspeed_gates[] = { /* clk rst name parent flags */ @@ -208,13 +167,6 @@ static struct clk_hw *aspeed_ast2500_calc_pll(const char *name, u32 val) mult, div); } -struct aspeed_clk_soc_data { - const struct clk_div_table *div_table; - const struct clk_div_table *eclk_div_table; - const struct clk_div_table *mac_div_table; - struct clk_hw *(*calc_pll)(const char *name, u32 val); -}; - static const struct aspeed_clk_soc_data ast2500_data = { .div_table = ast2500_div_table, .eclk_div_table = ast2500_eclk_div_table, @@ -315,18 +267,6 @@ static const struct clk_ops aspeed_clk_gate_ops = { .is_enabled = aspeed_clk_is_enabled, }; -/** - * struct aspeed_reset - Aspeed reset controller - * @map: regmap to access the containing system controller - * @rcdev: reset controller device - */ -struct aspeed_reset { - struct regmap *map; - struct reset_controller_dev rcdev; -}; - -#define to_aspeed_reset(p) container_of((p), struct aspeed_reset, rcdev) - static const u8 aspeed_resets[] = { /* SCU04 resets */ [ASPEED_RESET_XDMA] = 25, @@ -500,9 +440,14 @@ static int aspeed_clk_probe(struct platform_device *pdev) return PTR_ERR(hw); aspeed_clk_data->hws[ASPEED_CLK_MPLL] = hw; - /* SD/SDIO clock divider (TODO: There's a gate too) */ - hw = clk_hw_register_divider_table(dev, "sdio", "hpll", 0, - scu_base + ASPEED_CLK_SELECTION, 12, 3, 0, + /* SD/SDIO clock divider and gate */ + hw = clk_hw_register_gate(dev, "sd_extclk_gate", "hpll", 0, + scu_base + ASPEED_CLK_SELECTION, 15, 0, + &aspeed_clk_lock); + if (IS_ERR(hw)) + return PTR_ERR(hw); + hw = clk_hw_register_divider_table(dev, "sd_extclk", "sd_extclk_gate", + 0, scu_base + ASPEED_CLK_SELECTION, 12, 3, 0, soc_data->div_table, &aspeed_clk_lock); if (IS_ERR(hw)) @@ -518,6 +463,30 @@ static int aspeed_clk_probe(struct platform_device *pdev) return PTR_ERR(hw); aspeed_clk_data->hws[ASPEED_CLK_MAC] = hw; + if (of_device_is_compatible(pdev->dev.of_node, "aspeed,ast2500-scu")) { + /* RMII 50MHz RCLK */ + hw = clk_hw_register_fixed_rate(dev, "mac12rclk", "hpll", 0, + 50000000); + if (IS_ERR(hw)) + return PTR_ERR(hw); + + /* RMII1 50MHz (RCLK) output enable */ + hw = clk_hw_register_gate(dev, "mac1rclk", "mac12rclk", 0, + scu_base + ASPEED_MAC_CLK_DLY, 29, 0, + &aspeed_clk_lock); + if (IS_ERR(hw)) + return PTR_ERR(hw); + aspeed_clk_data->hws[ASPEED_CLK_MAC1RCLK] = hw; + + /* RMII2 50MHz (RCLK) output enable */ + hw = clk_hw_register_gate(dev, "mac2rclk", "mac12rclk", 0, + scu_base + ASPEED_MAC_CLK_DLY, 30, 0, + &aspeed_clk_lock); + if (IS_ERR(hw)) + return PTR_ERR(hw); + aspeed_clk_data->hws[ASPEED_CLK_MAC2RCLK] = hw; + } + /* LPC Host (LHCLK) clock divider */ hw = clk_hw_register_divider_table(dev, "lhclk", "hpll", 0, scu_base + ASPEED_CLK_SELECTION, 20, 3, 0, |