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/smp_plat.h>
  17. #include <asm/smp_scu.h>
  18. /*
  19. * There are two reset registers, one with self-clearing (SC)
  20. * reset and one with non-self-clearing reset (NON_SC).
  21. */
  22. #define CPU_RESET_SC 0x00
  23. #define CPU_RESET_NON_SC 0x20
  24. #define RESET_VECT 0x00
  25. #define SW_RESET_ADDR 0x94
  26. extern u32 boot_inst;
  27. static void __iomem *cpu_ctrl;
  28. static inline void berlin_perform_reset_cpu(unsigned int cpu)
  29. {
  30. u32 val;
  31. val = readl(cpu_ctrl + CPU_RESET_NON_SC);
  32. val &= ~BIT(cpu_logical_map(cpu));
  33. writel(val, cpu_ctrl + CPU_RESET_NON_SC);
  34. val |= BIT(cpu_logical_map(cpu));
  35. writel(val, cpu_ctrl + CPU_RESET_NON_SC);
  36. }
  37. static int berlin_boot_secondary(unsigned int cpu, struct task_struct *idle)
  38. {
  39. if (!cpu_ctrl)
  40. return -EFAULT;
  41. /*
  42. * Reset the CPU, making it to execute the instruction in the reset
  43. * exception vector.
  44. */
  45. berlin_perform_reset_cpu(cpu);
  46. return 0;
  47. }
  48. static void __init berlin_smp_prepare_cpus(unsigned int max_cpus)
  49. {
  50. struct device_node *np;
  51. void __iomem *scu_base;
  52. void __iomem *vectors_base;
  53. np = of_find_compatible_node(NULL, NULL, "arm,cortex-a9-scu");
  54. scu_base = of_iomap(np, 0);
  55. of_node_put(np);
  56. if (!scu_base)
  57. return;
  58. np = of_find_compatible_node(NULL, NULL, "marvell,berlin-cpu-ctrl");
  59. cpu_ctrl = of_iomap(np, 0);
  60. of_node_put(np);
  61. if (!cpu_ctrl)
  62. goto unmap_scu;
  63. vectors_base = ioremap(CONFIG_VECTORS_BASE, SZ_32K);
  64. if (!vectors_base)
  65. goto unmap_scu;
  66. scu_enable(scu_base);
  67. flush_cache_all();
  68. /*
  69. * Write the first instruction the CPU will execute after being reset
  70. * in the reset exception vector.
  71. */
  72. writel(boot_inst, vectors_base + RESET_VECT);
  73. /*
  74. * Write the secondary startup address into the SW reset address
  75. * vector. This is used by boot_inst.
  76. */
  77. writel(virt_to_phys(secondary_startup), vectors_base + SW_RESET_ADDR);
  78. iounmap(vectors_base);
  79. unmap_scu:
  80. iounmap(scu_base);
  81. }
  82. #ifdef CONFIG_HOTPLUG_CPU
  83. static void berlin_cpu_die(unsigned int cpu)
  84. {
  85. v7_exit_coherency_flush(louis);
  86. while (1)
  87. cpu_do_idle();
  88. }
  89. static int berlin_cpu_kill(unsigned int cpu)
  90. {
  91. u32 val;
  92. val = readl(cpu_ctrl + CPU_RESET_NON_SC);
  93. val &= ~BIT(cpu_logical_map(cpu));
  94. writel(val, cpu_ctrl + CPU_RESET_NON_SC);
  95. return 1;
  96. }
  97. #endif
  98. static const struct smp_operations berlin_smp_ops __initconst = {
  99. .smp_prepare_cpus = berlin_smp_prepare_cpus,
  100. .smp_boot_secondary = berlin_boot_secondary,
  101. #ifdef CONFIG_HOTPLUG_CPU
  102. .cpu_die = berlin_cpu_die,
  103. .cpu_kill = berlin_cpu_kill,
  104. #endif
  105. };
  106. CPU_METHOD_OF_DECLARE(berlin_smp, "marvell,berlin-smp", &berlin_smp_ops);