pm.c 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245
  1. /*
  2. * AVR32 AP Power Management
  3. *
  4. * Copyright (C) 2008 Atmel Corporation
  5. *
  6. * This program is free software; you can redistribute it and/or
  7. * modify it under the terms of the GNU General Public License
  8. * version 2 as published by the Free Software Foundation.
  9. */
  10. #include <linux/io.h>
  11. #include <linux/suspend.h>
  12. #include <linux/vmalloc.h>
  13. #include <asm/cacheflush.h>
  14. #include <asm/sysreg.h>
  15. #include <asm/arch/pm.h>
  16. #include <asm/arch/sram.h>
  17. /* FIXME: This is only valid for AP7000 */
  18. #define SDRAMC_BASE 0xfff03800
  19. #include "sdramc.h"
  20. #define SRAM_PAGE_FLAGS (SYSREG_BIT(TLBELO_D) | SYSREG_BF(SZ, 1) \
  21. | SYSREG_BF(AP, 3) | SYSREG_BIT(G))
  22. static unsigned long pm_sram_start;
  23. static size_t pm_sram_size;
  24. static struct vm_struct *pm_sram_area;
  25. static void (*avr32_pm_enter_standby)(unsigned long sdramc_base);
  26. static void (*avr32_pm_enter_str)(unsigned long sdramc_base);
  27. /*
  28. * Must be called with interrupts disabled. Exceptions will be masked
  29. * on return (i.e. all exceptions will be "unrecoverable".)
  30. */
  31. static void *avr32_pm_map_sram(void)
  32. {
  33. unsigned long vaddr;
  34. unsigned long page_addr;
  35. u32 tlbehi;
  36. u32 mmucr;
  37. vaddr = (unsigned long)pm_sram_area->addr;
  38. page_addr = pm_sram_start & PAGE_MASK;
  39. /*
  40. * Mask exceptions and grab the first TLB entry. We won't be
  41. * needing it while sleeping.
  42. */
  43. asm volatile("ssrf %0" : : "i"(SYSREG_EM_OFFSET) : "memory");
  44. mmucr = sysreg_read(MMUCR);
  45. tlbehi = sysreg_read(TLBEHI);
  46. sysreg_write(MMUCR, SYSREG_BFINS(DRP, 0, mmucr));
  47. tlbehi = SYSREG_BF(ASID, SYSREG_BFEXT(ASID, tlbehi));
  48. tlbehi |= vaddr & PAGE_MASK;
  49. tlbehi |= SYSREG_BIT(TLBEHI_V);
  50. sysreg_write(TLBELO, page_addr | SRAM_PAGE_FLAGS);
  51. sysreg_write(TLBEHI, tlbehi);
  52. __builtin_tlbw();
  53. return (void *)(vaddr + pm_sram_start - page_addr);
  54. }
  55. /*
  56. * Must be called with interrupts disabled. Exceptions will be
  57. * unmasked on return.
  58. */
  59. static void avr32_pm_unmap_sram(void)
  60. {
  61. u32 mmucr;
  62. u32 tlbehi;
  63. u32 tlbarlo;
  64. /* Going to update TLB entry at index 0 */
  65. mmucr = sysreg_read(MMUCR);
  66. tlbehi = sysreg_read(TLBEHI);
  67. sysreg_write(MMUCR, SYSREG_BFINS(DRP, 0, mmucr));
  68. /* Clear the "valid" bit */
  69. tlbehi = SYSREG_BF(ASID, SYSREG_BFEXT(ASID, tlbehi));
  70. sysreg_write(TLBEHI, tlbehi);
  71. /* Mark it as "not accessed" */
  72. tlbarlo = sysreg_read(TLBARLO);
  73. sysreg_write(TLBARLO, tlbarlo | 0x80000000U);
  74. /* Update the TLB */
  75. __builtin_tlbw();
  76. /* Unmask exceptions */
  77. asm volatile("csrf %0" : : "i"(SYSREG_EM_OFFSET) : "memory");
  78. }
  79. static int avr32_pm_valid_state(suspend_state_t state)
  80. {
  81. switch (state) {
  82. case PM_SUSPEND_ON:
  83. case PM_SUSPEND_STANDBY:
  84. case PM_SUSPEND_MEM:
  85. return 1;
  86. default:
  87. return 0;
  88. }
  89. }
  90. static int avr32_pm_enter(suspend_state_t state)
  91. {
  92. u32 lpr_saved;
  93. u32 evba_saved;
  94. void *sram;
  95. switch (state) {
  96. case PM_SUSPEND_STANDBY:
  97. sram = avr32_pm_map_sram();
  98. /* Switch to in-sram exception handlers */
  99. evba_saved = sysreg_read(EVBA);
  100. sysreg_write(EVBA, (unsigned long)sram);
  101. /*
  102. * Save the LPR register so that we can re-enable
  103. * SDRAM Low Power mode on resume.
  104. */
  105. lpr_saved = sdramc_readl(LPR);
  106. pr_debug("%s: Entering standby...\n", __func__);
  107. avr32_pm_enter_standby(SDRAMC_BASE);
  108. sdramc_writel(LPR, lpr_saved);
  109. /* Switch back to regular exception handlers */
  110. sysreg_write(EVBA, evba_saved);
  111. avr32_pm_unmap_sram();
  112. break;
  113. case PM_SUSPEND_MEM:
  114. sram = avr32_pm_map_sram();
  115. /* Switch to in-sram exception handlers */
  116. evba_saved = sysreg_read(EVBA);
  117. sysreg_write(EVBA, (unsigned long)sram);
  118. /*
  119. * Save the LPR register so that we can re-enable
  120. * SDRAM Low Power mode on resume.
  121. */
  122. lpr_saved = sdramc_readl(LPR);
  123. pr_debug("%s: Entering suspend-to-ram...\n", __func__);
  124. avr32_pm_enter_str(SDRAMC_BASE);
  125. sdramc_writel(LPR, lpr_saved);
  126. /* Switch back to regular exception handlers */
  127. sysreg_write(EVBA, evba_saved);
  128. avr32_pm_unmap_sram();
  129. break;
  130. case PM_SUSPEND_ON:
  131. pr_debug("%s: Entering idle...\n", __func__);
  132. cpu_enter_idle();
  133. break;
  134. default:
  135. pr_debug("%s: Invalid suspend state %d\n", __func__, state);
  136. goto out;
  137. }
  138. pr_debug("%s: wakeup\n", __func__);
  139. out:
  140. return 0;
  141. }
  142. static struct platform_suspend_ops avr32_pm_ops = {
  143. .valid = avr32_pm_valid_state,
  144. .enter = avr32_pm_enter,
  145. };
  146. static unsigned long avr32_pm_offset(void *symbol)
  147. {
  148. extern u8 pm_exception[];
  149. return (unsigned long)symbol - (unsigned long)pm_exception;
  150. }
  151. static int __init avr32_pm_init(void)
  152. {
  153. extern u8 pm_exception[];
  154. extern u8 pm_irq0[];
  155. extern u8 pm_standby[];
  156. extern u8 pm_suspend_to_ram[];
  157. extern u8 pm_sram_end[];
  158. void *dst;
  159. /*
  160. * To keep things simple, we depend on not needing more than a
  161. * single page.
  162. */
  163. pm_sram_size = avr32_pm_offset(pm_sram_end);
  164. if (pm_sram_size > PAGE_SIZE)
  165. goto err;
  166. pm_sram_start = sram_alloc(pm_sram_size);
  167. if (!pm_sram_start)
  168. goto err_alloc_sram;
  169. /* Grab a virtual area we can use later on. */
  170. pm_sram_area = get_vm_area(pm_sram_size, VM_IOREMAP);
  171. if (!pm_sram_area)
  172. goto err_vm_area;
  173. pm_sram_area->phys_addr = pm_sram_start;
  174. local_irq_disable();
  175. dst = avr32_pm_map_sram();
  176. memcpy(dst, pm_exception, pm_sram_size);
  177. flush_dcache_region(dst, pm_sram_size);
  178. invalidate_icache_region(dst, pm_sram_size);
  179. avr32_pm_unmap_sram();
  180. local_irq_enable();
  181. avr32_pm_enter_standby = dst + avr32_pm_offset(pm_standby);
  182. avr32_pm_enter_str = dst + avr32_pm_offset(pm_suspend_to_ram);
  183. intc_set_suspend_handler(avr32_pm_offset(pm_irq0));
  184. suspend_set_ops(&avr32_pm_ops);
  185. printk("AVR32 AP Power Management enabled\n");
  186. return 0;
  187. err_vm_area:
  188. sram_free(pm_sram_start, pm_sram_size);
  189. err_alloc_sram:
  190. err:
  191. pr_err("AVR32 Power Management initialization failed\n");
  192. return -ENOMEM;
  193. }
  194. arch_initcall(avr32_pm_init);