idle_6xx.S 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191
  1. /* SPDX-License-Identifier: GPL-2.0-or-later */
  2. /*
  3. * This file contains the power_save function for 6xx & 7xxx CPUs
  4. * rewritten in assembler
  5. *
  6. * Warning ! This code assumes that if your machine has a 750fx
  7. * it will have PLL 1 set to low speed mode (used during NAP/DOZE).
  8. * if this is not the case some additional changes will have to
  9. * be done to check a runtime var (a bit like powersave-nap)
  10. */
  11. #include <linux/threads.h>
  12. #include <asm/reg.h>
  13. #include <asm/page.h>
  14. #include <asm/cputable.h>
  15. #include <asm/thread_info.h>
  16. #include <asm/ppc_asm.h>
  17. #include <asm/asm-offsets.h>
  18. #include <asm/feature-fixups.h>
  19. .text
  20. /*
  21. * Init idle, called at early CPU setup time from head.S for each CPU
  22. * Make sure no rest of NAP mode remains in HID0, save default
  23. * values for some CPU specific registers. Called with r24
  24. * containing CPU number and r3 reloc offset
  25. */
  26. _GLOBAL(init_idle_6xx)
  27. BEGIN_FTR_SECTION
  28. mfspr r4,SPRN_HID0
  29. rlwinm r4,r4,0,10,8 /* Clear NAP */
  30. mtspr SPRN_HID0, r4
  31. b 1f
  32. END_FTR_SECTION_IFSET(CPU_FTR_CAN_NAP)
  33. blr
  34. 1:
  35. slwi r5,r24,2
  36. add r5,r5,r3
  37. BEGIN_FTR_SECTION
  38. mfspr r4,SPRN_MSSCR0
  39. addis r6,r5, nap_save_msscr0@ha
  40. stw r4,nap_save_msscr0@l(r6)
  41. END_FTR_SECTION_IFSET(CPU_FTR_NAP_DISABLE_L2_PR)
  42. BEGIN_FTR_SECTION
  43. mfspr r4,SPRN_HID1
  44. addis r6,r5,nap_save_hid1@ha
  45. stw r4,nap_save_hid1@l(r6)
  46. END_FTR_SECTION_IFSET(CPU_FTR_DUAL_PLL_750FX)
  47. blr
  48. /*
  49. * Here is the power_save_6xx function. This could eventually be
  50. * split into several functions & changing the function pointer
  51. * depending on the various features.
  52. */
  53. _GLOBAL(ppc6xx_idle)
  54. /* Check if we can nap or doze, put HID0 mask in r3
  55. */
  56. lis r3, 0
  57. BEGIN_FTR_SECTION
  58. lis r3,HID0_DOZE@h
  59. END_FTR_SECTION_IFSET(CPU_FTR_CAN_DOZE)
  60. BEGIN_FTR_SECTION
  61. /* We must dynamically check for the NAP feature as it
  62. * can be cleared by CPU init after the fixups are done
  63. */
  64. lis r4,cur_cpu_spec@ha
  65. lwz r4,cur_cpu_spec@l(r4)
  66. lwz r4,CPU_SPEC_FEATURES(r4)
  67. andi. r0,r4,CPU_FTR_CAN_NAP
  68. beq 1f
  69. /* Now check if user or arch enabled NAP mode */
  70. lis r4,powersave_nap@ha
  71. lwz r4,powersave_nap@l(r4)
  72. cmpwi 0,r4,0
  73. beq 1f
  74. lis r3,HID0_NAP@h
  75. 1:
  76. END_FTR_SECTION_IFSET(CPU_FTR_CAN_NAP)
  77. cmpwi 0,r3,0
  78. beqlr
  79. /* Some pre-nap cleanups needed on some CPUs */
  80. andis. r0,r3,HID0_NAP@h
  81. beq 2f
  82. BEGIN_FTR_SECTION
  83. /* Disable L2 prefetch on some 745x and try to ensure
  84. * L2 prefetch engines are idle. As explained by errata
  85. * text, we can't be sure they are, we just hope very hard
  86. * that well be enough (sic !). At least I noticed Apple
  87. * doesn't even bother doing the dcbf's here...
  88. */
  89. mfspr r4,SPRN_MSSCR0
  90. rlwinm r4,r4,0,0,29
  91. sync
  92. mtspr SPRN_MSSCR0,r4
  93. sync
  94. isync
  95. lis r4,KERNELBASE@h
  96. dcbf 0,r4
  97. dcbf 0,r4
  98. dcbf 0,r4
  99. dcbf 0,r4
  100. END_FTR_SECTION_IFSET(CPU_FTR_NAP_DISABLE_L2_PR)
  101. 2:
  102. BEGIN_FTR_SECTION
  103. /* Go to low speed mode on some 750FX */
  104. lis r4,powersave_lowspeed@ha
  105. lwz r4,powersave_lowspeed@l(r4)
  106. cmpwi 0,r4,0
  107. beq 1f
  108. mfspr r4,SPRN_HID1
  109. oris r4,r4,0x0001
  110. mtspr SPRN_HID1,r4
  111. 1:
  112. END_FTR_SECTION_IFSET(CPU_FTR_DUAL_PLL_750FX)
  113. /* Go to NAP or DOZE now */
  114. mfspr r4,SPRN_HID0
  115. lis r5,(HID0_NAP|HID0_SLEEP)@h
  116. BEGIN_FTR_SECTION
  117. oris r5,r5,HID0_DOZE@h
  118. END_FTR_SECTION_IFSET(CPU_FTR_CAN_DOZE)
  119. andc r4,r4,r5
  120. or r4,r4,r3
  121. BEGIN_FTR_SECTION
  122. oris r4,r4,HID0_DPM@h /* that should be done once for all */
  123. END_FTR_SECTION_IFCLR(CPU_FTR_NO_DPM)
  124. mtspr SPRN_HID0,r4
  125. BEGIN_FTR_SECTION
  126. PPC_DSSALL
  127. sync
  128. END_FTR_SECTION_IFSET(CPU_FTR_ALTIVEC)
  129. lwz r8,TI_LOCAL_FLAGS(r2) /* set napping bit */
  130. ori r8,r8,_TLF_NAPPING /* so when we take an exception */
  131. stw r8,TI_LOCAL_FLAGS(r2) /* it will return to our caller */
  132. mfmsr r7
  133. ori r7,r7,MSR_EE
  134. oris r7,r7,MSR_POW@h
  135. 1: sync
  136. mtmsr r7
  137. isync
  138. b 1b
  139. /*
  140. * Return from NAP/DOZE mode, restore some CPU specific registers,
  141. * R11 points to the exception frame. We have to preserve r10.
  142. */
  143. _GLOBAL(power_save_ppc32_restore)
  144. lwz r9,_LINK(r11) /* interrupted in ppc6xx_idle: */
  145. stw r9,_NIP(r11) /* make it do a blr */
  146. #ifdef CONFIG_SMP
  147. lwz r11,TASK_CPU(r2) /* get cpu number * 4 */
  148. slwi r11,r11,2
  149. #else
  150. li r11,0
  151. #endif
  152. /* Todo make sure all these are in the same page
  153. * and load r11 (@ha part + CPU offset) only once
  154. */
  155. BEGIN_FTR_SECTION
  156. mfspr r9,SPRN_HID0
  157. andis. r9,r9,HID0_NAP@h
  158. beq 1f
  159. addis r9, r11, nap_save_msscr0@ha
  160. lwz r9,nap_save_msscr0@l(r9)
  161. mtspr SPRN_MSSCR0, r9
  162. sync
  163. isync
  164. 1:
  165. END_FTR_SECTION_IFSET(CPU_FTR_NAP_DISABLE_L2_PR)
  166. BEGIN_FTR_SECTION
  167. addis r9, r11, nap_save_hid1@ha
  168. lwz r9,nap_save_hid1@l(r9)
  169. mtspr SPRN_HID1, r9
  170. END_FTR_SECTION_IFSET(CPU_FTR_DUAL_PLL_750FX)
  171. blr
  172. _ASM_NOKPROBE_SYMBOL(power_save_ppc32_restore)
  173. .data
  174. _GLOBAL(nap_save_msscr0)
  175. .space 4*NR_CPUS
  176. _GLOBAL(nap_save_hid1)
  177. .space 4*NR_CPUS
  178. _GLOBAL(powersave_lowspeed)
  179. .long 0