diff options
author | Fabio Estevam <fabio.estevam@freescale.com> | 2012-01-27 09:44:29 -0500 |
---|---|---|
committer | Shawn Guo <shawn.guo@linaro.org> | 2012-01-31 09:42:15 -0500 |
commit | 444a7c3bb897ec6a64b83d277102440c1dcc22a1 (patch) | |
tree | f6168d81c13b5e7641ca815bd5703fdee3adc5f5 /arch/arm/mach-mxs | |
parent | a62407256bbcba8e3f62695a87534050ceec0e6f (diff) |
ARM: mxs: Use a proper timeout mechanism
Introduce a function for checking the busy bits of CLKCTRL register that
uses a proper timeout mechanism.
Remove parts of code that use busy loops and replace them with the
mxs_clkctrl_timeout() function.
Tested on a mx28evk by performing audio playback.
Suggested-by: Wolfram Sang <w.sang@pengutronix.de>
Signed-off-by: Fabio Estevam <fabio.estevam@freescale.com>
Signed-off-by: Shawn Guo <shawn.guo@linaro.org>
Diffstat (limited to 'arch/arm/mach-mxs')
-rw-r--r-- | arch/arm/mach-mxs/clock-mx23.c | 34 | ||||
-rw-r--r-- | arch/arm/mach-mxs/clock-mx28.c | 49 | ||||
-rw-r--r-- | arch/arm/mach-mxs/include/mach/common.h | 2 | ||||
-rw-r--r-- | arch/arm/mach-mxs/system.c | 16 |
4 files changed, 29 insertions, 72 deletions
diff --git a/arch/arm/mach-mxs/clock-mx23.c b/arch/arm/mach-mxs/clock-mx23.c index e12e11231dc7..293958beb505 100644 --- a/arch/arm/mach-mxs/clock-mx23.c +++ b/arch/arm/mach-mxs/clock-mx23.c | |||
@@ -223,7 +223,6 @@ static int cpu_clk_set_rate(struct clk *clk, unsigned long rate) | |||
223 | { | 223 | { |
224 | u32 reg, bm_busy, div_max, d, f, div, frac; | 224 | u32 reg, bm_busy, div_max, d, f, div, frac; |
225 | unsigned long diff, parent_rate, calc_rate; | 225 | unsigned long diff, parent_rate, calc_rate; |
226 | int i; | ||
227 | 226 | ||
228 | parent_rate = clk_get_rate(clk->parent); | 227 | parent_rate = clk_get_rate(clk->parent); |
229 | 228 | ||
@@ -275,14 +274,7 @@ static int cpu_clk_set_rate(struct clk *clk, unsigned long rate) | |||
275 | reg |= div << BP_CLKCTRL_CPU_DIV_CPU; | 274 | reg |= div << BP_CLKCTRL_CPU_DIV_CPU; |
276 | __raw_writel(reg, CLKCTRL_BASE_ADDR + HW_CLKCTRL_CPU); | 275 | __raw_writel(reg, CLKCTRL_BASE_ADDR + HW_CLKCTRL_CPU); |
277 | 276 | ||
278 | for (i = 10000; i; i--) | 277 | mxs_clkctrl_timeout(HW_CLKCTRL_CPU, bm_busy); |
279 | if (!(__raw_readl(CLKCTRL_BASE_ADDR + | ||
280 | HW_CLKCTRL_CPU) & bm_busy)) | ||
281 | break; | ||
282 | if (!i) { | ||
283 | pr_err("%s: divider writing timeout\n", __func__); | ||
284 | return -ETIMEDOUT; | ||
285 | } | ||
286 | 278 | ||
287 | return 0; | 279 | return 0; |
288 | } | 280 | } |
@@ -292,7 +284,6 @@ static int name##_set_rate(struct clk *clk, unsigned long rate) \ | |||
292 | { \ | 284 | { \ |
293 | u32 reg, div_max, div; \ | 285 | u32 reg, div_max, div; \ |
294 | unsigned long parent_rate; \ | 286 | unsigned long parent_rate; \ |
295 | int i; \ | ||
296 | \ | 287 | \ |
297 | parent_rate = clk_get_rate(clk->parent); \ | 288 | parent_rate = clk_get_rate(clk->parent); \ |
298 | div_max = BM_CLKCTRL_##dr##_DIV >> BP_CLKCTRL_##dr##_DIV; \ | 289 | div_max = BM_CLKCTRL_##dr##_DIV >> BP_CLKCTRL_##dr##_DIV; \ |
@@ -310,15 +301,7 @@ static int name##_set_rate(struct clk *clk, unsigned long rate) \ | |||
310 | } \ | 301 | } \ |
311 | __raw_writel(reg, CLKCTRL_BASE_ADDR + HW_CLKCTRL_##dr); \ | 302 | __raw_writel(reg, CLKCTRL_BASE_ADDR + HW_CLKCTRL_##dr); \ |
312 | \ | 303 | \ |
313 | for (i = 10000; i; i--) \ | 304 | mxs_clkctrl_timeout(HW_CLKCTRL_##dr, BM_CLKCTRL_##dr##_BUSY); \ |
314 | if (!(__raw_readl(CLKCTRL_BASE_ADDR + \ | ||
315 | HW_CLKCTRL_##dr) & BM_CLKCTRL_##dr##_BUSY)) \ | ||
316 | break; \ | ||
317 | if (!i) { \ | ||
318 | pr_err("%s: divider writing timeout\n", __func__); \ | ||
319 | return -ETIMEDOUT; \ | ||
320 | } \ | ||
321 | \ | ||
322 | return 0; \ | 305 | return 0; \ |
323 | } | 306 | } |
324 | 307 | ||
@@ -461,7 +444,7 @@ static struct clk_lookup lookups[] = { | |||
461 | static int clk_misc_init(void) | 444 | static int clk_misc_init(void) |
462 | { | 445 | { |
463 | u32 reg; | 446 | u32 reg; |
464 | int i; | 447 | int ret; |
465 | 448 | ||
466 | /* Fix up parent per register setting */ | 449 | /* Fix up parent per register setting */ |
467 | reg = __raw_readl(CLKCTRL_BASE_ADDR + HW_CLKCTRL_CLKSEQ); | 450 | reg = __raw_readl(CLKCTRL_BASE_ADDR + HW_CLKCTRL_CLKSEQ); |
@@ -510,14 +493,7 @@ static int clk_misc_init(void) | |||
510 | reg |= 3 << BP_CLKCTRL_HBUS_DIV; | 493 | reg |= 3 << BP_CLKCTRL_HBUS_DIV; |
511 | __raw_writel(reg, CLKCTRL_BASE_ADDR + HW_CLKCTRL_HBUS); | 494 | __raw_writel(reg, CLKCTRL_BASE_ADDR + HW_CLKCTRL_HBUS); |
512 | 495 | ||
513 | for (i = 10000; i; i--) | 496 | ret = mxs_clkctrl_timeout(HW_CLKCTRL_HBUS, BM_CLKCTRL_HBUS_BUSY); |
514 | if (!(__raw_readl(CLKCTRL_BASE_ADDR + | ||
515 | HW_CLKCTRL_HBUS) & BM_CLKCTRL_HBUS_BUSY)) | ||
516 | break; | ||
517 | if (!i) { | ||
518 | pr_err("%s: divider writing timeout\n", __func__); | ||
519 | return -ETIMEDOUT; | ||
520 | } | ||
521 | 497 | ||
522 | /* Gate off cpu clock in WFI for power saving */ | 498 | /* Gate off cpu clock in WFI for power saving */ |
523 | __raw_writel(BM_CLKCTRL_CPU_INTERRUPT_WAIT, | 499 | __raw_writel(BM_CLKCTRL_CPU_INTERRUPT_WAIT, |
@@ -532,7 +508,7 @@ static int clk_misc_init(void) | |||
532 | reg |= 30 << BP_CLKCTRL_FRAC_IOFRAC; | 508 | reg |= 30 << BP_CLKCTRL_FRAC_IOFRAC; |
533 | __raw_writel(reg, CLKCTRL_BASE_ADDR + HW_CLKCTRL_FRAC); | 509 | __raw_writel(reg, CLKCTRL_BASE_ADDR + HW_CLKCTRL_FRAC); |
534 | 510 | ||
535 | return 0; | 511 | return ret; |
536 | } | 512 | } |
537 | 513 | ||
538 | int __init mx23_clocks_init(void) | 514 | int __init mx23_clocks_init(void) |
diff --git a/arch/arm/mach-mxs/clock-mx28.c b/arch/arm/mach-mxs/clock-mx28.c index 54d82a4b4cf0..22ad12f6e4de 100644 --- a/arch/arm/mach-mxs/clock-mx28.c +++ b/arch/arm/mach-mxs/clock-mx28.c | |||
@@ -322,7 +322,6 @@ static int name##_set_rate(struct clk *clk, unsigned long rate) \ | |||
322 | { \ | 322 | { \ |
323 | u32 reg, bm_busy, div_max, d, f, div, frac; \ | 323 | u32 reg, bm_busy, div_max, d, f, div, frac; \ |
324 | unsigned long diff, parent_rate, calc_rate; \ | 324 | unsigned long diff, parent_rate, calc_rate; \ |
325 | int i; \ | ||
326 | \ | 325 | \ |
327 | div_max = BM_CLKCTRL_##dr##_DIV >> BP_CLKCTRL_##dr##_DIV; \ | 326 | div_max = BM_CLKCTRL_##dr##_DIV >> BP_CLKCTRL_##dr##_DIV; \ |
328 | bm_busy = BM_CLKCTRL_##dr##_BUSY; \ | 327 | bm_busy = BM_CLKCTRL_##dr##_BUSY; \ |
@@ -396,16 +395,7 @@ static int name##_set_rate(struct clk *clk, unsigned long rate) \ | |||
396 | } \ | 395 | } \ |
397 | __raw_writel(reg, CLKCTRL_BASE_ADDR + HW_CLKCTRL_##dr); \ | 396 | __raw_writel(reg, CLKCTRL_BASE_ADDR + HW_CLKCTRL_##dr); \ |
398 | \ | 397 | \ |
399 | for (i = 10000; i; i--) \ | 398 | return mxs_clkctrl_timeout(HW_CLKCTRL_##dr, bm_busy); \ |
400 | if (!(__raw_readl(CLKCTRL_BASE_ADDR + \ | ||
401 | HW_CLKCTRL_##dr) & bm_busy)) \ | ||
402 | break; \ | ||
403 | if (!i) { \ | ||
404 | pr_err("%s: divider writing timeout\n", __func__); \ | ||
405 | return -ETIMEDOUT; \ | ||
406 | } \ | ||
407 | \ | ||
408 | return 0; \ | ||
409 | } | 399 | } |
410 | 400 | ||
411 | _CLK_SET_RATE(cpu_clk, CPU, FRAC0, CPU) | 401 | _CLK_SET_RATE(cpu_clk, CPU, FRAC0, CPU) |
@@ -421,7 +411,6 @@ static int name##_set_rate(struct clk *clk, unsigned long rate) \ | |||
421 | { \ | 411 | { \ |
422 | u32 reg, div_max, div; \ | 412 | u32 reg, div_max, div; \ |
423 | unsigned long parent_rate; \ | 413 | unsigned long parent_rate; \ |
424 | int i; \ | ||
425 | \ | 414 | \ |
426 | parent_rate = clk_get_rate(clk->parent); \ | 415 | parent_rate = clk_get_rate(clk->parent); \ |
427 | div_max = BM_CLKCTRL_##dr##_DIV >> BP_CLKCTRL_##dr##_DIV; \ | 416 | div_max = BM_CLKCTRL_##dr##_DIV >> BP_CLKCTRL_##dr##_DIV; \ |
@@ -439,16 +428,7 @@ static int name##_set_rate(struct clk *clk, unsigned long rate) \ | |||
439 | } \ | 428 | } \ |
440 | __raw_writel(reg, CLKCTRL_BASE_ADDR + HW_CLKCTRL_##dr); \ | 429 | __raw_writel(reg, CLKCTRL_BASE_ADDR + HW_CLKCTRL_##dr); \ |
441 | \ | 430 | \ |
442 | for (i = 10000; i; i--) \ | 431 | return mxs_clkctrl_timeout(HW_CLKCTRL_##dr, BM_CLKCTRL_##dr##_BUSY);\ |
443 | if (!(__raw_readl(CLKCTRL_BASE_ADDR + \ | ||
444 | HW_CLKCTRL_##dr) & BM_CLKCTRL_##dr##_BUSY)) \ | ||
445 | break; \ | ||
446 | if (!i) { \ | ||
447 | pr_err("%s: divider writing timeout\n", __func__); \ | ||
448 | return -ETIMEDOUT; \ | ||
449 | } \ | ||
450 | \ | ||
451 | return 0; \ | ||
452 | } | 432 | } |
453 | 433 | ||
454 | _CLK_SET_RATE1(xbus_clk, XBUS) | 434 | _CLK_SET_RATE1(xbus_clk, XBUS) |
@@ -461,7 +441,6 @@ static int name##_set_rate(struct clk *clk, unsigned long rate) \ | |||
461 | u32 reg; \ | 441 | u32 reg; \ |
462 | u64 lrate; \ | 442 | u64 lrate; \ |
463 | unsigned long parent_rate; \ | 443 | unsigned long parent_rate; \ |
464 | int i; \ | ||
465 | \ | 444 | \ |
466 | parent_rate = clk_get_rate(clk->parent); \ | 445 | parent_rate = clk_get_rate(clk->parent); \ |
467 | if (rate > parent_rate) \ | 446 | if (rate > parent_rate) \ |
@@ -483,16 +462,7 @@ static int name##_set_rate(struct clk *clk, unsigned long rate) \ | |||
483 | } \ | 462 | } \ |
484 | __raw_writel(reg, CLKCTRL_BASE_ADDR + HW_CLKCTRL_##rs); \ | 463 | __raw_writel(reg, CLKCTRL_BASE_ADDR + HW_CLKCTRL_##rs); \ |
485 | \ | 464 | \ |
486 | for (i = 10000; i; i--) \ | 465 | return mxs_clkctrl_timeout(HW_CLKCTRL_##rs, BM_CLKCTRL_##rs##_BUSY);\ |
487 | if (!(__raw_readl(CLKCTRL_BASE_ADDR + \ | ||
488 | HW_CLKCTRL_##rs) & BM_CLKCTRL_##rs##_BUSY)) \ | ||
489 | break; \ | ||
490 | if (!i) { \ | ||
491 | pr_err("%s: divider writing timeout\n", __func__); \ | ||
492 | return -ETIMEDOUT; \ | ||
493 | } \ | ||
494 | \ | ||
495 | return 0; \ | ||
496 | } | 466 | } |
497 | 467 | ||
498 | _CLK_SET_RATE_SAIF(saif0_clk, SAIF0) | 468 | _CLK_SET_RATE_SAIF(saif0_clk, SAIF0) |
@@ -682,7 +652,7 @@ static struct clk_lookup lookups[] = { | |||
682 | static int clk_misc_init(void) | 652 | static int clk_misc_init(void) |
683 | { | 653 | { |
684 | u32 reg; | 654 | u32 reg; |
685 | int i; | 655 | int ret; |
686 | 656 | ||
687 | /* Fix up parent per register setting */ | 657 | /* Fix up parent per register setting */ |
688 | reg = __raw_readl(CLKCTRL_BASE_ADDR + HW_CLKCTRL_CLKSEQ); | 658 | reg = __raw_readl(CLKCTRL_BASE_ADDR + HW_CLKCTRL_CLKSEQ); |
@@ -762,14 +732,7 @@ static int clk_misc_init(void) | |||
762 | reg |= 3 << BP_CLKCTRL_HBUS_DIV; | 732 | reg |= 3 << BP_CLKCTRL_HBUS_DIV; |
763 | __raw_writel(reg, CLKCTRL_BASE_ADDR + HW_CLKCTRL_HBUS); | 733 | __raw_writel(reg, CLKCTRL_BASE_ADDR + HW_CLKCTRL_HBUS); |
764 | 734 | ||
765 | for (i = 10000; i; i--) | 735 | ret = mxs_clkctrl_timeout(HW_CLKCTRL_HBUS, BM_CLKCTRL_HBUS_ASM_BUSY); |
766 | if (!(__raw_readl(CLKCTRL_BASE_ADDR + | ||
767 | HW_CLKCTRL_HBUS) & BM_CLKCTRL_HBUS_ASM_BUSY)) | ||
768 | break; | ||
769 | if (!i) { | ||
770 | pr_err("%s: divider writing timeout\n", __func__); | ||
771 | return -ETIMEDOUT; | ||
772 | } | ||
773 | 736 | ||
774 | /* Gate off cpu clock in WFI for power saving */ | 737 | /* Gate off cpu clock in WFI for power saving */ |
775 | __raw_writel(BM_CLKCTRL_CPU_INTERRUPT_WAIT, | 738 | __raw_writel(BM_CLKCTRL_CPU_INTERRUPT_WAIT, |
@@ -796,7 +759,7 @@ static int clk_misc_init(void) | |||
796 | reg |= 30 << BP_CLKCTRL_FRAC0_IO0FRAC; | 759 | reg |= 30 << BP_CLKCTRL_FRAC0_IO0FRAC; |
797 | __raw_writel(reg, CLKCTRL_BASE_ADDR + HW_CLKCTRL_FRAC0); | 760 | __raw_writel(reg, CLKCTRL_BASE_ADDR + HW_CLKCTRL_FRAC0); |
798 | 761 | ||
799 | return 0; | 762 | return ret; |
800 | } | 763 | } |
801 | 764 | ||
802 | int __init mx28_clocks_init(void) | 765 | int __init mx28_clocks_init(void) |
diff --git a/arch/arm/mach-mxs/include/mach/common.h b/arch/arm/mach-mxs/include/mach/common.h index e1237ab25862..c50c3ea28a9d 100644 --- a/arch/arm/mach-mxs/include/mach/common.h +++ b/arch/arm/mach-mxs/include/mach/common.h | |||
@@ -31,4 +31,6 @@ extern void mx28_init_irq(void); | |||
31 | 31 | ||
32 | extern void icoll_init_irq(void); | 32 | extern void icoll_init_irq(void); |
33 | 33 | ||
34 | extern int mxs_clkctrl_timeout(unsigned int reg_offset, unsigned int mask); | ||
35 | |||
34 | #endif /* __MACH_MXS_COMMON_H__ */ | 36 | #endif /* __MACH_MXS_COMMON_H__ */ |
diff --git a/arch/arm/mach-mxs/system.c b/arch/arm/mach-mxs/system.c index 54f91ad1c965..7aa5ac5d78bf 100644 --- a/arch/arm/mach-mxs/system.c +++ b/arch/arm/mach-mxs/system.c | |||
@@ -37,6 +37,8 @@ | |||
37 | #define MXS_MODULE_CLKGATE (1 << 30) | 37 | #define MXS_MODULE_CLKGATE (1 << 30) |
38 | #define MXS_MODULE_SFTRST (1 << 31) | 38 | #define MXS_MODULE_SFTRST (1 << 31) |
39 | 39 | ||
40 | #define CLKCTRL_TIMEOUT 10 /* 10 ms */ | ||
41 | |||
40 | static void __iomem *mxs_clkctrl_reset_addr; | 42 | static void __iomem *mxs_clkctrl_reset_addr; |
41 | 43 | ||
42 | /* | 44 | /* |
@@ -137,3 +139,17 @@ error: | |||
137 | return -ETIMEDOUT; | 139 | return -ETIMEDOUT; |
138 | } | 140 | } |
139 | EXPORT_SYMBOL(mxs_reset_block); | 141 | EXPORT_SYMBOL(mxs_reset_block); |
142 | |||
143 | int mxs_clkctrl_timeout(unsigned int reg_offset, unsigned int mask) | ||
144 | { | ||
145 | unsigned long timeout = jiffies + msecs_to_jiffies(CLKCTRL_TIMEOUT); | ||
146 | while (readl_relaxed(MXS_IO_ADDRESS(MXS_CLKCTRL_BASE_ADDR) | ||
147 | + reg_offset) & mask) { | ||
148 | if (time_after(jiffies, timeout)) { | ||
149 | pr_err("Timeout at CLKCTRL + 0x%x\n", reg_offset); | ||
150 | return -ETIMEDOUT; | ||
151 | } | ||
152 | } | ||
153 | |||
154 | return 0; | ||
155 | } | ||