diff options
Diffstat (limited to 'arch/arm/mach-mvebu/board-v7.c')
-rw-r--r-- | arch/arm/mach-mvebu/board-v7.c | 89 |
1 files changed, 84 insertions, 5 deletions
diff --git a/arch/arm/mach-mvebu/board-v7.c b/arch/arm/mach-mvebu/board-v7.c index 333fca8fdc41..8bb742fdf5ca 100644 --- a/arch/arm/mach-mvebu/board-v7.c +++ b/arch/arm/mach-mvebu/board-v7.c | |||
@@ -27,12 +27,30 @@ | |||
27 | #include <asm/mach/arch.h> | 27 | #include <asm/mach/arch.h> |
28 | #include <asm/mach/map.h> | 28 | #include <asm/mach/map.h> |
29 | #include <asm/mach/time.h> | 29 | #include <asm/mach/time.h> |
30 | #include <asm/smp_scu.h> | ||
30 | #include "armada-370-xp.h" | 31 | #include "armada-370-xp.h" |
31 | #include "common.h" | 32 | #include "common.h" |
32 | #include "coherency.h" | 33 | #include "coherency.h" |
33 | #include "mvebu-soc-id.h" | 34 | #include "mvebu-soc-id.h" |
34 | 35 | ||
35 | /* | 36 | /* |
37 | * Enables the SCU when available. Obviously, this is only useful on | ||
38 | * Cortex-A based SOCs, not on PJ4B based ones. | ||
39 | */ | ||
40 | static void __init mvebu_scu_enable(void) | ||
41 | { | ||
42 | void __iomem *scu_base; | ||
43 | |||
44 | struct device_node *np = | ||
45 | of_find_compatible_node(NULL, NULL, "arm,cortex-a9-scu"); | ||
46 | if (np) { | ||
47 | scu_base = of_iomap(np, 0); | ||
48 | scu_enable(scu_base); | ||
49 | of_node_put(np); | ||
50 | } | ||
51 | } | ||
52 | |||
53 | /* | ||
36 | * Early versions of Armada 375 SoC have a bug where the BootROM | 54 | * Early versions of Armada 375 SoC have a bug where the BootROM |
37 | * leaves an external data abort pending. The kernel is hit by this | 55 | * leaves an external data abort pending. The kernel is hit by this |
38 | * data abort as soon as it enters userspace, because it unmasks the | 56 | * data abort as soon as it enters userspace, because it unmasks the |
@@ -57,11 +75,9 @@ static void __init mvebu_timer_and_clk_init(void) | |||
57 | { | 75 | { |
58 | of_clk_init(NULL); | 76 | of_clk_init(NULL); |
59 | clocksource_of_init(); | 77 | clocksource_of_init(); |
78 | mvebu_scu_enable(); | ||
60 | coherency_init(); | 79 | coherency_init(); |
61 | BUG_ON(mvebu_mbus_dt_init()); | 80 | BUG_ON(mvebu_mbus_dt_init(coherency_available())); |
62 | #ifdef CONFIG_CACHE_L2X0 | ||
63 | l2x0_of_init(0, ~0UL); | ||
64 | #endif | ||
65 | 81 | ||
66 | if (of_machine_is_compatible("marvell,armada375")) | 82 | if (of_machine_is_compatible("marvell,armada375")) |
67 | hook_fault_code(16 + 6, armada_375_external_abort_wa, SIGBUS, 0, | 83 | hook_fault_code(16 + 6, armada_375_external_abort_wa, SIGBUS, 0, |
@@ -78,7 +94,7 @@ static void __init i2c_quirk(void) | |||
78 | * mechanism. We can exit only if we are sure that we can | 94 | * mechanism. We can exit only if we are sure that we can |
79 | * get the SoC revision and it is more recent than A0. | 95 | * get the SoC revision and it is more recent than A0. |
80 | */ | 96 | */ |
81 | if (mvebu_get_soc_id(&rev, &dev) == 0 && dev > MV78XX0_A0_REV) | 97 | if (mvebu_get_soc_id(&dev, &rev) == 0 && rev > MV78XX0_A0_REV) |
82 | return; | 98 | return; |
83 | 99 | ||
84 | for_each_compatible_node(np, NULL, "marvell,mv78230-i2c") { | 100 | for_each_compatible_node(np, NULL, "marvell,mv78230-i2c") { |
@@ -96,10 +112,66 @@ static void __init i2c_quirk(void) | |||
96 | return; | 112 | return; |
97 | } | 113 | } |
98 | 114 | ||
115 | #define A375_Z1_THERMAL_FIXUP_OFFSET 0xc | ||
116 | |||
117 | static void __init thermal_quirk(void) | ||
118 | { | ||
119 | struct device_node *np; | ||
120 | u32 dev, rev; | ||
121 | |||
122 | if (mvebu_get_soc_id(&dev, &rev) == 0 && rev > ARMADA_375_Z1_REV) | ||
123 | return; | ||
124 | |||
125 | for_each_compatible_node(np, NULL, "marvell,armada375-thermal") { | ||
126 | struct property *prop; | ||
127 | __be32 newval, *newprop, *oldprop; | ||
128 | int len; | ||
129 | |||
130 | /* | ||
131 | * The register offset is at a wrong location. This quirk | ||
132 | * creates a new reg property as a clone of the previous | ||
133 | * one and corrects the offset. | ||
134 | */ | ||
135 | oldprop = (__be32 *)of_get_property(np, "reg", &len); | ||
136 | if (!oldprop) | ||
137 | continue; | ||
138 | |||
139 | /* Create a duplicate of the 'reg' property */ | ||
140 | prop = kzalloc(sizeof(*prop), GFP_KERNEL); | ||
141 | prop->length = len; | ||
142 | prop->name = kstrdup("reg", GFP_KERNEL); | ||
143 | prop->value = kzalloc(len, GFP_KERNEL); | ||
144 | memcpy(prop->value, oldprop, len); | ||
145 | |||
146 | /* Fixup the register offset of the second entry */ | ||
147 | oldprop += 2; | ||
148 | newprop = (__be32 *)prop->value + 2; | ||
149 | newval = cpu_to_be32(be32_to_cpu(*oldprop) - | ||
150 | A375_Z1_THERMAL_FIXUP_OFFSET); | ||
151 | *newprop = newval; | ||
152 | of_update_property(np, prop); | ||
153 | |||
154 | /* | ||
155 | * The thermal controller needs some quirk too, so let's change | ||
156 | * the compatible string to reflect this. | ||
157 | */ | ||
158 | prop = kzalloc(sizeof(*prop), GFP_KERNEL); | ||
159 | prop->name = kstrdup("compatible", GFP_KERNEL); | ||
160 | prop->length = sizeof("marvell,armada375-z1-thermal"); | ||
161 | prop->value = kstrdup("marvell,armada375-z1-thermal", | ||
162 | GFP_KERNEL); | ||
163 | of_update_property(np, prop); | ||
164 | } | ||
165 | return; | ||
166 | } | ||
167 | |||
99 | static void __init mvebu_dt_init(void) | 168 | static void __init mvebu_dt_init(void) |
100 | { | 169 | { |
101 | if (of_machine_is_compatible("plathome,openblocks-ax3-4")) | 170 | if (of_machine_is_compatible("plathome,openblocks-ax3-4")) |
102 | i2c_quirk(); | 171 | i2c_quirk(); |
172 | if (of_machine_is_compatible("marvell,a375-db")) | ||
173 | thermal_quirk(); | ||
174 | |||
103 | of_platform_populate(NULL, of_default_bus_match_table, NULL, NULL); | 175 | of_platform_populate(NULL, of_default_bus_match_table, NULL, NULL); |
104 | } | 176 | } |
105 | 177 | ||
@@ -109,6 +181,8 @@ static const char * const armada_370_xp_dt_compat[] = { | |||
109 | }; | 181 | }; |
110 | 182 | ||
111 | DT_MACHINE_START(ARMADA_370_XP_DT, "Marvell Armada 370/XP (Device Tree)") | 183 | DT_MACHINE_START(ARMADA_370_XP_DT, "Marvell Armada 370/XP (Device Tree)") |
184 | .l2c_aux_val = 0, | ||
185 | .l2c_aux_mask = ~0, | ||
112 | .smp = smp_ops(armada_xp_smp_ops), | 186 | .smp = smp_ops(armada_xp_smp_ops), |
113 | .init_machine = mvebu_dt_init, | 187 | .init_machine = mvebu_dt_init, |
114 | .init_time = mvebu_timer_and_clk_init, | 188 | .init_time = mvebu_timer_and_clk_init, |
@@ -122,7 +196,10 @@ static const char * const armada_375_dt_compat[] = { | |||
122 | }; | 196 | }; |
123 | 197 | ||
124 | DT_MACHINE_START(ARMADA_375_DT, "Marvell Armada 375 (Device Tree)") | 198 | DT_MACHINE_START(ARMADA_375_DT, "Marvell Armada 375 (Device Tree)") |
199 | .l2c_aux_val = 0, | ||
200 | .l2c_aux_mask = ~0, | ||
125 | .init_time = mvebu_timer_and_clk_init, | 201 | .init_time = mvebu_timer_and_clk_init, |
202 | .init_machine = mvebu_dt_init, | ||
126 | .restart = mvebu_restart, | 203 | .restart = mvebu_restart, |
127 | .dt_compat = armada_375_dt_compat, | 204 | .dt_compat = armada_375_dt_compat, |
128 | MACHINE_END | 205 | MACHINE_END |
@@ -134,6 +211,8 @@ static const char * const armada_38x_dt_compat[] = { | |||
134 | }; | 211 | }; |
135 | 212 | ||
136 | DT_MACHINE_START(ARMADA_38X_DT, "Marvell Armada 380/385 (Device Tree)") | 213 | DT_MACHINE_START(ARMADA_38X_DT, "Marvell Armada 380/385 (Device Tree)") |
214 | .l2c_aux_val = 0, | ||
215 | .l2c_aux_mask = ~0, | ||
137 | .init_time = mvebu_timer_and_clk_init, | 216 | .init_time = mvebu_timer_and_clk_init, |
138 | .restart = mvebu_restart, | 217 | .restart = mvebu_restart, |
139 | .dt_compat = armada_38x_dt_compat, | 218 | .dt_compat = armada_38x_dt_compat, |