1/* 2 * Copyright (c) 2011 Samsung Electronics Co., Ltd. 3 * http://www.samsung.com 4 * 5 * Copyright 2008 Openmoko, Inc. 6 * Copyright 2008 Simtec Electronics 7 * Ben Dooks <ben@simtec.co.uk> 8 * http://armlinux.simtec.co.uk/ 9 * 10 * Common Codes for S3C64XX machines 11 * 12 * This program is free software; you can redistribute it and/or modify 13 * it under the terms of the GNU General Public License version 2 as 14 * published by the Free Software Foundation. 15 */ 16 17/* 18 * NOTE: Code in this file is not used when booting with Device Tree support. 19 */ 20 21#include <linux/kernel.h> 22#include <linux/init.h> 23#include <linux/module.h> 24#include <linux/clk-provider.h> 25#include <linux/interrupt.h> 26#include <linux/ioport.h> 27#include <linux/serial_core.h> 28#include <linux/serial_s3c.h> 29#include <linux/platform_device.h> 30#include <linux/reboot.h> 31#include <linux/io.h> 32#include <linux/dma-mapping.h> 33#include <linux/irq.h> 34#include <linux/gpio.h> 35#include <linux/irqchip/arm-vic.h> 36#include <clocksource/samsung_pwm.h> 37 38#include <asm/mach/arch.h> 39#include <asm/mach/map.h> 40#include <asm/system_misc.h> 41 42#include <mach/map.h> 43#include <mach/hardware.h> 44#include <mach/regs-gpio.h> 45#include <mach/gpio-samsung.h> 46 47#include <plat/cpu.h> 48#include <plat/devs.h> 49#include <plat/pm.h> 50#include <plat/gpio-cfg.h> 51#include <plat/irq-uart.h> 52#include <plat/pwm-core.h> 53#include <plat/regs-irqtype.h> 54#include <plat/watchdog-reset.h> 55 56#include "common.h" 57 58/* External clock frequency */ 59static unsigned long xtal_f = 12000000, xusbxti_f = 48000000; 60 61void __init s3c64xx_set_xtal_freq(unsigned long freq) 62{ 63 xtal_f = freq; 64} 65 66void __init s3c64xx_set_xusbxti_freq(unsigned long freq) 67{ 68 xusbxti_f = freq; 69} 70 71/* uart registration process */ 72 73static void __init s3c64xx_init_uarts(struct s3c2410_uartcfg *cfg, int no) 74{ 75 s3c24xx_init_uartdevs("s3c6400-uart", s3c64xx_uart_resources, cfg, no); 76} 77 78/* table of supported CPUs */ 79 80static const char name_s3c6400[] = "S3C6400"; 81static const char name_s3c6410[] = "S3C6410"; 82 83static struct cpu_table cpu_ids[] __initdata = { 84 { 85 .idcode = S3C6400_CPU_ID, 86 .idmask = S3C64XX_CPU_MASK, 87 .map_io = s3c6400_map_io, 88 .init_uarts = s3c64xx_init_uarts, 89 .init = s3c6400_init, 90 .name = name_s3c6400, 91 }, { 92 .idcode = S3C6410_CPU_ID, 93 .idmask = S3C64XX_CPU_MASK, 94 .map_io = s3c6410_map_io, 95 .init_uarts = s3c64xx_init_uarts, 96 .init = s3c6410_init, 97 .name = name_s3c6410, 98 }, 99}; 100 101/* minimal IO mapping */ 102 103/* see notes on uart map in arch/arm/mach-s3c64xx/include/mach/debug-macro.S */ 104#define UART_OFFS (S3C_PA_UART & 0xfffff) 105 106static struct map_desc s3c_iodesc[] __initdata = { 107 { 108 .virtual = (unsigned long)S3C_VA_SYS, 109 .pfn = __phys_to_pfn(S3C64XX_PA_SYSCON), 110 .length = SZ_4K, 111 .type = MT_DEVICE, 112 }, { 113 .virtual = (unsigned long)S3C_VA_MEM, 114 .pfn = __phys_to_pfn(S3C64XX_PA_SROM), 115 .length = SZ_4K, 116 .type = MT_DEVICE, 117 }, { 118 .virtual = (unsigned long)(S3C_VA_UART + UART_OFFS), 119 .pfn = __phys_to_pfn(S3C_PA_UART), 120 .length = SZ_4K, 121 .type = MT_DEVICE, 122 }, { 123 .virtual = (unsigned long)VA_VIC0, 124 .pfn = __phys_to_pfn(S3C64XX_PA_VIC0), 125 .length = SZ_16K, 126 .type = MT_DEVICE, 127 }, { 128 .virtual = (unsigned long)VA_VIC1, 129 .pfn = __phys_to_pfn(S3C64XX_PA_VIC1), 130 .length = SZ_16K, 131 .type = MT_DEVICE, 132 }, { 133 .virtual = (unsigned long)S3C_VA_TIMER, 134 .pfn = __phys_to_pfn(S3C_PA_TIMER), 135 .length = SZ_16K, 136 .type = MT_DEVICE, 137 }, { 138 .virtual = (unsigned long)S3C64XX_VA_GPIO, 139 .pfn = __phys_to_pfn(S3C64XX_PA_GPIO), 140 .length = SZ_4K, 141 .type = MT_DEVICE, 142 }, { 143 .virtual = (unsigned long)S3C64XX_VA_MODEM, 144 .pfn = __phys_to_pfn(S3C64XX_PA_MODEM), 145 .length = SZ_4K, 146 .type = MT_DEVICE, 147 }, { 148 .virtual = (unsigned long)S3C_VA_WATCHDOG, 149 .pfn = __phys_to_pfn(S3C64XX_PA_WATCHDOG), 150 .length = SZ_4K, 151 .type = MT_DEVICE, 152 }, { 153 .virtual = (unsigned long)S3C_VA_USB_HSPHY, 154 .pfn = __phys_to_pfn(S3C64XX_PA_USB_HSPHY), 155 .length = SZ_1K, 156 .type = MT_DEVICE, 157 }, 158}; 159 160static struct bus_type s3c64xx_subsys = { 161 .name = "s3c64xx-core", 162 .dev_name = "s3c64xx-core", 163}; 164 165static struct device s3c64xx_dev = { 166 .bus = &s3c64xx_subsys, 167}; 168 169static struct samsung_pwm_variant s3c64xx_pwm_variant = { 170 .bits = 32, 171 .div_base = 0, 172 .has_tint_cstat = true, 173 .tclk_mask = (1 << 7) | (1 << 6) | (1 << 5), 174}; 175 176void __init samsung_set_timer_source(unsigned int event, unsigned int source) 177{ 178 s3c64xx_pwm_variant.output_mask = BIT(SAMSUNG_PWM_NUM) - 1; 179 s3c64xx_pwm_variant.output_mask &= ~(BIT(event) | BIT(source)); 180} 181 182void __init samsung_timer_init(void) 183{ 184 unsigned int timer_irqs[SAMSUNG_PWM_NUM] = { 185 IRQ_TIMER0_VIC, IRQ_TIMER1_VIC, IRQ_TIMER2_VIC, 186 IRQ_TIMER3_VIC, IRQ_TIMER4_VIC, 187 }; 188 189 samsung_pwm_clocksource_init(S3C_VA_TIMER, 190 timer_irqs, &s3c64xx_pwm_variant); 191} 192 193/* read cpu identification code */ 194 195void __init s3c64xx_init_io(struct map_desc *mach_desc, int size) 196{ 197 /* initialise the io descriptors we need for initialisation */ 198 iotable_init(s3c_iodesc, ARRAY_SIZE(s3c_iodesc)); 199 iotable_init(mach_desc, size); 200 201 /* detect cpu id */ 202 s3c64xx_init_cpu(); 203 204 s3c_init_cpu(samsung_cpu_id, cpu_ids, ARRAY_SIZE(cpu_ids)); 205 206 samsung_pwm_set_platdata(&s3c64xx_pwm_variant); 207} 208 209static __init int s3c64xx_dev_init(void) 210{ 211 /* Not applicable when using DT. */ 212 if (of_have_populated_dt()) 213 return 0; 214 215 subsys_system_register(&s3c64xx_subsys, NULL); 216 return device_register(&s3c64xx_dev); 217} 218core_initcall(s3c64xx_dev_init); 219 220/* 221 * setup the sources the vic should advertise resume 222 * for, even though it is not doing the wake 223 * (set_irq_wake needs to be valid) 224 */ 225#define IRQ_VIC0_RESUME (1 << (IRQ_RTC_TIC - IRQ_VIC0_BASE)) 226#define IRQ_VIC1_RESUME (1 << (IRQ_RTC_ALARM - IRQ_VIC1_BASE) | \ 227 1 << (IRQ_PENDN - IRQ_VIC1_BASE) | \ 228 1 << (IRQ_HSMMC0 - IRQ_VIC1_BASE) | \ 229 1 << (IRQ_HSMMC1 - IRQ_VIC1_BASE) | \ 230 1 << (IRQ_HSMMC2 - IRQ_VIC1_BASE)) 231 232void __init s3c64xx_init_irq(u32 vic0_valid, u32 vic1_valid) 233{ 234 /* 235 * FIXME: there is no better place to put this at the moment 236 * (s3c64xx_clk_init needs ioremap and must happen before init_time 237 * samsung_wdt_reset_init needs clocks) 238 */ 239 s3c64xx_clk_init(NULL, xtal_f, xusbxti_f, soc_is_s3c6400(), S3C_VA_SYS); 240 samsung_wdt_reset_init(S3C_VA_WATCHDOG); 241 242 printk(KERN_DEBUG "%s: initialising interrupts\n", __func__); 243 244 /* initialise the pair of VICs */ 245 vic_init(VA_VIC0, IRQ_VIC0_BASE, vic0_valid, IRQ_VIC0_RESUME); 246 vic_init(VA_VIC1, IRQ_VIC1_BASE, vic1_valid, IRQ_VIC1_RESUME); 247} 248 249#define eint_offset(irq) ((irq) - IRQ_EINT(0)) 250#define eint_irq_to_bit(irq) ((u32)(1 << eint_offset(irq))) 251 252static inline void s3c_irq_eint_mask(struct irq_data *data) 253{ 254 u32 mask; 255 256 mask = __raw_readl(S3C64XX_EINT0MASK); 257 mask |= (u32)data->chip_data; 258 __raw_writel(mask, S3C64XX_EINT0MASK); 259} 260 261static void s3c_irq_eint_unmask(struct irq_data *data) 262{ 263 u32 mask; 264 265 mask = __raw_readl(S3C64XX_EINT0MASK); 266 mask &= ~((u32)data->chip_data); 267 __raw_writel(mask, S3C64XX_EINT0MASK); 268} 269 270static inline void s3c_irq_eint_ack(struct irq_data *data) 271{ 272 __raw_writel((u32)data->chip_data, S3C64XX_EINT0PEND); 273} 274 275static void s3c_irq_eint_maskack(struct irq_data *data) 276{ 277 /* compiler should in-line these */ 278 s3c_irq_eint_mask(data); 279 s3c_irq_eint_ack(data); 280} 281 282static int s3c_irq_eint_set_type(struct irq_data *data, unsigned int type) 283{ 284 int offs = eint_offset(data->irq); 285 int pin, pin_val; 286 int shift; 287 u32 ctrl, mask; 288 u32 newvalue = 0; 289 void __iomem *reg; 290 291 if (offs > 27) 292 return -EINVAL; 293 294 if (offs <= 15) 295 reg = S3C64XX_EINT0CON0; 296 else 297 reg = S3C64XX_EINT0CON1; 298 299 switch (type) { 300 case IRQ_TYPE_NONE: 301 printk(KERN_WARNING "No edge setting!\n"); 302 break; 303 304 case IRQ_TYPE_EDGE_RISING: 305 newvalue = S3C2410_EXTINT_RISEEDGE; 306 break; 307 308 case IRQ_TYPE_EDGE_FALLING: 309 newvalue = S3C2410_EXTINT_FALLEDGE; 310 break; 311 312 case IRQ_TYPE_EDGE_BOTH: 313 newvalue = S3C2410_EXTINT_BOTHEDGE; 314 break; 315 316 case IRQ_TYPE_LEVEL_LOW: 317 newvalue = S3C2410_EXTINT_LOWLEV; 318 break; 319 320 case IRQ_TYPE_LEVEL_HIGH: 321 newvalue = S3C2410_EXTINT_HILEV; 322 break; 323 324 default: 325 printk(KERN_ERR "No such irq type %d", type); 326 return -1; 327 } 328 329 if (offs <= 15) 330 shift = (offs / 2) * 4; 331 else 332 shift = ((offs - 16) / 2) * 4; 333 mask = 0x7 << shift; 334 335 ctrl = __raw_readl(reg); 336 ctrl &= ~mask; 337 ctrl |= newvalue << shift; 338 __raw_writel(ctrl, reg); 339 340 /* set the GPIO pin appropriately */ 341 342 if (offs < 16) { 343 pin = S3C64XX_GPN(offs); 344 pin_val = S3C_GPIO_SFN(2); 345 } else if (offs < 23) { 346 pin = S3C64XX_GPL(offs + 8 - 16); 347 pin_val = S3C_GPIO_SFN(3); 348 } else { 349 pin = S3C64XX_GPM(offs - 23); 350 pin_val = S3C_GPIO_SFN(3); 351 } 352 353 s3c_gpio_cfgpin(pin, pin_val); 354 355 return 0; 356} 357 358static struct irq_chip s3c_irq_eint = { 359 .name = "s3c-eint", 360 .irq_mask = s3c_irq_eint_mask, 361 .irq_unmask = s3c_irq_eint_unmask, 362 .irq_mask_ack = s3c_irq_eint_maskack, 363 .irq_ack = s3c_irq_eint_ack, 364 .irq_set_type = s3c_irq_eint_set_type, 365 .irq_set_wake = s3c_irqext_wake, 366}; 367 368/* s3c_irq_demux_eint 369 * 370 * This function demuxes the IRQ from the group0 external interrupts, 371 * from IRQ_EINT(0) to IRQ_EINT(27). It is designed to be inlined into 372 * the specific handlers s3c_irq_demux_eintX_Y. 373 */ 374static inline void s3c_irq_demux_eint(unsigned int start, unsigned int end) 375{ 376 u32 status = __raw_readl(S3C64XX_EINT0PEND); 377 u32 mask = __raw_readl(S3C64XX_EINT0MASK); 378 unsigned int irq; 379 380 status &= ~mask; 381 status >>= start; 382 status &= (1 << (end - start + 1)) - 1; 383 384 for (irq = IRQ_EINT(start); irq <= IRQ_EINT(end); irq++) { 385 if (status & 1) 386 generic_handle_irq(irq); 387 388 status >>= 1; 389 } 390} 391 392static void s3c_irq_demux_eint0_3(unsigned int irq, struct irq_desc *desc) 393{ 394 s3c_irq_demux_eint(0, 3); 395} 396 397static void s3c_irq_demux_eint4_11(unsigned int irq, struct irq_desc *desc) 398{ 399 s3c_irq_demux_eint(4, 11); 400} 401 402static void s3c_irq_demux_eint12_19(unsigned int irq, struct irq_desc *desc) 403{ 404 s3c_irq_demux_eint(12, 19); 405} 406 407static void s3c_irq_demux_eint20_27(unsigned int irq, struct irq_desc *desc) 408{ 409 s3c_irq_demux_eint(20, 27); 410} 411 412static int __init s3c64xx_init_irq_eint(void) 413{ 414 int irq; 415 416 /* On DT-enabled systems EINTs are handled by pinctrl-s3c64xx driver. */ 417 if (of_have_populated_dt()) 418 return -ENODEV; 419 420 for (irq = IRQ_EINT(0); irq <= IRQ_EINT(27); irq++) { 421 irq_set_chip_and_handler(irq, &s3c_irq_eint, handle_level_irq); 422 irq_set_chip_data(irq, (void *)eint_irq_to_bit(irq)); 423 set_irq_flags(irq, IRQF_VALID); 424 } 425 426 irq_set_chained_handler(IRQ_EINT0_3, s3c_irq_demux_eint0_3); 427 irq_set_chained_handler(IRQ_EINT4_11, s3c_irq_demux_eint4_11); 428 irq_set_chained_handler(IRQ_EINT12_19, s3c_irq_demux_eint12_19); 429 irq_set_chained_handler(IRQ_EINT20_27, s3c_irq_demux_eint20_27); 430 431 return 0; 432} 433arch_initcall(s3c64xx_init_irq_eint); 434 435void s3c64xx_restart(enum reboot_mode mode, const char *cmd) 436{ 437 if (mode != REBOOT_SOFT) 438 samsung_wdt_reset(); 439 440 /* if all else fails, or mode was for soft, jump to 0 */ 441 soft_restart(0); 442} 443