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/sched.h>
  17
  18#include <asm/hardware.h>
  19#include <asm/irq.h>
  20#include <asm/io.h>
  21#include <asm/hardware/amba.h>
  22#include <asm/arch/cm.h>
  23#include <asm/system.h>
  24#include <asm/leds.h>
  25#include <asm/mach/time.h>
  26
  27#include "common.h"
  28
  29static struct amba_device rtc_device = {
  30        .dev            = {
  31                .bus_id = "mb:15",
  32        },
  33        .res            = {
  34                .start  = INTEGRATOR_RTC_BASE,
  35                .end    = INTEGRATOR_RTC_BASE + SZ_4K - 1,
  36                .flags  = IORESOURCE_MEM,
  37        },
  38        .irq            = { IRQ_RTCINT, NO_IRQ },
  39        .periphid       = 0x00041030,
  40};
  41
  42static struct amba_device uart0_device = {
  43        .dev            = {
  44                .bus_id = "mb:16",
  45        },
  46        .res            = {
  47                .start  = INTEGRATOR_UART0_BASE,
  48                .end    = INTEGRATOR_UART0_BASE + SZ_4K - 1,
  49                .flags  = IORESOURCE_MEM,
  50        },
  51        .irq            = { IRQ_UARTINT0, NO_IRQ },
  52        .periphid       = 0x0041010,
  53};
  54
  55static struct amba_device uart1_device = {
  56        .dev            = {
  57                .bus_id = "mb:17",
  58        },
  59        .res            = {
  60                .start  = INTEGRATOR_UART1_BASE,
  61                .end    = INTEGRATOR_UART1_BASE + SZ_4K - 1,
  62                .flags  = IORESOURCE_MEM,
  63        },
  64        .irq            = { IRQ_UARTINT1, NO_IRQ },
  65        .periphid       = 0x0041010,
  66};
  67
  68static struct amba_device kmi0_device = {
  69        .dev            = {
  70                .bus_id = "mb:18",
  71        },
  72        .res            = {
  73                .start  = KMI0_BASE,
  74                .end    = KMI0_BASE + SZ_4K - 1,
  75                .flags  = IORESOURCE_MEM,
  76        },
  77        .irq            = { IRQ_KMIINT0, NO_IRQ },
  78        .periphid       = 0x00041050,
  79};
  80
  81static struct amba_device kmi1_device = {
  82        .dev            = {
  83                .bus_id = "mb:19",
  84        },
  85        .res            = {
  86                .start  = KMI1_BASE,
  87                .end    = KMI1_BASE + SZ_4K - 1,
  88                .flags  = IORESOURCE_MEM,
  89        },
  90        .irq            = { IRQ_KMIINT1, NO_IRQ },
  91        .periphid       = 0x00041050,
  92};
  93
  94static struct amba_device *amba_devs[] __initdata = {
  95        &rtc_device,
  96        &uart0_device,
  97        &uart1_device,
  98        &kmi0_device,
  99        &kmi1_device,
 100};
 101
 102static int __init integrator_init(void)
 103{
 104        int i;
 105
 106        for (i = 0; i < ARRAY_SIZE(amba_devs); i++) {
 107                struct amba_device *d = amba_devs[i];
 108                amba_device_register(d, &iomem_resource);
 109        }
 110
 111        return 0;
 112}
 113
 114arch_initcall(integrator_init);
 115
 116#define CM_CTRL IO_ADDRESS(INTEGRATOR_HDR_BASE) + INTEGRATOR_HDR_CTRL_OFFSET
 117
 118static DEFINE_SPINLOCK(cm_lock);
 119
 120/**
 121 * cm_control - update the CM_CTRL register.
 122 * @mask: bits to change
 123 * @set: bits to set
 124 */
 125void cm_control(u32 mask, u32 set)
 126{
 127        unsigned long flags;
 128        u32 val;
 129
 130        spin_lock_irqsave(&cm_lock, flags);
 131        val = readl(CM_CTRL) & ~mask;
 132        writel(val | set, CM_CTRL);
 133        spin_unlock_irqrestore(&cm_lock, flags);
 134}
 135
 136EXPORT_SYMBOL(cm_control);
 137
 138/*
 139 * Where is the timer (VA)?
 140 */
 141#define TIMER0_VA_BASE (IO_ADDRESS(INTEGRATOR_CT_BASE)+0x00000000)
 142#define TIMER1_VA_BASE (IO_ADDRESS(INTEGRATOR_CT_BASE)+0x00000100)
 143#define TIMER2_VA_BASE (IO_ADDRESS(INTEGRATOR_CT_BASE)+0x00000200)
 144#define VA_IC_BASE     IO_ADDRESS(INTEGRATOR_IC_BASE) 
 145
 146/*
 147 * How long is the timer interval?
 148 */
 149#define TIMER_INTERVAL  (TICKS_PER_uSEC * mSEC_10)
 150#if TIMER_INTERVAL >= 0x100000
 151#define TICKS2USECS(x)  (256 * (x) / TICKS_PER_uSEC)
 152#elif TIMER_INTERVAL >= 0x10000
 153#define TICKS2USECS(x)  (16 * (x) / TICKS_PER_uSEC)
 154#else
 155#define TICKS2USECS(x)  ((x) / TICKS_PER_uSEC)
 156#endif
 157
 158/*
 159 * What does it look like?
 160 */
 161typedef struct TimerStruct {
 162        unsigned long TimerLoad;
 163        unsigned long TimerValue;
 164        unsigned long TimerControl;
 165        unsigned long TimerClear;
 166} TimerStruct_t;
 167
 168static unsigned long timer_reload;
 169
 170/*
 171 * Returns number of ms since last clock interrupt.  Note that interrupts
 172 * will have been disabled by do_gettimeoffset()
 173 */
 174unsigned long integrator_gettimeoffset(void)
 175{
 176        volatile TimerStruct_t *timer1 = (TimerStruct_t *)TIMER1_VA_BASE;
 177        unsigned long ticks1, ticks2, status;
 178
 179        /*
 180         * Get the current number of ticks.  Note that there is a race
 181         * condition between us reading the timer and checking for
 182         * an interrupt.  We get around this by ensuring that the
 183         * counter has not reloaded between our two reads.
 184         */
 185        ticks2 = timer1->TimerValue & 0xffff;
 186        do {
 187                ticks1 = ticks2;
 188                status = __raw_readl(VA_IC_BASE + IRQ_RAW_STATUS);
 189                ticks2 = timer1->TimerValue & 0xffff;
 190        } while (ticks2 > ticks1);
 191
 192        /*
 193         * Number of ticks since last interrupt.
 194         */
 195        ticks1 = timer_reload - ticks2;
 196
 197        /*
 198         * Interrupt pending?  If so, we've reloaded once already.
 199         */
 200        if (status & (1 << IRQ_TIMERINT1))
 201                ticks1 += timer_reload;
 202
 203        /*
 204         * Convert the ticks to usecs
 205         */
 206        return TICKS2USECS(ticks1);
 207}
 208
 209/*
 210 * IRQ handler for the timer
 211 */
 212static irqreturn_t
 213integrator_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
 214{
 215        volatile TimerStruct_t *timer1 = (volatile TimerStruct_t *)TIMER1_VA_BASE;
 216
 217        write_seqlock(&xtime_lock);
 218
 219        // ...clear the interrupt
 220        timer1->TimerClear = 1;
 221
 222        timer_tick(regs);
 223
 224        write_sequnlock(&xtime_lock);
 225
 226        return IRQ_HANDLED;
 227}
 228
 229static struct irqaction integrator_timer_irq = {
 230        .name           = "Integrator Timer Tick",
 231        .flags          = SA_INTERRUPT,
 232        .handler        = integrator_timer_interrupt
 233};
 234
 235/*
 236 * Set up timer interrupt, and return the current time in seconds.
 237 */
 238void __init integrator_time_init(unsigned long reload, unsigned int ctrl)
 239{
 240        volatile TimerStruct_t *timer0 = (volatile TimerStruct_t *)TIMER0_VA_BASE;
 241        volatile TimerStruct_t *timer1 = (volatile TimerStruct_t *)TIMER1_VA_BASE;
 242        volatile TimerStruct_t *timer2 = (volatile TimerStruct_t *)TIMER2_VA_BASE;
 243        unsigned int timer_ctrl = 0x80 | 0x40;  /* periodic */
 244
 245        timer_reload = reload;
 246        timer_ctrl |= ctrl;
 247
 248        if (timer_reload > 0x100000) {
 249                timer_reload >>= 8;
 250                timer_ctrl |= 0x08; /* /256 */
 251        } else if (timer_reload > 0x010000) {
 252                timer_reload >>= 4;
 253                timer_ctrl |= 0x04; /* /16 */
 254        }
 255
 256        /*
 257         * Initialise to a known state (all timers off)
 258         */
 259        timer0->TimerControl = 0;
 260        timer1->TimerControl = 0;
 261        timer2->TimerControl = 0;
 262
 263        timer1->TimerLoad    = timer_reload;
 264        timer1->TimerValue   = timer_reload;
 265        timer1->TimerControl = timer_ctrl;
 266
 267        /* 
 268         * Make irqs happen for the system timer
 269         */
 270        setup_irq(IRQ_TIMERINT1, &integrator_timer_irq);
 271}
 272
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.