leon_pmc.c 2.0 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586
  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. unsigned int pmc_leon_fixup_ids[] = {
  13. AEROFLEX_UT699,
  14. GAISLER_GR712RC,
  15. LEON4_NEXTREME1,
  16. 0
  17. };
  18. 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. 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. __asm__ __volatile__ (
  44. "mov %%g0, %%asr19\n"
  45. "lda [%0] %1, %%g0\n"
  46. :
  47. : "r"(address), "i"(ASI_LEON_BYPASS));
  48. }
  49. /*
  50. * CPU idle callback function
  51. * See .../arch/sparc/kernel/process.c
  52. */
  53. void pmc_leon_idle(void)
  54. {
  55. /* For systems without power-down, this will be no-op */
  56. __asm__ __volatile__ ("mov %g0, %asr19\n\t");
  57. }
  58. /* Install LEON Power Down function */
  59. static int __init leon_pmc_install(void)
  60. {
  61. if (sparc_cpu_model == sparc_leon) {
  62. /* Assign power management IDLE handler */
  63. if (pmc_leon_need_fixup())
  64. sparc_idle = pmc_leon_idle_fixup;
  65. else
  66. sparc_idle = pmc_leon_idle;
  67. printk(KERN_INFO "leon: power management initialized\n");
  68. }
  69. return 0;
  70. }
  71. /* This driver is not critical to the boot process, don't care
  72. * if initialized late.
  73. */
  74. late_initcall(leon_pmc_install);