platsmp.c 2.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131
  1. /*
  2. * Copyright (C) 2014 Marvell Technology Group Ltd.
  3. *
  4. * Antoine Ténart <antoine.tenart@free-electrons.com>
  5. *
  6. * This program is free software; you can redistribute it and/or modify
  7. * it under the terms of the GNU General Public License version 2 as
  8. * published by the Free Software Foundation.
  9. */
  10. #include <linux/io.h>
  11. #include <linux/delay.h>
  12. #include <linux/of.h>
  13. #include <linux/of_address.h>
  14. #include <asm/cacheflush.h>
  15. #include <asm/cp15.h>
  16. #include <asm/memory.h>
  17. #include <asm/smp_plat.h>
  18. #include <asm/smp_scu.h>
  19. /*
  20. * There are two reset registers, one with self-clearing (SC)
  21. * reset and one with non-self-clearing reset (NON_SC).
  22. */
  23. #define CPU_RESET_SC 0x00
  24. #define CPU_RESET_NON_SC 0x20
  25. #define RESET_VECT 0x00
  26. #define SW_RESET_ADDR 0x94
  27. extern u32 boot_inst;
  28. static void __iomem *cpu_ctrl;
  29. static inline void berlin_perform_reset_cpu(unsigned int cpu)
  30. {
  31. u32 val;
  32. val = readl(cpu_ctrl + CPU_RESET_NON_SC);
  33. val &= ~BIT(cpu_logical_map(cpu));
  34. writel(val, cpu_ctrl + CPU_RESET_NON_SC);
  35. val |= BIT(cpu_logical_map(cpu));
  36. writel(val, cpu_ctrl + CPU_RESET_NON_SC);
  37. }
  38. static int berlin_boot_secondary(unsigned int cpu, struct task_struct *idle)
  39. {
  40. if (!cpu_ctrl)
  41. return -EFAULT;
  42. /*
  43. * Reset the CPU, making it to execute the instruction in the reset
  44. * exception vector.
  45. */
  46. berlin_perform_reset_cpu(cpu);
  47. return 0;
  48. }
  49. static void __init berlin_smp_prepare_cpus(unsigned int max_cpus)
  50. {
  51. struct device_node *np;
  52. void __iomem *scu_base;
  53. void __iomem *vectors_base;
  54. np = of_find_compatible_node(NULL, NULL, "arm,cortex-a9-scu");
  55. scu_base = of_iomap(np, 0);
  56. of_node_put(np);
  57. if (!scu_base)
  58. return;
  59. np = of_find_compatible_node(NULL, NULL, "marvell,berlin-cpu-ctrl");
  60. cpu_ctrl = of_iomap(np, 0);
  61. of_node_put(np);
  62. if (!cpu_ctrl)
  63. goto unmap_scu;
  64. vectors_base = ioremap(VECTORS_BASE, SZ_32K);
  65. if (!vectors_base)
  66. goto unmap_scu;
  67. scu_enable(scu_base);
  68. flush_cache_all();
  69. /*
  70. * Write the first instruction the CPU will execute after being reset
  71. * in the reset exception vector.
  72. */
  73. writel(boot_inst, vectors_base + RESET_VECT);
  74. /*
  75. * Write the secondary startup address into the SW reset address
  76. * vector. This is used by boot_inst.
  77. */
  78. writel(__pa_symbol(secondary_startup), vectors_base + SW_RESET_ADDR);
  79. iounmap(vectors_base);
  80. unmap_scu:
  81. iounmap(scu_base);
  82. }
  83. #ifdef CONFIG_HOTPLUG_CPU
  84. static void berlin_cpu_die(unsigned int cpu)
  85. {
  86. v7_exit_coherency_flush(louis);
  87. while (1)
  88. cpu_do_idle();
  89. }
  90. static int berlin_cpu_kill(unsigned int cpu)
  91. {
  92. u32 val;
  93. val = readl(cpu_ctrl + CPU_RESET_NON_SC);
  94. val &= ~BIT(cpu_logical_map(cpu));
  95. writel(val, cpu_ctrl + CPU_RESET_NON_SC);
  96. return 1;
  97. }
  98. #endif
  99. static const struct smp_operations berlin_smp_ops __initconst = {
  100. .smp_prepare_cpus = berlin_smp_prepare_cpus,
  101. .smp_boot_secondary = berlin_boot_secondary,
  102. #ifdef CONFIG_HOTPLUG_CPU
  103. .cpu_die = berlin_cpu_die,
  104. .cpu_kill = berlin_cpu_kill,
  105. #endif
  106. };
  107. CPU_METHOD_OF_DECLARE(berlin_smp, "marvell,berlin-smp", &berlin_smp_ops);