linux/drivers/video/geode/suspend_gx.c
<<
>>
Prefs
   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
  20static 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
  47static 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
  70static 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
  88static 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
 138static 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
 175static 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
 191static 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
 213static 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
 239int 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
 253int 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
 268