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 16 #include "gxfb.h" 17 18 #ifdef CONFIG_PM 19 20 static void gx_save_regs(struct gxfb_par *par) 21 { 22 int i; 23 24 /* wait for the BLT engine to stop being busy */ 25 do { 26 i = read_gp(par, GP_BLT_STATUS); 27 } while (i & (GP_BLT_STATUS_BLT_PENDING | GP_BLT_STATUS_BLT_BUSY)); 28 29 /* save MSRs */ 30 rdmsrl(MSR_GX_MSR_PADSEL, par->msr.padsel); 31 rdmsrl(MSR_GLCP_DOTPLL, par->msr.dotpll); 32 33 write_dc(par, DC_UNLOCK, DC_UNLOCK_UNLOCK); 34 35 /* save registers */ 36 memcpy(par->gp, par->gp_regs, sizeof(par->gp)); 37 memcpy(par->dc, par->dc_regs, sizeof(par->dc)); 38 memcpy(par->vp, par->vid_regs, sizeof(par->vp)); 39 memcpy(par->fp, par->vid_regs + VP_FP_START, sizeof(par->fp)); 40 41 /* save the palette */ 42 write_dc(par, DC_PAL_ADDRESS, 0); 43 for (i = 0; i < ARRAY_SIZE(par->pal); i++) 44 par->pal[i] = read_dc(par, DC_PAL_DATA); 45 } 46 47 static void gx_set_dotpll(uint32_t dotpll_hi) 48 { 49 uint32_t dotpll_lo; 50 int i; 51 52 rdmsrl(MSR_GLCP_DOTPLL, dotpll_lo); 53 dotpll_lo |= MSR_GLCP_DOTPLL_DOTRESET; 54 dotpll_lo &= ~MSR_GLCP_DOTPLL_BYPASS; 55 wrmsr(MSR_GLCP_DOTPLL, dotpll_lo, dotpll_hi); 56 57 /* wait for the PLL to lock */ 58 for (i = 0; i < 200; i++) { 59 rdmsrl(MSR_GLCP_DOTPLL, dotpll_lo); 60 if (dotpll_lo & MSR_GLCP_DOTPLL_LOCK) 61 break; 62 udelay(1); 63 } 64 65 /* PLL set, unlock */ 66 dotpll_lo &= ~MSR_GLCP_DOTPLL_DOTRESET; 67 wrmsr(MSR_GLCP_DOTPLL, dotpll_lo, dotpll_hi); 68 } 69 70 static void gx_restore_gfx_proc(struct gxfb_par *par) 71 { 72 int i; 73 74 for (i = 0; i < ARRAY_SIZE(par->gp); i++) { 75 switch (i) { 76 case GP_VECTOR_MODE: 77 case GP_BLT_MODE: 78 case GP_BLT_STATUS: 79 case GP_HST_SRC: 80 /* don't restore these registers */ 81 break; 82 default: 83 write_gp(par, i, par->gp[i]); 84 } 85 } 86 } 87 88 static void gx_restore_display_ctlr(struct gxfb_par *par) 89 { 90 int i; 91 92 for (i = 0; i < ARRAY_SIZE(par->dc); i++) { 93 switch (i) { 94 case DC_UNLOCK: 95 /* unlock the DC; runs first */ 96 write_dc(par, DC_UNLOCK, DC_UNLOCK_UNLOCK); 97 break; 98 99 case DC_GENERAL_CFG: 100 /* write without the enables */ 101 write_dc(par, i, par->dc[i] & ~(DC_GENERAL_CFG_VIDE | 102 DC_GENERAL_CFG_ICNE | 103 DC_GENERAL_CFG_CURE | 104 DC_GENERAL_CFG_DFLE)); 105 break; 106 107 case DC_DISPLAY_CFG: 108 /* write without the enables */ 109 write_dc(par, i, par->dc[i] & ~(DC_DISPLAY_CFG_VDEN | 110 DC_DISPLAY_CFG_GDEN | 111 DC_DISPLAY_CFG_TGEN)); 112 break; 113 114 case DC_RSVD_0: 115 case DC_RSVD_1: 116 case DC_RSVD_2: 117 case DC_RSVD_3: 118 case DC_RSVD_4: 119 case DC_LINE_CNT: 120 case DC_PAL_ADDRESS: 121 case DC_PAL_DATA: 122 case DC_DFIFO_DIAG: 123 case DC_CFIFO_DIAG: 124 case DC_RSVD_5: 125 /* don't restore these registers */ 126 break; 127 default: 128 write_dc(par, i, par->dc[i]); 129 } 130 } 131 132 /* restore the palette */ 133 write_dc(par, DC_PAL_ADDRESS, 0); 134 for (i = 0; i < ARRAY_SIZE(par->pal); i++) 135 write_dc(par, DC_PAL_DATA, par->pal[i]); 136 } 137 138 static void gx_restore_video_proc(struct gxfb_par *par) 139 { 140 int i; 141 142 wrmsrl(MSR_GX_MSR_PADSEL, par->msr.padsel); 143 144 for (i = 0; i < ARRAY_SIZE(par->vp); i++) { 145 switch (i) { 146 case VP_VCFG: 147 /* don't enable video yet */ 148 write_vp(par, i, par->vp[i] & ~VP_VCFG_VID_EN); 149 break; 150 151 case VP_DCFG: 152 /* don't enable CRT yet */ 153 write_vp(par, i, par->vp[i] & 154 ~(VP_DCFG_DAC_BL_EN | VP_DCFG_VSYNC_EN | 155 VP_DCFG_HSYNC_EN | VP_DCFG_CRT_EN)); 156 break; 157 158 case VP_GAR: 159 case VP_GDR: 160 case VP_RSVD_0: 161 case VP_RSVD_1: 162 case VP_RSVD_2: 163 case VP_RSVD_3: 164 case VP_CRC32: 165 case VP_AWT: 166 case VP_VTM: 167 /* don't restore these registers */ 168 break; 169 default: 170 write_vp(par, i, par->vp[i]); 171 } 172 } 173 } 174 175 static void gx_restore_regs(struct gxfb_par *par) 176 { 177 int i; 178 179 gx_set_dotpll((uint32_t) (par->msr.dotpll >> 32)); 180 gx_restore_gfx_proc(par); 181 gx_restore_display_ctlr(par); 182 gx_restore_video_proc(par); 183 184 /* Flat Panel */ 185 for (i = 0; i < ARRAY_SIZE(par->fp); i++) { 186 if (i != FP_PM && i != FP_RSVD_0) 187 write_fp(par, i, par->fp[i]); 188 } 189 } 190 191 static void gx_disable_graphics(struct gxfb_par *par) 192 { 193 /* shut down the engine */ 194 write_vp(par, VP_VCFG, par->vp[VP_VCFG] & ~VP_VCFG_VID_EN); 195 write_vp(par, VP_DCFG, par->vp[VP_DCFG] & ~(VP_DCFG_DAC_BL_EN | 196 VP_DCFG_VSYNC_EN | VP_DCFG_HSYNC_EN | VP_DCFG_CRT_EN)); 197 198 /* turn off the flat panel */ 199 write_fp(par, FP_PM, par->fp[FP_PM] & ~FP_PM_P); 200 201 202 /* turn off display */ 203 write_dc(par, DC_UNLOCK, DC_UNLOCK_UNLOCK); 204 write_dc(par, DC_GENERAL_CFG, par->dc[DC_GENERAL_CFG] & 205 ~(DC_GENERAL_CFG_VIDE | DC_GENERAL_CFG_ICNE | 206 DC_GENERAL_CFG_CURE | DC_GENERAL_CFG_DFLE)); 207 write_dc(par, DC_DISPLAY_CFG, par->dc[DC_DISPLAY_CFG] & 208 ~(DC_DISPLAY_CFG_VDEN | DC_DISPLAY_CFG_GDEN | 209 DC_DISPLAY_CFG_TGEN)); 210 write_dc(par, DC_UNLOCK, DC_UNLOCK_LOCK); 211 } 212 213 static void gx_enable_graphics(struct gxfb_par *par) 214 { 215 uint32_t fp; 216 217 fp = read_fp(par, FP_PM); 218 if (par->fp[FP_PM] & FP_PM_P) { 219 /* power on the panel if not already power{ed,ing} on */ 220 if (!(fp & (FP_PM_PANEL_ON|FP_PM_PANEL_PWR_UP))) 221 write_fp(par, FP_PM, par->fp[FP_PM]); 222 } else { 223 /* power down the panel if not already power{ed,ing} down */ 224 if (!(fp & (FP_PM_PANEL_OFF|FP_PM_PANEL_PWR_DOWN))) 225 write_fp(par, FP_PM, par->fp[FP_PM]); 226 } 227 228 /* turn everything on */ 229 write_vp(par, VP_VCFG, par->vp[VP_VCFG]); 230 write_vp(par, VP_DCFG, par->vp[VP_DCFG]); 231 write_dc(par, DC_DISPLAY_CFG, par->dc[DC_DISPLAY_CFG]); 232 /* do this last; it will enable the FIFO load */ 233 write_dc(par, DC_GENERAL_CFG, par->dc[DC_GENERAL_CFG]); 234 235 /* lock the door behind us */ 236 write_dc(par, DC_UNLOCK, DC_UNLOCK_LOCK); 237 } 238 239 int gx_powerdown(struct fb_info *info) 240 { 241 struct gxfb_par *par = info->par; 242 243 if (par->powered_down) 244 return 0; 245 246 gx_save_regs(par); 247 gx_disable_graphics(par); 248 249 par->powered_down = 1; 250 return 0; 251 } 252 253 int gx_powerup(struct fb_info *info) 254 { 255 struct gxfb_par *par = info->par; 256 257 if (!par->powered_down) 258 return 0; 259 260 gx_restore_regs(par); 261 gx_enable_graphics(par); 262 263 par->powered_down = 0; 264 return 0; 265 } 266 267 #endif 268