smp-j2.c 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139
  1. /*
  2. * SMP support for J2 processor
  3. *
  4. * Copyright (C) 2015-2016 Smart Energy Instruments, Inc.
  5. *
  6. * This file is subject to the terms and conditions of the GNU General Public
  7. * License. See the file "COPYING" in the main directory of this archive
  8. * for more details.
  9. */
  10. #include <linux/smp.h>
  11. #include <linux/interrupt.h>
  12. #include <linux/io.h>
  13. #include <linux/of_address.h>
  14. #include <linux/of_irq.h>
  15. #include <asm/cmpxchg.h>
  16. DEFINE_PER_CPU(unsigned, j2_ipi_messages);
  17. extern u32 *sh2_cpuid_addr;
  18. static u32 *j2_ipi_trigger;
  19. static int j2_ipi_irq;
  20. static irqreturn_t j2_ipi_interrupt_handler(int irq, void *arg)
  21. {
  22. unsigned cpu = hard_smp_processor_id();
  23. volatile unsigned *pmsg = &per_cpu(j2_ipi_messages, cpu);
  24. unsigned messages, i;
  25. do messages = *pmsg;
  26. while (cmpxchg(pmsg, messages, 0) != messages);
  27. if (!messages) return IRQ_NONE;
  28. for (i=0; i<SMP_MSG_NR; i++)
  29. if (messages & (1U<<i))
  30. smp_message_recv(i);
  31. return IRQ_HANDLED;
  32. }
  33. static void j2_smp_setup(void)
  34. {
  35. }
  36. static void j2_prepare_cpus(unsigned int max_cpus)
  37. {
  38. struct device_node *np;
  39. unsigned i, max = 1;
  40. np = of_find_compatible_node(NULL, NULL, "jcore,ipi-controller");
  41. if (!np)
  42. goto out;
  43. j2_ipi_irq = irq_of_parse_and_map(np, 0);
  44. j2_ipi_trigger = of_iomap(np, 0);
  45. if (!j2_ipi_irq || !j2_ipi_trigger)
  46. goto out;
  47. np = of_find_compatible_node(NULL, NULL, "jcore,cpuid-mmio");
  48. if (!np)
  49. goto out;
  50. sh2_cpuid_addr = of_iomap(np, 0);
  51. if (!sh2_cpuid_addr)
  52. goto out;
  53. if (request_irq(j2_ipi_irq, j2_ipi_interrupt_handler, IRQF_PERCPU,
  54. "ipi", (void *)j2_ipi_interrupt_handler) != 0)
  55. goto out;
  56. max = max_cpus;
  57. out:
  58. /* Disable any cpus past max_cpus, or all secondaries if we didn't
  59. * get the necessary resources to support SMP. */
  60. for (i=max; i<NR_CPUS; i++) {
  61. set_cpu_possible(i, false);
  62. set_cpu_present(i, false);
  63. }
  64. }
  65. static void j2_start_cpu(unsigned int cpu, unsigned long entry_point)
  66. {
  67. struct device_node *np;
  68. u32 regs[2];
  69. void __iomem *release, *initpc;
  70. if (!cpu) return;
  71. np = of_get_cpu_node(cpu, NULL);
  72. if (!np) return;
  73. if (of_property_read_u32_array(np, "cpu-release-addr", regs, 2)) return;
  74. release = ioremap_nocache(regs[0], sizeof(u32));
  75. initpc = ioremap_nocache(regs[1], sizeof(u32));
  76. __raw_writel(entry_point, initpc);
  77. __raw_writel(1, release);
  78. iounmap(initpc);
  79. iounmap(release);
  80. pr_info("J2 SMP: requested start of cpu %u\n", cpu);
  81. }
  82. static unsigned int j2_smp_processor_id(void)
  83. {
  84. return __raw_readl(sh2_cpuid_addr);
  85. }
  86. static void j2_send_ipi(unsigned int cpu, unsigned int message)
  87. {
  88. volatile unsigned *pmsg;
  89. unsigned old;
  90. unsigned long val;
  91. /* There is only one IPI interrupt shared by all messages, so
  92. * we keep a separate interrupt flag per message type in sw. */
  93. pmsg = &per_cpu(j2_ipi_messages, cpu);
  94. do old = *pmsg;
  95. while (cmpxchg(pmsg, old, old|(1U<<message)) != old);
  96. /* Generate the actual interrupt by writing to CCRn bit 28. */
  97. val = __raw_readl(j2_ipi_trigger + cpu);
  98. __raw_writel(val | (1U<<28), j2_ipi_trigger + cpu);
  99. }
  100. static struct plat_smp_ops j2_smp_ops = {
  101. .smp_setup = j2_smp_setup,
  102. .prepare_cpus = j2_prepare_cpus,
  103. .start_cpu = j2_start_cpu,
  104. .smp_processor_id = j2_smp_processor_id,
  105. .send_ipi = j2_send_ipi,
  106. .cpu_die = native_cpu_die,
  107. .cpu_disable = native_cpu_disable,
  108. .play_dead = native_play_dead,
  109. };
  110. CPU_METHOD_OF_DECLARE(j2_cpu_method, "jcore,spin-table", &j2_smp_ops);