leon_pmc.c 2.2 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394
  1. /* leon_pmc.c: LEON Power-down cpu_idle() handler
  2. *
  3. * Copyright (C) 2011 Daniel Hellstrom (daniel@gaisler.com) Aeroflex Gaisler AB
  4. */
  5. #include <linux/init.h>
  6. #include <linux/pm.h>
  7. #include <asm/leon_amba.h>
  8. #include <asm/cpu_type.h>
  9. #include <asm/leon.h>
  10. #include <asm/processor.h>
  11. /* List of Systems that need fixup instructions around power-down instruction */
  12. static unsigned int pmc_leon_fixup_ids[] = {
  13. AEROFLEX_UT699,
  14. GAISLER_GR712RC,
  15. LEON4_NEXTREME1,
  16. 0
  17. };
  18. static int pmc_leon_need_fixup(void)
  19. {
  20. unsigned int systemid = amba_system_id >> 16;
  21. unsigned int *id;
  22. id = &pmc_leon_fixup_ids[0];
  23. while (*id != 0) {
  24. if (*id == systemid)
  25. return 1;
  26. id++;
  27. }
  28. return 0;
  29. }
  30. /*
  31. * CPU idle callback function for systems that need some extra handling
  32. * See .../arch/sparc/kernel/process.c
  33. */
  34. static void pmc_leon_idle_fixup(void)
  35. {
  36. /* Prepare an address to a non-cachable region. APB is always
  37. * none-cachable. One instruction is executed after the Sleep
  38. * instruction, we make sure to read the bus and throw away the
  39. * value by accessing a non-cachable area, also we make sure the
  40. * MMU does not get a TLB miss here by using the MMU BYPASS ASI.
  41. */
  42. register unsigned int address = (unsigned int)leon3_irqctrl_regs;
  43. /* Interrupts need to be enabled to not hang the CPU */
  44. local_irq_enable();
  45. __asm__ __volatile__ (
  46. "wr %%g0, %%asr19\n"
  47. "lda [%0] %1, %%g0\n"
  48. :
  49. : "r"(address), "i"(ASI_LEON_BYPASS));
  50. }
  51. /*
  52. * CPU idle callback function
  53. * See .../arch/sparc/kernel/process.c
  54. */
  55. static void pmc_leon_idle(void)
  56. {
  57. /* Interrupts need to be enabled to not hang the CPU */
  58. local_irq_enable();
  59. /* For systems without power-down, this will be no-op */
  60. __asm__ __volatile__ ("wr %g0, %asr19\n\t");
  61. }
  62. /* Install LEON Power Down function */
  63. static int __init leon_pmc_install(void)
  64. {
  65. if (sparc_cpu_model == sparc_leon) {
  66. /* Assign power management IDLE handler */
  67. if (pmc_leon_need_fixup())
  68. sparc_idle = pmc_leon_idle_fixup;
  69. else
  70. sparc_idle = pmc_leon_idle;
  71. printk(KERN_INFO "leon: power management initialized\n");
  72. }
  73. return 0;
  74. }
  75. /* This driver is not critical to the boot process, don't care
  76. * if initialized late.
  77. */
  78. late_initcall(leon_pmc_install);