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