r9a06g032-smp.c 2.4 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697
  1. // SPDX-License-Identifier: GPL-2.0
  2. /*
  3. * R9A06G032 Second CA7 enabler.
  4. *
  5. * Copyright (C) 2018 Renesas Electronics Europe Limited
  6. *
  7. * Michel Pollet <michel.pollet@bp.renesas.com>, <buserror@gmail.com>
  8. * Derived from actions,s500-smp
  9. */
  10. #include <linux/io.h>
  11. #include <linux/of.h>
  12. #include <linux/of_address.h>
  13. #include <linux/smp.h>
  14. /*
  15. * The second CPU is parked in ROM at boot time. It requires waking it after
  16. * writing an address into the BOOTADDR register of sysctrl.
  17. *
  18. * So the default value of the "cpu-release-addr" corresponds to BOOTADDR...
  19. *
  20. * *However* the BOOTADDR register is not available when the kernel
  21. * starts in NONSEC mode.
  22. *
  23. * So for NONSEC mode, the bootloader re-parks the second CPU into a pen
  24. * in SRAM, and changes the "cpu-release-addr" of linux's DT to a SRAM address,
  25. * which is not restricted.
  26. */
  27. static void __iomem *cpu_bootaddr;
  28. static DEFINE_SPINLOCK(cpu_lock);
  29. static int
  30. r9a06g032_smp_boot_secondary(unsigned int cpu,
  31. struct task_struct *idle)
  32. {
  33. if (!cpu_bootaddr)
  34. return -ENODEV;
  35. spin_lock(&cpu_lock);
  36. writel(__pa_symbol(secondary_startup), cpu_bootaddr);
  37. arch_send_wakeup_ipi_mask(cpumask_of(cpu));
  38. spin_unlock(&cpu_lock);
  39. return 0;
  40. }
  41. static void __init r9a06g032_smp_prepare_cpus(unsigned int max_cpus)
  42. {
  43. struct device_node *dn;
  44. int ret = -EINVAL, dns;
  45. u32 bootaddr;
  46. dn = of_get_cpu_node(1, NULL);
  47. if (!dn) {
  48. pr_err("CPU#1: missing device tree node\n");
  49. return;
  50. }
  51. /*
  52. * Determine the address from which the CPU is polling.
  53. * The bootloader *does* change this property.
  54. * Note: The property can be either 64 or 32 bits, so handle both cases
  55. */
  56. if (of_find_property(dn, "cpu-release-addr", &dns)) {
  57. if (dns == sizeof(u64)) {
  58. u64 temp;
  59. ret = of_property_read_u64(dn,
  60. "cpu-release-addr", &temp);
  61. bootaddr = temp;
  62. } else {
  63. ret = of_property_read_u32(dn,
  64. "cpu-release-addr",
  65. &bootaddr);
  66. }
  67. }
  68. of_node_put(dn);
  69. if (ret) {
  70. pr_err("CPU#1: invalid cpu-release-addr property\n");
  71. return;
  72. }
  73. pr_info("CPU#1: cpu-release-addr %08x\n", bootaddr);
  74. cpu_bootaddr = ioremap(bootaddr, sizeof(bootaddr));
  75. }
  76. static const struct smp_operations r9a06g032_smp_ops __initconst = {
  77. .smp_prepare_cpus = r9a06g032_smp_prepare_cpus,
  78. .smp_boot_secondary = r9a06g032_smp_boot_secondary,
  79. };
  80. CPU_METHOD_OF_DECLARE(r9a06g032_smp,
  81. "renesas,r9a06g032-smp", &r9a06g032_smp_ops);