board-v7.c 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242
  1. /*
  2. * Device Tree support for Armada 370 and XP platforms.
  3. *
  4. * Copyright (C) 2012 Marvell
  5. *
  6. * Lior Amsalem <alior@marvell.com>
  7. * Gregory CLEMENT <gregory.clement@free-electrons.com>
  8. * Thomas Petazzoni <thomas.petazzoni@free-electrons.com>
  9. *
  10. * This file is licensed under the terms of the GNU General Public
  11. * License version 2. This program is licensed "as is" without any
  12. * warranty of any kind, whether express or implied.
  13. */
  14. #include <linux/kernel.h>
  15. #include <linux/init.h>
  16. #include <linux/clk-provider.h>
  17. #include <linux/of_address.h>
  18. #include <linux/of_platform.h>
  19. #include <linux/io.h>
  20. #include <linux/clocksource.h>
  21. #include <linux/dma-mapping.h>
  22. #include <linux/mbus.h>
  23. #include <linux/signal.h>
  24. #include <linux/slab.h>
  25. #include <linux/irqchip.h>
  26. #include <asm/hardware/cache-l2x0.h>
  27. #include <asm/mach/arch.h>
  28. #include <asm/mach/map.h>
  29. #include <asm/mach/time.h>
  30. #include <asm/smp_scu.h>
  31. #include "armada-370-xp.h"
  32. #include "common.h"
  33. #include "coherency.h"
  34. #include "mvebu-soc-id.h"
  35. static void __iomem *scu_base;
  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. struct device_node *np =
  43. of_find_compatible_node(NULL, NULL, "arm,cortex-a9-scu");
  44. if (np) {
  45. scu_base = of_iomap(np, 0);
  46. scu_enable(scu_base);
  47. of_node_put(np);
  48. }
  49. }
  50. void __iomem *mvebu_get_scu_base(void)
  51. {
  52. return scu_base;
  53. }
  54. /*
  55. * Early versions of Armada 375 SoC have a bug where the BootROM
  56. * leaves an external data abort pending. The kernel is hit by this
  57. * data abort as soon as it enters userspace, because it unmasks the
  58. * data aborts at this moment. We register a custom abort handler
  59. * below to ignore the first data abort to work around this
  60. * problem.
  61. */
  62. static int armada_375_external_abort_wa(unsigned long addr, unsigned int fsr,
  63. struct pt_regs *regs)
  64. {
  65. static int ignore_first;
  66. if (!ignore_first && fsr == 0x1406) {
  67. ignore_first = 1;
  68. return 0;
  69. }
  70. return 1;
  71. }
  72. static void __init mvebu_init_irq(void)
  73. {
  74. irqchip_init();
  75. mvebu_scu_enable();
  76. coherency_init();
  77. BUG_ON(mvebu_mbus_dt_init(coherency_available()));
  78. }
  79. static void __init external_abort_quirk(void)
  80. {
  81. u32 dev, rev;
  82. if (mvebu_get_soc_id(&dev, &rev) == 0 && rev > ARMADA_375_Z1_REV)
  83. return;
  84. hook_fault_code(16 + 6, armada_375_external_abort_wa, SIGBUS, 0,
  85. "imprecise external abort");
  86. }
  87. static void __init i2c_quirk(void)
  88. {
  89. struct device_node *np;
  90. u32 dev, rev;
  91. /*
  92. * Only revisons more recent than A0 support the offload
  93. * mechanism. We can exit only if we are sure that we can
  94. * get the SoC revision and it is more recent than A0.
  95. */
  96. if (mvebu_get_soc_id(&dev, &rev) == 0 && rev > MV78XX0_A0_REV)
  97. return;
  98. for_each_compatible_node(np, NULL, "marvell,mv78230-i2c") {
  99. struct property *new_compat;
  100. new_compat = kzalloc(sizeof(*new_compat), GFP_KERNEL);
  101. new_compat->name = kstrdup("compatible", GFP_KERNEL);
  102. new_compat->length = sizeof("marvell,mv78230-a0-i2c");
  103. new_compat->value = kstrdup("marvell,mv78230-a0-i2c",
  104. GFP_KERNEL);
  105. of_update_property(np, new_compat);
  106. }
  107. return;
  108. }
  109. #define A375_Z1_THERMAL_FIXUP_OFFSET 0xc
  110. static void __init thermal_quirk(void)
  111. {
  112. struct device_node *np;
  113. u32 dev, rev;
  114. int res;
  115. /*
  116. * The early SoC Z1 revision needs a quirk to be applied in order
  117. * for the thermal controller to work properly. This quirk breaks
  118. * the thermal support if applied on a SoC that doesn't need it,
  119. * so we enforce the SoC revision to be known.
  120. */
  121. res = mvebu_get_soc_id(&dev, &rev);
  122. if (res < 0 || (res == 0 && rev > ARMADA_375_Z1_REV))
  123. return;
  124. for_each_compatible_node(np, NULL, "marvell,armada375-thermal") {
  125. struct property *prop;
  126. __be32 newval, *newprop, *oldprop;
  127. int len;
  128. /*
  129. * The register offset is at a wrong location. This quirk
  130. * creates a new reg property as a clone of the previous
  131. * one and corrects the offset.
  132. */
  133. oldprop = (__be32 *)of_get_property(np, "reg", &len);
  134. if (!oldprop)
  135. continue;
  136. /* Create a duplicate of the 'reg' property */
  137. prop = kzalloc(sizeof(*prop), GFP_KERNEL);
  138. prop->length = len;
  139. prop->name = kstrdup("reg", GFP_KERNEL);
  140. prop->value = kzalloc(len, GFP_KERNEL);
  141. memcpy(prop->value, oldprop, len);
  142. /* Fixup the register offset of the second entry */
  143. oldprop += 2;
  144. newprop = (__be32 *)prop->value + 2;
  145. newval = cpu_to_be32(be32_to_cpu(*oldprop) -
  146. A375_Z1_THERMAL_FIXUP_OFFSET);
  147. *newprop = newval;
  148. of_update_property(np, prop);
  149. /*
  150. * The thermal controller needs some quirk too, so let's change
  151. * the compatible string to reflect this and allow the driver
  152. * the take the necessary action.
  153. */
  154. prop = kzalloc(sizeof(*prop), GFP_KERNEL);
  155. prop->name = kstrdup("compatible", GFP_KERNEL);
  156. prop->length = sizeof("marvell,armada375-z1-thermal");
  157. prop->value = kstrdup("marvell,armada375-z1-thermal",
  158. GFP_KERNEL);
  159. of_update_property(np, prop);
  160. }
  161. return;
  162. }
  163. static void __init mvebu_dt_init(void)
  164. {
  165. if (of_machine_is_compatible("marvell,armadaxp"))
  166. i2c_quirk();
  167. if (of_machine_is_compatible("marvell,a375-db")) {
  168. external_abort_quirk();
  169. thermal_quirk();
  170. }
  171. of_platform_populate(NULL, of_default_bus_match_table, NULL, NULL);
  172. }
  173. static const char * const armada_370_xp_dt_compat[] = {
  174. "marvell,armada-370-xp",
  175. NULL,
  176. };
  177. DT_MACHINE_START(ARMADA_370_XP_DT, "Marvell Armada 370/XP (Device Tree)")
  178. .l2c_aux_val = 0,
  179. .l2c_aux_mask = ~0,
  180. .smp = smp_ops(armada_xp_smp_ops),
  181. .init_machine = mvebu_dt_init,
  182. .init_irq = mvebu_init_irq,
  183. .restart = mvebu_restart,
  184. .dt_compat = armada_370_xp_dt_compat,
  185. MACHINE_END
  186. static const char * const armada_375_dt_compat[] = {
  187. "marvell,armada375",
  188. NULL,
  189. };
  190. DT_MACHINE_START(ARMADA_375_DT, "Marvell Armada 375 (Device Tree)")
  191. .l2c_aux_val = 0,
  192. .l2c_aux_mask = ~0,
  193. .init_irq = mvebu_init_irq,
  194. .init_machine = mvebu_dt_init,
  195. .restart = mvebu_restart,
  196. .dt_compat = armada_375_dt_compat,
  197. MACHINE_END
  198. static const char * const armada_38x_dt_compat[] = {
  199. "marvell,armada380",
  200. "marvell,armada385",
  201. NULL,
  202. };
  203. DT_MACHINE_START(ARMADA_38X_DT, "Marvell Armada 380/385 (Device Tree)")
  204. .l2c_aux_val = 0,
  205. .l2c_aux_mask = ~0,
  206. .init_irq = mvebu_init_irq,
  207. .restart = mvebu_restart,
  208. .dt_compat = armada_38x_dt_compat,
  209. MACHINE_END