linux/arch/arm/mach-s3c24xx/mach-osiris.c
<<
>>
Prefs
   1/*
   2 * Copyright (c) 2005-2008 Simtec Electronics
   3 *      http://armlinux.simtec.co.uk/
   4 *      Ben Dooks <ben@simtec.co.uk>
   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
  11#include <linux/kernel.h>
  12#include <linux/types.h>
  13#include <linux/interrupt.h>
  14#include <linux/list.h>
  15#include <linux/timer.h>
  16#include <linux/init.h>
  17#include <linux/gpio.h>
  18#include <linux/device.h>
  19#include <linux/syscore_ops.h>
  20#include <linux/serial_core.h>
  21#include <linux/serial_s3c.h>
  22#include <linux/clk.h>
  23#include <linux/i2c.h>
  24#include <linux/io.h>
  25#include <linux/platform_device.h>
  26
  27#include <linux/i2c/tps65010.h>
  28
  29#include <asm/mach-types.h>
  30#include <asm/mach/arch.h>
  31#include <asm/mach/map.h>
  32#include <asm/mach/irq.h>
  33#include <asm/irq.h>
  34
  35#include <linux/platform_data/mtd-nand-s3c2410.h>
  36#include <linux/platform_data/i2c-s3c2410.h>
  37
  38#include <linux/mtd/mtd.h>
  39#include <linux/mtd/nand.h>
  40#include <linux/mtd/nand_ecc.h>
  41#include <linux/mtd/partitions.h>
  42
  43#include <plat/cpu.h>
  44#include <plat/cpu-freq.h>
  45#include <plat/devs.h>
  46#include <plat/gpio-cfg.h>
  47#include <plat/samsung-time.h>
  48
  49#include <mach/hardware.h>
  50#include <mach/regs-gpio.h>
  51#include <mach/regs-lcd.h>
  52#include <mach/gpio-samsung.h>
  53
  54#include "common.h"
  55#include "osiris.h"
  56#include "regs-mem.h"
  57
  58/* onboard perihperal map */
  59
  60static struct map_desc osiris_iodesc[] __initdata = {
  61  /* ISA IO areas (may be over-written later) */
  62
  63  {
  64          .virtual      = (u32)S3C24XX_VA_ISA_BYTE,
  65          .pfn          = __phys_to_pfn(S3C2410_CS5),
  66          .length       = SZ_16M,
  67          .type         = MT_DEVICE,
  68  }, {
  69          .virtual      = (u32)S3C24XX_VA_ISA_WORD,
  70          .pfn          = __phys_to_pfn(S3C2410_CS5),
  71          .length       = SZ_16M,
  72          .type         = MT_DEVICE,
  73  },
  74
  75  /* CPLD control registers */
  76
  77  {
  78          .virtual      = (u32)OSIRIS_VA_CTRL0,
  79          .pfn          = __phys_to_pfn(OSIRIS_PA_CTRL0),
  80          .length       = SZ_16K,
  81          .type         = MT_DEVICE,
  82  }, {
  83          .virtual      = (u32)OSIRIS_VA_CTRL1,
  84          .pfn          = __phys_to_pfn(OSIRIS_PA_CTRL1),
  85          .length       = SZ_16K,
  86          .type         = MT_DEVICE,
  87  }, {
  88          .virtual      = (u32)OSIRIS_VA_CTRL2,
  89          .pfn          = __phys_to_pfn(OSIRIS_PA_CTRL2),
  90          .length       = SZ_16K,
  91          .type         = MT_DEVICE,
  92  }, {
  93          .virtual      = (u32)OSIRIS_VA_IDREG,
  94          .pfn          = __phys_to_pfn(OSIRIS_PA_IDREG),
  95          .length       = SZ_16K,
  96          .type         = MT_DEVICE,
  97  },
  98};
  99
 100#define UCON S3C2410_UCON_DEFAULT | S3C2410_UCON_UCLK
 101#define ULCON S3C2410_LCON_CS8 | S3C2410_LCON_PNONE | S3C2410_LCON_STOPB
 102#define UFCON S3C2410_UFCON_RXTRIG8 | S3C2410_UFCON_FIFOMODE
 103
 104static struct s3c2410_uartcfg osiris_uartcfgs[] __initdata = {
 105        [0] = {
 106                .hwport      = 0,
 107                .flags       = 0,
 108                .ucon        = UCON,
 109                .ulcon       = ULCON,
 110                .ufcon       = UFCON,
 111                .clk_sel        = S3C2410_UCON_CLKSEL1 | S3C2410_UCON_CLKSEL2,
 112        },
 113        [1] = {
 114                .hwport      = 1,
 115                .flags       = 0,
 116                .ucon        = UCON,
 117                .ulcon       = ULCON,
 118                .ufcon       = UFCON,
 119                .clk_sel        = S3C2410_UCON_CLKSEL1 | S3C2410_UCON_CLKSEL2,
 120        },
 121        [2] = {
 122                .hwport      = 2,
 123                .flags       = 0,
 124                .ucon        = UCON,
 125                .ulcon       = ULCON,
 126                .ufcon       = UFCON,
 127                .clk_sel        = S3C2410_UCON_CLKSEL1 | S3C2410_UCON_CLKSEL2,
 128        }
 129};
 130
 131/* NAND Flash on Osiris board */
 132
 133static int external_map[]   = { 2 };
 134static int chip0_map[]      = { 0 };
 135static int chip1_map[]      = { 1 };
 136
 137static struct mtd_partition __initdata osiris_default_nand_part[] = {
 138        [0] = {
 139                .name   = "Boot Agent",
 140                .size   = SZ_16K,
 141                .offset = 0,
 142        },
 143        [1] = {
 144                .name   = "/boot",
 145                .size   = SZ_4M - SZ_16K,
 146                .offset = SZ_16K,
 147        },
 148        [2] = {
 149                .name   = "user1",
 150                .offset = SZ_4M,
 151                .size   = SZ_32M - SZ_4M,
 152        },
 153        [3] = {
 154                .name   = "user2",
 155                .offset = SZ_32M,
 156                .size   = MTDPART_SIZ_FULL,
 157        }
 158};
 159
 160static struct mtd_partition __initdata osiris_default_nand_part_large[] = {
 161        [0] = {
 162                .name   = "Boot Agent",
 163                .size   = SZ_128K,
 164                .offset = 0,
 165        },
 166        [1] = {
 167                .name   = "/boot",
 168                .size   = SZ_4M - SZ_128K,
 169                .offset = SZ_128K,
 170        },
 171        [2] = {
 172                .name   = "user1",
 173                .offset = SZ_4M,
 174                .size   = SZ_32M - SZ_4M,
 175        },
 176        [3] = {
 177                .name   = "user2",
 178                .offset = SZ_32M,
 179                .size   = MTDPART_SIZ_FULL,
 180        }
 181};
 182
 183/* the Osiris has 3 selectable slots for nand-flash, the two
 184 * on-board chip areas, as well as the external slot.
 185 *
 186 * Note, there is no current hot-plug support for the External
 187 * socket.
 188*/
 189
 190static struct s3c2410_nand_set __initdata osiris_nand_sets[] = {
 191        [1] = {
 192                .name           = "External",
 193                .nr_chips       = 1,
 194                .nr_map         = external_map,
 195                .options        = NAND_SCAN_SILENT_NODEV,
 196                .nr_partitions  = ARRAY_SIZE(osiris_default_nand_part),
 197                .partitions     = osiris_default_nand_part,
 198        },
 199        [0] = {
 200                .name           = "chip0",
 201                .nr_chips       = 1,
 202                .nr_map         = chip0_map,
 203                .nr_partitions  = ARRAY_SIZE(osiris_default_nand_part),
 204                .partitions     = osiris_default_nand_part,
 205        },
 206        [2] = {
 207                .name           = "chip1",
 208                .nr_chips       = 1,
 209                .nr_map         = chip1_map,
 210                .options        = NAND_SCAN_SILENT_NODEV,
 211                .nr_partitions  = ARRAY_SIZE(osiris_default_nand_part),
 212                .partitions     = osiris_default_nand_part,
 213        },
 214};
 215
 216static void osiris_nand_select(struct s3c2410_nand_set *set, int slot)
 217{
 218        unsigned int tmp;
 219
 220        slot = set->nr_map[slot] & 3;
 221
 222        pr_debug("osiris_nand: selecting slot %d (set %p,%p)\n",
 223                 slot, set, set->nr_map);
 224
 225        tmp = __raw_readb(OSIRIS_VA_CTRL0);
 226        tmp &= ~OSIRIS_CTRL0_NANDSEL;
 227        tmp |= slot;
 228
 229        pr_debug("osiris_nand: ctrl0 now %02x\n", tmp);
 230
 231        __raw_writeb(tmp, OSIRIS_VA_CTRL0);
 232}
 233
 234static struct s3c2410_platform_nand __initdata osiris_nand_info = {
 235        .tacls          = 25,
 236        .twrph0         = 60,
 237        .twrph1         = 60,
 238        .nr_sets        = ARRAY_SIZE(osiris_nand_sets),
 239        .sets           = osiris_nand_sets,
 240        .select_chip    = osiris_nand_select,
 241        .ecc_mode       = NAND_ECC_SOFT,
 242};
 243
 244/* PCMCIA control and configuration */
 245
 246static struct resource osiris_pcmcia_resource[] = {
 247        [0] = DEFINE_RES_MEM(0x0f000000, SZ_1M),
 248        [1] = DEFINE_RES_MEM(0x0c000000, SZ_1M),
 249};
 250
 251static struct platform_device osiris_pcmcia = {
 252        .name           = "osiris-pcmcia",
 253        .id             = -1,
 254        .num_resources  = ARRAY_SIZE(osiris_pcmcia_resource),
 255        .resource       = osiris_pcmcia_resource,
 256};
 257
 258/* Osiris power management device */
 259
 260#ifdef CONFIG_PM
 261static unsigned char pm_osiris_ctrl0;
 262
 263static int osiris_pm_suspend(void)
 264{
 265        unsigned int tmp;
 266
 267        pm_osiris_ctrl0 = __raw_readb(OSIRIS_VA_CTRL0);
 268        tmp = pm_osiris_ctrl0 & ~OSIRIS_CTRL0_NANDSEL;
 269
 270        /* ensure correct NAND slot is selected on resume */
 271        if ((pm_osiris_ctrl0 & OSIRIS_CTRL0_BOOT_INT) == 0)
 272                tmp |= 2;
 273
 274        __raw_writeb(tmp, OSIRIS_VA_CTRL0);
 275
 276        /* ensure that an nRESET is not generated on resume. */
 277        gpio_request_one(S3C2410_GPA(21), GPIOF_OUT_INIT_HIGH, NULL);
 278        gpio_free(S3C2410_GPA(21));
 279
 280        return 0;
 281}
 282
 283static void osiris_pm_resume(void)
 284{
 285        if (pm_osiris_ctrl0 & OSIRIS_CTRL0_FIX8)
 286                __raw_writeb(OSIRIS_CTRL1_FIX8, OSIRIS_VA_CTRL1);
 287
 288        __raw_writeb(pm_osiris_ctrl0, OSIRIS_VA_CTRL0);
 289
 290        s3c_gpio_cfgpin(S3C2410_GPA(21), S3C2410_GPA21_nRSTOUT);
 291}
 292
 293#else
 294#define osiris_pm_suspend NULL
 295#define osiris_pm_resume NULL
 296#endif
 297
 298static struct syscore_ops osiris_pm_syscore_ops = {
 299        .suspend        = osiris_pm_suspend,
 300        .resume         = osiris_pm_resume,
 301};
 302
 303/* Link for DVS driver to TPS65011 */
 304
 305static void osiris_tps_release(struct device *dev)
 306{
 307        /* static device, do not need to release anything */
 308}
 309
 310static struct platform_device osiris_tps_device = {
 311        .name   = "osiris-dvs",
 312        .id     = -1,
 313        .dev.release = osiris_tps_release,
 314};
 315
 316static int osiris_tps_setup(struct i2c_client *client, void *context)
 317{
 318        osiris_tps_device.dev.parent = &client->dev;
 319        return platform_device_register(&osiris_tps_device);
 320}
 321
 322static int osiris_tps_remove(struct i2c_client *client, void *context)
 323{
 324        platform_device_unregister(&osiris_tps_device);
 325        return 0;
 326}
 327
 328static struct tps65010_board osiris_tps_board = {
 329        .base           = -1,   /* GPIO can go anywhere at the moment */
 330        .setup          = osiris_tps_setup,
 331        .teardown       = osiris_tps_remove,
 332};
 333
 334/* I2C devices fitted. */
 335
 336static struct i2c_board_info osiris_i2c_devs[] __initdata = {
 337        {
 338                I2C_BOARD_INFO("tps65011", 0x48),
 339                .irq    = IRQ_EINT20,
 340                .platform_data = &osiris_tps_board,
 341        },
 342};
 343
 344/* Standard Osiris devices */
 345
 346static struct platform_device *osiris_devices[] __initdata = {
 347        &s3c2410_device_dclk,
 348        &s3c_device_i2c0,
 349        &s3c_device_wdt,
 350        &s3c_device_nand,
 351        &osiris_pcmcia,
 352};
 353
 354static struct s3c_cpufreq_board __initdata osiris_cpufreq = {
 355        .refresh        = 7800, /* refresh period is 7.8usec */
 356        .auto_io        = 1,
 357        .need_io        = 1,
 358};
 359
 360static void __init osiris_map_io(void)
 361{
 362        unsigned long flags;
 363
 364        s3c24xx_init_io(osiris_iodesc, ARRAY_SIZE(osiris_iodesc));
 365        s3c24xx_init_uarts(osiris_uartcfgs, ARRAY_SIZE(osiris_uartcfgs));
 366        samsung_set_timer_source(SAMSUNG_PWM3, SAMSUNG_PWM4);
 367
 368        /* check for the newer revision boards with large page nand */
 369
 370        if ((__raw_readb(OSIRIS_VA_IDREG) & OSIRIS_ID_REVMASK) >= 4) {
 371                printk(KERN_INFO "OSIRIS-B detected (revision %d)\n",
 372                       __raw_readb(OSIRIS_VA_IDREG) & OSIRIS_ID_REVMASK);
 373                osiris_nand_sets[0].partitions = osiris_default_nand_part_large;
 374                osiris_nand_sets[0].nr_partitions = ARRAY_SIZE(osiris_default_nand_part_large);
 375        } else {
 376                /* write-protect line to the NAND */
 377                gpio_request_one(S3C2410_GPA(0), GPIOF_OUT_INIT_HIGH, NULL);
 378                gpio_free(S3C2410_GPA(0));
 379        }
 380
 381        /* fix bus configuration (nBE settings wrong on ABLE pre v2.20) */
 382
 383        local_irq_save(flags);
 384        __raw_writel(__raw_readl(S3C2410_BWSCON) | S3C2410_BWSCON_ST1 | S3C2410_BWSCON_ST2 | S3C2410_BWSCON_ST3 | S3C2410_BWSCON_ST4 | S3C2410_BWSCON_ST5, S3C2410_BWSCON);
 385        local_irq_restore(flags);
 386}
 387
 388static void __init osiris_init_time(void)
 389{
 390        s3c2440_init_clocks(12000000);
 391        samsung_timer_init();
 392}
 393
 394static void __init osiris_init(void)
 395{
 396        register_syscore_ops(&osiris_pm_syscore_ops);
 397
 398        s3c_i2c0_set_platdata(NULL);
 399        s3c_nand_set_platdata(&osiris_nand_info);
 400
 401        s3c_cpufreq_setboard(&osiris_cpufreq);
 402
 403        i2c_register_board_info(0, osiris_i2c_devs,
 404                                ARRAY_SIZE(osiris_i2c_devs));
 405
 406        platform_add_devices(osiris_devices, ARRAY_SIZE(osiris_devices));
 407};
 408
 409MACHINE_START(OSIRIS, "Simtec-OSIRIS")
 410        /* Maintainer: Ben Dooks <ben@simtec.co.uk> */
 411        .atag_offset    = 0x100,
 412        .map_io         = osiris_map_io,
 413        .init_irq       = s3c2440_init_irq,
 414        .init_machine   = osiris_init,
 415        .init_time      = osiris_init_time,
 416MACHINE_END
 417