linux/arch/arm/mach-integrator/core.c
<<
>>
Prefs
   1/*
   2 *  linux/arch/arm/mach-integrator/core.c
   3 *
   4 *  Copyright (C) 2000-2003 Deep Blue Solutions Ltd
   5 *
   6 * This program is free software; you can redistribute it and/or modify
   7 * it under the terms of the GNU General Public License version 2, as
   8 * published by the Free Software Foundation.
   9 */
  10#include <linux/types.h>
  11#include <linux/kernel.h>
  12#include <linux/init.h>
  13#include <linux/device.h>
  14#include <linux/spinlock.h>
  15#include <linux/interrupt.h>
  16#include <linux/irq.h>
  17#include <linux/memblock.h>
  18#include <linux/sched.h>
  19#include <linux/smp.h>
  20#include <linux/termios.h>
  21#include <linux/amba/bus.h>
  22#include <linux/amba/serial.h>
  23#include <linux/io.h>
  24#include <linux/clkdev.h>
  25
  26#include <mach/hardware.h>
  27#include <mach/platform.h>
  28#include <asm/irq.h>
  29#include <mach/cm.h>
  30#include <asm/system.h>
  31#include <asm/leds.h>
  32#include <asm/mach-types.h>
  33#include <asm/mach/time.h>
  34#include <asm/pgtable.h>
  35
  36static struct amba_pl010_data integrator_uart_data;
  37
  38static struct amba_device rtc_device = {
  39        .dev            = {
  40                .init_name = "mb:15",
  41        },
  42        .res            = {
  43                .start  = INTEGRATOR_RTC_BASE,
  44                .end    = INTEGRATOR_RTC_BASE + SZ_4K - 1,
  45                .flags  = IORESOURCE_MEM,
  46        },
  47        .irq            = { IRQ_RTCINT, NO_IRQ },
  48};
  49
  50static struct amba_device uart0_device = {
  51        .dev            = {
  52                .init_name = "mb:16",
  53                .platform_data = &integrator_uart_data,
  54        },
  55        .res            = {
  56                .start  = INTEGRATOR_UART0_BASE,
  57                .end    = INTEGRATOR_UART0_BASE + SZ_4K - 1,
  58                .flags  = IORESOURCE_MEM,
  59        },
  60        .irq            = { IRQ_UARTINT0, NO_IRQ },
  61};
  62
  63static struct amba_device uart1_device = {
  64        .dev            = {
  65                .init_name = "mb:17",
  66                .platform_data = &integrator_uart_data,
  67        },
  68        .res            = {
  69                .start  = INTEGRATOR_UART1_BASE,
  70                .end    = INTEGRATOR_UART1_BASE + SZ_4K - 1,
  71                .flags  = IORESOURCE_MEM,
  72        },
  73        .irq            = { IRQ_UARTINT1, NO_IRQ },
  74};
  75
  76static struct amba_device kmi0_device = {
  77        .dev            = {
  78                .init_name = "mb:18",
  79        },
  80        .res            = {
  81                .start  = KMI0_BASE,
  82                .end    = KMI0_BASE + SZ_4K - 1,
  83                .flags  = IORESOURCE_MEM,
  84        },
  85        .irq            = { IRQ_KMIINT0, NO_IRQ },
  86};
  87
  88static struct amba_device kmi1_device = {
  89        .dev            = {
  90                .init_name = "mb:19",
  91        },
  92        .res            = {
  93                .start  = KMI1_BASE,
  94                .end    = KMI1_BASE + SZ_4K - 1,
  95                .flags  = IORESOURCE_MEM,
  96        },
  97        .irq            = { IRQ_KMIINT1, NO_IRQ },
  98};
  99
 100static struct amba_device *amba_devs[] __initdata = {
 101        &rtc_device,
 102        &uart0_device,
 103        &uart1_device,
 104        &kmi0_device,
 105        &kmi1_device,
 106};
 107
 108/*
 109 * These are fixed clocks.
 110 */
 111static struct clk clk24mhz = {
 112        .rate   = 24000000,
 113};
 114
 115static struct clk uartclk = {
 116        .rate   = 14745600,
 117};
 118
 119static struct clk dummy_apb_pclk;
 120
 121static struct clk_lookup lookups[] = {
 122        {       /* Bus clock */
 123                .con_id         = "apb_pclk",
 124                .clk            = &dummy_apb_pclk,
 125        }, {
 126                /* Integrator/AP timer frequency */
 127                .dev_id         = "ap_timer",
 128                .clk            = &clk24mhz,
 129        }, {    /* UART0 */
 130                .dev_id         = "mb:16",
 131                .clk            = &uartclk,
 132        }, {    /* UART1 */
 133                .dev_id         = "mb:17",
 134                .clk            = &uartclk,
 135        }, {    /* KMI0 */
 136                .dev_id         = "mb:18",
 137                .clk            = &clk24mhz,
 138        }, {    /* KMI1 */
 139                .dev_id         = "mb:19",
 140                .clk            = &clk24mhz,
 141        }, {    /* MMCI - IntegratorCP */
 142                .dev_id         = "mb:1c",
 143                .clk            = &uartclk,
 144        }
 145};
 146
 147void __init integrator_init_early(void)
 148{
 149        clkdev_add_table(lookups, ARRAY_SIZE(lookups));
 150}
 151
 152static int __init integrator_init(void)
 153{
 154        int i;
 155
 156        /*
 157         * The Integrator/AP lacks necessary AMBA PrimeCell IDs, so we need to
 158         * hard-code them. The Integator/CP and forward have proper cell IDs.
 159         * Else we leave them undefined to the bus driver can autoprobe them.
 160         */
 161        if (machine_is_integrator()) {
 162                rtc_device.periphid     = 0x00041030;
 163                uart0_device.periphid   = 0x00041010;
 164                uart1_device.periphid   = 0x00041010;
 165                kmi0_device.periphid    = 0x00041050;
 166                kmi1_device.periphid    = 0x00041050;
 167        }
 168
 169        for (i = 0; i < ARRAY_SIZE(amba_devs); i++) {
 170                struct amba_device *d = amba_devs[i];
 171                amba_device_register(d, &iomem_resource);
 172        }
 173
 174        return 0;
 175}
 176
 177arch_initcall(integrator_init);
 178
 179/*
 180 * On the Integrator platform, the port RTS and DTR are provided by
 181 * bits in the following SC_CTRLS register bits:
 182 *        RTS  DTR
 183 *  UART0  7    6
 184 *  UART1  5    4
 185 */
 186#define SC_CTRLC        IO_ADDRESS(INTEGRATOR_SC_CTRLC)
 187#define SC_CTRLS        IO_ADDRESS(INTEGRATOR_SC_CTRLS)
 188
 189static void integrator_uart_set_mctrl(struct amba_device *dev, void __iomem *base, unsigned int mctrl)
 190{
 191        unsigned int ctrls = 0, ctrlc = 0, rts_mask, dtr_mask;
 192
 193        if (dev == &uart0_device) {
 194                rts_mask = 1 << 4;
 195                dtr_mask = 1 << 5;
 196        } else {
 197                rts_mask = 1 << 6;
 198                dtr_mask = 1 << 7;
 199        }
 200
 201        if (mctrl & TIOCM_RTS)
 202                ctrlc |= rts_mask;
 203        else
 204                ctrls |= rts_mask;
 205
 206        if (mctrl & TIOCM_DTR)
 207                ctrlc |= dtr_mask;
 208        else
 209                ctrls |= dtr_mask;
 210
 211        __raw_writel(ctrls, SC_CTRLS);
 212        __raw_writel(ctrlc, SC_CTRLC);
 213}
 214
 215static struct amba_pl010_data integrator_uart_data = {
 216        .set_mctrl = integrator_uart_set_mctrl,
 217};
 218
 219#define CM_CTRL IO_ADDRESS(INTEGRATOR_HDR_CTRL)
 220
 221static DEFINE_RAW_SPINLOCK(cm_lock);
 222
 223/**
 224 * cm_control - update the CM_CTRL register.
 225 * @mask: bits to change
 226 * @set: bits to set
 227 */
 228void cm_control(u32 mask, u32 set)
 229{
 230        unsigned long flags;
 231        u32 val;
 232
 233        raw_spin_lock_irqsave(&cm_lock, flags);
 234        val = readl(CM_CTRL) & ~mask;
 235        writel(val | set, CM_CTRL);
 236        raw_spin_unlock_irqrestore(&cm_lock, flags);
 237}
 238
 239EXPORT_SYMBOL(cm_control);
 240
 241/*
 242 * We need to stop things allocating the low memory; ideally we need a
 243 * better implementation of GFP_DMA which does not assume that DMA-able
 244 * memory starts at zero.
 245 */
 246void __init integrator_reserve(void)
 247{
 248        memblock_reserve(PHYS_OFFSET, __pa(swapper_pg_dir) - PHYS_OFFSET);
 249}
 250
 251/*
 252 * To reset, we hit the on-board reset register in the system FPGA
 253 */
 254void integrator_restart(char mode, const char *cmd)
 255{
 256        cm_control(CM_CTRL_RESET, CM_CTRL_RESET);
 257}
 258