linux/arch/arm/mach-aaec2000/core.c
<<
>>
Prefs
   1/*
   2 *  linux/arch/arm/mach-aaec2000/core.c
   3 *
   4 *  Code common to all AAEC-2000 machines
   5 *
   6 *  Copyright (c) 2005 Nicolas Bellido Y Ortega
   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#include <linux/module.h>
  13#include <linux/kernel.h>
  14#include <linux/init.h>
  15#include <linux/platform_device.h>
  16#include <linux/list.h>
  17#include <linux/errno.h>
  18#include <linux/dma-mapping.h>
  19#include <linux/interrupt.h>
  20#include <linux/timex.h>
  21#include <linux/signal.h>
  22#include <linux/clk.h>
  23
  24#include <mach/hardware.h>
  25#include <asm/irq.h>
  26#include <asm/sizes.h>
  27
  28#include <asm/mach/flash.h>
  29#include <asm/mach/irq.h>
  30#include <asm/mach/time.h>
  31#include <asm/mach/map.h>
  32
  33#include "core.h"
  34
  35/*
  36 * Common I/O mapping:
  37 *
  38 * Static virtual address mappings are as follow:
  39 *
  40 * 0xf8000000-0xf8001ffff: Devices connected to APB bus
  41 * 0xf8002000-0xf8003ffff: Devices connected to AHB bus
  42 *
  43 * Below 0xe8000000 is reserved for vm allocation.
  44 *
  45 * The machine specific code must provide the extra mapping beside the
  46 * default mapping provided here.
  47 */
  48static struct map_desc standard_io_desc[] __initdata = {
  49        {
  50                .virtual        = VIO_APB_BASE,
  51                .pfn            = __phys_to_pfn(PIO_APB_BASE),
  52                .length         = IO_APB_LENGTH,
  53                .type           = MT_DEVICE
  54        }, {
  55                .virtual        = VIO_AHB_BASE,
  56                .pfn            = __phys_to_pfn(PIO_AHB_BASE),
  57                .length         = IO_AHB_LENGTH,
  58                .type           = MT_DEVICE
  59        }
  60};
  61
  62void __init aaec2000_map_io(void)
  63{
  64        iotable_init(standard_io_desc, ARRAY_SIZE(standard_io_desc));
  65}
  66
  67/*
  68 * Interrupt handling routines
  69 */
  70static void aaec2000_int_ack(unsigned int irq)
  71{
  72        IRQ_INTSR = 1 << irq;
  73}
  74
  75static void aaec2000_int_mask(unsigned int irq)
  76{
  77        IRQ_INTENC |= (1 << irq);
  78}
  79
  80static void aaec2000_int_unmask(unsigned int irq)
  81{
  82        IRQ_INTENS |= (1 << irq);
  83}
  84
  85static struct irq_chip aaec2000_irq_chip = {
  86        .ack    = aaec2000_int_ack,
  87        .mask   = aaec2000_int_mask,
  88        .unmask = aaec2000_int_unmask,
  89};
  90
  91void __init aaec2000_init_irq(void)
  92{
  93        unsigned int i;
  94
  95        for (i = 0; i < NR_IRQS; i++) {
  96                set_irq_handler(i, handle_level_irq);
  97                set_irq_chip(i, &aaec2000_irq_chip);
  98                set_irq_flags(i, IRQF_VALID);
  99        }
 100
 101        /* Disable all interrupts */
 102        IRQ_INTENC = 0xffffffff;
 103
 104        /* Clear any pending interrupts */
 105        IRQ_INTSR = IRQ_INTSR;
 106}
 107
 108/*
 109 * Time keeping
 110 */
 111/* IRQs are disabled before entering here from do_gettimeofday() */
 112static unsigned long aaec2000_gettimeoffset(void)
 113{
 114        unsigned long ticks_to_match, elapsed, usec;
 115
 116        /* Get ticks before next timer match */
 117        ticks_to_match = TIMER1_LOAD - TIMER1_VAL;
 118
 119        /* We need elapsed ticks since last match */
 120        elapsed = LATCH - ticks_to_match;
 121
 122        /* Now, convert them to usec */
 123        usec = (unsigned long)(elapsed * (tick_nsec / 1000))/LATCH;
 124
 125        return usec;
 126}
 127
 128/* We enter here with IRQs enabled */
 129static irqreturn_t
 130aaec2000_timer_interrupt(int irq, void *dev_id)
 131{
 132        /* TODO: Check timer accuracy */
 133        timer_tick();
 134        TIMER1_CLEAR = 1;
 135
 136        return IRQ_HANDLED;
 137}
 138
 139static struct irqaction aaec2000_timer_irq = {
 140        .name           = "AAEC-2000 Timer Tick",
 141        .flags          = IRQF_DISABLED | IRQF_TIMER | IRQF_IRQPOLL,
 142        .handler        = aaec2000_timer_interrupt,
 143};
 144
 145static void __init aaec2000_timer_init(void)
 146{
 147        /* Disable timer 1 */
 148        TIMER1_CTRL = 0;
 149
 150        /* We have somehow to generate a 100Hz clock.
 151         * We then use the 508KHz timer in periodic mode.
 152         */
 153        TIMER1_LOAD = LATCH;
 154        TIMER1_CLEAR = 1; /* Clear interrupt */
 155
 156        setup_irq(INT_TMR1_OFL, &aaec2000_timer_irq);
 157
 158        TIMER1_CTRL = TIMER_CTRL_ENABLE |
 159                        TIMER_CTRL_PERIODIC |
 160                        TIMER_CTRL_CLKSEL_508K;
 161}
 162
 163struct sys_timer aaec2000_timer = {
 164        .init           = aaec2000_timer_init,
 165        .offset         = aaec2000_gettimeoffset,
 166};
 167
 168static struct clcd_panel mach_clcd_panel;
 169
 170static int aaec2000_clcd_setup(struct clcd_fb *fb)
 171{
 172        dma_addr_t dma;
 173
 174        fb->panel = &mach_clcd_panel;
 175
 176        fb->fb.screen_base = dma_alloc_writecombine(&fb->dev->dev, SZ_1M,
 177                        &dma, GFP_KERNEL);
 178
 179        if (!fb->fb.screen_base) {
 180                printk(KERN_ERR "CLCD: unable to map framebuffer\n");
 181                return -ENOMEM;
 182        }
 183
 184        fb->fb.fix.smem_start = dma;
 185        fb->fb.fix.smem_len = SZ_1M;
 186
 187        return 0;
 188}
 189
 190static int aaec2000_clcd_mmap(struct clcd_fb *fb, struct vm_area_struct *vma)
 191{
 192        return dma_mmap_writecombine(&fb->dev->dev, vma,
 193                        fb->fb.screen_base,
 194                        fb->fb.fix.smem_start,
 195                        fb->fb.fix.smem_len);
 196}
 197
 198static void aaec2000_clcd_remove(struct clcd_fb *fb)
 199{
 200        dma_free_writecombine(&fb->dev->dev, fb->fb.fix.smem_len,
 201                        fb->fb.screen_base, fb->fb.fix.smem_start);
 202}
 203
 204static struct clcd_board clcd_plat_data = {
 205        .name   = "AAEC-2000",
 206        .check  = clcdfb_check,
 207        .decode = clcdfb_decode,
 208        .setup  = aaec2000_clcd_setup,
 209        .mmap   = aaec2000_clcd_mmap,
 210        .remove = aaec2000_clcd_remove,
 211};
 212
 213static struct amba_device clcd_device = {
 214        .dev            = {
 215                .init_name              = "mb:16",
 216                .coherent_dma_mask      = ~0,
 217                .platform_data          = &clcd_plat_data,
 218        },
 219        .res            = {
 220                .start                  = AAEC_CLCD_PHYS,
 221                .end                    = AAEC_CLCD_PHYS + SZ_4K - 1,
 222                .flags                  = IORESOURCE_MEM,
 223        },
 224        .irq            = { INT_LCD, NO_IRQ },
 225        .periphid       = 0x41110,
 226};
 227
 228static struct amba_device *amba_devs[] __initdata = {
 229        &clcd_device,
 230};
 231
 232void clk_disable(struct clk *clk)
 233{
 234}
 235
 236int clk_set_rate(struct clk *clk, unsigned long rate)
 237{
 238        return 0;
 239}
 240
 241int clk_enable(struct clk *clk)
 242{
 243        return 0;
 244}
 245
 246struct clk *clk_get(struct device *dev, const char *id)
 247{
 248        return dev && strcmp(dev_name(dev), "mb:16") == 0 ? NULL : ERR_PTR(-ENOENT);
 249}
 250
 251void clk_put(struct clk *clk)
 252{
 253}
 254
 255void __init aaec2000_set_clcd_plat_data(struct aaec2000_clcd_info *clcd)
 256{
 257        clcd_plat_data.enable = clcd->enable;
 258        clcd_plat_data.disable = clcd->disable;
 259        memcpy(&mach_clcd_panel, &clcd->panel, sizeof(struct clcd_panel));
 260}
 261
 262static struct flash_platform_data aaec2000_flash_data = {
 263        .map_name       = "cfi_probe",
 264        .width          = 4,
 265};
 266
 267static struct resource aaec2000_flash_resource = {
 268        .start          = AAEC_FLASH_BASE,
 269        .end            = AAEC_FLASH_BASE + AAEC_FLASH_SIZE,
 270        .flags          = IORESOURCE_MEM,
 271};
 272
 273static struct platform_device aaec2000_flash_device = {
 274        .name           = "armflash",
 275        .id             = 0,
 276        .dev            = {
 277                .platform_data  = &aaec2000_flash_data,
 278        },
 279        .num_resources  = 1,
 280        .resource       = &aaec2000_flash_resource,
 281};
 282
 283static int __init aaec2000_init(void)
 284{
 285        int i;
 286
 287        for (i = 0; i < ARRAY_SIZE(amba_devs); i++) {
 288                struct amba_device *d = amba_devs[i];
 289                amba_device_register(d, &iomem_resource);
 290        }
 291
 292        platform_device_register(&aaec2000_flash_device);
 293
 294        return 0;
 295};
 296arch_initcall(aaec2000_init);
 297
 298