aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGregory CLEMENT <gregory.clement@free-electrons.com>2014-07-23 09:00:40 -0400
committerJason Cooper <jason@lakedaemon.net>2014-07-24 07:46:06 -0400
commit3076cc58c958090ad50acf50fc855845e3462523 (patch)
tree505107f431ba034ff26deaf369ef75744c8dd533
parent3e328428d4d0abe257ee9342d3e370c6487e9601 (diff)
ARM: mvebu: add a common function for the boot address work around
On some of the mvebu SoCs and due to internal BootROM issue, the CPU initial jump code must be placed in the SRAM memory of the SoC. In order to achieve this, we have to unmap the BootROM and at some specific location where the BootROM was placed, create a dedicated MBus window for the SRAM. This SRAM is initialized with a few instructions of code that allows to jump to the real secondary CPU boot address. The SRAM used is the Crypto engine one. This work around is currently needed for booting SMP on Armada 375 Z1 and will be needed for cpuidle support on Armada 370. Instead of duplicating the same code, this commit introduces a common function to handle it: mvebu_setup_boot_addr_wa(). Signed-off-by: Gregory CLEMENT <gregory.clement@free-electrons.com> Signed-off-by: Thomas Petazzoni <thomas.petazzoni@free-electrons.com> Link: https://lkml.kernel.org/r/1406120453-29291-4-git-send-email-thomas.petazzoni@free-electrons.com Signed-off-by: Jason Cooper <jason@lakedaemon.net>
-rw-r--r--arch/arm/mach-mvebu/pmsu.c47
-rw-r--r--arch/arm/mach-mvebu/pmsu.h3
-rw-r--r--arch/arm/mach-mvebu/pmsu_ll.S22
3 files changed, 72 insertions, 0 deletions
diff --git a/arch/arm/mach-mvebu/pmsu.c b/arch/arm/mach-mvebu/pmsu.c
index 9e18ccee0edd..272a9c0565b2 100644
--- a/arch/arm/mach-mvebu/pmsu.c
+++ b/arch/arm/mach-mvebu/pmsu.c
@@ -22,6 +22,7 @@
22#include <linux/init.h> 22#include <linux/init.h>
23#include <linux/io.h> 23#include <linux/io.h>
24#include <linux/kernel.h> 24#include <linux/kernel.h>
25#include <linux/mbus.h>
25#include <linux/of_address.h> 26#include <linux/of_address.h>
26#include <linux/platform_device.h> 27#include <linux/platform_device.h>
27#include <linux/resource.h> 28#include <linux/resource.h>
@@ -63,6 +64,10 @@ static void __iomem *pmsu_mp_base;
63#define L2C_NFABRIC_PM_CTL 0x4 64#define L2C_NFABRIC_PM_CTL 0x4
64#define L2C_NFABRIC_PM_CTL_PWR_DOWN BIT(20) 65#define L2C_NFABRIC_PM_CTL_PWR_DOWN BIT(20)
65 66
67#define SRAM_PHYS_BASE 0xFFFF0000
68#define BOOTROM_BASE 0xFFF00000
69#define BOOTROM_SIZE 0x100000
70
66extern void ll_disable_coherency(void); 71extern void ll_disable_coherency(void);
67extern void ll_enable_coherency(void); 72extern void ll_enable_coherency(void);
68 73
@@ -85,6 +90,48 @@ void mvebu_pmsu_set_cpu_boot_addr(int hw_cpu, void *boot_addr)
85 PMSU_BOOT_ADDR_REDIRECT_OFFSET(hw_cpu)); 90 PMSU_BOOT_ADDR_REDIRECT_OFFSET(hw_cpu));
86} 91}
87 92
93extern unsigned char mvebu_boot_wa_start;
94extern unsigned char mvebu_boot_wa_end;
95
96/*
97 * This function sets up the boot address workaround needed for SMP
98 * boot on Armada 375 Z1 and cpuidle on Armada 370. It unmaps the
99 * BootROM Mbus window, and instead remaps a crypto SRAM into which a
100 * custom piece of code is copied to replace the problematic BootROM.
101 */
102int mvebu_setup_boot_addr_wa(unsigned int crypto_eng_target,
103 unsigned int crypto_eng_attribute,
104 phys_addr_t resume_addr_reg)
105{
106 void __iomem *sram_virt_base;
107 u32 code_len = &mvebu_boot_wa_end - &mvebu_boot_wa_start;
108
109 mvebu_mbus_del_window(BOOTROM_BASE, BOOTROM_SIZE);
110 mvebu_mbus_add_window_by_id(crypto_eng_target, crypto_eng_attribute,
111 SRAM_PHYS_BASE, SZ_64K);
112
113 sram_virt_base = ioremap(SRAM_PHYS_BASE, SZ_64K);
114 if (!sram_virt_base) {
115 pr_err("Unable to map SRAM to setup the boot address WA\n");
116 return -ENOMEM;
117 }
118
119 memcpy(sram_virt_base, &mvebu_boot_wa_start, code_len);
120
121 /*
122 * The last word of the code copied in SRAM must contain the
123 * physical base address of the PMSU register. We
124 * intentionally store this address in the native endianness
125 * of the system.
126 */
127 __raw_writel((unsigned long)resume_addr_reg,
128 sram_virt_base + code_len - 4);
129
130 iounmap(sram_virt_base);
131
132 return 0;
133}
134
88static int __init armada_370_xp_pmsu_init(void) 135static int __init armada_370_xp_pmsu_init(void)
89{ 136{
90 struct device_node *np; 137 struct device_node *np;
diff --git a/arch/arm/mach-mvebu/pmsu.h b/arch/arm/mach-mvebu/pmsu.h
index 07a737c6b95d..ae501948ec73 100644
--- a/arch/arm/mach-mvebu/pmsu.h
+++ b/arch/arm/mach-mvebu/pmsu.h
@@ -12,5 +12,8 @@
12#define __MACH_MVEBU_PMSU_H 12#define __MACH_MVEBU_PMSU_H
13 13
14int armada_xp_boot_cpu(unsigned int cpu_id, void *phys_addr); 14int armada_xp_boot_cpu(unsigned int cpu_id, void *phys_addr);
15int mvebu_setup_boot_addr_wa(unsigned int crypto_eng_target,
16 unsigned int crypto_eng_attribute,
17 phys_addr_t resume_addr_reg);
15 18
16#endif /* __MACH_370_XP_PMSU_H */ 19#endif /* __MACH_370_XP_PMSU_H */
diff --git a/arch/arm/mach-mvebu/pmsu_ll.S b/arch/arm/mach-mvebu/pmsu_ll.S
index fc3de68d8c54..17d7f3b3976d 100644
--- a/arch/arm/mach-mvebu/pmsu_ll.S
+++ b/arch/arm/mach-mvebu/pmsu_ll.S
@@ -23,3 +23,25 @@ ARM_BE8(setend be ) @ go BE8 if entered LE
23 b cpu_resume 23 b cpu_resume
24ENDPROC(armada_370_xp_cpu_resume) 24ENDPROC(armada_370_xp_cpu_resume)
25 25
26.global mvebu_boot_wa_start
27.global mvebu_boot_wa_end
28
29/* The following code will be executed from SRAM */
30ENTRY(mvebu_boot_wa_start)
31mvebu_boot_wa_start:
32ARM_BE8(setend be)
33 adr r0, 1f
34 ldr r0, [r0] @ load the address of the
35 @ resume register
36 ldr r0, [r0] @ load the value in the
37 @ resume register
38ARM_BE8(rev r0, r0) @ the value is stored LE
39 mov pc, r0 @ jump to this value
40/*
41 * the last word of this piece of code will be filled by the physical
42 * address of the boot address register just after being copied in SRAM
43 */
441:
45 .long .
46mvebu_boot_wa_end:
47ENDPROC(mvebu_boot_wa_end)