cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

suspend_gx.c (5998B)


      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
     14static 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
     41static 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
     64static 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
     82static 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
    132static 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
    169static 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
    185static 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
    207static 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
    233int 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
    247int 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}