Commit 8a53fc51 authored by Eddie James's avatar Eddie James Committed by Stephen Boyd

clk: aspeed: Prevent reset if clock is enabled

According to the Aspeed specification, the reset and enable sequence
should be done when the clock is stopped. The specification doesn't
define behavior if the reset is done while the clock is enabled.

From testing on the AST2500, the LPC Controller has problems if the
clock is reset while enabled.

Therefore, check whether the clock is enabled or not before performing
the reset and enable sequence in the Aspeed clock driver.
Reported-by: default avatarLei Yu <mine260309@gmail.com>
Signed-off-by: default avatarEddie James <eajames@linux.vnet.ibm.com>
Fixes: 15ed8ce5 ("clk: aspeed: Register gated clocks")
Reviewed-by: default avatarJoel Stanley <joel@jms.id.au>
Signed-off-by: default avatarStephen Boyd <sboyd@kernel.org>
parent d90c76bb
...@@ -205,6 +205,18 @@ static const struct aspeed_clk_soc_data ast2400_data = { ...@@ -205,6 +205,18 @@ static const struct aspeed_clk_soc_data ast2400_data = {
.calc_pll = aspeed_ast2400_calc_pll, .calc_pll = aspeed_ast2400_calc_pll,
}; };
static int aspeed_clk_is_enabled(struct clk_hw *hw)
{
struct aspeed_clk_gate *gate = to_aspeed_clk_gate(hw);
u32 clk = BIT(gate->clock_idx);
u32 enval = (gate->flags & CLK_GATE_SET_TO_DISABLE) ? 0 : clk;
u32 reg;
regmap_read(gate->map, ASPEED_CLK_STOP_CTRL, &reg);
return ((reg & clk) == enval) ? 1 : 0;
}
static int aspeed_clk_enable(struct clk_hw *hw) static int aspeed_clk_enable(struct clk_hw *hw)
{ {
struct aspeed_clk_gate *gate = to_aspeed_clk_gate(hw); struct aspeed_clk_gate *gate = to_aspeed_clk_gate(hw);
...@@ -215,6 +227,11 @@ static int aspeed_clk_enable(struct clk_hw *hw) ...@@ -215,6 +227,11 @@ static int aspeed_clk_enable(struct clk_hw *hw)
spin_lock_irqsave(gate->lock, flags); spin_lock_irqsave(gate->lock, flags);
if (aspeed_clk_is_enabled(hw)) {
spin_unlock_irqrestore(gate->lock, flags);
return 0;
}
if (gate->reset_idx >= 0) { if (gate->reset_idx >= 0) {
/* Put IP in reset */ /* Put IP in reset */
regmap_update_bits(gate->map, ASPEED_RESET_CTRL, rst, rst); regmap_update_bits(gate->map, ASPEED_RESET_CTRL, rst, rst);
...@@ -255,18 +272,6 @@ static void aspeed_clk_disable(struct clk_hw *hw) ...@@ -255,18 +272,6 @@ static void aspeed_clk_disable(struct clk_hw *hw)
spin_unlock_irqrestore(gate->lock, flags); spin_unlock_irqrestore(gate->lock, flags);
} }
static int aspeed_clk_is_enabled(struct clk_hw *hw)
{
struct aspeed_clk_gate *gate = to_aspeed_clk_gate(hw);
u32 clk = BIT(gate->clock_idx);
u32 enval = (gate->flags & CLK_GATE_SET_TO_DISABLE) ? 0 : clk;
u32 reg;
regmap_read(gate->map, ASPEED_CLK_STOP_CTRL, &reg);
return ((reg & clk) == enval) ? 1 : 0;
}
static const struct clk_ops aspeed_clk_gate_ops = { static const struct clk_ops aspeed_clk_gate_ops = {
.enable = aspeed_clk_enable, .enable = aspeed_clk_enable,
.disable = aspeed_clk_disable, .disable = aspeed_clk_disable,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment