diff options
Diffstat (limited to 'arch/arm/mach-ux500/clock.c')
| -rw-r--r-- | arch/arm/mach-ux500/clock.c | 104 |
1 files changed, 98 insertions, 6 deletions
diff --git a/arch/arm/mach-ux500/clock.c b/arch/arm/mach-ux500/clock.c index 6544855af2f1..fe84b9021c7a 100644 --- a/arch/arm/mach-ux500/clock.c +++ b/arch/arm/mach-ux500/clock.c | |||
| @@ -16,6 +16,7 @@ | |||
| 16 | 16 | ||
| 17 | #include <asm/clkdev.h> | 17 | #include <asm/clkdev.h> |
| 18 | 18 | ||
| 19 | #include <plat/mtu.h> | ||
| 19 | #include <mach/hardware.h> | 20 | #include <mach/hardware.h> |
| 20 | #include "clock.h" | 21 | #include "clock.h" |
| 21 | 22 | ||
| @@ -59,6 +60,9 @@ | |||
| 59 | #define PRCM_DMACLK_MGT 0x074 | 60 | #define PRCM_DMACLK_MGT 0x074 |
| 60 | #define PRCM_B2R2CLK_MGT 0x078 | 61 | #define PRCM_B2R2CLK_MGT 0x078 |
| 61 | #define PRCM_TVCLK_MGT 0x07C | 62 | #define PRCM_TVCLK_MGT 0x07C |
| 63 | #define PRCM_TCR 0x1C8 | ||
| 64 | #define PRCM_TCR_STOPPED (1 << 16) | ||
| 65 | #define PRCM_TCR_DOZE_MODE (1 << 17) | ||
| 62 | #define PRCM_UNIPROCLK_MGT 0x278 | 66 | #define PRCM_UNIPROCLK_MGT 0x278 |
| 63 | #define PRCM_SSPCLK_MGT 0x280 | 67 | #define PRCM_SSPCLK_MGT 0x280 |
| 64 | #define PRCM_RNGCLK_MGT 0x284 | 68 | #define PRCM_RNGCLK_MGT 0x284 |
| @@ -120,10 +124,95 @@ void clk_disable(struct clk *clk) | |||
| 120 | } | 124 | } |
| 121 | EXPORT_SYMBOL(clk_disable); | 125 | EXPORT_SYMBOL(clk_disable); |
| 122 | 126 | ||
| 127 | /* | ||
| 128 | * The MTU has a separate, rather complex muxing setup | ||
| 129 | * with alternative parents (peripheral cluster or | ||
| 130 | * ULP or fixed 32768 Hz) depending on settings | ||
| 131 | */ | ||
| 132 | static unsigned long clk_mtu_get_rate(struct clk *clk) | ||
| 133 | { | ||
| 134 | void __iomem *addr = __io_address(U8500_PRCMU_BASE) | ||
| 135 | + PRCM_TCR; | ||
| 136 | u32 tcr = readl(addr); | ||
| 137 | int mtu = (int) clk->data; | ||
| 138 | /* | ||
| 139 | * One of these is selected eventually | ||
| 140 | * TODO: Replace the constant with a reference | ||
| 141 | * to the ULP source once this is modeled. | ||
| 142 | */ | ||
| 143 | unsigned long clk32k = 32768; | ||
| 144 | unsigned long mturate; | ||
| 145 | unsigned long retclk; | ||
| 146 | |||
| 147 | /* Get the rate from the parent as a default */ | ||
| 148 | if (clk->parent_periph) | ||
| 149 | mturate = clk_get_rate(clk->parent_periph); | ||
| 150 | else if (clk->parent_cluster) | ||
| 151 | mturate = clk_get_rate(clk->parent_cluster); | ||
| 152 | else | ||
| 153 | /* We need to be connected SOMEWHERE */ | ||
| 154 | BUG(); | ||
| 155 | |||
| 156 | /* | ||
| 157 | * Are we in doze mode? | ||
| 158 | * In this mode the parent peripheral or the fixed 32768 Hz | ||
| 159 | * clock is fed into the block. | ||
| 160 | */ | ||
| 161 | if (!(tcr & PRCM_TCR_DOZE_MODE)) { | ||
| 162 | /* | ||
| 163 | * Here we're using the clock input from the APE ULP | ||
| 164 | * clock domain. But first: are the timers stopped? | ||
| 165 | */ | ||
| 166 | if (tcr & PRCM_TCR_STOPPED) { | ||
| 167 | clk32k = 0; | ||
| 168 | mturate = 0; | ||
| 169 | } else { | ||
| 170 | /* Else default mode: 0 and 2.4 MHz */ | ||
| 171 | clk32k = 0; | ||
| 172 | if (cpu_is_u5500()) | ||
| 173 | /* DB5500 divides by 8 */ | ||
| 174 | mturate /= 8; | ||
| 175 | else if (cpu_is_u8500ed()) { | ||
| 176 | /* | ||
| 177 | * This clocking setting must not be used | ||
| 178 | * in the ED chip, it is simply not | ||
| 179 | * connected anywhere! | ||
| 180 | */ | ||
| 181 | mturate = 0; | ||
| 182 | BUG(); | ||
| 183 | } else | ||
| 184 | /* | ||
| 185 | * In this mode the ulp38m4 clock is divided | ||
| 186 | * by a factor 16, on the DB8500 typically | ||
| 187 | * 38400000 / 16 ~ 2.4 MHz. | ||
| 188 | * TODO: Replace the constant with a reference | ||
| 189 | * to the ULP source once this is modeled. | ||
| 190 | */ | ||
| 191 | mturate = 38400000 / 16; | ||
| 192 | } | ||
| 193 | } | ||
| 194 | |||
| 195 | /* Return the clock selected for this MTU */ | ||
| 196 | if (tcr & (1 << mtu)) | ||
| 197 | retclk = clk32k; | ||
| 198 | else | ||
| 199 | retclk = mturate; | ||
| 200 | |||
| 201 | pr_info("MTU%d clock rate: %lu Hz\n", mtu, retclk); | ||
| 202 | return retclk; | ||
| 203 | } | ||
| 204 | |||
| 123 | unsigned long clk_get_rate(struct clk *clk) | 205 | unsigned long clk_get_rate(struct clk *clk) |
| 124 | { | 206 | { |
| 125 | unsigned long rate; | 207 | unsigned long rate; |
| 126 | 208 | ||
| 209 | /* | ||
| 210 | * If there is a custom getrate callback for this clock, | ||
| 211 | * it will take precedence. | ||
| 212 | */ | ||
| 213 | if (clk->get_rate) | ||
| 214 | return clk->get_rate(clk); | ||
| 215 | |||
| 127 | if (clk->ops && clk->ops->get_rate) | 216 | if (clk->ops && clk->ops->get_rate) |
| 128 | return clk->ops->get_rate(clk); | 217 | return clk->ops->get_rate(clk); |
| 129 | 218 | ||
| @@ -341,8 +430,9 @@ static DEFINE_PRCC_CLK(5, usb_v1, 0, 0, NULL); | |||
| 341 | 430 | ||
| 342 | /* Peripheral Cluster #6 */ | 431 | /* Peripheral Cluster #6 */ |
| 343 | 432 | ||
| 344 | static DEFINE_PRCC_CLK(6, mtu1_v1, 8, -1, NULL); | 433 | /* MTU ID in data */ |
| 345 | static DEFINE_PRCC_CLK(6, mtu0_v1, 7, -1, NULL); | 434 | static DEFINE_PRCC_CLK_CUSTOM(6, mtu1_v1, 8, -1, NULL, clk_mtu_get_rate, 1); |
| 435 | static DEFINE_PRCC_CLK_CUSTOM(6, mtu0_v1, 7, -1, NULL, clk_mtu_get_rate, 0); | ||
| 346 | static DEFINE_PRCC_CLK(6, cfgreg_v1, 6, 6, NULL); | 436 | static DEFINE_PRCC_CLK(6, cfgreg_v1, 6, 6, NULL); |
| 347 | static DEFINE_PRCC_CLK(6, dmc_ed, 6, 6, NULL); | 437 | static DEFINE_PRCC_CLK(6, dmc_ed, 6, 6, NULL); |
| 348 | static DEFINE_PRCC_CLK(6, hash1, 5, -1, NULL); | 438 | static DEFINE_PRCC_CLK(6, hash1, 5, -1, NULL); |
| @@ -357,8 +447,9 @@ static DEFINE_PRCC_CLK(6, rng_v1, 0, 0, &clk_rngclk); | |||
| 357 | /* Peripheral Cluster #7 */ | 447 | /* Peripheral Cluster #7 */ |
| 358 | 448 | ||
| 359 | static DEFINE_PRCC_CLK(7, tzpc0_ed, 4, -1, NULL); | 449 | static DEFINE_PRCC_CLK(7, tzpc0_ed, 4, -1, NULL); |
| 360 | static DEFINE_PRCC_CLK(7, mtu1_ed, 3, -1, NULL); | 450 | /* MTU ID in data */ |
| 361 | static DEFINE_PRCC_CLK(7, mtu0_ed, 2, -1, NULL); | 451 | static DEFINE_PRCC_CLK_CUSTOM(7, mtu1_ed, 3, -1, NULL, clk_mtu_get_rate, 1); |
| 452 | static DEFINE_PRCC_CLK_CUSTOM(7, mtu0_ed, 2, -1, NULL, clk_mtu_get_rate, 0); | ||
| 362 | static DEFINE_PRCC_CLK(7, wdg_ed, 1, -1, NULL); | 453 | static DEFINE_PRCC_CLK(7, wdg_ed, 1, -1, NULL); |
| 363 | static DEFINE_PRCC_CLK(7, cfgreg_ed, 0, -1, NULL); | 454 | static DEFINE_PRCC_CLK(7, cfgreg_ed, 0, -1, NULL); |
| 364 | 455 | ||
| @@ -503,15 +594,17 @@ static struct clk_lookup u8500_v1_clks[] = { | |||
| 503 | CLK(uiccclk, "uicc", NULL), | 594 | CLK(uiccclk, "uicc", NULL), |
| 504 | }; | 595 | }; |
| 505 | 596 | ||
| 506 | static int __init clk_init(void) | 597 | int __init clk_init(void) |
| 507 | { | 598 | { |
| 508 | if (cpu_is_u8500ed()) { | 599 | if (cpu_is_u8500ed()) { |
| 509 | clk_prcmu_ops.enable = clk_prcmu_ed_enable; | 600 | clk_prcmu_ops.enable = clk_prcmu_ed_enable; |
| 510 | clk_prcmu_ops.disable = clk_prcmu_ed_disable; | 601 | clk_prcmu_ops.disable = clk_prcmu_ed_disable; |
| 602 | clk_per6clk.rate = 100000000; | ||
| 511 | } else if (cpu_is_u5500()) { | 603 | } else if (cpu_is_u5500()) { |
| 512 | /* Clock tree for U5500 not implemented yet */ | 604 | /* Clock tree for U5500 not implemented yet */ |
| 513 | clk_prcc_ops.enable = clk_prcc_ops.disable = NULL; | 605 | clk_prcc_ops.enable = clk_prcc_ops.disable = NULL; |
| 514 | clk_prcmu_ops.enable = clk_prcmu_ops.disable = NULL; | 606 | clk_prcmu_ops.enable = clk_prcmu_ops.disable = NULL; |
| 607 | clk_per6clk.rate = 26000000; | ||
| 515 | } | 608 | } |
| 516 | 609 | ||
| 517 | clkdev_add_table(u8500_common_clks, ARRAY_SIZE(u8500_common_clks)); | 610 | clkdev_add_table(u8500_common_clks, ARRAY_SIZE(u8500_common_clks)); |
| @@ -522,4 +615,3 @@ static int __init clk_init(void) | |||
| 522 | 615 | ||
| 523 | return 0; | 616 | return 0; |
| 524 | } | 617 | } |
| 525 | arch_initcall(clk_init); | ||
