mstarv7.c 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129
  1. // SPDX-License-Identifier: GPL-2.0
  2. /*
  3. * Device Tree support for MStar/Sigmastar Armv7 SoCs
  4. *
  5. * Copyright (c) 2020 thingy.jp
  6. * Author: Daniel Palmer <[email protected]>
  7. */
  8. #include <linux/init.h>
  9. #include <asm/mach/arch.h>
  10. #include <asm/mach/map.h>
  11. #include <linux/of.h>
  12. #include <linux/of_address.h>
  13. #include <linux/io.h>
  14. /*
  15. * In the u-boot code the area these registers are in is
  16. * called "L3 bridge" and there are register descriptions
  17. * for something in the same area called "AXI".
  18. *
  19. * It's not exactly known what this is but the vendor code
  20. * for both u-boot and linux share calls to "flush the miu pipe".
  21. * This seems to be to force pending CPU writes to memory so that
  22. * the state is right before DMA capable devices try to read
  23. * descriptors and data the CPU has prepared. Without doing this
  24. * ethernet doesn't work reliably for example.
  25. */
  26. #define MSTARV7_L3BRIDGE_FLUSH 0x14
  27. #define MSTARV7_L3BRIDGE_STATUS 0x40
  28. #define MSTARV7_L3BRIDGE_FLUSH_TRIGGER BIT(0)
  29. #define MSTARV7_L3BRIDGE_STATUS_DONE BIT(12)
  30. #ifdef CONFIG_SMP
  31. #define MSTARV7_CPU1_BOOT_ADDR_HIGH 0x4c
  32. #define MSTARV7_CPU1_BOOT_ADDR_LOW 0x50
  33. #define MSTARV7_CPU1_UNLOCK 0x58
  34. #define MSTARV7_CPU1_UNLOCK_MAGIC 0xbabe
  35. #endif
  36. static void __iomem *l3bridge;
  37. static const char * const mstarv7_board_dt_compat[] __initconst = {
  38. "mstar,infinity",
  39. "mstar,infinity2m",
  40. "mstar,infinity3",
  41. "mstar,mercury5",
  42. NULL,
  43. };
  44. /*
  45. * This may need locking to deal with situations where an interrupt
  46. * happens while we are in here and mb() gets called by the interrupt handler.
  47. *
  48. * The vendor code did have a spin lock but it doesn't seem to be needed and
  49. * removing it hasn't caused any side effects so far.
  50. *
  51. * [writel|readl]_relaxed have to be used here because otherwise
  52. * we'd end up right back in here.
  53. */
  54. static void mstarv7_mb(void)
  55. {
  56. /* toggle the flush miu pipe fire bit */
  57. writel_relaxed(0, l3bridge + MSTARV7_L3BRIDGE_FLUSH);
  58. writel_relaxed(MSTARV7_L3BRIDGE_FLUSH_TRIGGER, l3bridge
  59. + MSTARV7_L3BRIDGE_FLUSH);
  60. while (!(readl_relaxed(l3bridge + MSTARV7_L3BRIDGE_STATUS)
  61. & MSTARV7_L3BRIDGE_STATUS_DONE)) {
  62. /* wait for flush to complete */
  63. }
  64. }
  65. #ifdef CONFIG_SMP
  66. static int mstarv7_boot_secondary(unsigned int cpu, struct task_struct *idle)
  67. {
  68. struct device_node *np;
  69. u32 bootaddr = (u32) __pa_symbol(secondary_startup_arm);
  70. void __iomem *smpctrl;
  71. /*
  72. * right now we don't know how to boot anything except
  73. * cpu 1.
  74. */
  75. if (cpu != 1)
  76. return -EINVAL;
  77. np = of_find_compatible_node(NULL, NULL, "mstar,smpctrl");
  78. smpctrl = of_iomap(np, 0);
  79. if (!smpctrl)
  80. return -ENODEV;
  81. /* set the boot address for the second cpu */
  82. writew(bootaddr & 0xffff, smpctrl + MSTARV7_CPU1_BOOT_ADDR_LOW);
  83. writew((bootaddr >> 16) & 0xffff, smpctrl + MSTARV7_CPU1_BOOT_ADDR_HIGH);
  84. /* unlock the second cpu */
  85. writew(MSTARV7_CPU1_UNLOCK_MAGIC, smpctrl + MSTARV7_CPU1_UNLOCK);
  86. /* and away we go...*/
  87. arch_send_wakeup_ipi_mask(cpumask_of(cpu));
  88. iounmap(smpctrl);
  89. return 0;
  90. }
  91. static const struct smp_operations __initdata mstarv7_smp_ops = {
  92. .smp_boot_secondary = mstarv7_boot_secondary,
  93. };
  94. #endif
  95. static void __init mstarv7_init(void)
  96. {
  97. struct device_node *np;
  98. np = of_find_compatible_node(NULL, NULL, "mstar,l3bridge");
  99. l3bridge = of_iomap(np, 0);
  100. if (l3bridge)
  101. soc_mb = mstarv7_mb;
  102. else
  103. pr_warn("Failed to install memory barrier, DMA will be broken!\n");
  104. }
  105. DT_MACHINE_START(MSTARV7_DT, "MStar/Sigmastar Armv7 (Device Tree)")
  106. .dt_compat = mstarv7_board_dt_compat,
  107. .init_machine = mstarv7_init,
  108. .smp = smp_ops(mstarv7_smp_ops),
  109. MACHINE_END