diff options
Diffstat (limited to 'arch/arm/mach-exynos/common.c')
| -rw-r--r-- | arch/arm/mach-exynos/common.c | 422 | 
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);  |