1/* linux/arch/arm/mach-s3c2410/s3c2410.c 2 * 3 * Copyright (c) 2003-2005 Simtec Electronics 4 * Ben Dooks <ben@simtec.co.uk> 5 * 6 * http://www.simtec.co.uk/products/EB2410ITX/ 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 version 2 as 10 * published by the Free Software Foundation. 11*/ 12 13#include <linux/kernel.h> 14#include <linux/types.h> 15#include <linux/interrupt.h> 16#include <linux/list.h> 17#include <linux/timer.h> 18#include <linux/init.h> 19#include <linux/gpio.h> 20#include <linux/clk.h> 21#include <linux/device.h> 22#include <linux/syscore_ops.h> 23#include <linux/serial_core.h> 24#include <linux/platform_device.h> 25#include <linux/io.h> 26 27#include <asm/mach/arch.h> 28#include <asm/mach/map.h> 29#include <asm/mach/irq.h> 30 31#include <mach/hardware.h> 32#include <asm/irq.h> 33#include <asm/system_misc.h> 34 35#include <plat/cpu-freq.h> 36 37#include <mach/regs-clock.h> 38#include <plat/regs-serial.h> 39 40#include <plat/s3c2410.h> 41#include <plat/cpu.h> 42#include <plat/devs.h> 43#include <plat/clock.h> 44#include <plat/pll.h> 45#include <plat/pm.h> 46#include <plat/watchdog-reset.h> 47 48#include <plat/gpio-core.h> 49#include <plat/gpio-cfg.h> 50#include <plat/gpio-cfg-helpers.h> 51 52/* Initial IO mappings */ 53 54static struct map_desc s3c2410_iodesc[] __initdata = { 55 IODESC_ENT(CLKPWR), 56 IODESC_ENT(TIMER), 57 IODESC_ENT(WATCHDOG), 58}; 59 60/* our uart devices */ 61 62/* uart registration process */ 63 64void __init s3c2410_init_uarts(struct s3c2410_uartcfg *cfg, int no) 65{ 66 s3c24xx_init_uartdevs("s3c2410-uart", s3c2410_uart_resources, cfg, no); 67} 68 69/* s3c2410_map_io 70 * 71 * register the standard cpu IO areas, and any passed in from the 72 * machine specific initialisation. 73*/ 74 75void __init s3c2410_map_io(void) 76{ 77 s3c24xx_gpiocfg_default.set_pull = s3c24xx_gpio_setpull_1up; 78 s3c24xx_gpiocfg_default.get_pull = s3c24xx_gpio_getpull_1up; 79 80 iotable_init(s3c2410_iodesc, ARRAY_SIZE(s3c2410_iodesc)); 81} 82 83void __init_or_cpufreq s3c2410_setup_clocks(void) 84{ 85 struct clk *xtal_clk; 86 unsigned long tmp; 87 unsigned long xtal; 88 unsigned long fclk; 89 unsigned long hclk; 90 unsigned long pclk; 91 92 xtal_clk = clk_get(NULL, "xtal"); 93 xtal = clk_get_rate(xtal_clk); 94 clk_put(xtal_clk); 95 96 /* now we've got our machine bits initialised, work out what 97 * clocks we've got */ 98 99 fclk = s3c24xx_get_pll(__raw_readl(S3C2410_MPLLCON), xtal); 100 101 tmp = __raw_readl(S3C2410_CLKDIVN); 102 103 /* work out clock scalings */ 104 105 hclk = fclk / ((tmp & S3C2410_CLKDIVN_HDIVN) ? 2 : 1); 106 pclk = hclk / ((tmp & S3C2410_CLKDIVN_PDIVN) ? 2 : 1); 107 108 /* print brieft summary of clocks, etc */ 109 110 printk("S3C2410: core %ld.%03ld MHz, memory %ld.%03ld MHz, peripheral %ld.%03ld MHz\n", 111 print_mhz(fclk), print_mhz(hclk), print_mhz(pclk)); 112 113 /* initialise the clocks here, to allow other things like the 114 * console to use them 115 */ 116 117 s3c24xx_setup_clocks(fclk, hclk, pclk); 118} 119 120/* fake ARMCLK for use with cpufreq, etc. */ 121 122static struct clk s3c2410_armclk = { 123 .name = "armclk", 124 .parent = &clk_f, 125 .id = -1, 126}; 127 128static struct clk_lookup s3c2410_clk_lookup[] = { 129 CLKDEV_INIT(NULL, "clk_uart_baud0", &clk_p), 130 CLKDEV_INIT(NULL, "clk_uart_baud1", &s3c24xx_uclk), 131}; 132 133void __init s3c2410_init_clocks(int xtal) 134{ 135 s3c24xx_register_baseclocks(xtal); 136 s3c2410_setup_clocks(); 137 s3c2410_baseclk_add(); 138 s3c24xx_register_clock(&s3c2410_armclk); 139 clkdev_add_table(s3c2410_clk_lookup, ARRAY_SIZE(s3c2410_clk_lookup)); 140} 141 142struct bus_type s3c2410_subsys = { 143 .name = "s3c2410-core", 144 .dev_name = "s3c2410-core", 145}; 146 147/* Note, we would have liked to name this s3c2410-core, but we cannot 148 * register two subsystems with the same name. 149 */ 150struct bus_type s3c2410a_subsys = { 151 .name = "s3c2410a-core", 152 .dev_name = "s3c2410a-core", 153}; 154 155static struct device s3c2410_dev = { 156 .bus = &s3c2410_subsys, 157}; 158 159/* need to register the subsystem before we actually register the device, and 160 * we also need to ensure that it has been initialised before any of the 161 * drivers even try to use it (even if not on an s3c2410 based system) 162 * as a driver which may support both 2410 and 2440 may try and use it. 163*/ 164 165static int __init s3c2410_core_init(void) 166{ 167 return subsys_system_register(&s3c2410_subsys, NULL); 168} 169 170core_initcall(s3c2410_core_init); 171 172static int __init s3c2410a_core_init(void) 173{ 174 return subsys_system_register(&s3c2410a_subsys, NULL); 175} 176 177core_initcall(s3c2410a_core_init); 178 179int __init s3c2410_init(void) 180{ 181 printk("S3C2410: Initialising architecture\n"); 182 183#ifdef CONFIG_PM 184 register_syscore_ops(&s3c2410_pm_syscore_ops); 185#endif 186 register_syscore_ops(&s3c24xx_irq_syscore_ops); 187 188 return device_register(&s3c2410_dev); 189} 190 191int __init s3c2410a_init(void) 192{ 193 s3c2410_dev.bus = &s3c2410a_subsys; 194 return s3c2410_init(); 195} 196 197void s3c2410_restart(char mode, const char *cmd) 198{ 199 if (mode == 's') { 200 soft_restart(0); 201 } 202 203 arch_wdt_reset(); 204 205 /* we'll take a jump through zero as a poor second */ 206 soft_restart(0); 207} 208