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