linux/drivers/video/fbdev/geode/suspend_gx.c
<<
>>
Prefs
   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}
 260