platsmp.c 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123
  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. 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_smp, "allwinner,sun6i-a31", &sun6i_smp_ops);