summaryrefslogtreecommitdiff
path: root/arch/arm/mach-exynos/common.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/arm/mach-exynos/common.c')
-rw-r--r--arch/arm/mach-exynos/common.c422
1 files changed, 129 insertions, 293 deletions
diff --git a/arch/arm/mach-exynos/common.c b/arch/arm/mach-exynos/common.c
index 1a89824a5f7..745e304ad0d 100644
--- a/arch/arm/mach-exynos/common.c
+++ b/arch/arm/mach-exynos/common.c
@@ -12,6 +12,7 @@
#include <linux/kernel.h>
#include <linux/interrupt.h>
#include <linux/irq.h>
+#include <linux/irqchip.h>
#include <linux/io.h>
#include <linux/device.h>
#include <linux/gpio.h>
@@ -23,11 +24,14 @@
#include <linux/export.h>
#include <linux/irqdomain.h>
#include <linux/of_address.h>
+#include <linux/clocksource.h>
+#include <linux/clk-provider.h>
+#include <linux/irqchip/arm-gic.h>
+#include <linux/irqchip/chained_irq.h>
#include <asm/proc-fns.h>
#include <asm/exception.h>
#include <asm/hardware/cache-l2x0.h>
-#include <asm/hardware/gic.h>
#include <asm/mach/map.h>
#include <asm/mach/irq.h>
#include <asm/cacheflush.h>
@@ -35,10 +39,9 @@
#include <mach/regs-irq.h>
#include <mach/regs-pmu.h>
#include <mach/regs-gpio.h>
-#include <mach/pmu.h>
+#include <mach/irqs.h>
#include <plat/cpu.h>
-#include <plat/clock.h>
#include <plat/devs.h>
#include <plat/pm.h>
#include <plat/sdhci.h>
@@ -64,17 +67,16 @@ static const char name_exynos5440[] = "EXYNOS5440";
static void exynos4_map_io(void);
static void exynos5_map_io(void);
static void exynos5440_map_io(void);
-static void exynos4_init_clocks(int xtal);
-static void exynos5_init_clocks(int xtal);
static void exynos4_init_uarts(struct s3c2410_uartcfg *cfg, int no);
static int exynos_init(void);
+unsigned long xxti_f = 0, xusbxti_f = 0;
+
static struct cpu_table cpu_ids[] __initdata = {
{
.idcode = EXYNOS4210_CPU_ID,
.idmask = EXYNOS4_CPU_MASK,
.map_io = exynos4_map_io,
- .init_clocks = exynos4_init_clocks,
.init_uarts = exynos4_init_uarts,
.init = exynos_init,
.name = name_exynos4210,
@@ -82,7 +84,6 @@ static struct cpu_table cpu_ids[] __initdata = {
.idcode = EXYNOS4212_CPU_ID,
.idmask = EXYNOS4_CPU_MASK,
.map_io = exynos4_map_io,
- .init_clocks = exynos4_init_clocks,
.init_uarts = exynos4_init_uarts,
.init = exynos_init,
.name = name_exynos4212,
@@ -90,7 +91,6 @@ static struct cpu_table cpu_ids[] __initdata = {
.idcode = EXYNOS4412_CPU_ID,
.idmask = EXYNOS4_CPU_MASK,
.map_io = exynos4_map_io,
- .init_clocks = exynos4_init_clocks,
.init_uarts = exynos4_init_uarts,
.init = exynos_init,
.name = name_exynos4412,
@@ -98,7 +98,6 @@ static struct cpu_table cpu_ids[] __initdata = {
.idcode = EXYNOS5250_SOC_ID,
.idmask = EXYNOS5_SOC_MASK,
.map_io = exynos5_map_io,
- .init_clocks = exynos5_init_clocks,
.init = exynos_init,
.name = name_exynos5250,
}, {
@@ -121,17 +120,6 @@ static struct map_desc exynos_iodesc[] __initdata = {
},
};
-#ifdef CONFIG_ARCH_EXYNOS5
-static struct map_desc exynos5440_iodesc[] __initdata = {
- {
- .virtual = (unsigned long)S5P_VA_CHIPID,
- .pfn = __phys_to_pfn(EXYNOS5440_PA_CHIPID),
- .length = SZ_4K,
- .type = MT_DEVICE,
- },
-};
-#endif
-
static struct map_desc exynos4_iodesc[] __initdata = {
{
.virtual = (unsigned long)S3C_VA_SYS,
@@ -234,6 +222,33 @@ static struct map_desc exynos4_iodesc1[] __initdata = {
},
};
+static struct map_desc exynos4210_iodesc[] __initdata = {
+ {
+ .virtual = (unsigned long)S5P_VA_SYSRAM_NS,
+ .pfn = __phys_to_pfn(EXYNOS4210_PA_SYSRAM_NS),
+ .length = SZ_4K,
+ .type = MT_DEVICE,
+ },
+};
+
+static struct map_desc exynos4x12_iodesc[] __initdata = {
+ {
+ .virtual = (unsigned long)S5P_VA_SYSRAM_NS,
+ .pfn = __phys_to_pfn(EXYNOS4x12_PA_SYSRAM_NS),
+ .length = SZ_4K,
+ .type = MT_DEVICE,
+ },
+};
+
+static struct map_desc exynos5250_iodesc[] __initdata = {
+ {
+ .virtual = (unsigned long)S5P_VA_SYSRAM_NS,
+ .pfn = __phys_to_pfn(EXYNOS5250_PA_SYSRAM_NS),
+ .length = SZ_4K,
+ .type = MT_DEVICE,
+ },
+};
+
static struct map_desc exynos5_iodesc[] __initdata = {
{
.virtual = (unsigned long)S3C_VA_SYS,
@@ -256,11 +271,6 @@ static struct map_desc exynos5_iodesc[] __initdata = {
.length = SZ_4K,
.type = MT_DEVICE,
}, {
- .virtual = (unsigned long)S5P_VA_SYSTIMER,
- .pfn = __phys_to_pfn(EXYNOS5_PA_SYSTIMER),
- .length = SZ_4K,
- .type = MT_DEVICE,
- }, {
.virtual = (unsigned long)S5P_VA_SYSRAM,
.pfn = __phys_to_pfn(EXYNOS5_PA_SYSRAM),
.length = SZ_4K,
@@ -299,6 +309,7 @@ void exynos4_restart(char mode, const char *cmd)
void exynos5_restart(char mode, const char *cmd)
{
+ struct device_node *np;
u32 val;
void __iomem *addr;
@@ -306,8 +317,9 @@ void exynos5_restart(char mode, const char *cmd)
val = 0x1;
addr = EXYNOS_SWRESET;
} else if (of_machine_is_compatible("samsung,exynos5440")) {
- val = (0x10 << 20) | (0x1 << 16);
- addr = EXYNOS5440_SWRESET;
+ np = of_find_compatible_node(NULL, NULL, "samsung,exynos5440-clock");
+ addr = of_iomap(np, 0) + 0xcc;
+ val = (0xfff << 20) | (0x1 << 16);
} else {
pr_err("%s: cannot support non-DT\n", __func__);
return;
@@ -325,6 +337,31 @@ void __init exynos_init_late(void)
exynos_pm_late_initcall();
}
+#ifdef CONFIG_OF
+int __init exynos_fdt_map_chipid(unsigned long node, const char *uname,
+ int depth, void *data)
+{
+ struct map_desc iodesc;
+ __be32 *reg;
+ unsigned long len;
+
+ if (!of_flat_dt_is_compatible(node, "samsung,exynos4210-chipid") &&
+ !of_flat_dt_is_compatible(node, "samsung,exynos5440-clock"))
+ return 0;
+
+ reg = of_get_flat_dt_prop(node, "reg", &len);
+ if (reg == NULL || len != (sizeof(unsigned long) * 2))
+ return 0;
+
+ iodesc.pfn = __phys_to_pfn(be32_to_cpu(reg[0]));
+ iodesc.length = be32_to_cpu(reg[1]) - 1;
+ iodesc.virtual = (unsigned long)S5P_VA_CHIPID;
+ iodesc.type = MT_DEVICE;
+ iotable_init(&iodesc, 1);
+ return 1;
+}
+#endif
+
/*
* exynos_map_io
*
@@ -333,19 +370,12 @@ void __init exynos_init_late(void)
void __init exynos_init_io(struct map_desc *mach_desc, int size)
{
- struct map_desc *iodesc = exynos_iodesc;
- int iodesc_sz = ARRAY_SIZE(exynos_iodesc);
-#if defined(CONFIG_OF) && defined(CONFIG_ARCH_EXYNOS5)
- unsigned long root = of_get_flat_dt_root();
-
- /* initialize the io descriptors we need for initialization */
- if (of_flat_dt_is_compatible(root, "samsung,exynos5440")) {
- iodesc = exynos5440_iodesc;
- iodesc_sz = ARRAY_SIZE(exynos5440_iodesc);
- }
+#ifdef CONFIG_OF
+ if (initial_boot_params)
+ of_scan_flat_dt(exynos_fdt_map_chipid, NULL);
+ else
#endif
-
- iotable_init(iodesc, iodesc_sz);
+ iotable_init(exynos_iodesc, ARRAY_SIZE(exynos_iodesc));
if (mach_desc)
iotable_init(mach_desc, size);
@@ -365,6 +395,11 @@ static void __init exynos4_map_io(void)
else
iotable_init(exynos4_iodesc1, ARRAY_SIZE(exynos4_iodesc1));
+ if (soc_is_exynos4210())
+ iotable_init(exynos4210_iodesc, ARRAY_SIZE(exynos4210_iodesc));
+ if (soc_is_exynos4212() || soc_is_exynos4412())
+ iotable_init(exynos4x12_iodesc, ARRAY_SIZE(exynos4x12_iodesc));
+
/* initialize device information early */
exynos4_default_sdhci0();
exynos4_default_sdhci1();
@@ -397,22 +432,9 @@ static void __init exynos4_map_io(void)
static void __init exynos5_map_io(void)
{
iotable_init(exynos5_iodesc, ARRAY_SIZE(exynos5_iodesc));
-}
-
-static void __init exynos4_init_clocks(int xtal)
-{
- printk(KERN_DEBUG "%s: initializing clocks\n", __func__);
-
- s3c24xx_register_baseclocks(xtal);
- s5p_register_clocks(xtal);
- if (soc_is_exynos4210())
- exynos4210_register_clocks();
- else if (soc_is_exynos4212() || soc_is_exynos4412())
- exynos4212_register_clocks();
-
- exynos4_register_clocks();
- exynos4_setup_clocks();
+ if (soc_is_exynos5250())
+ iotable_init(exynos5250_iodesc, ARRAY_SIZE(exynos5250_iodesc));
}
static void __init exynos5440_map_io(void)
@@ -420,237 +442,35 @@ static void __init exynos5440_map_io(void)
iotable_init(exynos5440_iodesc0, ARRAY_SIZE(exynos5440_iodesc0));
}
-static void __init exynos5_init_clocks(int xtal)
-{
- printk(KERN_DEBUG "%s: initializing clocks\n", __func__);
-
- /* EXYNOS5440 can support only common clock framework */
-
- if (soc_is_exynos5440())
- return;
-
-#ifdef CONFIG_SOC_EXYNOS5250
- s3c24xx_register_baseclocks(xtal);
- s5p_register_clocks(xtal);
-
- exynos5_register_clocks();
- exynos5_setup_clocks();
-#endif
-}
-
-#define COMBINER_ENABLE_SET 0x0
-#define COMBINER_ENABLE_CLEAR 0x4
-#define COMBINER_INT_STATUS 0xC
-
-static DEFINE_SPINLOCK(irq_controller_lock);
-
-struct combiner_chip_data {
- unsigned int irq_offset;
- unsigned int irq_mask;
- void __iomem *base;
-};
-
-static struct irq_domain *combiner_irq_domain;
-static struct combiner_chip_data combiner_data[MAX_COMBINER_NR];
-
-static inline void __iomem *combiner_base(struct irq_data *data)
-{
- struct combiner_chip_data *combiner_data =
- irq_data_get_irq_chip_data(data);
-
- return combiner_data->base;
-}
-
-static void combiner_mask_irq(struct irq_data *data)
-{
- u32 mask = 1 << (data->hwirq % 32);
-
- __raw_writel(mask, combiner_base(data) + COMBINER_ENABLE_CLEAR);
-}
-
-static void combiner_unmask_irq(struct irq_data *data)
-{
- u32 mask = 1 << (data->hwirq % 32);
-
- __raw_writel(mask, combiner_base(data) + COMBINER_ENABLE_SET);
-}
-
-static void combiner_handle_cascade_irq(unsigned int irq, struct irq_desc *desc)
+void __init exynos_init_time(void)
{
- struct combiner_chip_data *chip_data = irq_get_handler_data(irq);
- struct irq_chip *chip = irq_get_chip(irq);
- unsigned int cascade_irq, combiner_irq;
- unsigned long status;
-
- chained_irq_enter(chip, desc);
-
- spin_lock(&irq_controller_lock);
- status = __raw_readl(chip_data->base + COMBINER_INT_STATUS);
- spin_unlock(&irq_controller_lock);
- status &= chip_data->irq_mask;
-
- if (status == 0)
- goto out;
-
- combiner_irq = __ffs(status);
-
- cascade_irq = combiner_irq + (chip_data->irq_offset & ~31);
- if (unlikely(cascade_irq >= NR_IRQS))
- do_bad_IRQ(cascade_irq, desc);
- else
- generic_handle_irq(cascade_irq);
-
- out:
- chained_irq_exit(chip, desc);
-}
-
-static struct irq_chip combiner_chip = {
- .name = "COMBINER",
- .irq_mask = combiner_mask_irq,
- .irq_unmask = combiner_unmask_irq,
-};
-
-static void __init combiner_cascade_irq(unsigned int combiner_nr, unsigned int irq)
-{
- unsigned int max_nr;
-
- if (soc_is_exynos5250())
- max_nr = EXYNOS5_MAX_COMBINER_NR;
- else
- max_nr = EXYNOS4_MAX_COMBINER_NR;
-
- if (combiner_nr >= max_nr)
- BUG();
- if (irq_set_handler_data(irq, &combiner_data[combiner_nr]) != 0)
- BUG();
- irq_set_chained_handler(irq, combiner_handle_cascade_irq);
-}
-
-static void __init combiner_init_one(unsigned int combiner_nr,
- void __iomem *base)
-{
- combiner_data[combiner_nr].base = base;
- combiner_data[combiner_nr].irq_offset = irq_find_mapping(
- combiner_irq_domain, combiner_nr * MAX_IRQ_IN_COMBINER);
- combiner_data[combiner_nr].irq_mask = 0xff << ((combiner_nr % 4) << 3);
-
- /* Disable all interrupts */
- __raw_writel(combiner_data[combiner_nr].irq_mask,
- base + COMBINER_ENABLE_CLEAR);
-}
-
+ if (of_have_populated_dt()) {
#ifdef CONFIG_OF
-static int combiner_irq_domain_xlate(struct irq_domain *d,
- struct device_node *controller,
- const u32 *intspec, unsigned int intsize,
- unsigned long *out_hwirq,
- unsigned int *out_type)
-{
- if (d->of_node != controller)
- return -EINVAL;
-
- if (intsize < 2)
- return -EINVAL;
-
- *out_hwirq = intspec[0] * MAX_IRQ_IN_COMBINER + intspec[1];
- *out_type = 0;
-
- return 0;
-}
-#else
-static int combiner_irq_domain_xlate(struct irq_domain *d,
- struct device_node *controller,
- const u32 *intspec, unsigned int intsize,
- unsigned long *out_hwirq,
- unsigned int *out_type)
-{
- return -EINVAL;
-}
+ of_clk_init(NULL);
+ clocksource_of_init();
#endif
-
-static int combiner_irq_domain_map(struct irq_domain *d, unsigned int irq,
- irq_hw_number_t hw)
-{
- irq_set_chip_and_handler(irq, &combiner_chip, handle_level_irq);
- irq_set_chip_data(irq, &combiner_data[hw >> 3]);
- set_irq_flags(irq, IRQF_VALID | IRQF_PROBE);
-
- return 0;
-}
-
-static struct irq_domain_ops combiner_irq_domain_ops = {
- .xlate = combiner_irq_domain_xlate,
- .map = combiner_irq_domain_map,
-};
-
-static void __init combiner_init(void __iomem *combiner_base,
- struct device_node *np)
-{
- int i, irq, irq_base;
- unsigned int max_nr, nr_irq;
-
- if (np) {
- if (of_property_read_u32(np, "samsung,combiner-nr", &max_nr)) {
- pr_warning("%s: number of combiners not specified, "
- "setting default as %d.\n",
- __func__, EXYNOS4_MAX_COMBINER_NR);
- max_nr = EXYNOS4_MAX_COMBINER_NR;
- }
} else {
- max_nr = soc_is_exynos5250() ? EXYNOS5_MAX_COMBINER_NR :
- EXYNOS4_MAX_COMBINER_NR;
- }
- nr_irq = max_nr * MAX_IRQ_IN_COMBINER;
-
- irq_base = irq_alloc_descs(COMBINER_IRQ(0, 0), 1, nr_irq, 0);
- if (IS_ERR_VALUE(irq_base)) {
- irq_base = COMBINER_IRQ(0, 0);
- pr_warning("%s: irq desc alloc failed. Continuing with %d as linux irq base\n", __func__, irq_base);
- }
-
- combiner_irq_domain = irq_domain_add_legacy(np, nr_irq, irq_base, 0,
- &combiner_irq_domain_ops, &combiner_data);
- if (WARN_ON(!combiner_irq_domain)) {
- pr_warning("%s: irq domain init failed\n", __func__);
- return;
- }
-
- for (i = 0; i < max_nr; i++) {
- combiner_init_one(i, combiner_base + (i >> 2) * 0x10);
- irq = IRQ_SPI(i);
-#ifdef CONFIG_OF
- if (np)
- irq = irq_of_parse_and_map(np, i);
+ /* todo: remove after migrating legacy E4 platforms to dt */
+#ifdef CONFIG_ARCH_EXYNOS4
+ exynos4_clk_init(NULL, !soc_is_exynos4210(), S5P_VA_CMU, readl(S5P_VA_CHIPID + 8) & 1);
+ exynos4_clk_register_fixed_ext(xxti_f, xusbxti_f);
#endif
- combiner_cascade_irq(i, irq);
+ mct_init(S5P_VA_SYSTIMER, EXYNOS4_IRQ_MCT_G0, EXYNOS4_IRQ_MCT_L0, EXYNOS4_IRQ_MCT_L1);
}
}
-#ifdef CONFIG_OF
-static int __init combiner_of_init(struct device_node *np,
- struct device_node *parent)
+static unsigned int max_combiner_nr(void)
{
- void __iomem *combiner_base;
-
- combiner_base = of_iomap(np, 0);
- if (!combiner_base) {
- pr_err("%s: failed to map combiner registers\n", __func__);
- return -ENXIO;
- }
-
- combiner_init(combiner_base, np);
-
- return 0;
+ if (soc_is_exynos5250())
+ return EXYNOS5_MAX_COMBINER_NR;
+ else if (soc_is_exynos4412())
+ return EXYNOS4412_MAX_COMBINER_NR;
+ else if (soc_is_exynos4212())
+ return EXYNOS4212_MAX_COMBINER_NR;
+ else
+ return EXYNOS4210_MAX_COMBINER_NR;
}
-static const struct of_device_id exynos_dt_irq_match[] = {
- { .compatible = "arm,cortex-a9-gic", .data = gic_of_init, },
- { .compatible = "arm,cortex-a15-gic", .data = gic_of_init, },
- { .compatible = "samsung,exynos4210-combiner",
- .data = combiner_of_init, },
- {},
-};
-#endif
void __init exynos4_init_irq(void)
{
@@ -662,33 +482,21 @@ void __init exynos4_init_irq(void)
gic_init_bases(0, IRQ_PPI(0), S5P_VA_GIC_DIST, S5P_VA_GIC_CPU, gic_bank_offset, NULL);
#ifdef CONFIG_OF
else
- of_irq_init(exynos_dt_irq_match);
+ irqchip_init();
#endif
if (!of_have_populated_dt())
- combiner_init(S5P_VA_COMBINER_BASE, NULL);
+ combiner_init(S5P_VA_COMBINER_BASE, NULL,
+ max_combiner_nr(), COMBINER_IRQ(0, 0));
- /*
- * The parameters of s5p_init_irq() are for VIC init.
- * Theses parameters should be NULL and 0 because EXYNOS4
- * uses GIC instead of VIC.
- */
- s5p_init_irq(NULL, 0);
+ gic_arch_extn.irq_set_wake = s3c_irq_wake;
}
void __init exynos5_init_irq(void)
{
#ifdef CONFIG_OF
- of_irq_init(exynos_dt_irq_match);
+ irqchip_init();
#endif
- /*
- * The parameters of s5p_init_irq() are for VIC init.
- * Theses parameters should be NULL and 0 because EXYNOS4
- * uses GIC instead of VIC.
- */
- if (!of_machine_is_compatible("samsung,exynos5440"))
- s5p_init_irq(NULL, 0);
-
gic_arch_extn.irq_set_wake = s3c_irq_wake;
}
@@ -1031,8 +839,9 @@ static int __init exynos_init_irq_eint(void)
* interrupt support code here can be completely removed.
*/
static const struct of_device_id exynos_pinctrl_ids[] = {
- { .compatible = "samsung,pinctrl-exynos4210", },
- { .compatible = "samsung,pinctrl-exynos4x12", },
+ { .compatible = "samsung,exynos4210-pinctrl", },
+ { .compatible = "samsung,exynos4x12-pinctrl", },
+ { .compatible = "samsung,exynos5250-pinctrl", },
};
struct device_node *pctrl_np, *wkup_np;
const char *wkup_compat = "samsung,exynos4210-wakeup-eint";
@@ -1086,3 +895,30 @@ static int __init exynos_init_irq_eint(void)
return 0;
}
arch_initcall(exynos_init_irq_eint);
+
+static struct resource exynos4_pmu_resource[] = {
+ DEFINE_RES_IRQ(EXYNOS4_IRQ_PMU),
+ DEFINE_RES_IRQ(EXYNOS4_IRQ_PMU_CPU1),
+#if defined(CONFIG_SOC_EXYNOS4412)
+ DEFINE_RES_IRQ(EXYNOS4_IRQ_PMU_CPU2),
+ DEFINE_RES_IRQ(EXYNOS4_IRQ_PMU_CPU3),
+#endif
+};
+
+static struct platform_device exynos4_device_pmu = {
+ .name = "arm-pmu",
+ .num_resources = ARRAY_SIZE(exynos4_pmu_resource),
+ .resource = exynos4_pmu_resource,
+};
+
+static int __init exynos_armpmu_init(void)
+{
+ if (!of_have_populated_dt()) {
+ if (soc_is_exynos4210() || soc_is_exynos4212())
+ exynos4_device_pmu.num_resources = 2;
+ platform_device_register(&exynos4_device_pmu);
+ }
+
+ return 0;
+}
+arch_initcall(exynos_armpmu_init);