Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

clocksource/drivers/fttmr010: Fix invalid interrupt register access

TIMER_INTR_MASK register (Base Address of Timer + 0x38) is not designed
for masking interrupts on ast2500 chips, and it's not even listed in
ast2400 datasheet, so it's not safe to access TIMER_INTR_MASK on aspeed
chips.

Similarly, TIMER_INTR_STATE register (Base Address of Timer + 0x34) is
not interrupt status register on ast2400 and ast2500 chips. Although
there is no side effect to reset the register in fttmr010_common_init(),
it's just misleading to do so.

Besides, "count_down" is renamed to "is_aspeed" in "fttmr010" structure,
and more comments are added so the code is more readble.

Signed-off-by: Tao Ren <taoren@fb.com>
Reviewed-by: Linus Walleij <linus.walleij@linaro.org>
Signed-off-by: Daniel Lezcano <daniel.lezcano@linaro.org>

authored by

Tao Ren and committed by
Daniel Lezcano
86fe57fc 5eb73c83

+42 -31
+42 -31
drivers/clocksource/timer-fttmr010.c
··· 21 21 #include <linux/delay.h> 22 22 23 23 /* 24 - * Register definitions for the timers 24 + * Register definitions common for all the timer variants. 25 25 */ 26 26 #define TIMER1_COUNT (0x00) 27 27 #define TIMER1_LOAD (0x04) ··· 36 36 #define TIMER3_MATCH1 (0x28) 37 37 #define TIMER3_MATCH2 (0x2c) 38 38 #define TIMER_CR (0x30) 39 - #define TIMER_INTR_STATE (0x34) 40 - #define TIMER_INTR_MASK (0x38) 41 39 40 + /* 41 + * Control register (TMC30) bit fields for fttmr010/gemini/moxart timers. 42 + */ 42 43 #define TIMER_1_CR_ENABLE BIT(0) 43 44 #define TIMER_1_CR_CLOCK BIT(1) 44 45 #define TIMER_1_CR_INT BIT(2) ··· 54 53 #define TIMER_3_CR_UPDOWN BIT(11) 55 54 56 55 /* 57 - * The Aspeed AST2400 moves bits around in the control register 58 - * and lacks bits for setting the timer to count upwards. 56 + * Control register (TMC30) bit fields for aspeed ast2400/ast2500 timers. 57 + * The aspeed timers move bits around in the control register and lacks 58 + * bits for setting the timer to count upwards. 59 59 */ 60 60 #define TIMER_1_CR_ASPEED_ENABLE BIT(0) 61 61 #define TIMER_1_CR_ASPEED_CLOCK BIT(1) ··· 68 66 #define TIMER_3_CR_ASPEED_CLOCK BIT(9) 69 67 #define TIMER_3_CR_ASPEED_INT BIT(10) 70 68 69 + /* 70 + * Interrupt status/mask register definitions for fttmr010/gemini/moxart 71 + * timers. 72 + * The registers don't exist and they are not needed on aspeed timers 73 + * because: 74 + * - aspeed timer overflow interrupt is controlled by bits in Control 75 + * Register (TMC30). 76 + * - aspeed timers always generate interrupt when either one of the 77 + * Match registers equals to Status register. 78 + */ 79 + #define TIMER_INTR_STATE (0x34) 80 + #define TIMER_INTR_MASK (0x38) 71 81 #define TIMER_1_INT_MATCH1 BIT(0) 72 82 #define TIMER_1_INT_MATCH2 BIT(1) 73 83 #define TIMER_1_INT_OVERFLOW BIT(2) ··· 94 80 struct fttmr010 { 95 81 void __iomem *base; 96 82 unsigned int tick_rate; 97 - bool count_down; 83 + bool is_aspeed; 98 84 u32 t1_enable_val; 99 85 struct clock_event_device clkevt; 100 86 #ifdef CONFIG_ARM ··· 144 130 cr &= ~fttmr010->t1_enable_val; 145 131 writel(cr, fttmr010->base + TIMER_CR); 146 132 147 - if (fttmr010->count_down) { 133 + if (fttmr010->is_aspeed) { 148 134 /* 149 135 * ASPEED Timer Controller will load TIMER1_LOAD register 150 136 * into TIMER1_COUNT register when the timer is re-enabled. ··· 189 175 190 176 /* Setup counter start from 0 or ~0 */ 191 177 writel(0, fttmr010->base + TIMER1_COUNT); 192 - if (fttmr010->count_down) 178 + if (fttmr010->is_aspeed) { 193 179 writel(~0, fttmr010->base + TIMER1_LOAD); 194 - else 180 + } else { 195 181 writel(0, fttmr010->base + TIMER1_LOAD); 196 182 197 - /* Enable interrupt */ 198 - cr = readl(fttmr010->base + TIMER_INTR_MASK); 199 - cr &= ~(TIMER_1_INT_OVERFLOW | TIMER_1_INT_MATCH2); 200 - cr |= TIMER_1_INT_MATCH1; 201 - writel(cr, fttmr010->base + TIMER_INTR_MASK); 183 + /* Enable interrupt */ 184 + cr = readl(fttmr010->base + TIMER_INTR_MASK); 185 + cr &= ~(TIMER_1_INT_OVERFLOW | TIMER_1_INT_MATCH2); 186 + cr |= TIMER_1_INT_MATCH1; 187 + writel(cr, fttmr010->base + TIMER_INTR_MASK); 188 + } 202 189 203 190 return 0; 204 191 } ··· 216 201 writel(cr, fttmr010->base + TIMER_CR); 217 202 218 203 /* Setup timer to fire at 1/HZ intervals. */ 219 - if (fttmr010->count_down) { 204 + if (fttmr010->is_aspeed) { 220 205 writel(period, fttmr010->base + TIMER1_LOAD); 221 - writel(0, fttmr010->base + TIMER1_MATCH1); 222 206 } else { 223 207 cr = 0xffffffff - (period - 1); 224 208 writel(cr, fttmr010->base + TIMER1_COUNT); ··· 295 281 } 296 282 297 283 /* 298 - * The Aspeed AST2400 moves bits around in the control register, 299 - * otherwise it works the same. 284 + * The Aspeed timers move bits around in the control register. 300 285 */ 301 286 if (is_aspeed) { 302 287 fttmr010->t1_enable_val = TIMER_1_CR_ASPEED_ENABLE | 303 288 TIMER_1_CR_ASPEED_INT; 304 - /* Downward not available */ 305 - fttmr010->count_down = true; 289 + fttmr010->is_aspeed = true; 306 290 } else { 307 291 fttmr010->t1_enable_val = TIMER_1_CR_ENABLE | TIMER_1_CR_INT; 308 - } 309 292 310 - /* 311 - * Reset the interrupt mask and status 312 - */ 313 - writel(TIMER_INT_ALL_MASK, fttmr010->base + TIMER_INTR_MASK); 314 - writel(0, fttmr010->base + TIMER_INTR_STATE); 293 + /* 294 + * Reset the interrupt mask and status 295 + */ 296 + writel(TIMER_INT_ALL_MASK, fttmr010->base + TIMER_INTR_MASK); 297 + writel(0, fttmr010->base + TIMER_INTR_STATE); 298 + } 315 299 316 300 /* 317 301 * Enable timer 1 count up, timer 2 count up, except on Aspeed, ··· 318 306 if (is_aspeed) 319 307 val = TIMER_2_CR_ASPEED_ENABLE; 320 308 else { 321 - val = TIMER_2_CR_ENABLE; 322 - if (!fttmr010->count_down) 323 - val |= TIMER_1_CR_UPDOWN | TIMER_2_CR_UPDOWN; 309 + val = TIMER_2_CR_ENABLE | TIMER_1_CR_UPDOWN | 310 + TIMER_2_CR_UPDOWN; 324 311 } 325 312 writel(val, fttmr010->base + TIMER_CR); 326 313 ··· 332 321 writel(0, fttmr010->base + TIMER2_MATCH1); 333 322 writel(0, fttmr010->base + TIMER2_MATCH2); 334 323 335 - if (fttmr010->count_down) { 324 + if (fttmr010->is_aspeed) { 336 325 writel(~0, fttmr010->base + TIMER2_LOAD); 337 326 clocksource_mmio_init(fttmr010->base + TIMER2_COUNT, 338 327 "FTTMR010-TIMER2", ··· 382 371 383 372 #ifdef CONFIG_ARM 384 373 /* Also use this timer for delays */ 385 - if (fttmr010->count_down) 374 + if (fttmr010->is_aspeed) 386 375 fttmr010->delay_timer.read_current_timer = 387 376 fttmr010_read_current_timer_down; 388 377 else