xref: /linux/drivers/video/fbdev/geode/suspend_gx.c (revision a4eb44a6435d6d8f9e642407a4a06f65eb90ca04)
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