Many platforms are duplicating code for enabling SCU, lets add common code to enable SCU by parsing SCU device node so the duplication in each platform can be avoided.
CC: Krzysztof Kozlowski <k...@kernel.org> CC: Jisheng Zhang <jszh...@marvell.com> CC: Russell King <li...@armlinux.org.uk> CC: Dinh Nguyen <dingu...@opensource.altera.com> CC: Patrice Chotard <patrice.chot...@st.com> CC: Linus Walleij <linus.wall...@linaro.org> CC: Liviu Dudau <liviu.du...@arm.com> CC: Ray Jui <r...@broadcom.com> CC: Stephen Warren <swar...@wwwdotorg.org> CC: Heiko Stuebner <he...@sntech.de> CC: Shawn Guo <shawn...@kernel.org> CC: Michal Simek <michal.si...@xilinx.com> CC: Wei Xu <xuw...@hisilicon.com> CC: Andrew Lunn <and...@lunn.ch> CC: Jun Nie <jun....@linaro.org> Suggested-by: Arnd Bergmann <a...@arndb.de> Signed-off-by: Pankaj Dubey <pankaj.du...@samsung.com> --- arch/arm/include/asm/smp_scu.h | 4 +++ arch/arm/kernel/smp_scu.c | 56 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 60 insertions(+) diff --git a/arch/arm/include/asm/smp_scu.h b/arch/arm/include/asm/smp_scu.h index bfe163c..fdeec07 100644 --- a/arch/arm/include/asm/smp_scu.h +++ b/arch/arm/include/asm/smp_scu.h @@ -39,8 +39,12 @@ static inline int scu_power_mode(void __iomem *scu_base, unsigned int mode) #if defined(CONFIG_SMP) && defined(CONFIG_HAVE_ARM_SCU) void scu_enable(void __iomem *scu_base); +void __iomem *of_scu_get_base(void); +int of_scu_enable(void); #else static inline void scu_enable(void __iomem *scu_base) {} +static inline void __iomem *of_scu_get_base(void) {return NULL; } +static inline int of_scu_enable(void) {return 0; } #endif #endif diff --git a/arch/arm/kernel/smp_scu.c b/arch/arm/kernel/smp_scu.c index 72f9241..d0ac3ed 100644 --- a/arch/arm/kernel/smp_scu.c +++ b/arch/arm/kernel/smp_scu.c @@ -10,6 +10,7 @@ */ #include <linux/init.h> #include <linux/io.h> +#include <linux/of_address.h> #include <asm/smp_plat.h> #include <asm/smp_scu.h> @@ -70,6 +71,61 @@ void scu_enable(void __iomem *scu_base) */ flush_cache_all(); } + +static const struct of_device_id scu_match[] = { + { .compatible = "arm,cortex-a9-scu", }, + { .compatible = "arm,cortex-a5-scu", }, + { } +}; + +/* + * Helper API to get SCU base address + * In case platform DT do not have SCU node, or iomap fails + * this call will fallback and will try to map via call to + * scu_a9_get_base. + * This will return ownership of scu_base to the caller + */ +void __iomem *of_scu_get_base(void) +{ + unsigned long base = 0; + struct device_node *np; + void __iomem *scu_base; + + np = of_find_matching_node(NULL, scu_match); + scu_base = of_iomap(np, 0); + of_node_put(np); + if (!scu_base) { + pr_err("%s failed to map scu_base via DT\n", __func__); + if (scu_a9_has_base()) { + base = scu_a9_get_base(); + scu_base = ioremap(base, SZ_4K); + } + if (!scu_base) { + pr_err("%s failed to map scu_base\n", __func__); + return IOMEM_ERR_PTR(-ENOMEM); + } + } + return scu_base; +} + +/* + * Enable SCU via mapping scu_base DT + * If scu_base mapped successfully scu will be enabled and in case of + * failure if will return non-zero error code + */ +int of_scu_enable(void) +{ + void __iomem *scu_base; + + scu_base = of_scu_get_base(); + if (!IS_ERR(scu_base)) { + scu_enable(scu_base); + iounmap(scu_base); + return 0; + } + return PTR_ERR(scu_base); +} + #endif /* -- 2.7.4