common.c revision d0ad52a6fa9018d18076a887898f7912ae91f246
1/* 2 * linux/arch/arm/mach-clps711x/core.c 3 * 4 * Core support for the CLPS711x-based machines. 5 * 6 * Copyright (C) 2001,2011 Deep Blue Solutions Ltd 7 * 8 * This program is free software; you can redistribute it and/or modify 9 * it under the terms of the GNU General Public License as published by 10 * the Free Software Foundation; either version 2 of the License, or 11 * (at your option) any later version. 12 * 13 * This program is distributed in the hope that it will be useful, 14 * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 * GNU General Public License for more details. 17 * 18 * You should have received a copy of the GNU General Public License 19 * along with this program; if not, write to the Free Software 20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 21 */ 22#include <linux/io.h> 23#include <linux/init.h> 24#include <linux/sizes.h> 25#include <linux/interrupt.h> 26#include <linux/irq.h> 27#include <linux/clk.h> 28#include <linux/clkdev.h> 29#include <linux/clockchips.h> 30#include <linux/clk-provider.h> 31 32#include <asm/exception.h> 33#include <asm/mach/irq.h> 34#include <asm/mach/map.h> 35#include <asm/mach/time.h> 36#include <asm/system_misc.h> 37 38#include <mach/hardware.h> 39 40static struct clk *clk_pll, *clk_bus, *clk_uart, *clk_timerl, *clk_timerh, 41 *clk_tint, *clk_spi; 42 43/* 44 * This maps the generic CLPS711x registers 45 */ 46static struct map_desc clps711x_io_desc[] __initdata = { 47 { 48 .virtual = (unsigned long)CLPS711X_VIRT_BASE, 49 .pfn = __phys_to_pfn(CLPS711X_PHYS_BASE), 50 .length = SZ_64K, 51 .type = MT_DEVICE 52 } 53}; 54 55void __init clps711x_map_io(void) 56{ 57 iotable_init(clps711x_io_desc, ARRAY_SIZE(clps711x_io_desc)); 58} 59 60static void int1_mask(struct irq_data *d) 61{ 62 u32 intmr1; 63 64 intmr1 = clps_readl(INTMR1); 65 intmr1 &= ~(1 << d->irq); 66 clps_writel(intmr1, INTMR1); 67} 68 69static void int1_eoi(struct irq_data *d) 70{ 71 switch (d->irq) { 72 case IRQ_CSINT: clps_writel(0, COEOI); break; 73 case IRQ_TC1OI: clps_writel(0, TC1EOI); break; 74 case IRQ_TC2OI: clps_writel(0, TC2EOI); break; 75 case IRQ_RTCMI: clps_writel(0, RTCEOI); break; 76 case IRQ_TINT: clps_writel(0, TEOI); break; 77 case IRQ_UMSINT: clps_writel(0, UMSEOI); break; 78 } 79} 80 81static void int1_unmask(struct irq_data *d) 82{ 83 u32 intmr1; 84 85 intmr1 = clps_readl(INTMR1); 86 intmr1 |= 1 << d->irq; 87 clps_writel(intmr1, INTMR1); 88} 89 90static struct irq_chip int1_chip = { 91 .name = "Interrupt Vector 1", 92 .irq_eoi = int1_eoi, 93 .irq_mask = int1_mask, 94 .irq_unmask = int1_unmask, 95}; 96 97static void int2_mask(struct irq_data *d) 98{ 99 u32 intmr2; 100 101 intmr2 = clps_readl(INTMR2); 102 intmr2 &= ~(1 << (d->irq - 16)); 103 clps_writel(intmr2, INTMR2); 104} 105 106static void int2_eoi(struct irq_data *d) 107{ 108 switch (d->irq) { 109 case IRQ_KBDINT: clps_writel(0, KBDEOI); break; 110 } 111} 112 113static void int2_unmask(struct irq_data *d) 114{ 115 u32 intmr2; 116 117 intmr2 = clps_readl(INTMR2); 118 intmr2 |= 1 << (d->irq - 16); 119 clps_writel(intmr2, INTMR2); 120} 121 122static struct irq_chip int2_chip = { 123 .name = "Interrupt Vector 2", 124 .irq_eoi = int2_eoi, 125 .irq_mask = int2_mask, 126 .irq_unmask = int2_unmask, 127}; 128 129static void int3_mask(struct irq_data *d) 130{ 131 u32 intmr3; 132 133 intmr3 = clps_readl(INTMR3); 134 intmr3 &= ~(1 << (d->irq - 32)); 135 clps_writel(intmr3, INTMR3); 136} 137 138static void int3_unmask(struct irq_data *d) 139{ 140 u32 intmr3; 141 142 intmr3 = clps_readl(INTMR3); 143 intmr3 |= 1 << (d->irq - 32); 144 clps_writel(intmr3, INTMR3); 145} 146 147static struct irq_chip int3_chip = { 148 .name = "Interrupt Vector 3", 149 .irq_mask = int3_mask, 150 .irq_unmask = int3_unmask, 151}; 152 153static struct { 154 int nr; 155 struct irq_chip *chip; 156 irq_flow_handler_t handle; 157} clps711x_irqdescs[] __initdata = { 158 { IRQ_CSINT, &int1_chip, handle_fasteoi_irq, }, 159 { IRQ_EINT1, &int1_chip, handle_level_irq, }, 160 { IRQ_EINT2, &int1_chip, handle_level_irq, }, 161 { IRQ_EINT3, &int1_chip, handle_level_irq, }, 162 { IRQ_TC1OI, &int1_chip, handle_fasteoi_irq, }, 163 { IRQ_TC2OI, &int1_chip, handle_fasteoi_irq, }, 164 { IRQ_RTCMI, &int1_chip, handle_fasteoi_irq, }, 165 { IRQ_TINT, &int1_chip, handle_fasteoi_irq, }, 166 { IRQ_UTXINT1, &int1_chip, handle_level_irq, }, 167 { IRQ_URXINT1, &int1_chip, handle_level_irq, }, 168 { IRQ_UMSINT, &int1_chip, handle_fasteoi_irq, }, 169 { IRQ_SSEOTI, &int1_chip, handle_level_irq, }, 170 { IRQ_KBDINT, &int2_chip, handle_fasteoi_irq, }, 171 { IRQ_SS2RX, &int2_chip, handle_level_irq, }, 172 { IRQ_SS2TX, &int2_chip, handle_level_irq, }, 173 { IRQ_UTXINT2, &int2_chip, handle_level_irq, }, 174 { IRQ_URXINT2, &int2_chip, handle_level_irq, }, 175}; 176 177void __init clps711x_init_irq(void) 178{ 179 unsigned int i; 180 181 /* Disable interrupts */ 182 clps_writel(0, INTMR1); 183 clps_writel(0, INTMR2); 184 clps_writel(0, INTMR3); 185 186 /* Clear down any pending interrupts */ 187 clps_writel(0, BLEOI); 188 clps_writel(0, MCEOI); 189 clps_writel(0, COEOI); 190 clps_writel(0, TC1EOI); 191 clps_writel(0, TC2EOI); 192 clps_writel(0, RTCEOI); 193 clps_writel(0, TEOI); 194 clps_writel(0, UMSEOI); 195 clps_writel(0, KBDEOI); 196 clps_writel(0, SRXEOF); 197 clps_writel(0xffffffff, DAISR); 198 199 for (i = 0; i < ARRAY_SIZE(clps711x_irqdescs); i++) { 200 irq_set_chip_and_handler(clps711x_irqdescs[i].nr, 201 clps711x_irqdescs[i].chip, 202 clps711x_irqdescs[i].handle); 203 set_irq_flags(clps711x_irqdescs[i].nr, 204 IRQF_VALID | IRQF_PROBE); 205 } 206 207 if (IS_ENABLED(CONFIG_FIQ)) { 208 init_FIQ(0); 209 irq_set_chip_and_handler(IRQ_DAIINT, &int3_chip, 210 handle_bad_irq); 211 set_irq_flags(IRQ_DAIINT, 212 IRQF_VALID | IRQF_PROBE | IRQF_NOAUTOEN); 213 } 214} 215 216inline u32 fls16(u32 x) 217{ 218 u32 r = 15; 219 220 if (!(x & 0xff00)) { 221 x <<= 8; 222 r -= 8; 223 } 224 if (!(x & 0xf000)) { 225 x <<= 4; 226 r -= 4; 227 } 228 if (!(x & 0xc000)) { 229 x <<= 2; 230 r -= 2; 231 } 232 if (!(x & 0x8000)) 233 r--; 234 235 return r; 236} 237 238asmlinkage void __exception_irq_entry clps711x_handle_irq(struct pt_regs *regs) 239{ 240 u32 irqstat; 241 void __iomem *base = CLPS711X_VIRT_BASE; 242 243 irqstat = readl_relaxed(base + INTSR1) & readl_relaxed(base + INTMR1); 244 if (irqstat) { 245 handle_IRQ(fls16(irqstat), regs); 246 return; 247 } 248 249 irqstat = readl_relaxed(base + INTSR2) & readl_relaxed(base + INTMR2); 250 if (likely(irqstat)) 251 handle_IRQ(fls16(irqstat) + 16, regs); 252} 253 254static void clps711x_clockevent_set_mode(enum clock_event_mode mode, 255 struct clock_event_device *evt) 256{ 257} 258 259static struct clock_event_device clockevent_clps711x = { 260 .name = "CLPS711x Clockevents", 261 .rating = 300, 262 .features = CLOCK_EVT_FEAT_PERIODIC, 263 .set_mode = clps711x_clockevent_set_mode, 264}; 265 266static irqreturn_t clps711x_timer_interrupt(int irq, void *dev_id) 267{ 268 clockevent_clps711x.event_handler(&clockevent_clps711x); 269 270 return IRQ_HANDLED; 271} 272 273static struct irqaction clps711x_timer_irq = { 274 .name = "CLPS711x Timer Tick", 275 .flags = IRQF_DISABLED | IRQF_TIMER | IRQF_IRQPOLL, 276 .handler = clps711x_timer_interrupt, 277}; 278 279static void add_fixed_clk(struct clk *clk, const char *name, int rate) 280{ 281 clk = clk_register_fixed_rate(NULL, name, NULL, CLK_IS_ROOT, rate); 282 clk_register_clkdev(clk, name, NULL); 283} 284 285void __init clps711x_timer_init(void) 286{ 287 int osc, ext, pll, cpu, bus, timl, timh, uart, spi; 288 u32 tmp; 289 290 osc = 3686400; 291 ext = 13000000; 292 293 tmp = clps_readl(PLLR) >> 24; 294 if (tmp) 295 pll = (osc * tmp) / 2; 296 else 297 pll = 73728000; /* Default value */ 298 299 tmp = clps_readl(SYSFLG2); 300 if (tmp & SYSFLG2_CKMODE) { 301 cpu = ext; 302 bus = cpu; 303 spi = 135400; 304 pll = 0; 305 } else { 306 cpu = pll; 307 if (cpu >= 36864000) 308 bus = cpu / 2; 309 else 310 bus = 36864000 / 2; 311 spi = cpu / 576; 312 } 313 314 uart = bus / 10; 315 316 if (tmp & SYSFLG2_CKMODE) { 317 tmp = clps_readl(SYSCON2); 318 if (tmp & SYSCON2_OSTB) 319 timh = ext / 26; 320 else 321 timh = 541440; 322 } else 323 timh = cpu / 144; 324 325 timl = timh / 256; 326 327 /* All clocks are fixed */ 328 add_fixed_clk(clk_pll, "pll", pll); 329 add_fixed_clk(clk_bus, "bus", bus); 330 add_fixed_clk(clk_uart, "uart", uart); 331 add_fixed_clk(clk_timerl, "timer_lf", timl); 332 add_fixed_clk(clk_timerh, "timer_hf", timh); 333 add_fixed_clk(clk_tint, "tint", 64); 334 add_fixed_clk(clk_spi, "spi", spi); 335 336 pr_info("CPU frequency set at %i Hz.\n", cpu); 337 338 clps_writew(DIV_ROUND_CLOSEST(timh, HZ), TC2D); 339 340 tmp = clps_readl(SYSCON1); 341 tmp |= SYSCON1_TC2S | SYSCON1_TC2M; 342 clps_writel(tmp, SYSCON1); 343 344 clockevents_config_and_register(&clockevent_clps711x, timh, 1, 0xffff); 345 346 setup_irq(IRQ_TC2OI, &clps711x_timer_irq); 347} 348 349void clps711x_restart(char mode, const char *cmd) 350{ 351 soft_restart(0); 352} 353 354static void clps711x_idle(void) 355{ 356 clps_writel(1, HALT); 357 asm("mov r0, r0"); 358 asm("mov r0, r0"); 359} 360 361void __init clps711x_init_early(void) 362{ 363 arm_pm_idle = clps711x_idle; 364} 365