diff options
Diffstat (limited to 'arch/arm/mach-keystone')
| -rw-r--r-- | arch/arm/mach-keystone/Kconfig | 8 | ||||
| -rw-r--r-- | arch/arm/mach-keystone/Makefile | 3 | ||||
| -rw-r--r-- | arch/arm/mach-keystone/keystone.c | 104 | ||||
| -rw-r--r-- | arch/arm/mach-keystone/keystone.h | 1 | ||||
| -rw-r--r-- | arch/arm/mach-keystone/memory.h | 24 | ||||
| -rw-r--r-- | arch/arm/mach-keystone/platsmp.c | 17 | ||||
| -rw-r--r-- | arch/arm/mach-keystone/pm_domain.c | 80 | 
7 files changed, 202 insertions, 35 deletions
diff --git a/arch/arm/mach-keystone/Kconfig b/arch/arm/mach-keystone/Kconfig index 366d1a3b418..98a156afaa9 100644 --- a/arch/arm/mach-keystone/Kconfig +++ b/arch/arm/mach-keystone/Kconfig @@ -1,14 +1,14 @@  config ARCH_KEYSTONE  	bool "Texas Instruments Keystone Devices"  	depends on ARCH_MULTI_V7 -	select CPU_V7 +	depends on ARM_PATCH_PHYS_VIRT  	select ARM_GIC  	select HAVE_ARM_ARCH_TIMER -	select HAVE_SMP  	select CLKSRC_MMIO -	select GENERIC_CLOCKEVENTS -	select ARCH_WANT_OPTIONAL_GPIOLIB  	select ARM_ERRATA_798181 if SMP +	select COMMON_CLK_KEYSTONE +	select ARCH_SUPPORTS_BIG_ENDIAN +	select ZONE_DMA if ARM_LPAE  	help  	  Support for boards based on the Texas Instruments Keystone family of  	  SoCs. diff --git a/arch/arm/mach-keystone/Makefile b/arch/arm/mach-keystone/Makefile index ddc52b05dc8..25d92396fbf 100644 --- a/arch/arm/mach-keystone/Makefile +++ b/arch/arm/mach-keystone/Makefile @@ -4,3 +4,6 @@ plus_sec := $(call as-instr,.arch_extension sec,+sec)  AFLAGS_smc.o				:=-Wa,-march=armv7-a$(plus_sec)  obj-$(CONFIG_SMP)			+= platsmp.o + +# PM domain driver for Keystone SOCs +obj-$(CONFIG_ARCH_KEYSTONE)		+= pm_domain.o diff --git a/arch/arm/mach-keystone/keystone.c b/arch/arm/mach-keystone/keystone.c index b661c5c2870..7f352de2609 100644 --- a/arch/arm/mach-keystone/keystone.c +++ b/arch/arm/mach-keystone/keystone.c @@ -14,62 +14,106 @@  #include <linux/init.h>  #include <linux/of_platform.h>  #include <linux/of_address.h> +#include <linux/memblock.h>  #include <asm/setup.h>  #include <asm/mach/map.h>  #include <asm/mach/arch.h>  #include <asm/mach/time.h>  #include <asm/smp_plat.h> +#include <asm/memory.h> -#include "keystone.h" +#include "memory.h" -#define PLL_RESET_WRITE_KEY_MASK		0xffff0000 -#define PLL_RESET_WRITE_KEY			0x5a69 -#define PLL_RESET				BIT(16) +#include "keystone.h" -static void __iomem *keystone_rstctrl; +static struct notifier_block platform_nb; +static unsigned long keystone_dma_pfn_offset __read_mostly; -static void __init keystone_init(void) +static int keystone_platform_notifier(struct notifier_block *nb, +				      unsigned long event, void *data)  { -	struct device_node *node; +	struct device *dev = data; -	node = of_find_compatible_node(NULL, NULL, "ti,keystone-reset"); -	if (WARN_ON(!node)) -		pr_warn("ti,keystone-reset node undefined\n"); +	if (event != BUS_NOTIFY_ADD_DEVICE) +		return NOTIFY_DONE; -	keystone_rstctrl = of_iomap(node, 0); -	if (WARN_ON(!keystone_rstctrl)) -		pr_warn("ti,keystone-reset iomap error\n"); +	if (!dev) +		return NOTIFY_BAD; + +	if (!dev->of_node) { +		dev->dma_pfn_offset = keystone_dma_pfn_offset; +		dev_err(dev, "set dma_pfn_offset%08lx\n", +			dev->dma_pfn_offset); +	} +	return NOTIFY_OK; +} +static void __init keystone_init(void) +{ +	keystone_pm_runtime_init(); +	if (platform_nb.notifier_call) +		bus_register_notifier(&platform_bus_type, &platform_nb);  	of_platform_populate(NULL, of_default_bus_match_table, NULL, NULL);  } -static const char *keystone_match[] __initconst = { -	"ti,keystone-evm", -	NULL, -}; +static phys_addr_t keystone_virt_to_idmap(unsigned long x) +{ +	return (phys_addr_t)(x) - CONFIG_PAGE_OFFSET + KEYSTONE_LOW_PHYS_START; +} -void keystone_restart(enum reboot_mode mode, const char *cmd) +static void __init keystone_init_meminfo(void)  { -	u32 val; +	bool lpae = IS_ENABLED(CONFIG_ARM_LPAE); +	bool pvpatch = IS_ENABLED(CONFIG_ARM_PATCH_PHYS_VIRT); +	phys_addr_t offset = PHYS_OFFSET - KEYSTONE_LOW_PHYS_START; +	phys_addr_t mem_start, mem_end; + +	mem_start = memblock_start_of_DRAM(); +	mem_end = memblock_end_of_DRAM(); + +	/* nothing to do if we are running out of the <32-bit space */ +	if (mem_start >= KEYSTONE_LOW_PHYS_START && +	    mem_end   <= KEYSTONE_LOW_PHYS_END) +		return; + +	if (!lpae || !pvpatch) { +		pr_crit("Enable %s%s%s to run outside 32-bit space\n", +		      !lpae ? __stringify(CONFIG_ARM_LPAE) : "", +		      (!lpae && !pvpatch) ? " and " : "", +		      !pvpatch ? __stringify(CONFIG_ARM_PATCH_PHYS_VIRT) : ""); +	} -	BUG_ON(!keystone_rstctrl); +	if (mem_start < KEYSTONE_HIGH_PHYS_START || +	    mem_end   > KEYSTONE_HIGH_PHYS_END) { +		pr_crit("Invalid address space for memory (%08llx-%08llx)\n", +		      (u64)mem_start, (u64)mem_end); +	} -	/* Enable write access to RSTCTRL */ -	val = readl(keystone_rstctrl); -	val &= PLL_RESET_WRITE_KEY_MASK; -	val |= PLL_RESET_WRITE_KEY; -	writel(val, keystone_rstctrl); +	offset += KEYSTONE_HIGH_PHYS_START; +	__pv_phys_pfn_offset = PFN_DOWN(offset); +	__pv_offset = (offset - PAGE_OFFSET); -	/* Reset the SOC */ -	val = readl(keystone_rstctrl); -	val &= ~PLL_RESET; -	writel(val, keystone_rstctrl); +	/* Populate the arch idmap hook */ +	arch_virt_to_idmap = keystone_virt_to_idmap; +	platform_nb.notifier_call = keystone_platform_notifier; +	keystone_dma_pfn_offset = PFN_DOWN(KEYSTONE_HIGH_PHYS_START - +						KEYSTONE_LOW_PHYS_START); + +	pr_info("Switching to high address space at 0x%llx\n", (u64)offset);  } +static const char *keystone_match[] __initconst = { +	"ti,keystone", +	NULL, +}; +  DT_MACHINE_START(KEYSTONE, "Keystone") +#if defined(CONFIG_ZONE_DMA) && defined(CONFIG_ARM_LPAE) +	.dma_zone_size	= SZ_2G, +#endif  	.smp		= smp_ops(keystone_smp_ops),  	.init_machine	= keystone_init,  	.dt_compat	= keystone_match, -	.restart	= keystone_restart, +	.init_meminfo   = keystone_init_meminfo,  MACHINE_END diff --git a/arch/arm/mach-keystone/keystone.h b/arch/arm/mach-keystone/keystone.h index 60bef9dedb1..cd04a1c14de 100644 --- a/arch/arm/mach-keystone/keystone.h +++ b/arch/arm/mach-keystone/keystone.h @@ -18,6 +18,7 @@  extern struct smp_operations keystone_smp_ops;  extern void secondary_startup(void);  extern u32 keystone_cpu_smc(u32 command, u32 cpu, u32 addr); +extern int keystone_pm_runtime_init(void);  #endif /* __ASSEMBLER__ */  #endif /* __KEYSTONE_H__ */ diff --git a/arch/arm/mach-keystone/memory.h b/arch/arm/mach-keystone/memory.h new file mode 100644 index 00000000000..b854fb18eef --- /dev/null +++ b/arch/arm/mach-keystone/memory.h @@ -0,0 +1,24 @@ +/* + * Copyright 2014 Texas Instruments, Inc. + *	Santosh Shilimkar <santosh.shilimkar@ti.com> + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + */ +#ifndef __MEMORY_H +#define __MEMORY_H + +#define MAX_PHYSMEM_BITS	36 +#define SECTION_SIZE_BITS	34 + +#define KEYSTONE_LOW_PHYS_START		0x80000000ULL +#define KEYSTONE_LOW_PHYS_SIZE		0x80000000ULL /* 2G */ +#define KEYSTONE_LOW_PHYS_END		(KEYSTONE_LOW_PHYS_START + \ +					 KEYSTONE_LOW_PHYS_SIZE - 1) + +#define KEYSTONE_HIGH_PHYS_START	0x800000000ULL +#define KEYSTONE_HIGH_PHYS_SIZE		0x400000000ULL	/* 16G */ +#define KEYSTONE_HIGH_PHYS_END		(KEYSTONE_HIGH_PHYS_START + \ +					 KEYSTONE_HIGH_PHYS_SIZE - 1) +#endif /* __MEMORY_H */ diff --git a/arch/arm/mach-keystone/platsmp.c b/arch/arm/mach-keystone/platsmp.c index c12296157d4..5f46a7cf907 100644 --- a/arch/arm/mach-keystone/platsmp.c +++ b/arch/arm/mach-keystone/platsmp.c @@ -18,13 +18,15 @@  #include <asm/smp_plat.h>  #include <asm/prom.h> +#include <asm/tlbflush.h> +#include <asm/pgtable.h>  #include "keystone.h"  static int keystone_smp_boot_secondary(unsigned int cpu,  						struct task_struct *idle)  { -	unsigned long start = virt_to_phys(&secondary_startup); +	unsigned long start = virt_to_idmap(&secondary_startup);  	int error;  	pr_debug("keystone-smp: booting cpu %d, vector %08lx\n", @@ -37,6 +39,19 @@ static int keystone_smp_boot_secondary(unsigned int cpu,  	return error;  } +#ifdef CONFIG_ARM_LPAE +static void __cpuinit keystone_smp_secondary_initmem(unsigned int cpu) +{ +	pgd_t *pgd0 = pgd_offset_k(0); +	cpu_set_ttbr(1, __pa(pgd0) + TTBR1_OFFSET); +	local_flush_tlb_all(); +} +#else +static inline void __cpuinit keystone_smp_secondary_initmem(unsigned int cpu) +{} +#endif +  struct smp_operations keystone_smp_ops __initdata = {  	.smp_boot_secondary	= keystone_smp_boot_secondary, +	.smp_secondary_init     = keystone_smp_secondary_initmem,  }; diff --git a/arch/arm/mach-keystone/pm_domain.c b/arch/arm/mach-keystone/pm_domain.c new file mode 100644 index 00000000000..ca79ddac38b --- /dev/null +++ b/arch/arm/mach-keystone/pm_domain.c @@ -0,0 +1,80 @@ +/* + * PM domain driver for Keystone2 devices + * + * Copyright 2013 Texas Instruments, Inc. + *	Santosh Shilimkar <santosh.shillimkar@ti.com> + * + * Based on Kevins work on DAVINCI SOCs + *	Kevin Hilman <khilman@linaro.org> + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + */ + +#include <linux/init.h> +#include <linux/pm_runtime.h> +#include <linux/pm_clock.h> +#include <linux/platform_device.h> +#include <linux/clk-provider.h> +#include <linux/of.h> + +#ifdef CONFIG_PM_RUNTIME +static int keystone_pm_runtime_suspend(struct device *dev) +{ +	int ret; + +	dev_dbg(dev, "%s\n", __func__); + +	ret = pm_generic_runtime_suspend(dev); +	if (ret) +		return ret; + +	ret = pm_clk_suspend(dev); +	if (ret) { +		pm_generic_runtime_resume(dev); +		return ret; +	} + +	return 0; +} + +static int keystone_pm_runtime_resume(struct device *dev) +{ +	dev_dbg(dev, "%s\n", __func__); + +	pm_clk_resume(dev); + +	return pm_generic_runtime_resume(dev); +} +#endif + +static struct dev_pm_domain keystone_pm_domain = { +	.ops = { +		SET_RUNTIME_PM_OPS(keystone_pm_runtime_suspend, +				   keystone_pm_runtime_resume, NULL) +		USE_PLATFORM_PM_SLEEP_OPS +	}, +}; + +static struct pm_clk_notifier_block platform_domain_notifier = { +	.pm_domain = &keystone_pm_domain, +}; + +static struct of_device_id of_keystone_table[] = { +	{.compatible = "ti,keystone"}, +	{ /* end of list */ }, +}; + +int __init keystone_pm_runtime_init(void) +{ +	struct device_node *np; + +	np = of_find_matching_node(NULL, of_keystone_table); +	if (!np) +		return 0; + +	pm_clk_add_notifier(&platform_bus_type, &platform_domain_notifier); + +	return 0; +}  | 
