pm.c 2.5 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798
  1. /*
  2. * arch/sh/kernel/cpu/shmobile/pm.c
  3. *
  4. * Power management support code for SuperH Mobile
  5. *
  6. * Copyright (C) 2009 Magnus Damm
  7. *
  8. * This file is subject to the terms and conditions of the GNU General Public
  9. * License. See the file "COPYING" in the main directory of this archive
  10. * for more details.
  11. */
  12. #include <linux/init.h>
  13. #include <linux/kernel.h>
  14. #include <linux/io.h>
  15. #include <linux/suspend.h>
  16. #include <asm/suspend.h>
  17. #include <asm/uaccess.h>
  18. /*
  19. * Notifier lists for pre/post sleep notification
  20. */
  21. ATOMIC_NOTIFIER_HEAD(sh_mobile_pre_sleep_notifier_list);
  22. ATOMIC_NOTIFIER_HEAD(sh_mobile_post_sleep_notifier_list);
  23. /*
  24. * Sleep modes available on SuperH Mobile:
  25. *
  26. * Sleep mode is just plain "sleep" instruction
  27. * Sleep Self-Refresh mode is above plus RAM put in Self-Refresh
  28. * Standby Self-Refresh mode is above plus stopped clocks
  29. */
  30. #define SUSP_MODE_SLEEP (SUSP_SH_SLEEP)
  31. #define SUSP_MODE_SLEEP_SF (SUSP_SH_SLEEP | SUSP_SH_SF)
  32. #define SUSP_MODE_STANDBY_SF (SUSP_SH_STANDBY | SUSP_SH_SF)
  33. /*
  34. * The following modes are not there yet:
  35. *
  36. * R-standby mode is unsupported, but will be added in the future
  37. * U-standby mode is low priority since it needs bootloader hacks
  38. */
  39. #define ILRAM_BASE 0xe5200000
  40. extern const unsigned char sh_mobile_standby[];
  41. extern const unsigned int sh_mobile_standby_size;
  42. void sh_mobile_call_standby(unsigned long mode)
  43. {
  44. void *onchip_mem = (void *)ILRAM_BASE;
  45. void (*standby_onchip_mem)(unsigned long, unsigned long) = onchip_mem;
  46. atomic_notifier_call_chain(&sh_mobile_pre_sleep_notifier_list,
  47. mode, NULL);
  48. /* Let assembly snippet in on-chip memory handle the rest */
  49. standby_onchip_mem(mode, ILRAM_BASE);
  50. atomic_notifier_call_chain(&sh_mobile_post_sleep_notifier_list,
  51. mode, NULL);
  52. }
  53. void sh_mobile_register_self_refresh(unsigned long flags,
  54. void *pre_start, void *pre_end,
  55. void *post_start, void *post_end)
  56. {
  57. }
  58. static int sh_pm_enter(suspend_state_t state)
  59. {
  60. local_irq_disable();
  61. set_bl_bit();
  62. sh_mobile_call_standby(SUSP_MODE_STANDBY_SF);
  63. local_irq_disable();
  64. clear_bl_bit();
  65. return 0;
  66. }
  67. static struct platform_suspend_ops sh_pm_ops = {
  68. .enter = sh_pm_enter,
  69. .valid = suspend_valid_only_mem,
  70. };
  71. static int __init sh_pm_init(void)
  72. {
  73. void *onchip_mem = (void *)ILRAM_BASE;
  74. /* Copy the assembly snippet to the otherwise ununsed ILRAM */
  75. memcpy(onchip_mem, sh_mobile_standby, sh_mobile_standby_size);
  76. wmb();
  77. ctrl_barrier();
  78. suspend_set_ops(&sh_pm_ops);
  79. sh_mobile_setup_cpuidle();
  80. return 0;
  81. }
  82. late_initcall(sh_pm_init);