platsmp.c 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194
  1. // SPDX-License-Identifier: GPL-2.0
  2. /*
  3. * SMP support for Allwinner SoCs
  4. *
  5. * Copyright (C) 2013 Maxime Ripard
  6. *
  7. * Maxime Ripard <[email protected]>
  8. *
  9. * Based on code
  10. * Copyright (C) 2012-2013 Allwinner Ltd.
  11. *
  12. */
  13. #include <linux/delay.h>
  14. #include <linux/init.h>
  15. #include <linux/io.h>
  16. #include <linux/memory.h>
  17. #include <linux/of.h>
  18. #include <linux/of_address.h>
  19. #include <linux/smp.h>
  20. #define CPUCFG_CPU_PWR_CLAMP_STATUS_REG(cpu) ((cpu) * 0x40 + 0x64)
  21. #define CPUCFG_CPU_RST_CTRL_REG(cpu) (((cpu) + 1) * 0x40)
  22. #define CPUCFG_CPU_CTRL_REG(cpu) (((cpu) + 1) * 0x40 + 0x04)
  23. #define CPUCFG_CPU_STATUS_REG(cpu) (((cpu) + 1) * 0x40 + 0x08)
  24. #define CPUCFG_GEN_CTRL_REG 0x184
  25. #define CPUCFG_PRIVATE0_REG 0x1a4
  26. #define CPUCFG_PRIVATE1_REG 0x1a8
  27. #define CPUCFG_DBG_CTL0_REG 0x1e0
  28. #define CPUCFG_DBG_CTL1_REG 0x1e4
  29. #define PRCM_CPU_PWROFF_REG 0x100
  30. #define PRCM_CPU_PWR_CLAMP_REG(cpu) (((cpu) * 4) + 0x140)
  31. static void __iomem *cpucfg_membase;
  32. static void __iomem *prcm_membase;
  33. static DEFINE_SPINLOCK(cpu_lock);
  34. static void __init sun6i_smp_prepare_cpus(unsigned int max_cpus)
  35. {
  36. struct device_node *node;
  37. node = of_find_compatible_node(NULL, NULL, "allwinner,sun6i-a31-prcm");
  38. if (!node) {
  39. pr_err("Missing A31 PRCM node in the device tree\n");
  40. return;
  41. }
  42. prcm_membase = of_iomap(node, 0);
  43. of_node_put(node);
  44. if (!prcm_membase) {
  45. pr_err("Couldn't map A31 PRCM registers\n");
  46. return;
  47. }
  48. node = of_find_compatible_node(NULL, NULL,
  49. "allwinner,sun6i-a31-cpuconfig");
  50. if (!node) {
  51. pr_err("Missing A31 CPU config node in the device tree\n");
  52. return;
  53. }
  54. cpucfg_membase = of_iomap(node, 0);
  55. of_node_put(node);
  56. if (!cpucfg_membase)
  57. pr_err("Couldn't map A31 CPU config registers\n");
  58. }
  59. static int sun6i_smp_boot_secondary(unsigned int cpu,
  60. struct task_struct *idle)
  61. {
  62. u32 reg;
  63. int i;
  64. if (!(prcm_membase && cpucfg_membase))
  65. return -EFAULT;
  66. spin_lock(&cpu_lock);
  67. /* Set CPU boot address */
  68. writel(__pa_symbol(secondary_startup),
  69. cpucfg_membase + CPUCFG_PRIVATE0_REG);
  70. /* Assert the CPU core in reset */
  71. writel(0, cpucfg_membase + CPUCFG_CPU_RST_CTRL_REG(cpu));
  72. /* Assert the L1 cache in reset */
  73. reg = readl(cpucfg_membase + CPUCFG_GEN_CTRL_REG);
  74. writel(reg & ~BIT(cpu), cpucfg_membase + CPUCFG_GEN_CTRL_REG);
  75. /* Disable external debug access */
  76. reg = readl(cpucfg_membase + CPUCFG_DBG_CTL1_REG);
  77. writel(reg & ~BIT(cpu), cpucfg_membase + CPUCFG_DBG_CTL1_REG);
  78. /* Power up the CPU */
  79. for (i = 0; i <= 8; i++)
  80. writel(0xff >> i, prcm_membase + PRCM_CPU_PWR_CLAMP_REG(cpu));
  81. mdelay(10);
  82. /* Clear CPU power-off gating */
  83. reg = readl(prcm_membase + PRCM_CPU_PWROFF_REG);
  84. writel(reg & ~BIT(cpu), prcm_membase + PRCM_CPU_PWROFF_REG);
  85. mdelay(1);
  86. /* Deassert the CPU core reset */
  87. writel(3, cpucfg_membase + CPUCFG_CPU_RST_CTRL_REG(cpu));
  88. /* Enable back the external debug accesses */
  89. reg = readl(cpucfg_membase + CPUCFG_DBG_CTL1_REG);
  90. writel(reg | BIT(cpu), cpucfg_membase + CPUCFG_DBG_CTL1_REG);
  91. spin_unlock(&cpu_lock);
  92. return 0;
  93. }
  94. static const struct smp_operations sun6i_smp_ops __initconst = {
  95. .smp_prepare_cpus = sun6i_smp_prepare_cpus,
  96. .smp_boot_secondary = sun6i_smp_boot_secondary,
  97. };
  98. CPU_METHOD_OF_DECLARE(sun6i_a31_smp, "allwinner,sun6i-a31", &sun6i_smp_ops);
  99. static void __init sun8i_smp_prepare_cpus(unsigned int max_cpus)
  100. {
  101. struct device_node *node;
  102. node = of_find_compatible_node(NULL, NULL, "allwinner,sun8i-a23-prcm");
  103. if (!node) {
  104. pr_err("Missing A23 PRCM node in the device tree\n");
  105. return;
  106. }
  107. prcm_membase = of_iomap(node, 0);
  108. of_node_put(node);
  109. if (!prcm_membase) {
  110. pr_err("Couldn't map A23 PRCM registers\n");
  111. return;
  112. }
  113. node = of_find_compatible_node(NULL, NULL,
  114. "allwinner,sun8i-a23-cpuconfig");
  115. if (!node) {
  116. pr_err("Missing A23 CPU config node in the device tree\n");
  117. return;
  118. }
  119. cpucfg_membase = of_iomap(node, 0);
  120. of_node_put(node);
  121. if (!cpucfg_membase)
  122. pr_err("Couldn't map A23 CPU config registers\n");
  123. }
  124. static int sun8i_smp_boot_secondary(unsigned int cpu,
  125. struct task_struct *idle)
  126. {
  127. u32 reg;
  128. if (!(prcm_membase && cpucfg_membase))
  129. return -EFAULT;
  130. spin_lock(&cpu_lock);
  131. /* Set CPU boot address */
  132. writel(__pa_symbol(secondary_startup),
  133. cpucfg_membase + CPUCFG_PRIVATE0_REG);
  134. /* Assert the CPU core in reset */
  135. writel(0, cpucfg_membase + CPUCFG_CPU_RST_CTRL_REG(cpu));
  136. /* Assert the L1 cache in reset */
  137. reg = readl(cpucfg_membase + CPUCFG_GEN_CTRL_REG);
  138. writel(reg & ~BIT(cpu), cpucfg_membase + CPUCFG_GEN_CTRL_REG);
  139. /* Clear CPU power-off gating */
  140. reg = readl(prcm_membase + PRCM_CPU_PWROFF_REG);
  141. writel(reg & ~BIT(cpu), prcm_membase + PRCM_CPU_PWROFF_REG);
  142. mdelay(1);
  143. /* Deassert the CPU core reset */
  144. writel(3, cpucfg_membase + CPUCFG_CPU_RST_CTRL_REG(cpu));
  145. spin_unlock(&cpu_lock);
  146. return 0;
  147. }
  148. static const struct smp_operations sun8i_smp_ops __initconst = {
  149. .smp_prepare_cpus = sun8i_smp_prepare_cpus,
  150. .smp_boot_secondary = sun8i_smp_boot_secondary,
  151. };
  152. CPU_METHOD_OF_DECLARE(sun8i_a23_smp, "allwinner,sun8i-a23", &sun8i_smp_ops);