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/kernel.h>
  11#include <linux/amba/mmci.h>
  12#include <linux/io.h>
  13#include <linux/irqchip.h>
  14#include <linux/of_irq.h>
  15#include <linux/of_address.h>
  16#include <linux/of_platform.h>
  17#include <linux/sched_clock.h>
  18#include <linux/regmap.h>
  19#include <linux/mfd/syscon.h>
  20
  21#include <asm/mach/arch.h>
  22#include <asm/mach/map.h>
  23
  24#include "hardware.h"
  25#include "cm.h"
  26#include "common.h"
  27
  28/* Base address to the core module header */
  29static struct regmap *cm_map;
  30/* Base address to the CP controller */
  31static void __iomem *intcp_con_base;
  32
  33#define CM_COUNTER_OFFSET 0x28
  34
  35/*
  36 * Logical      Physical
  37 * f1400000     14000000        Interrupt controller
  38 * f1600000     16000000        UART 0
  39 * fca00000     ca000000        SIC
  40 */
  41
  42static struct map_desc intcp_io_desc[] __initdata __maybe_unused = {
  43        {
  44                .virtual        = IO_ADDRESS(INTEGRATOR_IC_BASE),
  45                .pfn            = __phys_to_pfn(INTEGRATOR_IC_BASE),
  46                .length         = SZ_4K,
  47                .type           = MT_DEVICE
  48        }, {
  49                .virtual        = IO_ADDRESS(INTEGRATOR_UART0_BASE),
  50                .pfn            = __phys_to_pfn(INTEGRATOR_UART0_BASE),
  51                .length         = SZ_4K,
  52                .type           = MT_DEVICE
  53        }, {
  54                .virtual        = IO_ADDRESS(INTEGRATOR_CP_SIC_BASE),
  55                .pfn            = __phys_to_pfn(INTEGRATOR_CP_SIC_BASE),
  56                .length         = SZ_4K,
  57                .type           = MT_DEVICE
  58        }
  59};
  60
  61static void __init intcp_map_io(void)
  62{
  63        iotable_init(intcp_io_desc, ARRAY_SIZE(intcp_io_desc));
  64}
  65
  66/*
  67 * It seems that the card insertion interrupt remains active after
  68 * we've acknowledged it.  We therefore ignore the interrupt, and
  69 * rely on reading it from the SIC.  This also means that we must
  70 * clear the latched interrupt.
  71 */
  72static unsigned int mmc_status(struct device *dev)
  73{
  74        unsigned int status = readl(__io_address(0xca000000 + 4));
  75        writel(8, intcp_con_base + 8);
  76
  77        return status & 8;
  78}
  79
  80static struct mmci_platform_data mmc_data = {
  81        .ocr_mask       = MMC_VDD_32_33|MMC_VDD_33_34,
  82        .status         = mmc_status,
  83        .gpio_wp        = -1,
  84        .gpio_cd        = -1,
  85};
  86
  87static u64 notrace intcp_read_sched_clock(void)
  88{
  89        unsigned int val;
  90
  91        /* MMIO so discard return code */
  92        regmap_read(cm_map, CM_COUNTER_OFFSET, &val);
  93        return val;
  94}
  95
  96static void __init intcp_init_early(void)
  97{
  98        cm_map = syscon_regmap_lookup_by_compatible("arm,core-module-integrator");
  99        if (IS_ERR(cm_map))
 100                return;
 101        sched_clock_register(intcp_read_sched_clock, 32, 24000000);
 102}
 103
 104static void __init intcp_init_irq_of(void)
 105{
 106        cm_init();
 107        irqchip_init();
 108}
 109
 110/*
 111 * For the Device Tree, add in the UART, MMC and CLCD specifics as AUXDATA
 112 * and enforce the bus names since these are used for clock lookups.
 113 */
 114static struct of_dev_auxdata intcp_auxdata_lookup[] __initdata = {
 115        OF_DEV_AUXDATA("arm,primecell", INTEGRATOR_CP_MMC_BASE,
 116                "mmci", &mmc_data),
 117        { /* sentinel */ },
 118};
 119
 120static const struct of_device_id intcp_syscon_match[] = {
 121        { .compatible = "arm,integrator-cp-syscon"},
 122        { },
 123};
 124
 125static void __init intcp_init_of(void)
 126{
 127        struct device_node *cpcon;
 128
 129        cpcon = of_find_matching_node(NULL, intcp_syscon_match);
 130        if (!cpcon)
 131                return;
 132
 133        intcp_con_base = of_iomap(cpcon, 0);
 134        if (!intcp_con_base)
 135                return;
 136
 137        of_platform_default_populate(NULL, intcp_auxdata_lookup, NULL);
 138}
 139
 140static const char * intcp_dt_board_compat[] = {
 141        "arm,integrator-cp",
 142        NULL,
 143};
 144
 145DT_MACHINE_START(INTEGRATOR_CP_DT, "ARM Integrator/CP (Device Tree)")
 146        .reserve        = integrator_reserve,
 147        .map_io         = intcp_map_io,
 148        .init_early     = intcp_init_early,
 149        .init_irq       = intcp_init_irq_of,
 150        .init_machine   = intcp_init_of,
 151        .dt_compat      = intcp_dt_board_compat,
 152MACHINE_END
 153