platsmp.c 3.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147
  1. // SPDX-License-Identifier: GPL-2.0
  2. /*
  3. * Copyright: (C) 2018 Socionext Inc.
  4. * Copyright: (C) 2015 Linaro Ltd.
  5. */
  6. #include <linux/cpu_pm.h>
  7. #include <linux/irqchip/arm-gic.h>
  8. #include <linux/of_address.h>
  9. #include <linux/suspend.h>
  10. #include <asm/cacheflush.h>
  11. #include <asm/cp15.h>
  12. #include <asm/idmap.h>
  13. #include <asm/smp_plat.h>
  14. #include <asm/suspend.h>
  15. #define M10V_MAX_CPU 4
  16. #define KERNEL_UNBOOT_FLAG 0x12345678
  17. static void __iomem *m10v_smp_base;
  18. static int m10v_boot_secondary(unsigned int l_cpu, struct task_struct *idle)
  19. {
  20. unsigned int mpidr, cpu, cluster;
  21. if (!m10v_smp_base)
  22. return -ENXIO;
  23. mpidr = cpu_logical_map(l_cpu);
  24. cpu = MPIDR_AFFINITY_LEVEL(mpidr, 0);
  25. cluster = MPIDR_AFFINITY_LEVEL(mpidr, 1);
  26. if (cpu >= M10V_MAX_CPU)
  27. return -EINVAL;
  28. pr_info("%s: cpu %u l_cpu %u cluster %u\n",
  29. __func__, cpu, l_cpu, cluster);
  30. writel(__pa_symbol(secondary_startup), m10v_smp_base + cpu * 4);
  31. arch_send_wakeup_ipi_mask(cpumask_of(l_cpu));
  32. return 0;
  33. }
  34. static void m10v_smp_init(unsigned int max_cpus)
  35. {
  36. unsigned int mpidr, cpu, cluster;
  37. struct device_node *np;
  38. np = of_find_compatible_node(NULL, NULL, "socionext,milbeaut-smp-sram");
  39. if (!np)
  40. return;
  41. m10v_smp_base = of_iomap(np, 0);
  42. if (!m10v_smp_base)
  43. return;
  44. mpidr = read_cpuid_mpidr();
  45. cpu = MPIDR_AFFINITY_LEVEL(mpidr, 0);
  46. cluster = MPIDR_AFFINITY_LEVEL(mpidr, 1);
  47. pr_info("MCPM boot on cpu_%u cluster_%u\n", cpu, cluster);
  48. for (cpu = 0; cpu < M10V_MAX_CPU; cpu++)
  49. writel(KERNEL_UNBOOT_FLAG, m10v_smp_base + cpu * 4);
  50. }
  51. #ifdef CONFIG_HOTPLUG_CPU
  52. static void m10v_cpu_die(unsigned int l_cpu)
  53. {
  54. gic_cpu_if_down(0);
  55. v7_exit_coherency_flush(louis);
  56. wfi();
  57. }
  58. static int m10v_cpu_kill(unsigned int l_cpu)
  59. {
  60. unsigned int mpidr, cpu;
  61. mpidr = cpu_logical_map(l_cpu);
  62. cpu = MPIDR_AFFINITY_LEVEL(mpidr, 0);
  63. writel(KERNEL_UNBOOT_FLAG, m10v_smp_base + cpu * 4);
  64. return 1;
  65. }
  66. #endif
  67. static struct smp_operations m10v_smp_ops __initdata = {
  68. .smp_prepare_cpus = m10v_smp_init,
  69. .smp_boot_secondary = m10v_boot_secondary,
  70. #ifdef CONFIG_HOTPLUG_CPU
  71. .cpu_die = m10v_cpu_die,
  72. .cpu_kill = m10v_cpu_kill,
  73. #endif
  74. };
  75. CPU_METHOD_OF_DECLARE(m10v_smp, "socionext,milbeaut-m10v-smp", &m10v_smp_ops);
  76. static int m10v_pm_valid(suspend_state_t state)
  77. {
  78. return (state == PM_SUSPEND_STANDBY) || (state == PM_SUSPEND_MEM);
  79. }
  80. typedef void (*phys_reset_t)(unsigned long);
  81. static phys_reset_t phys_reset;
  82. static int m10v_die(unsigned long arg)
  83. {
  84. setup_mm_for_reboot();
  85. asm("wfi");
  86. /* Boot just like a secondary */
  87. phys_reset = (phys_reset_t)(unsigned long)virt_to_phys(cpu_reset);
  88. phys_reset(virt_to_phys(cpu_resume));
  89. return 0;
  90. }
  91. static int m10v_pm_enter(suspend_state_t state)
  92. {
  93. switch (state) {
  94. case PM_SUSPEND_STANDBY:
  95. asm("wfi");
  96. break;
  97. case PM_SUSPEND_MEM:
  98. cpu_pm_enter();
  99. cpu_suspend(0, m10v_die);
  100. cpu_pm_exit();
  101. break;
  102. }
  103. return 0;
  104. }
  105. static const struct platform_suspend_ops m10v_pm_ops = {
  106. .valid = m10v_pm_valid,
  107. .enter = m10v_pm_enter,
  108. };
  109. struct clk *m10v_clclk_register(struct device *cpu_dev);
  110. static int __init m10v_pm_init(void)
  111. {
  112. if (of_machine_is_compatible("socionext,milbeaut-evb"))
  113. suspend_set_ops(&m10v_pm_ops);
  114. return 0;
  115. }
  116. late_initcall(m10v_pm_init);