Skip to content

Commit 6726d55

Browse files
Aidan MacDonaldbebarino
authored andcommitted
clk: ingenic-tcu: Properly enable registers before accessing timers
Access to registers is guarded by ingenic_tcu_{enable,disable}_regs() so the stop bit can be cleared before accessing a timer channel, but those functions did not clear the stop bit on SoCs with a global TCU clock gate. Testing on the X1000 has revealed that the stop bits must be cleared _and_ the global TCU clock must be ungated to access timer registers. This appears to be the norm on Ingenic SoCs, and is specified in the documentation for the X1000 and numerous JZ47xx SoCs. If the stop bit isn't cleared, register writes don't take effect and the system can be left in a broken state, eg. the watchdog timer may not run. The bug probably went unnoticed because stop bits are zeroed when the SoC is reset, and the kernel does not set them unless a timer gets disabled at runtime. However, it is possible that a bootloader or a previous kernel (if using kexec) leaves the stop bits set and we should not rely on them being cleared. Fixing this is easy: have ingenic_tcu_{enable,disable}_regs() always clear the stop bit, regardless of the presence of a global TCU gate. Reviewed-by: Paul Cercueil <[email protected]> Tested-by: Paul Cercueil <[email protected]> Fixes: 4f89e4b ("clk: ingenic: Add driver for the TCU clocks") Cc: [email protected] Signed-off-by: Aidan MacDonald <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Stephen Boyd <[email protected]>
1 parent abb5f3f commit 6726d55

File tree

1 file changed

+5
-10
lines changed

1 file changed

+5
-10
lines changed

drivers/clk/ingenic/tcu.c

Lines changed: 5 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -101,15 +101,11 @@ static bool ingenic_tcu_enable_regs(struct clk_hw *hw)
101101
bool enabled = false;
102102

103103
/*
104-
* If the SoC has no global TCU clock, we must ungate the channel's
105-
* clock to be able to access its registers.
106-
* If we have a TCU clock, it will be enabled automatically as it has
107-
* been attached to the regmap.
104+
* According to the programming manual, a timer channel's registers can
105+
* only be accessed when the channel's stop bit is clear.
108106
*/
109-
if (!tcu->clk) {
110-
enabled = !!ingenic_tcu_is_enabled(hw);
111-
regmap_write(tcu->map, TCU_REG_TSCR, BIT(info->gate_bit));
112-
}
107+
enabled = !!ingenic_tcu_is_enabled(hw);
108+
regmap_write(tcu->map, TCU_REG_TSCR, BIT(info->gate_bit));
113109

114110
return enabled;
115111
}
@@ -120,8 +116,7 @@ static void ingenic_tcu_disable_regs(struct clk_hw *hw)
120116
const struct ingenic_tcu_clk_info *info = tcu_clk->info;
121117
struct ingenic_tcu *tcu = tcu_clk->tcu;
122118

123-
if (!tcu->clk)
124-
regmap_write(tcu->map, TCU_REG_TSSR, BIT(info->gate_bit));
119+
regmap_write(tcu->map, TCU_REG_TSSR, BIT(info->gate_bit));
125120
}
126121

127122
static u8 ingenic_tcu_get_parent(struct clk_hw *hw)

0 commit comments

Comments
 (0)