Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  *  Copyright (C) 2003 Deep Blue Solutions Ltd
0004  */
0005 #include <linux/kernel.h>
0006 #include <linux/amba/mmci.h>
0007 #include <linux/io.h>
0008 #include <linux/irqchip.h>
0009 #include <linux/of_irq.h>
0010 #include <linux/of_address.h>
0011 #include <linux/of_platform.h>
0012 #include <linux/sched_clock.h>
0013 #include <linux/regmap.h>
0014 #include <linux/mfd/syscon.h>
0015 
0016 #include <asm/mach/arch.h>
0017 #include <asm/mach/map.h>
0018 
0019 #include "integrator-hardware.h"
0020 #include "integrator-cm.h"
0021 #include "integrator.h"
0022 
0023 /* Base address to the core module header */
0024 static struct regmap *cm_map;
0025 /* Base address to the CP controller */
0026 static void __iomem *intcp_con_base;
0027 
0028 #define CM_COUNTER_OFFSET 0x28
0029 
0030 /*
0031  * Logical      Physical
0032  * f1400000 14000000    Interrupt controller
0033  * f1600000 16000000    UART 0
0034  * fca00000 ca000000    SIC
0035  */
0036 
0037 static struct map_desc intcp_io_desc[] __initdata __maybe_unused = {
0038     {
0039         .virtual    = IO_ADDRESS(INTEGRATOR_IC_BASE),
0040         .pfn        = __phys_to_pfn(INTEGRATOR_IC_BASE),
0041         .length     = SZ_4K,
0042         .type       = MT_DEVICE
0043     }, {
0044         .virtual    = IO_ADDRESS(INTEGRATOR_UART0_BASE),
0045         .pfn        = __phys_to_pfn(INTEGRATOR_UART0_BASE),
0046         .length     = SZ_4K,
0047         .type       = MT_DEVICE
0048     }, {
0049         .virtual    = IO_ADDRESS(INTEGRATOR_CP_SIC_BASE),
0050         .pfn        = __phys_to_pfn(INTEGRATOR_CP_SIC_BASE),
0051         .length     = SZ_4K,
0052         .type       = MT_DEVICE
0053     }
0054 };
0055 
0056 static void __init intcp_map_io(void)
0057 {
0058     iotable_init(intcp_io_desc, ARRAY_SIZE(intcp_io_desc));
0059 }
0060 
0061 /*
0062  * It seems that the card insertion interrupt remains active after
0063  * we've acknowledged it.  We therefore ignore the interrupt, and
0064  * rely on reading it from the SIC.  This also means that we must
0065  * clear the latched interrupt.
0066  */
0067 static unsigned int mmc_status(struct device *dev)
0068 {
0069     unsigned int status = readl(__io_address(0xca000000 + 4));
0070     writel(8, intcp_con_base + 8);
0071 
0072     return status & 8;
0073 }
0074 
0075 static struct mmci_platform_data mmc_data = {
0076     .ocr_mask   = MMC_VDD_32_33|MMC_VDD_33_34,
0077     .status     = mmc_status,
0078 };
0079 
0080 static u64 notrace intcp_read_sched_clock(void)
0081 {
0082     unsigned int val;
0083 
0084     /* MMIO so discard return code */
0085     regmap_read(cm_map, CM_COUNTER_OFFSET, &val);
0086     return val;
0087 }
0088 
0089 static void __init intcp_init_early(void)
0090 {
0091     cm_map = syscon_regmap_lookup_by_compatible("arm,core-module-integrator");
0092     if (IS_ERR(cm_map))
0093         return;
0094     sched_clock_register(intcp_read_sched_clock, 32, 24000000);
0095 }
0096 
0097 static void __init intcp_init_irq_of(void)
0098 {
0099     cm_init();
0100     irqchip_init();
0101 }
0102 
0103 /*
0104  * For the Device Tree, add in the UART, MMC and CLCD specifics as AUXDATA
0105  * and enforce the bus names since these are used for clock lookups.
0106  */
0107 static struct of_dev_auxdata intcp_auxdata_lookup[] __initdata = {
0108     OF_DEV_AUXDATA("arm,primecell", INTEGRATOR_CP_MMC_BASE,
0109         "mmci", &mmc_data),
0110     { /* sentinel */ },
0111 };
0112 
0113 static const struct of_device_id intcp_syscon_match[] = {
0114     { .compatible = "arm,integrator-cp-syscon"},
0115     { },
0116 };
0117 
0118 static void __init intcp_init_of(void)
0119 {
0120     struct device_node *cpcon;
0121 
0122     cpcon = of_find_matching_node(NULL, intcp_syscon_match);
0123     if (!cpcon)
0124         return;
0125 
0126     intcp_con_base = of_iomap(cpcon, 0);
0127     if (!intcp_con_base)
0128         return;
0129 
0130     of_platform_default_populate(NULL, intcp_auxdata_lookup, NULL);
0131 }
0132 
0133 static const char * intcp_dt_board_compat[] = {
0134     "arm,integrator-cp",
0135     NULL,
0136 };
0137 
0138 DT_MACHINE_START(INTEGRATOR_CP_DT, "ARM Integrator/CP (Device Tree)")
0139     .reserve    = integrator_reserve,
0140     .map_io     = intcp_map_io,
0141     .init_early = intcp_init_early,
0142     .init_irq   = intcp_init_irq_of,
0143     .init_machine   = intcp_init_of,
0144     .dt_compat      = intcp_dt_board_compat,
0145 MACHINE_END