smp-r8a7779.c 3.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125
  1. /*
  2. * SMP support for R-Mobile / SH-Mobile - r8a7779 portion
  3. *
  4. * Copyright (C) 2011 Renesas Solutions Corp.
  5. * Copyright (C) 2011 Magnus Damm
  6. *
  7. * This program is free software; you can redistribute it and/or modify
  8. * it under the terms of the GNU General Public License as published by
  9. * the Free Software Foundation; version 2 of the License.
  10. *
  11. * This program is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. * GNU General Public License for more details.
  15. */
  16. #include <linux/kernel.h>
  17. #include <linux/init.h>
  18. #include <linux/smp.h>
  19. #include <linux/spinlock.h>
  20. #include <linux/io.h>
  21. #include <linux/delay.h>
  22. #include <linux/soc/renesas/rcar-sysc.h>
  23. #include <asm/cacheflush.h>
  24. #include <asm/smp_plat.h>
  25. #include <asm/smp_scu.h>
  26. #include "common.h"
  27. #include "r8a7779.h"
  28. #define AVECR IOMEM(0xfe700040)
  29. #define R8A7779_SCU_BASE 0xf0000000
  30. static const struct rcar_sysc_ch r8a7779_ch_cpu1 = {
  31. .chan_offs = 0x40, /* PWRSR0 .. PWRER0 */
  32. .chan_bit = 1, /* ARM1 */
  33. .isr_bit = 1, /* ARM1 */
  34. };
  35. static const struct rcar_sysc_ch r8a7779_ch_cpu2 = {
  36. .chan_offs = 0x40, /* PWRSR0 .. PWRER0 */
  37. .chan_bit = 2, /* ARM2 */
  38. .isr_bit = 2, /* ARM2 */
  39. };
  40. static const struct rcar_sysc_ch r8a7779_ch_cpu3 = {
  41. .chan_offs = 0x40, /* PWRSR0 .. PWRER0 */
  42. .chan_bit = 3, /* ARM3 */
  43. .isr_bit = 3, /* ARM3 */
  44. };
  45. static const struct rcar_sysc_ch * const r8a7779_ch_cpu[4] = {
  46. [1] = &r8a7779_ch_cpu1,
  47. [2] = &r8a7779_ch_cpu2,
  48. [3] = &r8a7779_ch_cpu3,
  49. };
  50. static int r8a7779_platform_cpu_kill(unsigned int cpu)
  51. {
  52. const struct rcar_sysc_ch *ch = NULL;
  53. int ret = -EIO;
  54. cpu = cpu_logical_map(cpu);
  55. if (cpu < ARRAY_SIZE(r8a7779_ch_cpu))
  56. ch = r8a7779_ch_cpu[cpu];
  57. if (ch)
  58. ret = rcar_sysc_power_down(ch);
  59. return ret ? ret : 1;
  60. }
  61. static int r8a7779_boot_secondary(unsigned int cpu, struct task_struct *idle)
  62. {
  63. const struct rcar_sysc_ch *ch = NULL;
  64. unsigned int lcpu = cpu_logical_map(cpu);
  65. int ret;
  66. if (lcpu < ARRAY_SIZE(r8a7779_ch_cpu))
  67. ch = r8a7779_ch_cpu[lcpu];
  68. if (ch)
  69. ret = rcar_sysc_power_up(ch);
  70. else
  71. ret = -EIO;
  72. return ret;
  73. }
  74. static void __init r8a7779_smp_prepare_cpus(unsigned int max_cpus)
  75. {
  76. /* Map the reset vector (in headsmp-scu.S, headsmp.S) */
  77. __raw_writel(__pa(shmobile_boot_vector), AVECR);
  78. /* setup r8a7779 specific SCU bits */
  79. shmobile_smp_scu_prepare_cpus(R8A7779_SCU_BASE, max_cpus);
  80. r8a7779_pm_init();
  81. /* power off secondary CPUs */
  82. r8a7779_platform_cpu_kill(1);
  83. r8a7779_platform_cpu_kill(2);
  84. r8a7779_platform_cpu_kill(3);
  85. }
  86. #ifdef CONFIG_HOTPLUG_CPU
  87. static int r8a7779_cpu_kill(unsigned int cpu)
  88. {
  89. if (shmobile_smp_scu_cpu_kill(cpu))
  90. return r8a7779_platform_cpu_kill(cpu);
  91. return 0;
  92. }
  93. #endif /* CONFIG_HOTPLUG_CPU */
  94. const struct smp_operations r8a7779_smp_ops __initconst = {
  95. .smp_prepare_cpus = r8a7779_smp_prepare_cpus,
  96. .smp_boot_secondary = r8a7779_boot_secondary,
  97. #ifdef CONFIG_HOTPLUG_CPU
  98. .cpu_die = shmobile_smp_scu_cpu_die,
  99. .cpu_kill = r8a7779_cpu_kill,
  100. #endif
  101. };