Merge git://git.kernel.org/pub/scm/linux/kernel/git/davem/net-2.6
[linux-2.6] / drivers / video / geode / suspend_gx.c
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 <asm/geode.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