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