1 // SPDX-License-Identifier: GPL-2.0-or-later
3 * Copyright (C) 2007 Advanced Micro Devices, Inc.
4 * Copyright (C) 2008 Andres Salomon <dilinger@debian.org>
9 #include <linux/cs5535.h>
10 #include <asm/delay.h>
14 static void gx_save_regs(struct gxfb_par
*par
)
18 /* wait for the BLT engine to stop being busy */
20 i
= read_gp(par
, GP_BLT_STATUS
);
21 } while (i
& (GP_BLT_STATUS_BLT_PENDING
| GP_BLT_STATUS_BLT_BUSY
));
24 rdmsrl(MSR_GX_MSR_PADSEL
, par
->msr
.padsel
);
25 rdmsrl(MSR_GLCP_DOTPLL
, par
->msr
.dotpll
);
27 write_dc(par
, DC_UNLOCK
, DC_UNLOCK_UNLOCK
);
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
));
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
);
41 static void gx_set_dotpll(uint32_t dotpll_hi
)
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
);
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
)
60 dotpll_lo
&= ~MSR_GLCP_DOTPLL_DOTRESET
;
61 wrmsr(MSR_GLCP_DOTPLL
, dotpll_lo
, dotpll_hi
);
64 static void gx_restore_gfx_proc(struct gxfb_par
*par
)
68 for (i
= 0; i
< ARRAY_SIZE(par
->gp
); i
++) {
74 /* don't restore these registers */
77 write_gp(par
, i
, par
->gp
[i
]);
82 static void gx_restore_display_ctlr(struct gxfb_par
*par
)
86 for (i
= 0; i
< ARRAY_SIZE(par
->dc
); i
++) {
89 /* unlock the DC; runs first */
90 write_dc(par
, DC_UNLOCK
, DC_UNLOCK_UNLOCK
);
94 /* write without the enables */
95 write_dc(par
, i
, par
->dc
[i
] & ~(DC_GENERAL_CFG_VIDE
|
98 DC_GENERAL_CFG_DFLE
));
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
));
119 /* don't restore these registers */
122 write_dc(par
, i
, par
->dc
[i
]);
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
]);
132 static void gx_restore_video_proc(struct gxfb_par
*par
)
136 wrmsrl(MSR_GX_MSR_PADSEL
, par
->msr
.padsel
);
138 for (i
= 0; i
< ARRAY_SIZE(par
->vp
); i
++) {
141 /* don't enable video yet */
142 write_vp(par
, i
, par
->vp
[i
] & ~VP_VCFG_VID_EN
);
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
));
161 /* don't restore these registers */
164 write_vp(par
, i
, par
->vp
[i
]);
169 static void gx_restore_regs(struct gxfb_par
*par
)
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
);
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
]);
185 static void gx_disable_graphics(struct gxfb_par
*par
)
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
));
192 /* turn off the flat panel */
193 write_fp(par
, FP_PM
, par
->fp
[FP_PM
] & ~FP_PM_P
);
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
);
207 static void gx_enable_graphics(struct gxfb_par
*par
)
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
]);
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
]);
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
]);
229 /* lock the door behind us */
230 write_dc(par
, DC_UNLOCK
, DC_UNLOCK_LOCK
);
233 int gx_powerdown(struct fb_info
*info
)
235 struct gxfb_par
*par
= info
->par
;
237 if (par
->powered_down
)
241 gx_disable_graphics(par
);
243 par
->powered_down
= 1;
247 int gx_powerup(struct fb_info
*info
)
249 struct gxfb_par
*par
= info
->par
;
251 if (!par
->powered_down
)
254 gx_restore_regs(par
);
255 gx_enable_graphics(par
);
257 par
->powered_down
= 0;