162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Copyright (C) 2003 Deep Blue Solutions Ltd 462306a36Sopenharmony_ci */ 562306a36Sopenharmony_ci#include <linux/kernel.h> 662306a36Sopenharmony_ci#include <linux/amba/mmci.h> 762306a36Sopenharmony_ci#include <linux/io.h> 862306a36Sopenharmony_ci#include <linux/irqchip.h> 962306a36Sopenharmony_ci#include <linux/of_irq.h> 1062306a36Sopenharmony_ci#include <linux/of_address.h> 1162306a36Sopenharmony_ci#include <linux/of_platform.h> 1262306a36Sopenharmony_ci#include <linux/sched_clock.h> 1362306a36Sopenharmony_ci#include <linux/regmap.h> 1462306a36Sopenharmony_ci#include <linux/mfd/syscon.h> 1562306a36Sopenharmony_ci 1662306a36Sopenharmony_ci#include <asm/mach/arch.h> 1762306a36Sopenharmony_ci#include <asm/mach/map.h> 1862306a36Sopenharmony_ci 1962306a36Sopenharmony_ci#include "integrator-hardware.h" 2062306a36Sopenharmony_ci#include "integrator-cm.h" 2162306a36Sopenharmony_ci#include "integrator.h" 2262306a36Sopenharmony_ci 2362306a36Sopenharmony_ci/* Base address to the core module header */ 2462306a36Sopenharmony_cistatic struct regmap *cm_map; 2562306a36Sopenharmony_ci/* Base address to the CP controller */ 2662306a36Sopenharmony_cistatic void __iomem *intcp_con_base; 2762306a36Sopenharmony_ci 2862306a36Sopenharmony_ci#define CM_COUNTER_OFFSET 0x28 2962306a36Sopenharmony_ci 3062306a36Sopenharmony_ci/* 3162306a36Sopenharmony_ci * Logical Physical 3262306a36Sopenharmony_ci * f1400000 14000000 Interrupt controller 3362306a36Sopenharmony_ci * f1600000 16000000 UART 0 3462306a36Sopenharmony_ci * fca00000 ca000000 SIC 3562306a36Sopenharmony_ci */ 3662306a36Sopenharmony_ci 3762306a36Sopenharmony_cistatic struct map_desc intcp_io_desc[] __initdata __maybe_unused = { 3862306a36Sopenharmony_ci { 3962306a36Sopenharmony_ci .virtual = IO_ADDRESS(INTEGRATOR_IC_BASE), 4062306a36Sopenharmony_ci .pfn = __phys_to_pfn(INTEGRATOR_IC_BASE), 4162306a36Sopenharmony_ci .length = SZ_4K, 4262306a36Sopenharmony_ci .type = MT_DEVICE 4362306a36Sopenharmony_ci }, { 4462306a36Sopenharmony_ci .virtual = IO_ADDRESS(INTEGRATOR_UART0_BASE), 4562306a36Sopenharmony_ci .pfn = __phys_to_pfn(INTEGRATOR_UART0_BASE), 4662306a36Sopenharmony_ci .length = SZ_4K, 4762306a36Sopenharmony_ci .type = MT_DEVICE 4862306a36Sopenharmony_ci }, { 4962306a36Sopenharmony_ci .virtual = IO_ADDRESS(INTEGRATOR_CP_SIC_BASE), 5062306a36Sopenharmony_ci .pfn = __phys_to_pfn(INTEGRATOR_CP_SIC_BASE), 5162306a36Sopenharmony_ci .length = SZ_4K, 5262306a36Sopenharmony_ci .type = MT_DEVICE 5362306a36Sopenharmony_ci } 5462306a36Sopenharmony_ci}; 5562306a36Sopenharmony_ci 5662306a36Sopenharmony_cistatic void __init intcp_map_io(void) 5762306a36Sopenharmony_ci{ 5862306a36Sopenharmony_ci iotable_init(intcp_io_desc, ARRAY_SIZE(intcp_io_desc)); 5962306a36Sopenharmony_ci} 6062306a36Sopenharmony_ci 6162306a36Sopenharmony_ci/* 6262306a36Sopenharmony_ci * It seems that the card insertion interrupt remains active after 6362306a36Sopenharmony_ci * we've acknowledged it. We therefore ignore the interrupt, and 6462306a36Sopenharmony_ci * rely on reading it from the SIC. This also means that we must 6562306a36Sopenharmony_ci * clear the latched interrupt. 6662306a36Sopenharmony_ci */ 6762306a36Sopenharmony_cistatic unsigned int mmc_status(struct device *dev) 6862306a36Sopenharmony_ci{ 6962306a36Sopenharmony_ci unsigned int status = readl(__io_address(0xca000000 + 4)); 7062306a36Sopenharmony_ci writel(8, intcp_con_base + 8); 7162306a36Sopenharmony_ci 7262306a36Sopenharmony_ci return status & 8; 7362306a36Sopenharmony_ci} 7462306a36Sopenharmony_ci 7562306a36Sopenharmony_cistatic struct mmci_platform_data mmc_data = { 7662306a36Sopenharmony_ci .ocr_mask = MMC_VDD_32_33|MMC_VDD_33_34, 7762306a36Sopenharmony_ci .status = mmc_status, 7862306a36Sopenharmony_ci}; 7962306a36Sopenharmony_ci 8062306a36Sopenharmony_cistatic u64 notrace intcp_read_sched_clock(void) 8162306a36Sopenharmony_ci{ 8262306a36Sopenharmony_ci unsigned int val; 8362306a36Sopenharmony_ci 8462306a36Sopenharmony_ci /* MMIO so discard return code */ 8562306a36Sopenharmony_ci regmap_read(cm_map, CM_COUNTER_OFFSET, &val); 8662306a36Sopenharmony_ci return val; 8762306a36Sopenharmony_ci} 8862306a36Sopenharmony_ci 8962306a36Sopenharmony_cistatic void __init intcp_init_early(void) 9062306a36Sopenharmony_ci{ 9162306a36Sopenharmony_ci cm_map = syscon_regmap_lookup_by_compatible("arm,core-module-integrator"); 9262306a36Sopenharmony_ci if (IS_ERR(cm_map)) 9362306a36Sopenharmony_ci return; 9462306a36Sopenharmony_ci sched_clock_register(intcp_read_sched_clock, 32, 24000000); 9562306a36Sopenharmony_ci} 9662306a36Sopenharmony_ci 9762306a36Sopenharmony_cistatic void __init intcp_init_irq_of(void) 9862306a36Sopenharmony_ci{ 9962306a36Sopenharmony_ci cm_init(); 10062306a36Sopenharmony_ci irqchip_init(); 10162306a36Sopenharmony_ci} 10262306a36Sopenharmony_ci 10362306a36Sopenharmony_ci/* 10462306a36Sopenharmony_ci * For the Device Tree, add in the UART, MMC and CLCD specifics as AUXDATA 10562306a36Sopenharmony_ci * and enforce the bus names since these are used for clock lookups. 10662306a36Sopenharmony_ci */ 10762306a36Sopenharmony_cistatic struct of_dev_auxdata intcp_auxdata_lookup[] __initdata = { 10862306a36Sopenharmony_ci OF_DEV_AUXDATA("arm,primecell", INTEGRATOR_CP_MMC_BASE, 10962306a36Sopenharmony_ci "mmci", &mmc_data), 11062306a36Sopenharmony_ci { /* sentinel */ }, 11162306a36Sopenharmony_ci}; 11262306a36Sopenharmony_ci 11362306a36Sopenharmony_cistatic const struct of_device_id intcp_syscon_match[] = { 11462306a36Sopenharmony_ci { .compatible = "arm,integrator-cp-syscon"}, 11562306a36Sopenharmony_ci { }, 11662306a36Sopenharmony_ci}; 11762306a36Sopenharmony_ci 11862306a36Sopenharmony_cistatic void __init intcp_init_of(void) 11962306a36Sopenharmony_ci{ 12062306a36Sopenharmony_ci struct device_node *cpcon; 12162306a36Sopenharmony_ci 12262306a36Sopenharmony_ci cpcon = of_find_matching_node(NULL, intcp_syscon_match); 12362306a36Sopenharmony_ci if (!cpcon) 12462306a36Sopenharmony_ci return; 12562306a36Sopenharmony_ci 12662306a36Sopenharmony_ci intcp_con_base = of_iomap(cpcon, 0); 12762306a36Sopenharmony_ci if (!intcp_con_base) 12862306a36Sopenharmony_ci return; 12962306a36Sopenharmony_ci 13062306a36Sopenharmony_ci of_platform_default_populate(NULL, intcp_auxdata_lookup, NULL); 13162306a36Sopenharmony_ci} 13262306a36Sopenharmony_ci 13362306a36Sopenharmony_cistatic const char * intcp_dt_board_compat[] = { 13462306a36Sopenharmony_ci "arm,integrator-cp", 13562306a36Sopenharmony_ci NULL, 13662306a36Sopenharmony_ci}; 13762306a36Sopenharmony_ci 13862306a36Sopenharmony_ciDT_MACHINE_START(INTEGRATOR_CP_DT, "ARM Integrator/CP (Device Tree)") 13962306a36Sopenharmony_ci .reserve = integrator_reserve, 14062306a36Sopenharmony_ci .map_io = intcp_map_io, 14162306a36Sopenharmony_ci .init_early = intcp_init_early, 14262306a36Sopenharmony_ci .init_irq = intcp_init_irq_of, 14362306a36Sopenharmony_ci .init_machine = intcp_init_of, 14462306a36Sopenharmony_ci .dt_compat = intcp_dt_board_compat, 14562306a36Sopenharmony_ciMACHINE_END 146