diff options
| -rw-r--r-- | arch/arm/mach-ep93xx/clock.c | 69 | ||||
| -rw-r--r-- | arch/arm/mach-ep93xx/include/mach/ep93xx-regs.h | 5 |
2 files changed, 65 insertions, 9 deletions
diff --git a/arch/arm/mach-ep93xx/clock.c b/arch/arm/mach-ep93xx/clock.c index e8ebeaea6c48..b2eede5531c8 100644 --- a/arch/arm/mach-ep93xx/clock.c +++ b/arch/arm/mach-ep93xx/clock.c | |||
| @@ -21,15 +21,50 @@ | |||
| 21 | #include <asm/div64.h> | 21 | #include <asm/div64.h> |
| 22 | #include <mach/hardware.h> | 22 | #include <mach/hardware.h> |
| 23 | 23 | ||
| 24 | |||
| 25 | /* | ||
| 26 | * The EP93xx has two external crystal oscillators. To generate the | ||
| 27 | * required high-frequency clocks, the processor uses two phase-locked- | ||
| 28 | * loops (PLLs) to multiply the incoming external clock signal to much | ||
| 29 | * higher frequencies that are then divided down by programmable dividers | ||
| 30 | * to produce the needed clocks. The PLLs operate independently of one | ||
| 31 | * another. | ||
| 32 | */ | ||
| 33 | #define EP93XX_EXT_CLK_RATE 14745600 | ||
| 34 | #define EP93XX_EXT_RTC_RATE 32768 | ||
| 35 | |||
| 36 | |||
| 24 | struct clk { | 37 | struct clk { |
| 25 | unsigned long rate; | 38 | unsigned long rate; |
| 26 | int users; | 39 | int users; |
| 40 | int sw_locked; | ||
| 27 | u32 enable_reg; | 41 | u32 enable_reg; |
| 28 | u32 enable_mask; | 42 | u32 enable_mask; |
| 43 | |||
| 44 | unsigned long (*get_rate)(struct clk *clk); | ||
| 29 | }; | 45 | }; |
| 30 | 46 | ||
| 31 | static struct clk clk_uart = { | 47 | |
| 32 | .rate = 14745600, | 48 | static unsigned long get_uart_rate(struct clk *clk); |
| 49 | |||
| 50 | |||
| 51 | static struct clk clk_uart1 = { | ||
| 52 | .sw_locked = 1, | ||
| 53 | .enable_reg = EP93XX_SYSCON_DEVICE_CONFIG, | ||
| 54 | .enable_mask = EP93XX_SYSCON_DEVICE_CONFIG_U1EN, | ||
| 55 | .get_rate = get_uart_rate, | ||
| 56 | }; | ||
| 57 | static struct clk clk_uart2 = { | ||
| 58 | .sw_locked = 1, | ||
| 59 | .enable_reg = EP93XX_SYSCON_DEVICE_CONFIG, | ||
| 60 | .enable_mask = EP93XX_SYSCON_DEVICE_CONFIG_U2EN, | ||
| 61 | .get_rate = get_uart_rate, | ||
| 62 | }; | ||
| 63 | static struct clk clk_uart3 = { | ||
| 64 | .sw_locked = 1, | ||
| 65 | .enable_reg = EP93XX_SYSCON_DEVICE_CONFIG, | ||
| 66 | .enable_mask = EP93XX_SYSCON_DEVICE_CONFIG_U3EN, | ||
| 67 | .get_rate = get_uart_rate, | ||
| 33 | }; | 68 | }; |
| 34 | static struct clk clk_pll1; | 69 | static struct clk clk_pll1; |
| 35 | static struct clk clk_f; | 70 | static struct clk clk_f; |
| @@ -95,9 +130,9 @@ static struct clk clk_m2m1 = { | |||
| 95 | { .dev_id = dev, .con_id = con, .clk = ck } | 130 | { .dev_id = dev, .con_id = con, .clk = ck } |
| 96 | 131 | ||
| 97 | static struct clk_lookup clocks[] = { | 132 | static struct clk_lookup clocks[] = { |
| 98 | INIT_CK("apb:uart1", NULL, &clk_uart), | 133 | INIT_CK("apb:uart1", NULL, &clk_uart1), |
| 99 | INIT_CK("apb:uart2", NULL, &clk_uart), | 134 | INIT_CK("apb:uart2", NULL, &clk_uart2), |
| 100 | INIT_CK("apb:uart3", NULL, &clk_uart), | 135 | INIT_CK("apb:uart3", NULL, &clk_uart3), |
| 101 | INIT_CK(NULL, "pll1", &clk_pll1), | 136 | INIT_CK(NULL, "pll1", &clk_pll1), |
| 102 | INIT_CK(NULL, "fclk", &clk_f), | 137 | INIT_CK(NULL, "fclk", &clk_f), |
| 103 | INIT_CK(NULL, "hclk", &clk_h), | 138 | INIT_CK(NULL, "hclk", &clk_h), |
| @@ -125,6 +160,8 @@ int clk_enable(struct clk *clk) | |||
| 125 | u32 value; | 160 | u32 value; |
| 126 | 161 | ||
| 127 | value = __raw_readl(clk->enable_reg); | 162 | value = __raw_readl(clk->enable_reg); |
| 163 | if (clk->sw_locked) | ||
| 164 | __raw_writel(0xaa, EP93XX_SYSCON_SWLOCK); | ||
| 128 | __raw_writel(value | clk->enable_mask, clk->enable_reg); | 165 | __raw_writel(value | clk->enable_mask, clk->enable_reg); |
| 129 | } | 166 | } |
| 130 | 167 | ||
| @@ -138,13 +175,29 @@ void clk_disable(struct clk *clk) | |||
| 138 | u32 value; | 175 | u32 value; |
| 139 | 176 | ||
| 140 | value = __raw_readl(clk->enable_reg); | 177 | value = __raw_readl(clk->enable_reg); |
| 178 | if (clk->sw_locked) | ||
| 179 | __raw_writel(0xaa, EP93XX_SYSCON_SWLOCK); | ||
| 141 | __raw_writel(value & ~clk->enable_mask, clk->enable_reg); | 180 | __raw_writel(value & ~clk->enable_mask, clk->enable_reg); |
| 142 | } | 181 | } |
| 143 | } | 182 | } |
| 144 | EXPORT_SYMBOL(clk_disable); | 183 | EXPORT_SYMBOL(clk_disable); |
| 145 | 184 | ||
| 185 | static unsigned long get_uart_rate(struct clk *clk) | ||
| 186 | { | ||
| 187 | u32 value; | ||
| 188 | |||
| 189 | value = __raw_readl(EP93XX_SYSCON_CLOCK_CONTROL); | ||
| 190 | if (value & EP93XX_SYSCON_CLOCK_UARTBAUD) | ||
| 191 | return EP93XX_EXT_CLK_RATE; | ||
| 192 | else | ||
| 193 | return EP93XX_EXT_CLK_RATE / 2; | ||
| 194 | } | ||
| 195 | |||
| 146 | unsigned long clk_get_rate(struct clk *clk) | 196 | unsigned long clk_get_rate(struct clk *clk) |
| 147 | { | 197 | { |
| 198 | if (clk->get_rate) | ||
| 199 | return clk->get_rate(clk); | ||
| 200 | |||
| 148 | return clk->rate; | 201 | return clk->rate; |
| 149 | } | 202 | } |
| 150 | EXPORT_SYMBOL(clk_get_rate); | 203 | EXPORT_SYMBOL(clk_get_rate); |
| @@ -162,7 +215,7 @@ static unsigned long calc_pll_rate(u32 config_word) | |||
| 162 | unsigned long long rate; | 215 | unsigned long long rate; |
| 163 | int i; | 216 | int i; |
| 164 | 217 | ||
| 165 | rate = 14745600; | 218 | rate = EP93XX_EXT_CLK_RATE; |
| 166 | rate *= ((config_word >> 11) & 0x1f) + 1; /* X1FBD */ | 219 | rate *= ((config_word >> 11) & 0x1f) + 1; /* X1FBD */ |
| 167 | rate *= ((config_word >> 5) & 0x3f) + 1; /* X2FBD */ | 220 | rate *= ((config_word >> 5) & 0x3f) + 1; /* X2FBD */ |
| 168 | do_div(rate, (config_word & 0x1f) + 1); /* X2IPD */ | 221 | do_div(rate, (config_word & 0x1f) + 1); /* X2IPD */ |
| @@ -195,7 +248,7 @@ static int __init ep93xx_clock_init(void) | |||
| 195 | 248 | ||
| 196 | value = __raw_readl(EP93XX_SYSCON_CLOCK_SET1); | 249 | value = __raw_readl(EP93XX_SYSCON_CLOCK_SET1); |
| 197 | if (!(value & 0x00800000)) { /* PLL1 bypassed? */ | 250 | if (!(value & 0x00800000)) { /* PLL1 bypassed? */ |
| 198 | clk_pll1.rate = 14745600; | 251 | clk_pll1.rate = EP93XX_EXT_CLK_RATE; |
| 199 | } else { | 252 | } else { |
| 200 | clk_pll1.rate = calc_pll_rate(value); | 253 | clk_pll1.rate = calc_pll_rate(value); |
| 201 | } | 254 | } |
| @@ -206,7 +259,7 @@ static int __init ep93xx_clock_init(void) | |||
| 206 | 259 | ||
| 207 | value = __raw_readl(EP93XX_SYSCON_CLOCK_SET2); | 260 | value = __raw_readl(EP93XX_SYSCON_CLOCK_SET2); |
| 208 | if (!(value & 0x00080000)) { /* PLL2 bypassed? */ | 261 | if (!(value & 0x00080000)) { /* PLL2 bypassed? */ |
| 209 | clk_pll2.rate = 14745600; | 262 | clk_pll2.rate = EP93XX_EXT_CLK_RATE; |
| 210 | } else if (value & 0x00040000) { /* PLL2 enabled? */ | 263 | } else if (value & 0x00040000) { /* PLL2 enabled? */ |
| 211 | clk_pll2.rate = calc_pll_rate(value); | 264 | clk_pll2.rate = calc_pll_rate(value); |
| 212 | } else { | 265 | } else { |
diff --git a/arch/arm/mach-ep93xx/include/mach/ep93xx-regs.h b/arch/arm/mach-ep93xx/include/mach/ep93xx-regs.h index f66be12b856e..1732de7629a5 100644 --- a/arch/arm/mach-ep93xx/include/mach/ep93xx-regs.h +++ b/arch/arm/mach-ep93xx/include/mach/ep93xx-regs.h | |||
| @@ -159,7 +159,10 @@ | |||
| 159 | #define EP93XX_SYSCON_CLOCK_SET1 EP93XX_SYSCON_REG(0x20) | 159 | #define EP93XX_SYSCON_CLOCK_SET1 EP93XX_SYSCON_REG(0x20) |
| 160 | #define EP93XX_SYSCON_CLOCK_SET2 EP93XX_SYSCON_REG(0x24) | 160 | #define EP93XX_SYSCON_CLOCK_SET2 EP93XX_SYSCON_REG(0x24) |
| 161 | #define EP93XX_SYSCON_DEVICE_CONFIG EP93XX_SYSCON_REG(0x80) | 161 | #define EP93XX_SYSCON_DEVICE_CONFIG EP93XX_SYSCON_REG(0x80) |
| 162 | #define EP93XX_SYSCON_DEVICE_CONFIG_CRUNCH_ENABLE 0x00800000 | 162 | #define EP93XX_SYSCON_DEVICE_CONFIG_U3EN (1<<24) |
| 163 | #define EP93XX_SYSCON_DEVICE_CONFIG_CRUNCH_ENABLE (1<<23) | ||
| 164 | #define EP93XX_SYSCON_DEVICE_CONFIG_U2EN (1<<20) | ||
| 165 | #define EP93XX_SYSCON_DEVICE_CONFIG_U1EN (1<<18) | ||
| 163 | #define EP93XX_SYSCON_SWLOCK EP93XX_SYSCON_REG(0xc0) | 166 | #define EP93XX_SYSCON_SWLOCK EP93XX_SYSCON_REG(0xc0) |
| 164 | 167 | ||
| 165 | #define EP93XX_WATCHDOG_BASE (EP93XX_APB_VIRT_BASE + 0x00140000) | 168 | #define EP93XX_WATCHDOG_BASE (EP93XX_APB_VIRT_BASE + 0x00140000) |
