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