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