platsmp.c 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192
  1. /*
  2. * SMP support for Allwinner SoCs
  3. *
  4. * Copyright (C) 2013 Maxime Ripard
  5. *
  6. * Maxime Ripard <maxime.ripard@free-electrons.com>
  7. *
  8. * Based on code
  9. * Copyright (C) 2012-2013 Allwinner Ltd.
  10. *
  11. * This file is licensed under the terms of the GNU General Public
  12. * License version 2. This program is licensed "as is" without any
  13. * warranty of any kind, whether express or implied.
  14. */
  15. #include <linux/delay.h>
  16. #include <linux/init.h>
  17. #include <linux/io.h>
  18. #include <linux/memory.h>
  19. #include <linux/of.h>
  20. #include <linux/of_address.h>
  21. #include <linux/smp.h>
  22. #define CPUCFG_CPU_PWR_CLAMP_STATUS_REG(cpu) ((cpu) * 0x40 + 0x64)
  23. #define CPUCFG_CPU_RST_CTRL_REG(cpu) (((cpu) + 1) * 0x40)
  24. #define CPUCFG_CPU_CTRL_REG(cpu) (((cpu) + 1) * 0x40 + 0x04)
  25. #define CPUCFG_CPU_STATUS_REG(cpu) (((cpu) + 1) * 0x40 + 0x08)
  26. #define CPUCFG_GEN_CTRL_REG 0x184
  27. #define CPUCFG_PRIVATE0_REG 0x1a4
  28. #define CPUCFG_PRIVATE1_REG 0x1a8
  29. #define CPUCFG_DBG_CTL0_REG 0x1e0
  30. #define CPUCFG_DBG_CTL1_REG 0x1e4
  31. #define PRCM_CPU_PWROFF_REG 0x100
  32. #define PRCM_CPU_PWR_CLAMP_REG(cpu) (((cpu) * 4) + 0x140)
  33. static void __iomem *cpucfg_membase;
  34. static void __iomem *prcm_membase;
  35. static DEFINE_SPINLOCK(cpu_lock);
  36. static void __init sun6i_smp_prepare_cpus(unsigned int max_cpus)
  37. {
  38. struct device_node *node;
  39. node = of_find_compatible_node(NULL, NULL, "allwinner,sun6i-a31-prcm");
  40. if (!node) {
  41. pr_err("Missing A31 PRCM node in the device tree\n");
  42. return;
  43. }
  44. prcm_membase = of_iomap(node, 0);
  45. if (!prcm_membase) {
  46. pr_err("Couldn't map A31 PRCM registers\n");
  47. return;
  48. }
  49. node = of_find_compatible_node(NULL, NULL,
  50. "allwinner,sun6i-a31-cpuconfig");
  51. if (!node) {
  52. pr_err("Missing A31 CPU config node in the device tree\n");
  53. return;
  54. }
  55. cpucfg_membase = of_iomap(node, 0);
  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(virt_to_phys(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 struct smp_operations sun6i_smp_ops __initdata = {
  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. if (!prcm_membase) {
  109. pr_err("Couldn't map A23 PRCM registers\n");
  110. return;
  111. }
  112. node = of_find_compatible_node(NULL, NULL,
  113. "allwinner,sun8i-a23-cpuconfig");
  114. if (!node) {
  115. pr_err("Missing A23 CPU config node in the device tree\n");
  116. return;
  117. }
  118. cpucfg_membase = of_iomap(node, 0);
  119. if (!cpucfg_membase)
  120. pr_err("Couldn't map A23 CPU config registers\n");
  121. }
  122. static int sun8i_smp_boot_secondary(unsigned int cpu,
  123. struct task_struct *idle)
  124. {
  125. u32 reg;
  126. if (!(prcm_membase && cpucfg_membase))
  127. return -EFAULT;
  128. spin_lock(&cpu_lock);
  129. /* Set CPU boot address */
  130. writel(virt_to_phys(secondary_startup),
  131. cpucfg_membase + CPUCFG_PRIVATE0_REG);
  132. /* Assert the CPU core in reset */
  133. writel(0, cpucfg_membase + CPUCFG_CPU_RST_CTRL_REG(cpu));
  134. /* Assert the L1 cache in reset */
  135. reg = readl(cpucfg_membase + CPUCFG_GEN_CTRL_REG);
  136. writel(reg & ~BIT(cpu), cpucfg_membase + CPUCFG_GEN_CTRL_REG);
  137. /* Clear CPU power-off gating */
  138. reg = readl(prcm_membase + PRCM_CPU_PWROFF_REG);
  139. writel(reg & ~BIT(cpu), prcm_membase + PRCM_CPU_PWROFF_REG);
  140. mdelay(1);
  141. /* Deassert the CPU core reset */
  142. writel(3, cpucfg_membase + CPUCFG_CPU_RST_CTRL_REG(cpu));
  143. spin_unlock(&cpu_lock);
  144. return 0;
  145. }
  146. struct smp_operations sun8i_smp_ops __initdata = {
  147. .smp_prepare_cpus = sun8i_smp_prepare_cpus,
  148. .smp_boot_secondary = sun8i_smp_boot_secondary,
  149. };
  150. CPU_METHOD_OF_DECLARE(sun8i_a23_smp, "allwinner,sun8i-a23", &sun8i_smp_ops);