suspend_gx.c 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268
  1. /*
  2. * Copyright (C) 2007 Advanced Micro Devices, Inc.
  3. * Copyright (C) 2008 Andres Salomon <dilinger@debian.org>
  4. *
  5. * This program is free software; you can redistribute it and/or modify it
  6. * under the terms of the GNU General Public License as published by the
  7. * Free Software Foundation; either version 2 of the License, or (at your
  8. * option) any later version.
  9. */
  10. #include <linux/fb.h>
  11. #include <asm/io.h>
  12. #include <asm/msr.h>
  13. #include <linux/cs5535.h>
  14. #include <asm/delay.h>
  15. #include "gxfb.h"
  16. #ifdef CONFIG_PM
  17. static void gx_save_regs(struct gxfb_par *par)
  18. {
  19. int i;
  20. /* wait for the BLT engine to stop being busy */
  21. do {
  22. i = read_gp(par, GP_BLT_STATUS);
  23. } while (i & (GP_BLT_STATUS_BLT_PENDING | GP_BLT_STATUS_BLT_BUSY));
  24. /* save MSRs */
  25. rdmsrl(MSR_GX_MSR_PADSEL, par->msr.padsel);
  26. rdmsrl(MSR_GLCP_DOTPLL, par->msr.dotpll);
  27. write_dc(par, DC_UNLOCK, DC_UNLOCK_UNLOCK);
  28. /* save registers */
  29. memcpy(par->gp, par->gp_regs, sizeof(par->gp));
  30. memcpy(par->dc, par->dc_regs, sizeof(par->dc));
  31. memcpy(par->vp, par->vid_regs, sizeof(par->vp));
  32. memcpy(par->fp, par->vid_regs + VP_FP_START, sizeof(par->fp));
  33. /* save the palette */
  34. write_dc(par, DC_PAL_ADDRESS, 0);
  35. for (i = 0; i < ARRAY_SIZE(par->pal); i++)
  36. par->pal[i] = read_dc(par, DC_PAL_DATA);
  37. }
  38. static void gx_set_dotpll(uint32_t dotpll_hi)
  39. {
  40. uint32_t dotpll_lo;
  41. int i;
  42. rdmsrl(MSR_GLCP_DOTPLL, dotpll_lo);
  43. dotpll_lo |= MSR_GLCP_DOTPLL_DOTRESET;
  44. dotpll_lo &= ~MSR_GLCP_DOTPLL_BYPASS;
  45. wrmsr(MSR_GLCP_DOTPLL, dotpll_lo, dotpll_hi);
  46. /* wait for the PLL to lock */
  47. for (i = 0; i < 200; i++) {
  48. rdmsrl(MSR_GLCP_DOTPLL, dotpll_lo);
  49. if (dotpll_lo & MSR_GLCP_DOTPLL_LOCK)
  50. break;
  51. udelay(1);
  52. }
  53. /* PLL set, unlock */
  54. dotpll_lo &= ~MSR_GLCP_DOTPLL_DOTRESET;
  55. wrmsr(MSR_GLCP_DOTPLL, dotpll_lo, dotpll_hi);
  56. }
  57. static void gx_restore_gfx_proc(struct gxfb_par *par)
  58. {
  59. int i;
  60. for (i = 0; i < ARRAY_SIZE(par->gp); i++) {
  61. switch (i) {
  62. case GP_VECTOR_MODE:
  63. case GP_BLT_MODE:
  64. case GP_BLT_STATUS:
  65. case GP_HST_SRC:
  66. /* don't restore these registers */
  67. break;
  68. default:
  69. write_gp(par, i, par->gp[i]);
  70. }
  71. }
  72. }
  73. static void gx_restore_display_ctlr(struct gxfb_par *par)
  74. {
  75. int i;
  76. for (i = 0; i < ARRAY_SIZE(par->dc); i++) {
  77. switch (i) {
  78. case DC_UNLOCK:
  79. /* unlock the DC; runs first */
  80. write_dc(par, DC_UNLOCK, DC_UNLOCK_UNLOCK);
  81. break;
  82. case DC_GENERAL_CFG:
  83. /* write without the enables */
  84. write_dc(par, i, par->dc[i] & ~(DC_GENERAL_CFG_VIDE |
  85. DC_GENERAL_CFG_ICNE |
  86. DC_GENERAL_CFG_CURE |
  87. DC_GENERAL_CFG_DFLE));
  88. break;
  89. case DC_DISPLAY_CFG:
  90. /* write without the enables */
  91. write_dc(par, i, par->dc[i] & ~(DC_DISPLAY_CFG_VDEN |
  92. DC_DISPLAY_CFG_GDEN |
  93. DC_DISPLAY_CFG_TGEN));
  94. break;
  95. case DC_RSVD_0:
  96. case DC_RSVD_1:
  97. case DC_RSVD_2:
  98. case DC_RSVD_3:
  99. case DC_RSVD_4:
  100. case DC_LINE_CNT:
  101. case DC_PAL_ADDRESS:
  102. case DC_PAL_DATA:
  103. case DC_DFIFO_DIAG:
  104. case DC_CFIFO_DIAG:
  105. case DC_RSVD_5:
  106. /* don't restore these registers */
  107. break;
  108. default:
  109. write_dc(par, i, par->dc[i]);
  110. }
  111. }
  112. /* restore the palette */
  113. write_dc(par, DC_PAL_ADDRESS, 0);
  114. for (i = 0; i < ARRAY_SIZE(par->pal); i++)
  115. write_dc(par, DC_PAL_DATA, par->pal[i]);
  116. }
  117. static void gx_restore_video_proc(struct gxfb_par *par)
  118. {
  119. int i;
  120. wrmsrl(MSR_GX_MSR_PADSEL, par->msr.padsel);
  121. for (i = 0; i < ARRAY_SIZE(par->vp); i++) {
  122. switch (i) {
  123. case VP_VCFG:
  124. /* don't enable video yet */
  125. write_vp(par, i, par->vp[i] & ~VP_VCFG_VID_EN);
  126. break;
  127. case VP_DCFG:
  128. /* don't enable CRT yet */
  129. write_vp(par, i, par->vp[i] &
  130. ~(VP_DCFG_DAC_BL_EN | VP_DCFG_VSYNC_EN |
  131. VP_DCFG_HSYNC_EN | VP_DCFG_CRT_EN));
  132. break;
  133. case VP_GAR:
  134. case VP_GDR:
  135. case VP_RSVD_0:
  136. case VP_RSVD_1:
  137. case VP_RSVD_2:
  138. case VP_RSVD_3:
  139. case VP_CRC32:
  140. case VP_AWT:
  141. case VP_VTM:
  142. /* don't restore these registers */
  143. break;
  144. default:
  145. write_vp(par, i, par->vp[i]);
  146. }
  147. }
  148. }
  149. static void gx_restore_regs(struct gxfb_par *par)
  150. {
  151. int i;
  152. gx_set_dotpll((uint32_t) (par->msr.dotpll >> 32));
  153. gx_restore_gfx_proc(par);
  154. gx_restore_display_ctlr(par);
  155. gx_restore_video_proc(par);
  156. /* Flat Panel */
  157. for (i = 0; i < ARRAY_SIZE(par->fp); i++) {
  158. if (i != FP_PM && i != FP_RSVD_0)
  159. write_fp(par, i, par->fp[i]);
  160. }
  161. }
  162. static void gx_disable_graphics(struct gxfb_par *par)
  163. {
  164. /* shut down the engine */
  165. write_vp(par, VP_VCFG, par->vp[VP_VCFG] & ~VP_VCFG_VID_EN);
  166. write_vp(par, VP_DCFG, par->vp[VP_DCFG] & ~(VP_DCFG_DAC_BL_EN |
  167. VP_DCFG_VSYNC_EN | VP_DCFG_HSYNC_EN | VP_DCFG_CRT_EN));
  168. /* turn off the flat panel */
  169. write_fp(par, FP_PM, par->fp[FP_PM] & ~FP_PM_P);
  170. /* turn off display */
  171. write_dc(par, DC_UNLOCK, DC_UNLOCK_UNLOCK);
  172. write_dc(par, DC_GENERAL_CFG, par->dc[DC_GENERAL_CFG] &
  173. ~(DC_GENERAL_CFG_VIDE | DC_GENERAL_CFG_ICNE |
  174. DC_GENERAL_CFG_CURE | DC_GENERAL_CFG_DFLE));
  175. write_dc(par, DC_DISPLAY_CFG, par->dc[DC_DISPLAY_CFG] &
  176. ~(DC_DISPLAY_CFG_VDEN | DC_DISPLAY_CFG_GDEN |
  177. DC_DISPLAY_CFG_TGEN));
  178. write_dc(par, DC_UNLOCK, DC_UNLOCK_LOCK);
  179. }
  180. static void gx_enable_graphics(struct gxfb_par *par)
  181. {
  182. uint32_t fp;
  183. fp = read_fp(par, FP_PM);
  184. if (par->fp[FP_PM] & FP_PM_P) {
  185. /* power on the panel if not already power{ed,ing} on */
  186. if (!(fp & (FP_PM_PANEL_ON|FP_PM_PANEL_PWR_UP)))
  187. write_fp(par, FP_PM, par->fp[FP_PM]);
  188. } else {
  189. /* power down the panel if not already power{ed,ing} down */
  190. if (!(fp & (FP_PM_PANEL_OFF|FP_PM_PANEL_PWR_DOWN)))
  191. write_fp(par, FP_PM, par->fp[FP_PM]);
  192. }
  193. /* turn everything on */
  194. write_vp(par, VP_VCFG, par->vp[VP_VCFG]);
  195. write_vp(par, VP_DCFG, par->vp[VP_DCFG]);
  196. write_dc(par, DC_DISPLAY_CFG, par->dc[DC_DISPLAY_CFG]);
  197. /* do this last; it will enable the FIFO load */
  198. write_dc(par, DC_GENERAL_CFG, par->dc[DC_GENERAL_CFG]);
  199. /* lock the door behind us */
  200. write_dc(par, DC_UNLOCK, DC_UNLOCK_LOCK);
  201. }
  202. int gx_powerdown(struct fb_info *info)
  203. {
  204. struct gxfb_par *par = info->par;
  205. if (par->powered_down)
  206. return 0;
  207. gx_save_regs(par);
  208. gx_disable_graphics(par);
  209. par->powered_down = 1;
  210. return 0;
  211. }
  212. int gx_powerup(struct fb_info *info)
  213. {
  214. struct gxfb_par *par = info->par;
  215. if (!par->powered_down)
  216. return 0;
  217. gx_restore_regs(par);
  218. gx_enable_graphics(par);
  219. par->powered_down = 0;
  220. return 0;
  221. }
  222. #endif