GNU Linux-libre 5.10.215-gnu1
[releases.git] / drivers / video / fbdev / geode / suspend_gx.c
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 }