platsmp-scu.c 2.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081
  1. /*
  2. * SMP support for SoCs with SCU covered by mach-shmobile
  3. *
  4. * Copyright (C) 2013 Magnus Damm
  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/delay.h>
  11. #include <linux/init.h>
  12. #include <linux/io.h>
  13. #include <linux/smp.h>
  14. #include <asm/cacheflush.h>
  15. #include <asm/smp_plat.h>
  16. #include <asm/smp_scu.h>
  17. #include <mach/common.h>
  18. void __init shmobile_smp_scu_prepare_cpus(unsigned int max_cpus)
  19. {
  20. /* install boot code shared by all CPUs */
  21. shmobile_boot_fn = virt_to_phys(shmobile_smp_boot);
  22. shmobile_boot_arg = MPIDR_HWID_BITMASK;
  23. /* enable SCU and cache coherency on booting CPU */
  24. scu_enable(shmobile_scu_base);
  25. scu_power_mode(shmobile_scu_base, SCU_PM_NORMAL);
  26. }
  27. int shmobile_smp_scu_boot_secondary(unsigned int cpu, struct task_struct *idle)
  28. {
  29. /* For this particular CPU register SCU boot vector */
  30. shmobile_smp_hook(cpu, virt_to_phys(shmobile_boot_scu),
  31. (unsigned long)shmobile_scu_base);
  32. return 0;
  33. }
  34. #ifdef CONFIG_HOTPLUG_CPU
  35. void shmobile_smp_scu_cpu_die(unsigned int cpu)
  36. {
  37. /* For this particular CPU deregister boot vector */
  38. shmobile_smp_hook(cpu, 0, 0);
  39. dsb();
  40. flush_cache_all();
  41. /* disable cache coherency */
  42. scu_power_mode(shmobile_scu_base, SCU_PM_POWEROFF);
  43. /* jump to shared mach-shmobile sleep / reset code */
  44. shmobile_smp_sleep();
  45. }
  46. static int shmobile_smp_scu_psr_core_disabled(int cpu)
  47. {
  48. unsigned long mask = SCU_PM_POWEROFF << (cpu * 8);
  49. if ((__raw_readl(shmobile_scu_base + 8) & mask) == mask)
  50. return 1;
  51. return 0;
  52. }
  53. int shmobile_smp_scu_cpu_kill(unsigned int cpu)
  54. {
  55. int k;
  56. /* this function is running on another CPU than the offline target,
  57. * here we need wait for shutdown code in platform_cpu_die() to
  58. * finish before asking SoC-specific code to power off the CPU core.
  59. */
  60. for (k = 0; k < 1000; k++) {
  61. if (shmobile_smp_scu_psr_core_disabled(cpu))
  62. return 1;
  63. mdelay(1);
  64. }
  65. return 0;
  66. }
  67. #endif