linux/arch/arm/mach-integrator/integrator_cp.c
<<
>>
Prefs
   1/*
   2 *  linux/arch/arm/mach-integrator/integrator_cp.c
   3 *
   4 *  Copyright (C) 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 as published by
   8 * the Free Software Foundation; either version 2 of the License.
   9 */
  10#include <linux/types.h>
  11#include <linux/kernel.h>
  12#include <linux/init.h>
  13#include <linux/list.h>
  14#include <linux/platform_device.h>
  15#include <linux/dma-mapping.h>
  16#include <linux/string.h>
  17#include <linux/device.h>
  18#include <linux/amba/bus.h>
  19#include <linux/amba/kmi.h>
  20#include <linux/amba/clcd.h>
  21#include <linux/amba/mmci.h>
  22#include <linux/io.h>
  23#include <linux/irqchip/versatile-fpga.h>
  24#include <linux/gfp.h>
  25#include <linux/mtd/physmap.h>
  26#include <linux/platform_data/clk-integrator.h>
  27#include <linux/of_irq.h>
  28#include <linux/of_address.h>
  29#include <linux/of_platform.h>
  30#include <linux/sys_soc.h>
  31
  32#include <mach/hardware.h>
  33#include <mach/platform.h>
  34#include <asm/setup.h>
  35#include <asm/mach-types.h>
  36#include <asm/hardware/arm_timer.h>
  37#include <asm/hardware/icst.h>
  38
  39#include <mach/cm.h>
  40#include <mach/lm.h>
  41#include <mach/irqs.h>
  42
  43#include <asm/mach/arch.h>
  44#include <asm/mach/irq.h>
  45#include <asm/mach/map.h>
  46#include <asm/mach/time.h>
  47
  48#include <asm/hardware/timer-sp.h>
  49
  50#include <plat/clcd.h>
  51#include <plat/sched_clock.h>
  52
  53#include "common.h"
  54
  55/* Base address to the CP controller */
  56static void __iomem *intcp_con_base;
  57
  58#define INTCP_PA_FLASH_BASE             0x24000000
  59
  60#define INTCP_PA_CLCD_BASE              0xc0000000
  61
  62#define INTCP_FLASHPROG                 0x04
  63#define CINTEGRATOR_FLASHPROG_FLVPPEN   (1 << 0)
  64#define CINTEGRATOR_FLASHPROG_FLWREN    (1 << 1)
  65
  66/*
  67 * Logical      Physical
  68 * f1000000     10000000        Core module registers
  69 * f1100000     11000000        System controller registers
  70 * f1200000     12000000        EBI registers
  71 * f1300000     13000000        Counter/Timer
  72 * f1400000     14000000        Interrupt controller
  73 * f1600000     16000000        UART 0
  74 * f1700000     17000000        UART 1
  75 * f1a00000     1a000000        Debug LEDs
  76 * fc900000     c9000000        GPIO
  77 * fca00000     ca000000        SIC
  78 * fcb00000     cb000000        CP system control
  79 */
  80
  81static struct map_desc intcp_io_desc[] __initdata = {
  82        {
  83                .virtual        = IO_ADDRESS(INTEGRATOR_HDR_BASE),
  84                .pfn            = __phys_to_pfn(INTEGRATOR_HDR_BASE),
  85                .length         = SZ_4K,
  86                .type           = MT_DEVICE
  87        }, {
  88                .virtual        = IO_ADDRESS(INTEGRATOR_EBI_BASE),
  89                .pfn            = __phys_to_pfn(INTEGRATOR_EBI_BASE),
  90                .length         = SZ_4K,
  91                .type           = MT_DEVICE
  92        }, {
  93                .virtual        = IO_ADDRESS(INTEGRATOR_CT_BASE),
  94                .pfn            = __phys_to_pfn(INTEGRATOR_CT_BASE),
  95                .length         = SZ_4K,
  96                .type           = MT_DEVICE
  97        }, {
  98                .virtual        = IO_ADDRESS(INTEGRATOR_IC_BASE),
  99                .pfn            = __phys_to_pfn(INTEGRATOR_IC_BASE),
 100                .length         = SZ_4K,
 101                .type           = MT_DEVICE
 102        }, {
 103                .virtual        = IO_ADDRESS(INTEGRATOR_UART0_BASE),
 104                .pfn            = __phys_to_pfn(INTEGRATOR_UART0_BASE),
 105                .length         = SZ_4K,
 106                .type           = MT_DEVICE
 107        }, {
 108                .virtual        = IO_ADDRESS(INTEGRATOR_DBG_BASE),
 109                .pfn            = __phys_to_pfn(INTEGRATOR_DBG_BASE),
 110                .length         = SZ_4K,
 111                .type           = MT_DEVICE
 112        }, {
 113                .virtual        = IO_ADDRESS(INTEGRATOR_CP_GPIO_BASE),
 114                .pfn            = __phys_to_pfn(INTEGRATOR_CP_GPIO_BASE),
 115                .length         = SZ_4K,
 116                .type           = MT_DEVICE
 117        }, {
 118                .virtual        = IO_ADDRESS(INTEGRATOR_CP_SIC_BASE),
 119                .pfn            = __phys_to_pfn(INTEGRATOR_CP_SIC_BASE),
 120                .length         = SZ_4K,
 121                .type           = MT_DEVICE
 122        }
 123};
 124
 125static void __init intcp_map_io(void)
 126{
 127        iotable_init(intcp_io_desc, ARRAY_SIZE(intcp_io_desc));
 128}
 129
 130/*
 131 * Flash handling.
 132 */
 133static int intcp_flash_init(struct platform_device *dev)
 134{
 135        u32 val;
 136
 137        val = readl(intcp_con_base + INTCP_FLASHPROG);
 138        val |= CINTEGRATOR_FLASHPROG_FLWREN;
 139        writel(val, intcp_con_base + INTCP_FLASHPROG);
 140
 141        return 0;
 142}
 143
 144static void intcp_flash_exit(struct platform_device *dev)
 145{
 146        u32 val;
 147
 148        val = readl(intcp_con_base + INTCP_FLASHPROG);
 149        val &= ~(CINTEGRATOR_FLASHPROG_FLVPPEN|CINTEGRATOR_FLASHPROG_FLWREN);
 150        writel(val, intcp_con_base + INTCP_FLASHPROG);
 151}
 152
 153static void intcp_flash_set_vpp(struct platform_device *pdev, int on)
 154{
 155        u32 val;
 156
 157        val = readl(intcp_con_base + INTCP_FLASHPROG);
 158        if (on)
 159                val |= CINTEGRATOR_FLASHPROG_FLVPPEN;
 160        else
 161                val &= ~CINTEGRATOR_FLASHPROG_FLVPPEN;
 162        writel(val, intcp_con_base + INTCP_FLASHPROG);
 163}
 164
 165static struct physmap_flash_data intcp_flash_data = {
 166        .width          = 4,
 167        .init           = intcp_flash_init,
 168        .exit           = intcp_flash_exit,
 169        .set_vpp        = intcp_flash_set_vpp,
 170};
 171
 172/*
 173 * It seems that the card insertion interrupt remains active after
 174 * we've acknowledged it.  We therefore ignore the interrupt, and
 175 * rely on reading it from the SIC.  This also means that we must
 176 * clear the latched interrupt.
 177 */
 178static unsigned int mmc_status(struct device *dev)
 179{
 180        unsigned int status = readl(__io_address(0xca000000 + 4));
 181        writel(8, intcp_con_base + 8);
 182
 183        return status & 8;
 184}
 185
 186static struct mmci_platform_data mmc_data = {
 187        .ocr_mask       = MMC_VDD_32_33|MMC_VDD_33_34,
 188        .status         = mmc_status,
 189        .gpio_wp        = -1,
 190        .gpio_cd        = -1,
 191};
 192
 193/*
 194 * CLCD support
 195 */
 196/*
 197 * Ensure VGA is selected.
 198 */
 199static void cp_clcd_enable(struct clcd_fb *fb)
 200{
 201        struct fb_var_screeninfo *var = &fb->fb.var;
 202        u32 val = CM_CTRL_STATIC1 | CM_CTRL_STATIC2;
 203
 204        if (var->bits_per_pixel <= 8 ||
 205            (var->bits_per_pixel == 16 && var->green.length == 5))
 206                /* Pseudocolor, RGB555, BGR555 */
 207                val |= CM_CTRL_LCDMUXSEL_VGA555_TFT555;
 208        else if (fb->fb.var.bits_per_pixel <= 16)
 209                /* truecolor RGB565 */
 210                val |= CM_CTRL_LCDMUXSEL_VGA565_TFT555;
 211        else
 212                val = 0; /* no idea for this, don't trust the docs */
 213
 214        cm_control(CM_CTRL_LCDMUXSEL_MASK|
 215                   CM_CTRL_LCDEN0|
 216                   CM_CTRL_LCDEN1|
 217                   CM_CTRL_STATIC1|
 218                   CM_CTRL_STATIC2|
 219                   CM_CTRL_STATIC|
 220                   CM_CTRL_n24BITEN, val);
 221}
 222
 223static int cp_clcd_setup(struct clcd_fb *fb)
 224{
 225        fb->panel = versatile_clcd_get_panel("VGA");
 226        if (!fb->panel)
 227                return -EINVAL;
 228
 229        return versatile_clcd_setup_dma(fb, SZ_1M);
 230}
 231
 232static struct clcd_board clcd_data = {
 233        .name           = "Integrator/CP",
 234        .caps           = CLCD_CAP_5551 | CLCD_CAP_RGB565 | CLCD_CAP_888,
 235        .check          = clcdfb_check,
 236        .decode         = clcdfb_decode,
 237        .enable         = cp_clcd_enable,
 238        .setup          = cp_clcd_setup,
 239        .mmap           = versatile_clcd_mmap_dma,
 240        .remove         = versatile_clcd_remove_dma,
 241};
 242
 243#define REFCOUNTER (__io_address(INTEGRATOR_HDR_BASE) + 0x28)
 244
 245static void __init intcp_init_early(void)
 246{
 247#ifdef CONFIG_PLAT_VERSATILE_SCHED_CLOCK
 248        versatile_sched_clock_init(REFCOUNTER, 24000000);
 249#endif
 250}
 251
 252#ifdef CONFIG_OF
 253
 254static void __init intcp_timer_init_of(void)
 255{
 256        struct device_node *node;
 257        const char *path;
 258        void __iomem *base;
 259        int err;
 260        int irq;
 261
 262        err = of_property_read_string(of_aliases,
 263                                "arm,timer-primary", &path);
 264        if (WARN_ON(err))
 265                return;
 266        node = of_find_node_by_path(path);
 267        base = of_iomap(node, 0);
 268        if (WARN_ON(!base))
 269                return;
 270        writel(0, base + TIMER_CTRL);
 271        sp804_clocksource_init(base, node->name);
 272
 273        err = of_property_read_string(of_aliases,
 274                                "arm,timer-secondary", &path);
 275        if (WARN_ON(err))
 276                return;
 277        node = of_find_node_by_path(path);
 278        base = of_iomap(node, 0);
 279        if (WARN_ON(!base))
 280                return;
 281        irq = irq_of_parse_and_map(node, 0);
 282        writel(0, base + TIMER_CTRL);
 283        sp804_clockevents_init(base, irq, node->name);
 284}
 285
 286static struct sys_timer cp_of_timer = {
 287        .init           = intcp_timer_init_of,
 288};
 289
 290static const struct of_device_id fpga_irq_of_match[] __initconst = {
 291        { .compatible = "arm,versatile-fpga-irq", .data = fpga_irq_of_init, },
 292        { /* Sentinel */ }
 293};
 294
 295static void __init intcp_init_irq_of(void)
 296{
 297        of_irq_init(fpga_irq_of_match);
 298        integrator_clk_init(true);
 299}
 300
 301/*
 302 * For the Device Tree, add in the UART, MMC and CLCD specifics as AUXDATA
 303 * and enforce the bus names since these are used for clock lookups.
 304 */
 305static struct of_dev_auxdata intcp_auxdata_lookup[] __initdata = {
 306        OF_DEV_AUXDATA("arm,primecell", INTEGRATOR_RTC_BASE,
 307                "rtc", NULL),
 308        OF_DEV_AUXDATA("arm,primecell", INTEGRATOR_UART0_BASE,
 309                "uart0", NULL),
 310        OF_DEV_AUXDATA("arm,primecell", INTEGRATOR_UART1_BASE,
 311                "uart1", NULL),
 312        OF_DEV_AUXDATA("arm,primecell", KMI0_BASE,
 313                "kmi0", NULL),
 314        OF_DEV_AUXDATA("arm,primecell", KMI1_BASE,
 315                "kmi1", NULL),
 316        OF_DEV_AUXDATA("arm,primecell", INTEGRATOR_CP_MMC_BASE,
 317                "mmci", &mmc_data),
 318        OF_DEV_AUXDATA("arm,primecell", INTEGRATOR_CP_AACI_BASE,
 319                "aaci", &mmc_data),
 320        OF_DEV_AUXDATA("arm,primecell", INTCP_PA_CLCD_BASE,
 321                "clcd", &clcd_data),
 322        OF_DEV_AUXDATA("cfi-flash", INTCP_PA_FLASH_BASE,
 323                "physmap-flash", &intcp_flash_data),
 324        { /* sentinel */ },
 325};
 326
 327static void __init intcp_init_of(void)
 328{
 329        struct device_node *root;
 330        struct device_node *cpcon;
 331        struct device *parent;
 332        struct soc_device *soc_dev;
 333        struct soc_device_attribute *soc_dev_attr;
 334        u32 intcp_sc_id;
 335        int err;
 336
 337        /* Here we create an SoC device for the root node */
 338        root = of_find_node_by_path("/");
 339        if (!root)
 340                return;
 341        cpcon = of_find_node_by_path("/cpcon");
 342        if (!cpcon)
 343                return;
 344
 345        intcp_con_base = of_iomap(cpcon, 0);
 346        if (!intcp_con_base)
 347                return;
 348
 349        intcp_sc_id = readl(intcp_con_base);
 350
 351        soc_dev_attr = kzalloc(sizeof(*soc_dev_attr), GFP_KERNEL);
 352        if (!soc_dev_attr)
 353                return;
 354
 355        err = of_property_read_string(root, "compatible",
 356                                      &soc_dev_attr->soc_id);
 357        if (err)
 358                return;
 359        err = of_property_read_string(root, "model", &soc_dev_attr->machine);
 360        if (err)
 361                return;
 362        soc_dev_attr->family = "Integrator";
 363        soc_dev_attr->revision = kasprintf(GFP_KERNEL, "%c",
 364                                           'A' + (intcp_sc_id & 0x0f));
 365
 366        soc_dev = soc_device_register(soc_dev_attr);
 367        if (IS_ERR_OR_NULL(soc_dev)) {
 368                kfree(soc_dev_attr->revision);
 369                kfree(soc_dev_attr);
 370                return;
 371        }
 372
 373        parent = soc_device_to_device(soc_dev);
 374
 375        if (!IS_ERR_OR_NULL(parent))
 376                integrator_init_sysfs(parent, intcp_sc_id);
 377
 378        of_platform_populate(root, of_default_bus_match_table,
 379                        intcp_auxdata_lookup, parent);
 380}
 381
 382static const char * intcp_dt_board_compat[] = {
 383        "arm,integrator-cp",
 384        NULL,
 385};
 386
 387DT_MACHINE_START(INTEGRATOR_CP_DT, "ARM Integrator/CP (Device Tree)")
 388        .reserve        = integrator_reserve,
 389        .map_io         = intcp_map_io,
 390        .init_early     = intcp_init_early,
 391        .init_irq       = intcp_init_irq_of,
 392        .handle_irq     = fpga_handle_irq,
 393        .timer          = &cp_of_timer,
 394        .init_machine   = intcp_init_of,
 395        .restart        = integrator_restart,
 396        .dt_compat      = intcp_dt_board_compat,
 397MACHINE_END
 398
 399#endif
 400
 401#ifdef CONFIG_ATAGS
 402
 403/*
 404 * For the ATAG boot some static mappings are needed. This will
 405 * go away with the ATAG support down the road.
 406 */
 407
 408static struct map_desc intcp_io_desc_atag[] __initdata = {
 409        {
 410                .virtual        = IO_ADDRESS(INTEGRATOR_CP_CTL_BASE),
 411                .pfn            = __phys_to_pfn(INTEGRATOR_CP_CTL_BASE),
 412                .length         = SZ_4K,
 413                .type           = MT_DEVICE
 414        },
 415};
 416
 417static void __init intcp_map_io_atag(void)
 418{
 419        iotable_init(intcp_io_desc_atag, ARRAY_SIZE(intcp_io_desc_atag));
 420        intcp_con_base = __io_address(INTEGRATOR_CP_CTL_BASE);
 421        intcp_map_io();
 422}
 423
 424
 425/*
 426 * This is where non-devicetree initialization code is collected and stashed
 427 * for eventual deletion.
 428 */
 429
 430#define INTCP_FLASH_SIZE                SZ_32M
 431
 432static struct resource intcp_flash_resource = {
 433        .start          = INTCP_PA_FLASH_BASE,
 434        .end            = INTCP_PA_FLASH_BASE + INTCP_FLASH_SIZE - 1,
 435        .flags          = IORESOURCE_MEM,
 436};
 437
 438static struct platform_device intcp_flash_device = {
 439        .name           = "physmap-flash",
 440        .id             = 0,
 441        .dev            = {
 442                .platform_data  = &intcp_flash_data,
 443        },
 444        .num_resources  = 1,
 445        .resource       = &intcp_flash_resource,
 446};
 447
 448#define INTCP_ETH_SIZE                  0x10
 449
 450static struct resource smc91x_resources[] = {
 451        [0] = {
 452                .start  = INTEGRATOR_CP_ETH_BASE,
 453                .end    = INTEGRATOR_CP_ETH_BASE + INTCP_ETH_SIZE - 1,
 454                .flags  = IORESOURCE_MEM,
 455        },
 456        [1] = {
 457                .start  = IRQ_CP_ETHINT,
 458                .end    = IRQ_CP_ETHINT,
 459                .flags  = IORESOURCE_IRQ,
 460        },
 461};
 462
 463static struct platform_device smc91x_device = {
 464        .name           = "smc91x",
 465        .id             = 0,
 466        .num_resources  = ARRAY_SIZE(smc91x_resources),
 467        .resource       = smc91x_resources,
 468};
 469
 470static struct platform_device *intcp_devs[] __initdata = {
 471        &intcp_flash_device,
 472        &smc91x_device,
 473};
 474
 475#define INTCP_VA_CIC_BASE               __io_address(INTEGRATOR_HDR_BASE + 0x40)
 476#define INTCP_VA_PIC_BASE               __io_address(INTEGRATOR_IC_BASE)
 477#define INTCP_VA_SIC_BASE               __io_address(INTEGRATOR_CP_SIC_BASE)
 478
 479static void __init intcp_init_irq(void)
 480{
 481        u32 pic_mask, cic_mask, sic_mask;
 482
 483        /* These masks are for the HW IRQ registers */
 484        pic_mask = ~((~0u) << (11 - 0));
 485        pic_mask |= (~((~0u) << (29 - 22))) << 22;
 486        cic_mask = ~((~0u) << (1 + IRQ_CIC_END - IRQ_CIC_START));
 487        sic_mask = ~((~0u) << (1 + IRQ_SIC_END - IRQ_SIC_START));
 488
 489        /*
 490         * Disable all interrupt sources
 491         */
 492        writel(0xffffffff, INTCP_VA_PIC_BASE + IRQ_ENABLE_CLEAR);
 493        writel(0xffffffff, INTCP_VA_PIC_BASE + FIQ_ENABLE_CLEAR);
 494        writel(0xffffffff, INTCP_VA_CIC_BASE + IRQ_ENABLE_CLEAR);
 495        writel(0xffffffff, INTCP_VA_CIC_BASE + FIQ_ENABLE_CLEAR);
 496        writel(sic_mask, INTCP_VA_SIC_BASE + IRQ_ENABLE_CLEAR);
 497        writel(sic_mask, INTCP_VA_SIC_BASE + FIQ_ENABLE_CLEAR);
 498
 499        fpga_irq_init(INTCP_VA_PIC_BASE, "PIC", IRQ_PIC_START,
 500                      -1, pic_mask, NULL);
 501
 502        fpga_irq_init(INTCP_VA_CIC_BASE, "CIC", IRQ_CIC_START,
 503                      -1, cic_mask, NULL);
 504
 505        fpga_irq_init(INTCP_VA_SIC_BASE, "SIC", IRQ_SIC_START,
 506                      IRQ_CP_CPPLDINT, sic_mask, NULL);
 507
 508        integrator_clk_init(true);
 509}
 510
 511#define TIMER0_VA_BASE __io_address(INTEGRATOR_TIMER0_BASE)
 512#define TIMER1_VA_BASE __io_address(INTEGRATOR_TIMER1_BASE)
 513#define TIMER2_VA_BASE __io_address(INTEGRATOR_TIMER2_BASE)
 514
 515static void __init intcp_timer_init(void)
 516{
 517        writel(0, TIMER0_VA_BASE + TIMER_CTRL);
 518        writel(0, TIMER1_VA_BASE + TIMER_CTRL);
 519        writel(0, TIMER2_VA_BASE + TIMER_CTRL);
 520
 521        sp804_clocksource_init(TIMER2_VA_BASE, "timer2");
 522        sp804_clockevents_init(TIMER1_VA_BASE, IRQ_TIMERINT1, "timer1");
 523}
 524
 525static struct sys_timer cp_timer = {
 526        .init           = intcp_timer_init,
 527};
 528
 529#define INTEGRATOR_CP_MMC_IRQS  { IRQ_CP_MMCIINT0, IRQ_CP_MMCIINT1 }
 530#define INTEGRATOR_CP_AACI_IRQS { IRQ_CP_AACIINT }
 531
 532static AMBA_APB_DEVICE(mmc, "mmci", 0, INTEGRATOR_CP_MMC_BASE,
 533        INTEGRATOR_CP_MMC_IRQS, &mmc_data);
 534
 535static AMBA_APB_DEVICE(aaci, "aaci", 0, INTEGRATOR_CP_AACI_BASE,
 536        INTEGRATOR_CP_AACI_IRQS, NULL);
 537
 538static AMBA_AHB_DEVICE(clcd, "clcd", 0, INTCP_PA_CLCD_BASE,
 539        { IRQ_CP_CLCDCINT }, &clcd_data);
 540
 541static struct amba_device *amba_devs[] __initdata = {
 542        &mmc_device,
 543        &aaci_device,
 544        &clcd_device,
 545};
 546
 547static void __init intcp_init(void)
 548{
 549        int i;
 550
 551        platform_add_devices(intcp_devs, ARRAY_SIZE(intcp_devs));
 552
 553        for (i = 0; i < ARRAY_SIZE(amba_devs); i++) {
 554                struct amba_device *d = amba_devs[i];
 555                amba_device_register(d, &iomem_resource);
 556        }
 557        integrator_init(true);
 558}
 559
 560MACHINE_START(CINTEGRATOR, "ARM-IntegratorCP")
 561        /* Maintainer: ARM Ltd/Deep Blue Solutions Ltd */
 562        .atag_offset    = 0x100,
 563        .reserve        = integrator_reserve,
 564        .map_io         = intcp_map_io_atag,
 565        .init_early     = intcp_init_early,
 566        .init_irq       = intcp_init_irq,
 567        .handle_irq     = fpga_handle_irq,
 568        .timer          = &cp_timer,
 569        .init_machine   = intcp_init,
 570        .restart        = integrator_restart,
 571MACHINE_END
 572
 573#endif
 574