linux/arch/arm/mach-realview/core.c
<<
>>
Prefs
   1/*
   2 *  linux/arch/arm/mach-realview/core.c
   3 *
   4 *  Copyright (C) 1999 - 2003 ARM Limited
   5 *  Copyright (C) 2000 Deep Blue Solutions Ltd
   6 *
   7 * This program is free software; you can redistribute it and/or modify
   8 * it under the terms of the GNU General Public License as published by
   9 * the Free Software Foundation; either version 2 of the License, or
  10 * (at your option) any later version.
  11 *
  12 * This program is distributed in the hope that it will be useful,
  13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
  14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  15 * GNU General Public License for more details.
  16 *
  17 * You should have received a copy of the GNU General Public License
  18 * along with this program; if not, write to the Free Software
  19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  20 */
  21#include <linux/init.h>
  22#include <linux/platform_device.h>
  23#include <linux/dma-mapping.h>
  24#include <linux/sysdev.h>
  25#include <linux/interrupt.h>
  26#include <linux/amba/bus.h>
  27#include <linux/amba/clcd.h>
  28#include <linux/clocksource.h>
  29#include <linux/clockchips.h>
  30#include <linux/io.h>
  31
  32#include <asm/system.h>
  33#include <mach/hardware.h>
  34#include <asm/irq.h>
  35#include <asm/leds.h>
  36#include <asm/hardware/arm_timer.h>
  37#include <asm/hardware/icst307.h>
  38
  39#include <asm/mach/arch.h>
  40#include <asm/mach/flash.h>
  41#include <asm/mach/irq.h>
  42#include <asm/mach/map.h>
  43#include <asm/mach/mmc.h>
  44
  45#include <asm/hardware/gic.h>
  46
  47#include "core.h"
  48#include "clock.h"
  49
  50#define REALVIEW_REFCOUNTER     (__io_address(REALVIEW_SYS_BASE) + REALVIEW_SYS_24MHz_OFFSET)
  51
  52/* used by entry-macro.S */
  53void __iomem *gic_cpu_base_addr;
  54
  55/*
  56 * This is the RealView sched_clock implementation.  This has
  57 * a resolution of 41.7ns, and a maximum value of about 179s.
  58 */
  59unsigned long long sched_clock(void)
  60{
  61        unsigned long long v;
  62
  63        v = (unsigned long long)readl(REALVIEW_REFCOUNTER) * 125;
  64        do_div(v, 3);
  65
  66        return v;
  67}
  68
  69
  70#define REALVIEW_FLASHCTRL    (__io_address(REALVIEW_SYS_BASE) + REALVIEW_SYS_FLASH_OFFSET)
  71
  72static int realview_flash_init(void)
  73{
  74        u32 val;
  75
  76        val = __raw_readl(REALVIEW_FLASHCTRL);
  77        val &= ~REALVIEW_FLASHPROG_FLVPPEN;
  78        __raw_writel(val, REALVIEW_FLASHCTRL);
  79
  80        return 0;
  81}
  82
  83static void realview_flash_exit(void)
  84{
  85        u32 val;
  86
  87        val = __raw_readl(REALVIEW_FLASHCTRL);
  88        val &= ~REALVIEW_FLASHPROG_FLVPPEN;
  89        __raw_writel(val, REALVIEW_FLASHCTRL);
  90}
  91
  92static void realview_flash_set_vpp(int on)
  93{
  94        u32 val;
  95
  96        val = __raw_readl(REALVIEW_FLASHCTRL);
  97        if (on)
  98                val |= REALVIEW_FLASHPROG_FLVPPEN;
  99        else
 100                val &= ~REALVIEW_FLASHPROG_FLVPPEN;
 101        __raw_writel(val, REALVIEW_FLASHCTRL);
 102}
 103
 104static struct flash_platform_data realview_flash_data = {
 105        .map_name               = "cfi_probe",
 106        .width                  = 4,
 107        .init                   = realview_flash_init,
 108        .exit                   = realview_flash_exit,
 109        .set_vpp                = realview_flash_set_vpp,
 110};
 111
 112struct platform_device realview_flash_device = {
 113        .name                   = "armflash",
 114        .id                     = 0,
 115        .dev                    = {
 116                .platform_data  = &realview_flash_data,
 117        },
 118};
 119
 120int realview_flash_register(struct resource *res, u32 num)
 121{
 122        realview_flash_device.resource = res;
 123        realview_flash_device.num_resources = num;
 124        return platform_device_register(&realview_flash_device);
 125}
 126
 127static struct resource realview_i2c_resource = {
 128        .start          = REALVIEW_I2C_BASE,
 129        .end            = REALVIEW_I2C_BASE + SZ_4K - 1,
 130        .flags          = IORESOURCE_MEM,
 131};
 132
 133struct platform_device realview_i2c_device = {
 134        .name           = "versatile-i2c",
 135        .id             = -1,
 136        .num_resources  = 1,
 137        .resource       = &realview_i2c_resource,
 138};
 139
 140#define REALVIEW_SYSMCI (__io_address(REALVIEW_SYS_BASE) + REALVIEW_SYS_MCI_OFFSET)
 141
 142static unsigned int realview_mmc_status(struct device *dev)
 143{
 144        struct amba_device *adev = container_of(dev, struct amba_device, dev);
 145        u32 mask;
 146
 147        if (adev->res.start == REALVIEW_MMCI0_BASE)
 148                mask = 1;
 149        else
 150                mask = 2;
 151
 152        return readl(REALVIEW_SYSMCI) & mask;
 153}
 154
 155struct mmc_platform_data realview_mmc0_plat_data = {
 156        .ocr_mask       = MMC_VDD_32_33|MMC_VDD_33_34,
 157        .status         = realview_mmc_status,
 158};
 159
 160struct mmc_platform_data realview_mmc1_plat_data = {
 161        .ocr_mask       = MMC_VDD_32_33|MMC_VDD_33_34,
 162        .status         = realview_mmc_status,
 163};
 164
 165/*
 166 * Clock handling
 167 */
 168static const struct icst307_params realview_oscvco_params = {
 169        .ref            = 24000,
 170        .vco_max        = 200000,
 171        .vd_min         = 4 + 8,
 172        .vd_max         = 511 + 8,
 173        .rd_min         = 1 + 2,
 174        .rd_max         = 127 + 2,
 175};
 176
 177static void realview_oscvco_set(struct clk *clk, struct icst307_vco vco)
 178{
 179        void __iomem *sys_lock = __io_address(REALVIEW_SYS_BASE) + REALVIEW_SYS_LOCK_OFFSET;
 180        void __iomem *sys_osc = __io_address(REALVIEW_SYS_BASE) + REALVIEW_SYS_OSC4_OFFSET;
 181        u32 val;
 182
 183        val = readl(sys_osc) & ~0x7ffff;
 184        val |= vco.v | (vco.r << 9) | (vco.s << 16);
 185
 186        writel(0xa05f, sys_lock);
 187        writel(val, sys_osc);
 188        writel(0, sys_lock);
 189}
 190
 191struct clk realview_clcd_clk = {
 192        .name   = "CLCDCLK",
 193        .params = &realview_oscvco_params,
 194        .setvco = realview_oscvco_set,
 195};
 196
 197/*
 198 * CLCD support.
 199 */
 200#define SYS_CLCD_NLCDIOON       (1 << 2)
 201#define SYS_CLCD_VDDPOSSWITCH   (1 << 3)
 202#define SYS_CLCD_PWR3V5SWITCH   (1 << 4)
 203#define SYS_CLCD_ID_MASK        (0x1f << 8)
 204#define SYS_CLCD_ID_SANYO_3_8   (0x00 << 8)
 205#define SYS_CLCD_ID_UNKNOWN_8_4 (0x01 << 8)
 206#define SYS_CLCD_ID_EPSON_2_2   (0x02 << 8)
 207#define SYS_CLCD_ID_SANYO_2_5   (0x07 << 8)
 208#define SYS_CLCD_ID_VGA         (0x1f << 8)
 209
 210static struct clcd_panel vga = {
 211        .mode           = {
 212                .name           = "VGA",
 213                .refresh        = 60,
 214                .xres           = 640,
 215                .yres           = 480,
 216                .pixclock       = 39721,
 217                .left_margin    = 40,
 218                .right_margin   = 24,
 219                .upper_margin   = 32,
 220                .lower_margin   = 11,
 221                .hsync_len      = 96,
 222                .vsync_len      = 2,
 223                .sync           = 0,
 224                .vmode          = FB_VMODE_NONINTERLACED,
 225        },
 226        .width          = -1,
 227        .height         = -1,
 228        .tim2           = TIM2_BCD | TIM2_IPC,
 229        .cntl           = CNTL_LCDTFT | CNTL_LCDVCOMP(1),
 230        .bpp            = 16,
 231};
 232
 233static struct clcd_panel sanyo_3_8_in = {
 234        .mode           = {
 235                .name           = "Sanyo QVGA",
 236                .refresh        = 116,
 237                .xres           = 320,
 238                .yres           = 240,
 239                .pixclock       = 100000,
 240                .left_margin    = 6,
 241                .right_margin   = 6,
 242                .upper_margin   = 5,
 243                .lower_margin   = 5,
 244                .hsync_len      = 6,
 245                .vsync_len      = 6,
 246                .sync           = 0,
 247                .vmode          = FB_VMODE_NONINTERLACED,
 248        },
 249        .width          = -1,
 250        .height         = -1,
 251        .tim2           = TIM2_BCD,
 252        .cntl           = CNTL_LCDTFT | CNTL_LCDVCOMP(1),
 253        .bpp            = 16,
 254};
 255
 256static struct clcd_panel sanyo_2_5_in = {
 257        .mode           = {
 258                .name           = "Sanyo QVGA Portrait",
 259                .refresh        = 116,
 260                .xres           = 240,
 261                .yres           = 320,
 262                .pixclock       = 100000,
 263                .left_margin    = 20,
 264                .right_margin   = 10,
 265                .upper_margin   = 2,
 266                .lower_margin   = 2,
 267                .hsync_len      = 10,
 268                .vsync_len      = 2,
 269                .sync           = FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
 270                .vmode          = FB_VMODE_NONINTERLACED,
 271        },
 272        .width          = -1,
 273        .height         = -1,
 274        .tim2           = TIM2_IVS | TIM2_IHS | TIM2_IPC,
 275        .cntl           = CNTL_LCDTFT | CNTL_LCDVCOMP(1),
 276        .bpp            = 16,
 277};
 278
 279static struct clcd_panel epson_2_2_in = {
 280        .mode           = {
 281                .name           = "Epson QCIF",
 282                .refresh        = 390,
 283                .xres           = 176,
 284                .yres           = 220,
 285                .pixclock       = 62500,
 286                .left_margin    = 3,
 287                .right_margin   = 2,
 288                .upper_margin   = 1,
 289                .lower_margin   = 0,
 290                .hsync_len      = 3,
 291                .vsync_len      = 2,
 292                .sync           = 0,
 293                .vmode          = FB_VMODE_NONINTERLACED,
 294        },
 295        .width          = -1,
 296        .height         = -1,
 297        .tim2           = TIM2_BCD | TIM2_IPC,
 298        .cntl           = CNTL_LCDTFT | CNTL_LCDVCOMP(1),
 299        .bpp            = 16,
 300};
 301
 302/*
 303 * Detect which LCD panel is connected, and return the appropriate
 304 * clcd_panel structure.  Note: we do not have any information on
 305 * the required timings for the 8.4in panel, so we presently assume
 306 * VGA timings.
 307 */
 308static struct clcd_panel *realview_clcd_panel(void)
 309{
 310        void __iomem *sys_clcd = __io_address(REALVIEW_SYS_BASE) + REALVIEW_SYS_CLCD_OFFSET;
 311        struct clcd_panel *panel = &vga;
 312        u32 val;
 313
 314        val = readl(sys_clcd) & SYS_CLCD_ID_MASK;
 315        if (val == SYS_CLCD_ID_SANYO_3_8)
 316                panel = &sanyo_3_8_in;
 317        else if (val == SYS_CLCD_ID_SANYO_2_5)
 318                panel = &sanyo_2_5_in;
 319        else if (val == SYS_CLCD_ID_EPSON_2_2)
 320                panel = &epson_2_2_in;
 321        else if (val == SYS_CLCD_ID_VGA)
 322                panel = &vga;
 323        else {
 324                printk(KERN_ERR "CLCD: unknown LCD panel ID 0x%08x, using VGA\n",
 325                        val);
 326                panel = &vga;
 327        }
 328
 329        return panel;
 330}
 331
 332/*
 333 * Disable all display connectors on the interface module.
 334 */
 335static void realview_clcd_disable(struct clcd_fb *fb)
 336{
 337        void __iomem *sys_clcd = __io_address(REALVIEW_SYS_BASE) + REALVIEW_SYS_CLCD_OFFSET;
 338        u32 val;
 339
 340        val = readl(sys_clcd);
 341        val &= ~SYS_CLCD_NLCDIOON | SYS_CLCD_PWR3V5SWITCH;
 342        writel(val, sys_clcd);
 343}
 344
 345/*
 346 * Enable the relevant connector on the interface module.
 347 */
 348static void realview_clcd_enable(struct clcd_fb *fb)
 349{
 350        void __iomem *sys_clcd = __io_address(REALVIEW_SYS_BASE) + REALVIEW_SYS_CLCD_OFFSET;
 351        u32 val;
 352
 353        /*
 354         * Enable the PSUs
 355         */
 356        val = readl(sys_clcd);
 357        val |= SYS_CLCD_NLCDIOON | SYS_CLCD_PWR3V5SWITCH;
 358        writel(val, sys_clcd);
 359}
 360
 361static unsigned long framesize = SZ_1M;
 362
 363static int realview_clcd_setup(struct clcd_fb *fb)
 364{
 365        dma_addr_t dma;
 366
 367        fb->panel               = realview_clcd_panel();
 368
 369        fb->fb.screen_base = dma_alloc_writecombine(&fb->dev->dev, framesize,
 370                                                    &dma, GFP_KERNEL);
 371        if (!fb->fb.screen_base) {
 372                printk(KERN_ERR "CLCD: unable to map framebuffer\n");
 373                return -ENOMEM;
 374        }
 375
 376        fb->fb.fix.smem_start   = dma;
 377        fb->fb.fix.smem_len     = framesize;
 378
 379        return 0;
 380}
 381
 382static int realview_clcd_mmap(struct clcd_fb *fb, struct vm_area_struct *vma)
 383{
 384        return dma_mmap_writecombine(&fb->dev->dev, vma,
 385                                     fb->fb.screen_base,
 386                                     fb->fb.fix.smem_start,
 387                                     fb->fb.fix.smem_len);
 388}
 389
 390static void realview_clcd_remove(struct clcd_fb *fb)
 391{
 392        dma_free_writecombine(&fb->dev->dev, fb->fb.fix.smem_len,
 393                              fb->fb.screen_base, fb->fb.fix.smem_start);
 394}
 395
 396struct clcd_board clcd_plat_data = {
 397        .name           = "RealView",
 398        .check          = clcdfb_check,
 399        .decode         = clcdfb_decode,
 400        .disable        = realview_clcd_disable,
 401        .enable         = realview_clcd_enable,
 402        .setup          = realview_clcd_setup,
 403        .mmap           = realview_clcd_mmap,
 404        .remove         = realview_clcd_remove,
 405};
 406
 407#ifdef CONFIG_LEDS
 408#define VA_LEDS_BASE (__io_address(REALVIEW_SYS_BASE) + REALVIEW_SYS_LED_OFFSET)
 409
 410void realview_leds_event(led_event_t ledevt)
 411{
 412        unsigned long flags;
 413        u32 val;
 414
 415        local_irq_save(flags);
 416        val = readl(VA_LEDS_BASE);
 417
 418        switch (ledevt) {
 419        case led_idle_start:
 420                val = val & ~REALVIEW_SYS_LED0;
 421                break;
 422
 423        case led_idle_end:
 424                val = val | REALVIEW_SYS_LED0;
 425                break;
 426
 427        case led_timer:
 428                val = val ^ REALVIEW_SYS_LED1;
 429                break;
 430
 431        case led_halted:
 432                val = 0;
 433                break;
 434
 435        default:
 436                break;
 437        }
 438
 439        writel(val, VA_LEDS_BASE);
 440        local_irq_restore(flags);
 441}
 442#endif  /* CONFIG_LEDS */
 443
 444/*
 445 * Where is the timer (VA)?
 446 */
 447void __iomem *timer0_va_base;
 448void __iomem *timer1_va_base;
 449void __iomem *timer2_va_base;
 450void __iomem *timer3_va_base;
 451
 452/*
 453 * How long is the timer interval?
 454 */
 455#define TIMER_INTERVAL  (TICKS_PER_uSEC * mSEC_10)
 456#if TIMER_INTERVAL >= 0x100000
 457#define TIMER_RELOAD    (TIMER_INTERVAL >> 8)
 458#define TIMER_DIVISOR   (TIMER_CTRL_DIV256)
 459#define TICKS2USECS(x)  (256 * (x) / TICKS_PER_uSEC)
 460#elif TIMER_INTERVAL >= 0x10000
 461#define TIMER_RELOAD    (TIMER_INTERVAL >> 4)           /* Divide by 16 */
 462#define TIMER_DIVISOR   (TIMER_CTRL_DIV16)
 463#define TICKS2USECS(x)  (16 * (x) / TICKS_PER_uSEC)
 464#else
 465#define TIMER_RELOAD    (TIMER_INTERVAL)
 466#define TIMER_DIVISOR   (TIMER_CTRL_DIV1)
 467#define TICKS2USECS(x)  ((x) / TICKS_PER_uSEC)
 468#endif
 469
 470static void timer_set_mode(enum clock_event_mode mode,
 471                           struct clock_event_device *clk)
 472{
 473        unsigned long ctrl;
 474
 475        switch(mode) {
 476        case CLOCK_EVT_MODE_PERIODIC:
 477                writel(TIMER_RELOAD, timer0_va_base + TIMER_LOAD);
 478
 479                ctrl = TIMER_CTRL_PERIODIC;
 480                ctrl |= TIMER_CTRL_32BIT | TIMER_CTRL_IE | TIMER_CTRL_ENABLE;
 481                break;
 482        case CLOCK_EVT_MODE_ONESHOT:
 483                /* period set, and timer enabled in 'next_event' hook */
 484                ctrl = TIMER_CTRL_ONESHOT;
 485                ctrl |= TIMER_CTRL_32BIT | TIMER_CTRL_IE;
 486                break;
 487        case CLOCK_EVT_MODE_UNUSED:
 488        case CLOCK_EVT_MODE_SHUTDOWN:
 489        default:
 490                ctrl = 0;
 491        }
 492
 493        writel(ctrl, timer0_va_base + TIMER_CTRL);
 494}
 495
 496static int timer_set_next_event(unsigned long evt,
 497                                struct clock_event_device *unused)
 498{
 499        unsigned long ctrl = readl(timer0_va_base + TIMER_CTRL);
 500
 501        writel(evt, timer0_va_base + TIMER_LOAD);
 502        writel(ctrl | TIMER_CTRL_ENABLE, timer0_va_base + TIMER_CTRL);
 503
 504        return 0;
 505}
 506
 507static struct clock_event_device timer0_clockevent =     {
 508        .name           = "timer0",
 509        .shift          = 32,
 510        .features       = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT,
 511        .set_mode       = timer_set_mode,
 512        .set_next_event = timer_set_next_event,
 513        .rating         = 300,
 514        .cpumask        = CPU_MASK_ALL,
 515};
 516
 517static void __init realview_clockevents_init(unsigned int timer_irq)
 518{
 519        timer0_clockevent.irq = timer_irq;
 520        timer0_clockevent.mult =
 521                div_sc(1000000, NSEC_PER_SEC, timer0_clockevent.shift);
 522        timer0_clockevent.max_delta_ns =
 523                clockevent_delta2ns(0xffffffff, &timer0_clockevent);
 524        timer0_clockevent.min_delta_ns =
 525                clockevent_delta2ns(0xf, &timer0_clockevent);
 526
 527        clockevents_register_device(&timer0_clockevent);
 528}
 529
 530/*
 531 * IRQ handler for the timer
 532 */
 533static irqreturn_t realview_timer_interrupt(int irq, void *dev_id)
 534{
 535        struct clock_event_device *evt = &timer0_clockevent;
 536
 537        /* clear the interrupt */
 538        writel(1, timer0_va_base + TIMER_INTCLR);
 539
 540        evt->event_handler(evt);
 541
 542        return IRQ_HANDLED;
 543}
 544
 545static struct irqaction realview_timer_irq = {
 546        .name           = "RealView Timer Tick",
 547        .flags          = IRQF_DISABLED | IRQF_TIMER | IRQF_IRQPOLL,
 548        .handler        = realview_timer_interrupt,
 549};
 550
 551static cycle_t realview_get_cycles(void)
 552{
 553        return ~readl(timer3_va_base + TIMER_VALUE);
 554}
 555
 556static struct clocksource clocksource_realview = {
 557        .name   = "timer3",
 558        .rating = 200,
 559        .read   = realview_get_cycles,
 560        .mask   = CLOCKSOURCE_MASK(32),
 561        .shift  = 20,
 562        .flags  = CLOCK_SOURCE_IS_CONTINUOUS,
 563};
 564
 565static void __init realview_clocksource_init(void)
 566{
 567        /* setup timer 0 as free-running clocksource */
 568        writel(0, timer3_va_base + TIMER_CTRL);
 569        writel(0xffffffff, timer3_va_base + TIMER_LOAD);
 570        writel(0xffffffff, timer3_va_base + TIMER_VALUE);
 571        writel(TIMER_CTRL_32BIT | TIMER_CTRL_ENABLE | TIMER_CTRL_PERIODIC,
 572                timer3_va_base + TIMER_CTRL);
 573
 574        clocksource_realview.mult =
 575                clocksource_khz2mult(1000, clocksource_realview.shift);
 576        clocksource_register(&clocksource_realview);
 577}
 578
 579/*
 580 * Set up the clock source and clock events devices
 581 */
 582void __init realview_timer_init(unsigned int timer_irq)
 583{
 584        u32 val;
 585
 586#ifdef CONFIG_GENERIC_CLOCKEVENTS_BROADCAST
 587        /*
 588         * The dummy clock device has to be registered before the main device
 589         * so that the latter will broadcast the clock events
 590         */
 591        local_timer_setup(smp_processor_id());
 592#endif
 593
 594        /* 
 595         * set clock frequency: 
 596         *      REALVIEW_REFCLK is 32KHz
 597         *      REALVIEW_TIMCLK is 1MHz
 598         */
 599        val = readl(__io_address(REALVIEW_SCTL_BASE));
 600        writel((REALVIEW_TIMCLK << REALVIEW_TIMER1_EnSel) |
 601               (REALVIEW_TIMCLK << REALVIEW_TIMER2_EnSel) | 
 602               (REALVIEW_TIMCLK << REALVIEW_TIMER3_EnSel) |
 603               (REALVIEW_TIMCLK << REALVIEW_TIMER4_EnSel) | val,
 604               __io_address(REALVIEW_SCTL_BASE));
 605
 606        /*
 607         * Initialise to a known state (all timers off)
 608         */
 609        writel(0, timer0_va_base + TIMER_CTRL);
 610        writel(0, timer1_va_base + TIMER_CTRL);
 611        writel(0, timer2_va_base + TIMER_CTRL);
 612        writel(0, timer3_va_base + TIMER_CTRL);
 613
 614        /* 
 615         * Make irqs happen for the system timer
 616         */
 617        setup_irq(timer_irq, &realview_timer_irq);
 618
 619        realview_clocksource_init();
 620        realview_clockevents_init(timer_irq);
 621}
 622
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.