aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/video/geode
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/video/geode')
-rw-r--r--drivers/video/geode/Kconfig20
-rw-r--r--drivers/video/geode/Makefile2
-rw-r--r--drivers/video/geode/display_gx.c125
-rw-r--r--drivers/video/geode/display_gx.h101
-rw-r--r--drivers/video/geode/gxfb.h358
-rw-r--r--drivers/video/geode/gxfb_core.c160
-rw-r--r--drivers/video/geode/lxfb.h527
-rw-r--r--drivers/video/geode/lxfb_core.c118
-rw-r--r--drivers/video/geode/lxfb_ops.c699
-rw-r--r--drivers/video/geode/suspend_gx.c267
-rw-r--r--drivers/video/geode/video_gx.c162
-rw-r--r--drivers/video/geode/video_gx.h72
12 files changed, 1879 insertions, 732 deletions
diff --git a/drivers/video/geode/Kconfig b/drivers/video/geode/Kconfig
index 7608429b3943..c5d8ba4b9fc3 100644
--- a/drivers/video/geode/Kconfig
+++ b/drivers/video/geode/Kconfig
@@ -38,26 +38,6 @@ config FB_GEODE_GX
38 38
39 If unsure, say N. 39 If unsure, say N.
40 40
41config FB_GEODE_GX_SET_FBSIZE
42 bool "Manually specify the Geode GX framebuffer size"
43 depends on FB_GEODE_GX
44 default n
45 ---help---
46 If you want to manually specify the size of your GX framebuffer,
47 say Y here, otherwise say N to dynamically probe it.
48
49 Say N unless you know what you are doing.
50
51config FB_GEODE_GX_FBSIZE
52 hex "Size of the GX framebuffer, in bytes"
53 depends on FB_GEODE_GX_SET_FBSIZE
54 default "0x1600000"
55 ---help---
56 Specify the size of the GX framebuffer. Normally, you will
57 want this to be MB aligned. Common values are 0x80000 (8MB)
58 and 0x1600000 (16MB). Don't change this unless you know what
59 you are doing
60
61config FB_GEODE_GX1 41config FB_GEODE_GX1
62 tristate "AMD Geode GX1 framebuffer support (EXPERIMENTAL)" 42 tristate "AMD Geode GX1 framebuffer support (EXPERIMENTAL)"
63 depends on FB && FB_GEODE && EXPERIMENTAL 43 depends on FB && FB_GEODE && EXPERIMENTAL
diff --git a/drivers/video/geode/Makefile b/drivers/video/geode/Makefile
index 957304b45fba..5c98da126883 100644
--- a/drivers/video/geode/Makefile
+++ b/drivers/video/geode/Makefile
@@ -5,5 +5,5 @@ obj-$(CONFIG_FB_GEODE_GX) += gxfb.o
5obj-$(CONFIG_FB_GEODE_LX) += lxfb.o 5obj-$(CONFIG_FB_GEODE_LX) += lxfb.o
6 6
7gx1fb-objs := gx1fb_core.o display_gx1.o video_cs5530.o 7gx1fb-objs := gx1fb_core.o display_gx1.o video_cs5530.o
8gxfb-objs := gxfb_core.o display_gx.o video_gx.o 8gxfb-objs := gxfb_core.o display_gx.o video_gx.o suspend_gx.o
9lxfb-objs := lxfb_core.o lxfb_ops.o 9lxfb-objs := lxfb_core.o lxfb_ops.o
diff --git a/drivers/video/geode/display_gx.c b/drivers/video/geode/display_gx.c
index 0f16e4bffc6c..e759895bf3d3 100644
--- a/drivers/video/geode/display_gx.c
+++ b/drivers/video/geode/display_gx.c
@@ -17,31 +17,40 @@
17#include <asm/io.h> 17#include <asm/io.h>
18#include <asm/div64.h> 18#include <asm/div64.h>
19#include <asm/delay.h> 19#include <asm/delay.h>
20#include <asm/geode.h>
20 21
21#include "geodefb.h" 22#include "gxfb.h"
22#include "display_gx.h"
23 23
24#ifdef CONFIG_FB_GEODE_GX_SET_FBSIZE
25unsigned int gx_frame_buffer_size(void)
26{
27 return CONFIG_FB_GEODE_GX_FBSIZE;
28}
29#else
30unsigned int gx_frame_buffer_size(void) 24unsigned int gx_frame_buffer_size(void)
31{ 25{
32 unsigned int val; 26 unsigned int val;
33 27
34 /* FB size is reported by a virtual register */ 28 if (!geode_has_vsa2()) {
29 uint32_t hi, lo;
30
31 /* The number of pages is (PMAX - PMIN)+1 */
32 rdmsr(MSR_GLIU_P2D_RO0, lo, hi);
33
34 /* PMAX */
35 val = ((hi & 0xff) << 12) | ((lo & 0xfff00000) >> 20);
36 /* PMIN */
37 val -= (lo & 0x000fffff);
38 val += 1;
39
40 /* The page size is 4k */
41 return (val << 12);
42 }
43
44 /* FB size can be obtained from the VSA II */
35 /* Virtual register class = 0x02 */ 45 /* Virtual register class = 0x02 */
36 /* VG_MEM_SIZE(512Kb units) = 0x00 */ 46 /* VG_MEM_SIZE(512Kb units) = 0x00 */
37 47
38 outw(0xFC53, 0xAC1C); 48 outw(VSA_VR_UNLOCK, VSA_VRC_INDEX);
39 outw(0x0200, 0xAC1C); 49 outw(VSA_VR_MEM_SIZE, VSA_VRC_INDEX);
40 50
41 val = (unsigned int)(inw(0xAC1E)) & 0xFFl; 51 val = (unsigned int)(inw(VSA_VRC_DATA)) & 0xFFl;
42 return (val << 19); 52 return (val << 19);
43} 53}
44#endif
45 54
46int gx_line_delta(int xres, int bpp) 55int gx_line_delta(int xres, int bpp)
47{ 56{
@@ -49,75 +58,76 @@ int gx_line_delta(int xres, int bpp)
49 return (xres * (bpp >> 3) + 7) & ~0x7; 58 return (xres * (bpp >> 3) + 7) & ~0x7;
50} 59}
51 60
52static void gx_set_mode(struct fb_info *info) 61void gx_set_mode(struct fb_info *info)
53{ 62{
54 struct geodefb_par *par = info->par; 63 struct gxfb_par *par = info->par;
55 u32 gcfg, dcfg; 64 u32 gcfg, dcfg;
56 int hactive, hblankstart, hsyncstart, hsyncend, hblankend, htotal; 65 int hactive, hblankstart, hsyncstart, hsyncend, hblankend, htotal;
57 int vactive, vblankstart, vsyncstart, vsyncend, vblankend, vtotal; 66 int vactive, vblankstart, vsyncstart, vsyncend, vblankend, vtotal;
58 67
59 /* Unlock the display controller registers. */ 68 /* Unlock the display controller registers. */
60 readl(par->dc_regs + DC_UNLOCK); 69 write_dc(par, DC_UNLOCK, DC_UNLOCK_UNLOCK);
61 writel(DC_UNLOCK_CODE, par->dc_regs + DC_UNLOCK);
62 70
63 gcfg = readl(par->dc_regs + DC_GENERAL_CFG); 71 gcfg = read_dc(par, DC_GENERAL_CFG);
64 dcfg = readl(par->dc_regs + DC_DISPLAY_CFG); 72 dcfg = read_dc(par, DC_DISPLAY_CFG);
65 73
66 /* Disable the timing generator. */ 74 /* Disable the timing generator. */
67 dcfg &= ~(DC_DCFG_TGEN); 75 dcfg &= ~DC_DISPLAY_CFG_TGEN;
68 writel(dcfg, par->dc_regs + DC_DISPLAY_CFG); 76 write_dc(par, DC_DISPLAY_CFG, dcfg);
69 77
70 /* Wait for pending memory requests before disabling the FIFO load. */ 78 /* Wait for pending memory requests before disabling the FIFO load. */
71 udelay(100); 79 udelay(100);
72 80
73 /* Disable FIFO load and compression. */ 81 /* Disable FIFO load and compression. */
74 gcfg &= ~(DC_GCFG_DFLE | DC_GCFG_CMPE | DC_GCFG_DECE); 82 gcfg &= ~(DC_GENERAL_CFG_DFLE | DC_GENERAL_CFG_CMPE |
75 writel(gcfg, par->dc_regs + DC_GENERAL_CFG); 83 DC_GENERAL_CFG_DECE);
84 write_dc(par, DC_GENERAL_CFG, gcfg);
76 85
77 /* Setup DCLK and its divisor. */ 86 /* Setup DCLK and its divisor. */
78 par->vid_ops->set_dclk(info); 87 gx_set_dclk_frequency(info);
79 88
80 /* 89 /*
81 * Setup new mode. 90 * Setup new mode.
82 */ 91 */
83 92
84 /* Clear all unused feature bits. */ 93 /* Clear all unused feature bits. */
85 gcfg &= DC_GCFG_YUVM | DC_GCFG_VDSE; 94 gcfg &= DC_GENERAL_CFG_YUVM | DC_GENERAL_CFG_VDSE;
86 dcfg = 0; 95 dcfg = 0;
87 96
88 /* Set FIFO priority (default 6/5) and enable. */ 97 /* Set FIFO priority (default 6/5) and enable. */
89 /* FIXME: increase fifo priority for 1280x1024 and higher modes? */ 98 /* FIXME: increase fifo priority for 1280x1024 and higher modes? */
90 gcfg |= (6 << DC_GCFG_DFHPEL_POS) | (5 << DC_GCFG_DFHPSL_POS) | DC_GCFG_DFLE; 99 gcfg |= (6 << DC_GENERAL_CFG_DFHPEL_SHIFT) |
100 (5 << DC_GENERAL_CFG_DFHPSL_SHIFT) | DC_GENERAL_CFG_DFLE;
91 101
92 /* Framebuffer start offset. */ 102 /* Framebuffer start offset. */
93 writel(0, par->dc_regs + DC_FB_ST_OFFSET); 103 write_dc(par, DC_FB_ST_OFFSET, 0);
94 104
95 /* Line delta and line buffer length. */ 105 /* Line delta and line buffer length. */
96 writel(info->fix.line_length >> 3, par->dc_regs + DC_GFX_PITCH); 106 write_dc(par, DC_GFX_PITCH, info->fix.line_length >> 3);
97 writel(((info->var.xres * info->var.bits_per_pixel/8) >> 3) + 2, 107 write_dc(par, DC_LINE_SIZE,
98 par->dc_regs + DC_LINE_SIZE); 108 ((info->var.xres * info->var.bits_per_pixel/8) >> 3) + 2);
99 109
100 110
101 /* Enable graphics and video data and unmask address lines. */ 111 /* Enable graphics and video data and unmask address lines. */
102 dcfg |= DC_DCFG_GDEN | DC_DCFG_VDEN | DC_DCFG_A20M | DC_DCFG_A18M; 112 dcfg |= DC_DISPLAY_CFG_GDEN | DC_DISPLAY_CFG_VDEN |
113 DC_DISPLAY_CFG_A20M | DC_DISPLAY_CFG_A18M;
103 114
104 /* Set pixel format. */ 115 /* Set pixel format. */
105 switch (info->var.bits_per_pixel) { 116 switch (info->var.bits_per_pixel) {
106 case 8: 117 case 8:
107 dcfg |= DC_DCFG_DISP_MODE_8BPP; 118 dcfg |= DC_DISPLAY_CFG_DISP_MODE_8BPP;
108 break; 119 break;
109 case 16: 120 case 16:
110 dcfg |= DC_DCFG_DISP_MODE_16BPP; 121 dcfg |= DC_DISPLAY_CFG_DISP_MODE_16BPP;
111 dcfg |= DC_DCFG_16BPP_MODE_565;
112 break; 122 break;
113 case 32: 123 case 32:
114 dcfg |= DC_DCFG_DISP_MODE_24BPP; 124 dcfg |= DC_DISPLAY_CFG_DISP_MODE_24BPP;
115 dcfg |= DC_DCFG_PALB; 125 dcfg |= DC_DISPLAY_CFG_PALB;
116 break; 126 break;
117 } 127 }
118 128
119 /* Enable timing generator. */ 129 /* Enable timing generator. */
120 dcfg |= DC_DCFG_TGEN; 130 dcfg |= DC_DISPLAY_CFG_TGEN;
121 131
122 /* Horizontal and vertical timings. */ 132 /* Horizontal and vertical timings. */
123 hactive = info->var.xres; 133 hactive = info->var.xres;
@@ -134,28 +144,34 @@ static void gx_set_mode(struct fb_info *info)
134 vblankend = vsyncend + info->var.upper_margin; 144 vblankend = vsyncend + info->var.upper_margin;
135 vtotal = vblankend; 145 vtotal = vblankend;
136 146
137 writel((hactive - 1) | ((htotal - 1) << 16), par->dc_regs + DC_H_ACTIVE_TIMING); 147 write_dc(par, DC_H_ACTIVE_TIMING, (hactive - 1) |
138 writel((hblankstart - 1) | ((hblankend - 1) << 16), par->dc_regs + DC_H_BLANK_TIMING); 148 ((htotal - 1) << 16));
139 writel((hsyncstart - 1) | ((hsyncend - 1) << 16), par->dc_regs + DC_H_SYNC_TIMING); 149 write_dc(par, DC_H_BLANK_TIMING, (hblankstart - 1) |
150 ((hblankend - 1) << 16));
151 write_dc(par, DC_H_SYNC_TIMING, (hsyncstart - 1) |
152 ((hsyncend - 1) << 16));
140 153
141 writel((vactive - 1) | ((vtotal - 1) << 16), par->dc_regs + DC_V_ACTIVE_TIMING); 154 write_dc(par, DC_V_ACTIVE_TIMING, (vactive - 1) |
142 writel((vblankstart - 1) | ((vblankend - 1) << 16), par->dc_regs + DC_V_BLANK_TIMING); 155 ((vtotal - 1) << 16));
143 writel((vsyncstart - 1) | ((vsyncend - 1) << 16), par->dc_regs + DC_V_SYNC_TIMING); 156 write_dc(par, DC_V_BLANK_TIMING, (vblankstart - 1) |
157 ((vblankend - 1) << 16));
158 write_dc(par, DC_V_SYNC_TIMING, (vsyncstart - 1) |
159 ((vsyncend - 1) << 16));
144 160
145 /* Write final register values. */ 161 /* Write final register values. */
146 writel(dcfg, par->dc_regs + DC_DISPLAY_CFG); 162 write_dc(par, DC_DISPLAY_CFG, dcfg);
147 writel(gcfg, par->dc_regs + DC_GENERAL_CFG); 163 write_dc(par, DC_GENERAL_CFG, gcfg);
148 164
149 par->vid_ops->configure_display(info); 165 gx_configure_display(info);
150 166
151 /* Relock display controller registers */ 167 /* Relock display controller registers */
152 writel(0, par->dc_regs + DC_UNLOCK); 168 write_dc(par, DC_UNLOCK, DC_UNLOCK_LOCK);
153} 169}
154 170
155static void gx_set_hw_palette_reg(struct fb_info *info, unsigned regno, 171void gx_set_hw_palette_reg(struct fb_info *info, unsigned regno,
156 unsigned red, unsigned green, unsigned blue) 172 unsigned red, unsigned green, unsigned blue)
157{ 173{
158 struct geodefb_par *par = info->par; 174 struct gxfb_par *par = info->par;
159 int val; 175 int val;
160 176
161 /* Hardware palette is in RGB 8-8-8 format. */ 177 /* Hardware palette is in RGB 8-8-8 format. */
@@ -163,11 +179,6 @@ static void gx_set_hw_palette_reg(struct fb_info *info, unsigned regno,
163 val |= (green) & 0x00ff00; 179 val |= (green) & 0x00ff00;
164 val |= (blue >> 8) & 0x0000ff; 180 val |= (blue >> 8) & 0x0000ff;
165 181
166 writel(regno, par->dc_regs + DC_PAL_ADDRESS); 182 write_dc(par, DC_PAL_ADDRESS, regno);
167 writel(val, par->dc_regs + DC_PAL_DATA); 183 write_dc(par, DC_PAL_DATA, val);
168} 184}
169
170struct geode_dc_ops gx_dc_ops = {
171 .set_mode = gx_set_mode,
172 .set_palette_reg = gx_set_hw_palette_reg,
173};
diff --git a/drivers/video/geode/display_gx.h b/drivers/video/geode/display_gx.h
deleted file mode 100644
index 0af33f329e88..000000000000
--- a/drivers/video/geode/display_gx.h
+++ /dev/null
@@ -1,101 +0,0 @@
1/*
2 * Geode GX display controller
3 *
4 * Copyright (C) 2006 Arcom Control Systems Ltd.
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 */
11#ifndef __DISPLAY_GX_H__
12#define __DISPLAY_GX_H__
13
14unsigned int gx_frame_buffer_size(void);
15int gx_line_delta(int xres, int bpp);
16
17extern struct geode_dc_ops gx_dc_ops;
18
19/* MSR that tells us if a TFT or CRT is attached */
20#define GLD_MSR_CONFIG 0xC0002001
21#define GLD_MSR_CONFIG_DM_FP 0x40
22
23/* Display controller registers */
24
25#define DC_UNLOCK 0x00
26# define DC_UNLOCK_CODE 0x00004758
27
28#define DC_GENERAL_CFG 0x04
29# define DC_GCFG_DFLE 0x00000001
30# define DC_GCFG_CURE 0x00000002
31# define DC_GCFG_ICNE 0x00000004
32# define DC_GCFG_VIDE 0x00000008
33# define DC_GCFG_CMPE 0x00000020
34# define DC_GCFG_DECE 0x00000040
35# define DC_GCFG_VGAE 0x00000080
36# define DC_GCFG_DFHPSL_MASK 0x00000F00
37# define DC_GCFG_DFHPSL_POS 8
38# define DC_GCFG_DFHPEL_MASK 0x0000F000
39# define DC_GCFG_DFHPEL_POS 12
40# define DC_GCFG_STFM 0x00010000
41# define DC_GCFG_FDTY 0x00020000
42# define DC_GCFG_VGAFT 0x00040000
43# define DC_GCFG_VDSE 0x00080000
44# define DC_GCFG_YUVM 0x00100000
45# define DC_GCFG_VFSL 0x00800000
46# define DC_GCFG_SIGE 0x01000000
47# define DC_GCFG_SGRE 0x02000000
48# define DC_GCFG_SGFR 0x04000000
49# define DC_GCFG_CRC_MODE 0x08000000
50# define DC_GCFG_DIAG 0x10000000
51# define DC_GCFG_CFRW 0x20000000
52
53#define DC_DISPLAY_CFG 0x08
54# define DC_DCFG_TGEN 0x00000001
55# define DC_DCFG_GDEN 0x00000008
56# define DC_DCFG_VDEN 0x00000010
57# define DC_DCFG_TRUP 0x00000040
58# define DC_DCFG_DISP_MODE_MASK 0x00000300
59# define DC_DCFG_DISP_MODE_8BPP 0x00000000
60# define DC_DCFG_DISP_MODE_16BPP 0x00000100
61# define DC_DCFG_DISP_MODE_24BPP 0x00000200
62# define DC_DCFG_16BPP_MODE_MASK 0x00000c00
63# define DC_DCFG_16BPP_MODE_565 0x00000000
64# define DC_DCFG_16BPP_MODE_555 0x00000100
65# define DC_DCFG_16BPP_MODE_444 0x00000200
66# define DC_DCFG_DCEN 0x00080000
67# define DC_DCFG_PALB 0x02000000
68# define DC_DCFG_FRLK 0x04000000
69# define DC_DCFG_VISL 0x08000000
70# define DC_DCFG_FRSL 0x20000000
71# define DC_DCFG_A18M 0x40000000
72# define DC_DCFG_A20M 0x80000000
73
74#define DC_FB_ST_OFFSET 0x10
75
76#define DC_LINE_SIZE 0x30
77# define DC_LINE_SIZE_FB_LINE_SIZE_MASK 0x000007ff
78# define DC_LINE_SIZE_FB_LINE_SIZE_POS 0
79# define DC_LINE_SIZE_CB_LINE_SIZE_MASK 0x007f0000
80# define DC_LINE_SIZE_CB_LINE_SIZE_POS 16
81# define DC_LINE_SIZE_VID_LINE_SIZE_MASK 0xff000000
82# define DC_LINE_SIZE_VID_LINE_SIZE_POS 24
83
84#define DC_GFX_PITCH 0x34
85# define DC_GFX_PITCH_FB_PITCH_MASK 0x0000ffff
86# define DC_GFX_PITCH_FB_PITCH_POS 0
87# define DC_GFX_PITCH_CB_PITCH_MASK 0xffff0000
88# define DC_GFX_PITCH_CB_PITCH_POS 16
89
90#define DC_H_ACTIVE_TIMING 0x40
91#define DC_H_BLANK_TIMING 0x44
92#define DC_H_SYNC_TIMING 0x48
93#define DC_V_ACTIVE_TIMING 0x50
94#define DC_V_BLANK_TIMING 0x54
95#define DC_V_SYNC_TIMING 0x58
96
97#define DC_PAL_ADDRESS 0x70
98#define DC_PAL_DATA 0x74
99
100#define DC_GLIU0_MEM_OFFSET 0x84
101#endif /* !__DISPLAY_GX1_H__ */
diff --git a/drivers/video/geode/gxfb.h b/drivers/video/geode/gxfb.h
new file mode 100644
index 000000000000..16a96f8fd8c5
--- /dev/null
+++ b/drivers/video/geode/gxfb.h
@@ -0,0 +1,358 @@
1/*
2 * Copyright (C) 2008 Andres Salomon <dilinger@debian.org>
3 *
4 * Geode GX2 header information
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 */
11#ifndef _GXFB_H_
12#define _GXFB_H_
13
14#include <linux/io.h>
15
16#define GP_REG_COUNT (0x50 / 4)
17#define DC_REG_COUNT (0x90 / 4)
18#define VP_REG_COUNT (0x138 / 8)
19#define FP_REG_COUNT (0x68 / 8)
20
21#define DC_PAL_COUNT 0x104
22
23struct gxfb_par {
24 int enable_crt;
25 void __iomem *dc_regs;
26 void __iomem *vid_regs;
27 void __iomem *gp_regs;
28#ifdef CONFIG_PM
29 int powered_down;
30
31 /* register state, for power management functionality */
32 struct {
33 uint64_t padsel;
34 uint64_t dotpll;
35 } msr;
36
37 uint32_t gp[GP_REG_COUNT];
38 uint32_t dc[DC_REG_COUNT];
39 uint64_t vp[VP_REG_COUNT];
40 uint64_t fp[FP_REG_COUNT];
41
42 uint32_t pal[DC_PAL_COUNT];
43#endif
44};
45
46unsigned int gx_frame_buffer_size(void);
47int gx_line_delta(int xres, int bpp);
48void gx_set_mode(struct fb_info *info);
49void gx_set_hw_palette_reg(struct fb_info *info, unsigned regno,
50 unsigned red, unsigned green, unsigned blue);
51
52void gx_set_dclk_frequency(struct fb_info *info);
53void gx_configure_display(struct fb_info *info);
54int gx_blank_display(struct fb_info *info, int blank_mode);
55
56#ifdef CONFIG_PM
57int gx_powerdown(struct fb_info *info);
58int gx_powerup(struct fb_info *info);
59#endif
60
61
62/* Graphics Processor registers (table 6-23 from the data book) */
63enum gp_registers {
64 GP_DST_OFFSET = 0,
65 GP_SRC_OFFSET,
66 GP_STRIDE,
67 GP_WID_HEIGHT,
68
69 GP_SRC_COLOR_FG,
70 GP_SRC_COLOR_BG,
71 GP_PAT_COLOR_0,
72 GP_PAT_COLOR_1,
73
74 GP_PAT_COLOR_2,
75 GP_PAT_COLOR_3,
76 GP_PAT_COLOR_4,
77 GP_PAT_COLOR_5,
78
79 GP_PAT_DATA_0,
80 GP_PAT_DATA_1,
81 GP_RASTER_MODE,
82 GP_VECTOR_MODE,
83
84 GP_BLT_MODE,
85 GP_BLT_STATUS,
86 GP_HST_SRC,
87 GP_BASE_OFFSET, /* 0x4c */
88};
89
90#define GP_BLT_STATUS_BLT_PENDING (1 << 2)
91#define GP_BLT_STATUS_BLT_BUSY (1 << 0)
92
93
94/* Display Controller registers (table 6-38 from the data book) */
95enum dc_registers {
96 DC_UNLOCK = 0,
97 DC_GENERAL_CFG,
98 DC_DISPLAY_CFG,
99 DC_RSVD_0,
100
101 DC_FB_ST_OFFSET,
102 DC_CB_ST_OFFSET,
103 DC_CURS_ST_OFFSET,
104 DC_ICON_ST_OFFSET,
105
106 DC_VID_Y_ST_OFFSET,
107 DC_VID_U_ST_OFFSET,
108 DC_VID_V_ST_OFFSET,
109 DC_RSVD_1,
110
111 DC_LINE_SIZE,
112 DC_GFX_PITCH,
113 DC_VID_YUV_PITCH,
114 DC_RSVD_2,
115
116 DC_H_ACTIVE_TIMING,
117 DC_H_BLANK_TIMING,
118 DC_H_SYNC_TIMING,
119 DC_RSVD_3,
120
121 DC_V_ACTIVE_TIMING,
122 DC_V_BLANK_TIMING,
123 DC_V_SYNC_TIMING,
124 DC_RSVD_4,
125
126 DC_CURSOR_X,
127 DC_CURSOR_Y,
128 DC_ICON_X,
129 DC_LINE_CNT,
130
131 DC_PAL_ADDRESS,
132 DC_PAL_DATA,
133 DC_DFIFO_DIAG,
134 DC_CFIFO_DIAG,
135
136 DC_VID_DS_DELTA,
137 DC_GLIU0_MEM_OFFSET,
138 DC_RSVD_5,
139 DC_DV_ACC, /* 0x8c */
140};
141
142#define DC_UNLOCK_LOCK 0x00000000
143#define DC_UNLOCK_UNLOCK 0x00004758 /* magic value */
144
145#define DC_GENERAL_CFG_YUVM (1 << 20)
146#define DC_GENERAL_CFG_VDSE (1 << 19)
147#define DC_GENERAL_CFG_DFHPEL_SHIFT 12
148#define DC_GENERAL_CFG_DFHPSL_SHIFT 8
149#define DC_GENERAL_CFG_DECE (1 << 6)
150#define DC_GENERAL_CFG_CMPE (1 << 5)
151#define DC_GENERAL_CFG_VIDE (1 << 3)
152#define DC_GENERAL_CFG_ICNE (1 << 2)
153#define DC_GENERAL_CFG_CURE (1 << 1)
154#define DC_GENERAL_CFG_DFLE (1 << 0)
155
156#define DC_DISPLAY_CFG_A20M (1 << 31)
157#define DC_DISPLAY_CFG_A18M (1 << 30)
158#define DC_DISPLAY_CFG_PALB (1 << 25)
159#define DC_DISPLAY_CFG_DISP_MODE_24BPP (1 << 9)
160#define DC_DISPLAY_CFG_DISP_MODE_16BPP (1 << 8)
161#define DC_DISPLAY_CFG_DISP_MODE_8BPP (0)
162#define DC_DISPLAY_CFG_VDEN (1 << 4)
163#define DC_DISPLAY_CFG_GDEN (1 << 3)
164#define DC_DISPLAY_CFG_TGEN (1 << 0)
165
166
167/*
168 * Video Processor registers (table 6-54).
169 * There is space for 64 bit values, but we never use more than the
170 * lower 32 bits. The actual register save/restore code only bothers
171 * to restore those 32 bits.
172 */
173enum vp_registers {
174 VP_VCFG = 0,
175 VP_DCFG,
176
177 VP_VX,
178 VP_VY,
179
180 VP_VS,
181 VP_VCK,
182
183 VP_VCM,
184 VP_GAR,
185
186 VP_GDR,
187 VP_RSVD_0,
188
189 VP_MISC,
190 VP_CCS,
191
192 VP_RSVD_1,
193 VP_RSVD_2,
194
195 VP_RSVD_3,
196 VP_VDC,
197
198 VP_VCO,
199 VP_CRC,
200
201 VP_CRC32,
202 VP_VDE,
203
204 VP_CCK,
205 VP_CCM,
206
207 VP_CC1,
208 VP_CC2,
209
210 VP_A1X,
211 VP_A1Y,
212
213 VP_A1C,
214 VP_A1T,
215
216 VP_A2X,
217 VP_A2Y,
218
219 VP_A2C,
220 VP_A2T,
221
222 VP_A3X,
223 VP_A3Y,
224
225 VP_A3C,
226 VP_A3T,
227
228 VP_VRR,
229 VP_AWT,
230
231 VP_VTM, /* 0x130 */
232};
233
234#define VP_VCFG_VID_EN (1 << 0)
235
236#define VP_DCFG_DAC_VREF (1 << 26)
237#define VP_DCFG_GV_GAM (1 << 21)
238#define VP_DCFG_VG_CK (1 << 20)
239#define VP_DCFG_CRT_SYNC_SKW_DEFAULT (1 << 16)
240#define VP_DCFG_CRT_SYNC_SKW ((1 << 14) | (1 << 15) | (1 << 16))
241#define VP_DCFG_CRT_VSYNC_POL (1 << 9)
242#define VP_DCFG_CRT_HSYNC_POL (1 << 8)
243#define VP_DCFG_FP_DATA_EN (1 << 7) /* undocumented */
244#define VP_DCFG_FP_PWR_EN (1 << 6) /* undocumented */
245#define VP_DCFG_DAC_BL_EN (1 << 3)
246#define VP_DCFG_VSYNC_EN (1 << 2)
247#define VP_DCFG_HSYNC_EN (1 << 1)
248#define VP_DCFG_CRT_EN (1 << 0)
249
250#define VP_MISC_GAM_EN (1 << 0)
251#define VP_MISC_DACPWRDN (1 << 10)
252#define VP_MISC_APWRDN (1 << 11)
253
254
255/*
256 * Flat Panel registers (table 6-55).
257 * Also 64 bit registers; see above note about 32-bit handling.
258 */
259
260/* we're actually in the VP register space, starting at address 0x400 */
261#define VP_FP_START 0x400
262
263enum fp_registers {
264 FP_PT1 = 0,
265 FP_PT2,
266
267 FP_PM,
268 FP_DFC,
269
270 FP_BLFSR,
271 FP_RLFSR,
272
273 FP_FMI,
274 FP_FMD,
275
276 FP_RSVD_0,
277 FP_DCA,
278
279 FP_DMD,
280 FP_CRC,
281
282 FP_FBB, /* 0x460 */
283};
284
285#define FP_PT1_VSIZE_SHIFT 16 /* undocumented? */
286#define FP_PT1_VSIZE_MASK 0x7FF0000 /* undocumented? */
287
288#define FP_PT2_HSP (1 << 22)
289#define FP_PT2_VSP (1 << 23)
290
291#define FP_PM_P (1 << 24) /* panel power on */
292#define FP_PM_PANEL_PWR_UP (1 << 3) /* r/o */
293#define FP_PM_PANEL_PWR_DOWN (1 << 2) /* r/o */
294#define FP_PM_PANEL_OFF (1 << 1) /* r/o */
295#define FP_PM_PANEL_ON (1 << 0) /* r/o */
296
297#define FP_DFC_NFI ((1 << 4) | (1 << 5) | (1 << 6))
298
299
300/* register access functions */
301
302static inline uint32_t read_gp(struct gxfb_par *par, int reg)
303{
304 return readl(par->gp_regs + 4*reg);
305}
306
307static inline void write_gp(struct gxfb_par *par, int reg, uint32_t val)
308{
309 writel(val, par->gp_regs + 4*reg);
310}
311
312static inline uint32_t read_dc(struct gxfb_par *par, int reg)
313{
314 return readl(par->dc_regs + 4*reg);
315}
316
317static inline void write_dc(struct gxfb_par *par, int reg, uint32_t val)
318{
319 writel(val, par->dc_regs + 4*reg);
320}
321
322static inline uint32_t read_vp(struct gxfb_par *par, int reg)
323{
324 return readl(par->vid_regs + 8*reg);
325}
326
327static inline void write_vp(struct gxfb_par *par, int reg, uint32_t val)
328{
329 writel(val, par->vid_regs + 8*reg);
330}
331
332static inline uint32_t read_fp(struct gxfb_par *par, int reg)
333{
334 return readl(par->vid_regs + 8*reg + VP_FP_START);
335}
336
337static inline void write_fp(struct gxfb_par *par, int reg, uint32_t val)
338{
339 writel(val, par->vid_regs + 8*reg + VP_FP_START);
340}
341
342
343/* MSRs are defined in asm/geode.h; their bitfields are here */
344
345#define MSR_GLCP_SYS_RSTPLL_DOTPOSTDIV3 (1 << 3)
346#define MSR_GLCP_SYS_RSTPLL_DOTPREMULT2 (1 << 2)
347#define MSR_GLCP_SYS_RSTPLL_DOTPREDIV2 (1 << 1)
348
349#define MSR_GLCP_DOTPLL_LOCK (1 << 25) /* r/o */
350#define MSR_GLCP_DOTPLL_BYPASS (1 << 15)
351#define MSR_GLCP_DOTPLL_DOTRESET (1 << 0)
352
353#define MSR_GX_MSR_PADSEL_MASK 0x3FFFFFFF /* undocumented? */
354#define MSR_GX_MSR_PADSEL_TFT 0x1FFFFFFF /* undocumented? */
355
356#define MSR_GX_GLD_MSR_CONFIG_FP (1 << 3)
357
358#endif
diff --git a/drivers/video/geode/gxfb_core.c b/drivers/video/geode/gxfb_core.c
index cf841efa229a..de2b8f9876a5 100644
--- a/drivers/video/geode/gxfb_core.c
+++ b/drivers/video/geode/gxfb_core.c
@@ -28,17 +28,20 @@
28#include <linux/slab.h> 28#include <linux/slab.h>
29#include <linux/delay.h> 29#include <linux/delay.h>
30#include <linux/fb.h> 30#include <linux/fb.h>
31#include <linux/console.h>
32#include <linux/suspend.h>
31#include <linux/init.h> 33#include <linux/init.h>
32#include <linux/pci.h> 34#include <linux/pci.h>
35#include <asm/geode.h>
33 36
34#include "geodefb.h" 37#include "gxfb.h"
35#include "display_gx.h"
36#include "video_gx.h"
37 38
38static char *mode_option; 39static char *mode_option;
40static int vram;
41static int vt_switch;
39 42
40/* Modes relevant to the GX (taken from modedb.c) */ 43/* Modes relevant to the GX (taken from modedb.c) */
41static const struct fb_videomode gx_modedb[] __initdata = { 44static struct fb_videomode gx_modedb[] __initdata = {
42 /* 640x480-60 VESA */ 45 /* 640x480-60 VESA */
43 { NULL, 60, 640, 480, 39682, 48, 16, 33, 10, 96, 2, 46 { NULL, 60, 640, 480, 39682, 48, 16, 33, 10, 96, 2,
44 0, FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA }, 47 0, FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA },
@@ -105,6 +108,35 @@ static const struct fb_videomode gx_modedb[] __initdata = {
105 FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA }, 108 FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA },
106}; 109};
107 110
111#ifdef CONFIG_OLPC
112#include <asm/olpc.h>
113
114static struct fb_videomode gx_dcon_modedb[] __initdata = {
115 /* The only mode the DCON has is 1200x900 */
116 { NULL, 50, 1200, 900, 17460, 24, 8, 4, 5, 8, 3,
117 FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
118 FB_VMODE_NONINTERLACED, 0 }
119};
120
121static void __init get_modedb(struct fb_videomode **modedb, unsigned int *size)
122{
123 if (olpc_has_dcon()) {
124 *modedb = (struct fb_videomode *) gx_dcon_modedb;
125 *size = ARRAY_SIZE(gx_dcon_modedb);
126 } else {
127 *modedb = (struct fb_videomode *) gx_modedb;
128 *size = ARRAY_SIZE(gx_modedb);
129 }
130}
131
132#else
133static void __init get_modedb(struct fb_videomode **modedb, unsigned int *size)
134{
135 *modedb = (struct fb_videomode *) gx_modedb;
136 *size = ARRAY_SIZE(gx_modedb);
137}
138#endif
139
108static int gxfb_check_var(struct fb_var_screeninfo *var, struct fb_info *info) 140static int gxfb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
109{ 141{
110 if (var->xres > 1600 || var->yres > 1200) 142 if (var->xres > 1600 || var->yres > 1200)
@@ -139,8 +171,6 @@ static int gxfb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
139 171
140static int gxfb_set_par(struct fb_info *info) 172static int gxfb_set_par(struct fb_info *info)
141{ 173{
142 struct geodefb_par *par = info->par;
143
144 if (info->var.bits_per_pixel > 8) { 174 if (info->var.bits_per_pixel > 8) {
145 info->fix.visual = FB_VISUAL_TRUECOLOR; 175 info->fix.visual = FB_VISUAL_TRUECOLOR;
146 fb_dealloc_cmap(&info->cmap); 176 fb_dealloc_cmap(&info->cmap);
@@ -151,7 +181,7 @@ static int gxfb_set_par(struct fb_info *info)
151 181
152 info->fix.line_length = gx_line_delta(info->var.xres, info->var.bits_per_pixel); 182 info->fix.line_length = gx_line_delta(info->var.xres, info->var.bits_per_pixel);
153 183
154 par->dc_ops->set_mode(info); 184 gx_set_mode(info);
155 185
156 return 0; 186 return 0;
157} 187}
@@ -167,8 +197,6 @@ static int gxfb_setcolreg(unsigned regno, unsigned red, unsigned green,
167 unsigned blue, unsigned transp, 197 unsigned blue, unsigned transp,
168 struct fb_info *info) 198 struct fb_info *info)
169{ 199{
170 struct geodefb_par *par = info->par;
171
172 if (info->var.grayscale) { 200 if (info->var.grayscale) {
173 /* grayscale = 0.30*R + 0.59*G + 0.11*B */ 201 /* grayscale = 0.30*R + 0.59*G + 0.11*B */
174 red = green = blue = (red * 77 + green * 151 + blue * 28) >> 8; 202 red = green = blue = (red * 77 + green * 151 + blue * 28) >> 8;
@@ -191,7 +219,7 @@ static int gxfb_setcolreg(unsigned regno, unsigned red, unsigned green,
191 if (regno >= 256) 219 if (regno >= 256)
192 return -EINVAL; 220 return -EINVAL;
193 221
194 par->dc_ops->set_palette_reg(info, regno, red, green, blue); 222 gx_set_hw_palette_reg(info, regno, red, green, blue);
195 } 223 }
196 224
197 return 0; 225 return 0;
@@ -199,15 +227,12 @@ static int gxfb_setcolreg(unsigned regno, unsigned red, unsigned green,
199 227
200static int gxfb_blank(int blank_mode, struct fb_info *info) 228static int gxfb_blank(int blank_mode, struct fb_info *info)
201{ 229{
202 struct geodefb_par *par = info->par; 230 return gx_blank_display(info, blank_mode);
203
204 return par->vid_ops->blank_display(info, blank_mode);
205} 231}
206 232
207static int __init gxfb_map_video_memory(struct fb_info *info, struct pci_dev *dev) 233static int __init gxfb_map_video_memory(struct fb_info *info, struct pci_dev *dev)
208{ 234{
209 struct geodefb_par *par = info->par; 235 struct gxfb_par *par = info->par;
210 int fb_len;
211 int ret; 236 int ret;
212 237
213 ret = pci_enable_device(dev); 238 ret = pci_enable_device(dev);
@@ -229,24 +254,31 @@ static int __init gxfb_map_video_memory(struct fb_info *info, struct pci_dev *de
229 if (!par->dc_regs) 254 if (!par->dc_regs)
230 return -ENOMEM; 255 return -ENOMEM;
231 256
232 ret = pci_request_region(dev, 0, "gxfb (framebuffer)"); 257 ret = pci_request_region(dev, 1, "gxfb (graphics processor)");
233 if (ret < 0) 258 if (ret < 0)
234 return ret; 259 return ret;
235 if ((fb_len = gx_frame_buffer_size()) < 0) 260 par->gp_regs = ioremap(pci_resource_start(dev, 1),
261 pci_resource_len(dev, 1));
262
263 if (!par->gp_regs)
236 return -ENOMEM; 264 return -ENOMEM;
265
266 ret = pci_request_region(dev, 0, "gxfb (framebuffer)");
267 if (ret < 0)
268 return ret;
269
237 info->fix.smem_start = pci_resource_start(dev, 0); 270 info->fix.smem_start = pci_resource_start(dev, 0);
238 info->fix.smem_len = fb_len; 271 info->fix.smem_len = vram ? vram : gx_frame_buffer_size();
239 info->screen_base = ioremap(info->fix.smem_start, info->fix.smem_len); 272 info->screen_base = ioremap(info->fix.smem_start, info->fix.smem_len);
240 if (!info->screen_base) 273 if (!info->screen_base)
241 return -ENOMEM; 274 return -ENOMEM;
242 275
243 /* Set the 16MB aligned base address of the graphics memory region 276 /* Set the 16MiB aligned base address of the graphics memory region
244 * in the display controller */ 277 * in the display controller */
245 278
246 writel(info->fix.smem_start & 0xFF000000, 279 write_dc(par, DC_GLIU0_MEM_OFFSET, info->fix.smem_start & 0xFF000000);
247 par->dc_regs + DC_GLIU0_MEM_OFFSET);
248 280
249 dev_info(&dev->dev, "%d Kibyte of video memory at 0x%lx\n", 281 dev_info(&dev->dev, "%d KiB of video memory at 0x%lx\n",
250 info->fix.smem_len / 1024, info->fix.smem_start); 282 info->fix.smem_len / 1024, info->fix.smem_start);
251 283
252 return 0; 284 return 0;
@@ -266,11 +298,12 @@ static struct fb_ops gxfb_ops = {
266 298
267static struct fb_info * __init gxfb_init_fbinfo(struct device *dev) 299static struct fb_info * __init gxfb_init_fbinfo(struct device *dev)
268{ 300{
269 struct geodefb_par *par; 301 struct gxfb_par *par;
270 struct fb_info *info; 302 struct fb_info *info;
271 303
272 /* Alloc enough space for the pseudo palette. */ 304 /* Alloc enough space for the pseudo palette. */
273 info = framebuffer_alloc(sizeof(struct geodefb_par) + sizeof(u32) * 16, dev); 305 info = framebuffer_alloc(sizeof(struct gxfb_par) + sizeof(u32) * 16,
306 dev);
274 if (!info) 307 if (!info)
275 return NULL; 308 return NULL;
276 309
@@ -296,29 +329,64 @@ static struct fb_info * __init gxfb_init_fbinfo(struct device *dev)
296 info->flags = FBINFO_DEFAULT; 329 info->flags = FBINFO_DEFAULT;
297 info->node = -1; 330 info->node = -1;
298 331
299 info->pseudo_palette = (void *)par + sizeof(struct geodefb_par); 332 info->pseudo_palette = (void *)par + sizeof(struct gxfb_par);
300 333
301 info->var.grayscale = 0; 334 info->var.grayscale = 0;
302 335
303 return info; 336 return info;
304} 337}
305 338
339#ifdef CONFIG_PM
340static int gxfb_suspend(struct pci_dev *pdev, pm_message_t state)
341{
342 struct fb_info *info = pci_get_drvdata(pdev);
343
344 if (state.event == PM_EVENT_SUSPEND) {
345 acquire_console_sem();
346 gx_powerdown(info);
347 fb_set_suspend(info, 1);
348 release_console_sem();
349 }
350
351 /* there's no point in setting PCI states; we emulate PCI, so
352 * we don't end up getting power savings anyways */
353
354 return 0;
355}
356
357static int gxfb_resume(struct pci_dev *pdev)
358{
359 struct fb_info *info = pci_get_drvdata(pdev);
360 int ret;
361
362 acquire_console_sem();
363 ret = gx_powerup(info);
364 if (ret) {
365 printk(KERN_ERR "gxfb: power up failed!\n");
366 return ret;
367 }
368
369 fb_set_suspend(info, 0);
370 release_console_sem();
371 return 0;
372}
373#endif
374
306static int __init gxfb_probe(struct pci_dev *pdev, const struct pci_device_id *id) 375static int __init gxfb_probe(struct pci_dev *pdev, const struct pci_device_id *id)
307{ 376{
308 struct geodefb_par *par; 377 struct gxfb_par *par;
309 struct fb_info *info; 378 struct fb_info *info;
310 int ret; 379 int ret;
311 unsigned long val; 380 unsigned long val;
312 381
382 struct fb_videomode *modedb_ptr;
383 unsigned int modedb_size;
384
313 info = gxfb_init_fbinfo(&pdev->dev); 385 info = gxfb_init_fbinfo(&pdev->dev);
314 if (!info) 386 if (!info)
315 return -ENOMEM; 387 return -ENOMEM;
316 par = info->par; 388 par = info->par;
317 389
318 /* GX display controller and GX video device. */
319 par->dc_ops = &gx_dc_ops;
320 par->vid_ops = &gx_vid_ops;
321
322 if ((ret = gxfb_map_video_memory(info, pdev)) < 0) { 390 if ((ret = gxfb_map_video_memory(info, pdev)) < 0) {
323 dev_err(&pdev->dev, "failed to map frame buffer or controller registers\n"); 391 dev_err(&pdev->dev, "failed to map frame buffer or controller registers\n");
324 goto err; 392 goto err;
@@ -326,15 +394,16 @@ static int __init gxfb_probe(struct pci_dev *pdev, const struct pci_device_id *i
326 394
327 /* Figure out if this is a TFT or CRT part */ 395 /* Figure out if this is a TFT or CRT part */
328 396
329 rdmsrl(GLD_MSR_CONFIG, val); 397 rdmsrl(MSR_GX_GLD_MSR_CONFIG, val);
330 398
331 if ((val & GLD_MSR_CONFIG_DM_FP) == GLD_MSR_CONFIG_DM_FP) 399 if ((val & MSR_GX_GLD_MSR_CONFIG_FP) == MSR_GX_GLD_MSR_CONFIG_FP)
332 par->enable_crt = 0; 400 par->enable_crt = 0;
333 else 401 else
334 par->enable_crt = 1; 402 par->enable_crt = 1;
335 403
404 get_modedb(&modedb_ptr, &modedb_size);
336 ret = fb_find_mode(&info->var, info, mode_option, 405 ret = fb_find_mode(&info->var, info, mode_option,
337 gx_modedb, ARRAY_SIZE(gx_modedb), NULL, 16); 406 modedb_ptr, modedb_size, NULL, 16);
338 if (ret == 0 || ret == 4) { 407 if (ret == 0 || ret == 4) {
339 dev_err(&pdev->dev, "could not find valid video mode\n"); 408 dev_err(&pdev->dev, "could not find valid video mode\n");
340 ret = -EINVAL; 409 ret = -EINVAL;
@@ -348,6 +417,8 @@ static int __init gxfb_probe(struct pci_dev *pdev, const struct pci_device_id *i
348 gxfb_check_var(&info->var, info); 417 gxfb_check_var(&info->var, info);
349 gxfb_set_par(info); 418 gxfb_set_par(info);
350 419
420 pm_set_vt_switch(vt_switch);
421
351 if (register_framebuffer(info) < 0) { 422 if (register_framebuffer(info) < 0) {
352 ret = -EINVAL; 423 ret = -EINVAL;
353 goto err; 424 goto err;
@@ -369,6 +440,10 @@ static int __init gxfb_probe(struct pci_dev *pdev, const struct pci_device_id *i
369 iounmap(par->dc_regs); 440 iounmap(par->dc_regs);
370 pci_release_region(pdev, 2); 441 pci_release_region(pdev, 2);
371 } 442 }
443 if (par->gp_regs) {
444 iounmap(par->gp_regs);
445 pci_release_region(pdev, 1);
446 }
372 447
373 if (info) 448 if (info)
374 framebuffer_release(info); 449 framebuffer_release(info);
@@ -378,7 +453,7 @@ static int __init gxfb_probe(struct pci_dev *pdev, const struct pci_device_id *i
378static void gxfb_remove(struct pci_dev *pdev) 453static void gxfb_remove(struct pci_dev *pdev)
379{ 454{
380 struct fb_info *info = pci_get_drvdata(pdev); 455 struct fb_info *info = pci_get_drvdata(pdev);
381 struct geodefb_par *par = info->par; 456 struct gxfb_par *par = info->par;
382 457
383 unregister_framebuffer(info); 458 unregister_framebuffer(info);
384 459
@@ -391,15 +466,16 @@ static void gxfb_remove(struct pci_dev *pdev)
391 iounmap(par->dc_regs); 466 iounmap(par->dc_regs);
392 pci_release_region(pdev, 2); 467 pci_release_region(pdev, 2);
393 468
469 iounmap(par->gp_regs);
470 pci_release_region(pdev, 1);
471
394 pci_set_drvdata(pdev, NULL); 472 pci_set_drvdata(pdev, NULL);
395 473
396 framebuffer_release(info); 474 framebuffer_release(info);
397} 475}
398 476
399static struct pci_device_id gxfb_id_table[] = { 477static struct pci_device_id gxfb_id_table[] = {
400 { PCI_VENDOR_ID_NS, PCI_DEVICE_ID_NS_GX_VIDEO, 478 { PCI_DEVICE(PCI_VENDOR_ID_NS, PCI_DEVICE_ID_NS_GX_VIDEO) },
401 PCI_ANY_ID, PCI_ANY_ID, PCI_BASE_CLASS_DISPLAY << 16,
402 0xff0000, 0 },
403 { 0, } 479 { 0, }
404}; 480};
405 481
@@ -410,6 +486,10 @@ static struct pci_driver gxfb_driver = {
410 .id_table = gxfb_id_table, 486 .id_table = gxfb_id_table,
411 .probe = gxfb_probe, 487 .probe = gxfb_probe,
412 .remove = gxfb_remove, 488 .remove = gxfb_remove,
489#ifdef CONFIG_PM
490 .suspend = gxfb_suspend,
491 .resume = gxfb_resume,
492#endif
413}; 493};
414 494
415#ifndef MODULE 495#ifndef MODULE
@@ -456,5 +536,11 @@ module_exit(gxfb_cleanup);
456module_param(mode_option, charp, 0); 536module_param(mode_option, charp, 0);
457MODULE_PARM_DESC(mode_option, "video mode (<x>x<y>[-<bpp>][@<refr>])"); 537MODULE_PARM_DESC(mode_option, "video mode (<x>x<y>[-<bpp>][@<refr>])");
458 538
539module_param(vram, int, 0);
540MODULE_PARM_DESC(vram, "video memory size");
541
542module_param(vt_switch, int, 0);
543MODULE_PARM_DESC(vt_switch, "enable VT switch during suspend/resume");
544
459MODULE_DESCRIPTION("Framebuffer driver for the AMD Geode GX"); 545MODULE_DESCRIPTION("Framebuffer driver for the AMD Geode GX");
460MODULE_LICENSE("GPL"); 546MODULE_LICENSE("GPL");
diff --git a/drivers/video/geode/lxfb.h b/drivers/video/geode/lxfb.h
index ca13c48d19b0..3b9416f4ee20 100644
--- a/drivers/video/geode/lxfb.h
+++ b/drivers/video/geode/lxfb.h
@@ -3,17 +3,46 @@
3 3
4#include <linux/fb.h> 4#include <linux/fb.h>
5 5
6#define GP_REG_COUNT (0x7c / 4)
7#define DC_REG_COUNT (0xf0 / 4)
8#define VP_REG_COUNT (0x158 / 8)
9#define FP_REG_COUNT (0x60 / 8)
10
11#define DC_PAL_COUNT 0x104
12#define DC_HFILT_COUNT 0x100
13#define DC_VFILT_COUNT 0x100
14#define VP_COEFF_SIZE 0x1000
15
6#define OUTPUT_CRT 0x01 16#define OUTPUT_CRT 0x01
7#define OUTPUT_PANEL 0x02 17#define OUTPUT_PANEL 0x02
8 18
9struct lxfb_par { 19struct lxfb_par {
10 int output; 20 int output;
11 int panel_width;
12 int panel_height;
13 21
14 void __iomem *gp_regs; 22 void __iomem *gp_regs;
15 void __iomem *dc_regs; 23 void __iomem *dc_regs;
16 void __iomem *df_regs; 24 void __iomem *vp_regs;
25#ifdef CONFIG_PM
26 int powered_down;
27
28 /* register state, for power mgmt functionality */
29 struct {
30 uint64_t padsel;
31 uint64_t dotpll;
32 uint64_t dfglcfg;
33 uint64_t dcspare;
34 } msr;
35
36 uint32_t gp[GP_REG_COUNT];
37 uint32_t dc[DC_REG_COUNT];
38 uint64_t vp[VP_REG_COUNT];
39 uint64_t fp[FP_REG_COUNT];
40
41 uint32_t pal[DC_PAL_COUNT];
42 uint32_t hcoeff[DC_HFILT_COUNT * 2];
43 uint32_t vcoeff[DC_VFILT_COUNT];
44 uint32_t vp_coeff[VP_COEFF_SIZE / 4];
45#endif
17}; 46};
18 47
19static inline unsigned int lx_get_pitch(unsigned int xres, int bpp) 48static inline unsigned int lx_get_pitch(unsigned int xres, int bpp)
@@ -29,171 +58,383 @@ int lx_blank_display(struct fb_info *, int);
29void lx_set_palette_reg(struct fb_info *, unsigned int, unsigned int, 58void lx_set_palette_reg(struct fb_info *, unsigned int, unsigned int,
30 unsigned int, unsigned int); 59 unsigned int, unsigned int);
31 60
32/* MSRS */ 61#ifdef CONFIG_PM
62int lx_powerdown(struct fb_info *info);
63int lx_powerup(struct fb_info *info);
64#endif
65
66
67/* Graphics Processor registers (table 6-29 from the data book) */
68enum gp_registers {
69 GP_DST_OFFSET = 0,
70 GP_SRC_OFFSET,
71 GP_STRIDE,
72 GP_WID_HEIGHT,
73
74 GP_SRC_COLOR_FG,
75 GP_SRC_COLOR_BG,
76 GP_PAT_COLOR_0,
77 GP_PAT_COLOR_1,
78
79 GP_PAT_COLOR_2,
80 GP_PAT_COLOR_3,
81 GP_PAT_COLOR_4,
82 GP_PAT_COLOR_5,
83
84 GP_PAT_DATA_0,
85 GP_PAT_DATA_1,
86 GP_RASTER_MODE,
87 GP_VECTOR_MODE,
88
89 GP_BLT_MODE,
90 GP_BLT_STATUS,
91 GP_HST_SRC,
92 GP_BASE_OFFSET,
93
94 GP_CMD_TOP,
95 GP_CMD_BOT,
96 GP_CMD_READ,
97 GP_CMD_WRITE,
98
99 GP_CH3_OFFSET,
100 GP_CH3_MODE_STR,
101 GP_CH3_WIDHI,
102 GP_CH3_HSRC,
103
104 GP_LUT_INDEX,
105 GP_LUT_DATA,
106 GP_INT_CNTRL, /* 0x78 */
107};
108
109#define GP_BLT_STATUS_CE (1 << 4) /* cmd buf empty */
110#define GP_BLT_STATUS_PB (1 << 0) /* primative busy */
111
112
113/* Display Controller registers (table 6-47 from the data book) */
114enum dc_registers {
115 DC_UNLOCK = 0,
116 DC_GENERAL_CFG,
117 DC_DISPLAY_CFG,
118 DC_ARB_CFG,
119
120 DC_FB_ST_OFFSET,
121 DC_CB_ST_OFFSET,
122 DC_CURS_ST_OFFSET,
123 DC_RSVD_0,
124
125 DC_VID_Y_ST_OFFSET,
126 DC_VID_U_ST_OFFSET,
127 DC_VID_V_ST_OFFSET,
128 DC_DV_TOP,
129
130 DC_LINE_SIZE,
131 DC_GFX_PITCH,
132 DC_VID_YUV_PITCH,
133 DC_RSVD_1,
134
135 DC_H_ACTIVE_TIMING,
136 DC_H_BLANK_TIMING,
137 DC_H_SYNC_TIMING,
138 DC_RSVD_2,
139
140 DC_V_ACTIVE_TIMING,
141 DC_V_BLANK_TIMING,
142 DC_V_SYNC_TIMING,
143 DC_FB_ACTIVE,
144
145 DC_CURSOR_X,
146 DC_CURSOR_Y,
147 DC_RSVD_3,
148 DC_LINE_CNT,
149
150 DC_PAL_ADDRESS,
151 DC_PAL_DATA,
152 DC_DFIFO_DIAG,
153 DC_CFIFO_DIAG,
154
155 DC_VID_DS_DELTA,
156 DC_GLIU0_MEM_OFFSET,
157 DC_DV_CTL,
158 DC_DV_ACCESS,
159
160 DC_GFX_SCALE,
161 DC_IRQ_FILT_CTL,
162 DC_FILT_COEFF1,
163 DC_FILT_COEFF2,
164
165 DC_VBI_EVEN_CTL,
166 DC_VBI_ODD_CTL,
167 DC_VBI_HOR,
168 DC_VBI_LN_ODD,
169
170 DC_VBI_LN_EVEN,
171 DC_VBI_PITCH,
172 DC_CLR_KEY,
173 DC_CLR_KEY_MASK,
174
175 DC_CLR_KEY_X,
176 DC_CLR_KEY_Y,
177 DC_IRQ,
178 DC_RSVD_4,
179
180 DC_RSVD_5,
181 DC_GENLK_CTL,
182 DC_VID_EVEN_Y_ST_OFFSET,
183 DC_VID_EVEN_U_ST_OFFSET,
184
185 DC_VID_EVEN_V_ST_OFFSET,
186 DC_V_ACTIVE_EVEN_TIMING,
187 DC_V_BLANK_EVEN_TIMING,
188 DC_V_SYNC_EVEN_TIMING, /* 0xec */
189};
190
191#define DC_UNLOCK_LOCK 0x00000000
192#define DC_UNLOCK_UNLOCK 0x00004758 /* magic value */
193
194#define DC_GENERAL_CFG_FDTY (1 << 17)
195#define DC_GENERAL_CFG_DFHPEL_SHIFT (12)
196#define DC_GENERAL_CFG_DFHPSL_SHIFT (8)
197#define DC_GENERAL_CFG_VGAE (1 << 7)
198#define DC_GENERAL_CFG_DECE (1 << 6)
199#define DC_GENERAL_CFG_CMPE (1 << 5)
200#define DC_GENERAL_CFG_VIDE (1 << 3)
201#define DC_GENERAL_CFG_DFLE (1 << 0)
202
203#define DC_DISPLAY_CFG_VISL (1 << 27)
204#define DC_DISPLAY_CFG_PALB (1 << 25)
205#define DC_DISPLAY_CFG_DCEN (1 << 24)
206#define DC_DISPLAY_CFG_DISP_MODE_24BPP (1 << 9)
207#define DC_DISPLAY_CFG_DISP_MODE_16BPP (1 << 8)
208#define DC_DISPLAY_CFG_DISP_MODE_8BPP (0)
209#define DC_DISPLAY_CFG_TRUP (1 << 6)
210#define DC_DISPLAY_CFG_VDEN (1 << 4)
211#define DC_DISPLAY_CFG_GDEN (1 << 3)
212#define DC_DISPLAY_CFG_TGEN (1 << 0)
213
214#define DC_DV_TOP_DV_TOP_EN (1 << 0)
215
216#define DC_DV_CTL_DV_LINE_SIZE ((1 << 10) | (1 << 11))
217#define DC_DV_CTL_DV_LINE_SIZE_1K (0)
218#define DC_DV_CTL_DV_LINE_SIZE_2K (1 << 10)
219#define DC_DV_CTL_DV_LINE_SIZE_4K (1 << 11)
220#define DC_DV_CTL_DV_LINE_SIZE_8K ((1 << 10) | (1 << 11))
221#define DC_DV_CTL_CLEAR_DV_RAM (1 << 0)
222
223#define DC_IRQ_FILT_CTL_H_FILT_SEL (1 << 10)
224
225#define DC_CLR_KEY_CLR_KEY_EN (1 << 24)
226
227#define DC_IRQ_VIP_VSYNC_IRQ_STATUS (1 << 21) /* undocumented? */
228#define DC_IRQ_STATUS (1 << 20) /* undocumented? */
229#define DC_IRQ_VIP_VSYNC_LOSS_IRQ_MASK (1 << 1)
230#define DC_IRQ_MASK (1 << 0)
33 231
34#define MSR_LX_GLD_CONFIG 0x48002001 232#define DC_GENLK_CTL_FLICK_SEL_MASK (0x0F << 28)
35#define MSR_LX_GLCP_DOTPLL 0x4c000015 233#define DC_GENLK_CTL_ALPHA_FLICK_EN (1 << 25)
36#define MSR_LX_DF_PADSEL 0x48002011 234#define DC_GENLK_CTL_FLICK_EN (1 << 24)
37#define MSR_LX_DC_SPARE 0x80000011 235#define DC_GENLK_CTL_GENLK_EN (1 << 18)
38#define MSR_LX_DF_GLCONFIG 0x48002001
39
40#define MSR_LX_GLIU0_P2D_RO0 0x10000029
41
42#define GLCP_DOTPLL_RESET (1 << 0)
43#define GLCP_DOTPLL_BYPASS (1 << 15)
44#define GLCP_DOTPLL_HALFPIX (1 << 24)
45#define GLCP_DOTPLL_LOCK (1 << 25)
46
47#define DF_CONFIG_OUTPUT_MASK 0x38
48#define DF_OUTPUT_PANEL 0x08
49#define DF_OUTPUT_CRT 0x00
50#define DF_SIMULTANEOUS_CRT_AND_FP (1 << 15)
51
52#define DF_DEFAULT_TFT_PAD_SEL_LOW 0xDFFFFFFF
53#define DF_DEFAULT_TFT_PAD_SEL_HIGH 0x0000003F
54
55#define DC_SPARE_DISABLE_CFIFO_HGO 0x00000800
56#define DC_SPARE_VFIFO_ARB_SELECT 0x00000400
57#define DC_SPARE_WM_LPEN_OVRD 0x00000200
58#define DC_SPARE_LOAD_WM_LPEN_MASK 0x00000100
59#define DC_SPARE_DISABLE_INIT_VID_PRI 0x00000080
60#define DC_SPARE_DISABLE_VFIFO_WM 0x00000040
61#define DC_SPARE_DISABLE_CWD_CHECK 0x00000020
62#define DC_SPARE_PIX8_PAN_FIX 0x00000010
63#define DC_SPARE_FIRST_REQ_MASK 0x00000002
64
65/* Registers */
66
67#define DC_UNLOCK 0x00
68#define DC_UNLOCK_CODE 0x4758
69 236
70#define DC_GENERAL_CFG 0x04
71#define DC_GCFG_DFLE (1 << 0)
72#define DC_GCFG_VIDE (1 << 3)
73#define DC_GCFG_VGAE (1 << 7)
74#define DC_GCFG_CMPE (1 << 5)
75#define DC_GCFG_DECE (1 << 6)
76#define DC_GCFG_FDTY (1 << 17)
77 237
78#define DC_DISPLAY_CFG 0x08 238/*
79#define DC_DCFG_TGEN (1 << 0) 239 * Video Processor registers (table 6-71).
80#define DC_DCFG_GDEN (1 << 3) 240 * There is space for 64 bit values, but we never use more than the
81#define DC_DCFG_VDEN (1 << 4) 241 * lower 32 bits. The actual register save/restore code only bothers
82#define DC_DCFG_TRUP (1 << 6) 242 * to restore those 32 bits.
83#define DC_DCFG_DCEN (1 << 24) 243 */
84#define DC_DCFG_PALB (1 << 25) 244enum vp_registers {
85#define DC_DCFG_VISL (1 << 27) 245 VP_VCFG = 0,
246 VP_DCFG,
86 247
87#define DC_DCFG_16BPP 0x0 248 VP_VX,
249 VP_VY,
88 250
89#define DC_DCFG_DISP_MODE_MASK 0x00000300 251 VP_SCL,
90#define DC_DCFG_DISP_MODE_8BPP 0x00000000 252 VP_VCK,
91#define DC_DCFG_DISP_MODE_16BPP 0x00000100
92#define DC_DCFG_DISP_MODE_24BPP 0x00000200
93#define DC_DCFG_DISP_MODE_32BPP 0x00000300
94 253
254 VP_VCM,
255 VP_PAR,
95 256
96#define DC_ARB_CFG 0x0C 257 VP_PDR,
258 VP_SLR,
97 259
98#define DC_FB_START 0x10 260 VP_MISC,
99#define DC_CB_START 0x14 261 VP_CCS,
100#define DC_CURSOR_START 0x18
101 262
102#define DC_DV_TOP 0x2C 263 VP_VYS,
103#define DC_DV_TOP_ENABLE (1 << 0) 264 VP_VXS,
104 265
105#define DC_LINE_SIZE 0x30 266 VP_RSVD_0,
106#define DC_GRAPHICS_PITCH 0x34 267 VP_VDC,
107#define DC_H_ACTIVE_TIMING 0x40 268
108#define DC_H_BLANK_TIMING 0x44 269 VP_RSVD_1,
109#define DC_H_SYNC_TIMING 0x48 270 VP_CRC,
110#define DC_V_ACTIVE_TIMING 0x50 271
111#define DC_V_BLANK_TIMING 0x54 272 VP_CRC32,
112#define DC_V_SYNC_TIMING 0x58 273 VP_VDE,
113#define DC_FB_ACTIVE 0x5C 274
275 VP_CCK,
276 VP_CCM,
277
278 VP_CC1,
279 VP_CC2,
280
281 VP_A1X,
282 VP_A1Y,
283
284 VP_A1C,
285 VP_A1T,
286
287 VP_A2X,
288 VP_A2Y,
289
290 VP_A2C,
291 VP_A2T,
292
293 VP_A3X,
294 VP_A3Y,
295
296 VP_A3C,
297 VP_A3T,
298
299 VP_VRR,
300 VP_AWT,
301
302 VP_VTM,
303 VP_VYE,
304
305 VP_A1YE,
306 VP_A2YE,
307
308 VP_A3YE, /* 0x150 */
309
310 VP_VCR = 0x1000, /* 0x1000 - 0x1fff */
311};
114 312
115#define DC_PAL_ADDRESS 0x70 313#define VP_VCFG_VID_EN (1 << 0)
116#define DC_PAL_DATA 0x74
117 314
118#define DC_PHY_MEM_OFFSET 0x84 315#define VP_DCFG_GV_GAM (1 << 21)
316#define VP_DCFG_PWR_SEQ_DELAY ((1 << 17) | (1 << 18) | (1 << 19))
317#define VP_DCFG_PWR_SEQ_DELAY_DEFAULT (1 << 19) /* undocumented */
318#define VP_DCFG_CRT_SYNC_SKW ((1 << 14) | (1 << 15) | (1 << 16))
319#define VP_DCFG_CRT_SYNC_SKW_DEFAULT (1 << 16)
320#define VP_DCFG_CRT_VSYNC_POL (1 << 9)
321#define VP_DCFG_CRT_HSYNC_POL (1 << 8)
322#define VP_DCFG_DAC_BL_EN (1 << 3)
323#define VP_DCFG_VSYNC_EN (1 << 2)
324#define VP_DCFG_HSYNC_EN (1 << 1)
325#define VP_DCFG_CRT_EN (1 << 0)
119 326
120#define DC_DV_CTL 0x88 327#define VP_MISC_APWRDN (1 << 11)
121#define DC_DV_LINE_SIZE_MASK 0x00000C00 328#define VP_MISC_DACPWRDN (1 << 10)
122#define DC_DV_LINE_SIZE_1024 0x00000000 329#define VP_MISC_BYP_BOTH (1 << 0)
123#define DC_DV_LINE_SIZE_2048 0x00000400
124#define DC_DV_LINE_SIZE_4096 0x00000800
125#define DC_DV_LINE_SIZE_8192 0x00000C00
126 330
127 331
128#define DC_GFX_SCALE 0x90 332/*
129#define DC_IRQ_FILT_CTL 0x94 333 * Flat Panel registers (table 6-71).
334 * Also 64 bit registers; see above note about 32-bit handling.
335 */
130 336
337/* we're actually in the VP register space, starting at address 0x400 */
338#define VP_FP_START 0x400
131 339
132#define DC_IRQ 0xC8 340enum fp_registers {
133#define DC_IRQ_MASK (1 << 0) 341 FP_PT1 = 0,
134#define DC_VSYNC_IRQ_MASK (1 << 1) 342 FP_PT2,
135#define DC_IRQ_STATUS (1 << 20)
136#define DC_VSYNC_IRQ_STATUS (1 << 21)
137
138#define DC_GENLCK_CTRL 0xD4
139#define DC_GENLCK_ENABLE (1 << 18)
140#define DC_GC_ALPHA_FLICK_ENABLE (1 << 25)
141#define DC_GC_FLICKER_FILTER_ENABLE (1 << 24)
142#define DC_GC_FLICKER_FILTER_MASK (0x0F << 28)
143
144#define DC_COLOR_KEY 0xB8
145#define DC_CLR_KEY_ENABLE (1 << 24)
146
147
148#define DC3_DV_LINE_SIZE_MASK 0x00000C00
149#define DC3_DV_LINE_SIZE_1024 0x00000000
150#define DC3_DV_LINE_SIZE_2048 0x00000400
151#define DC3_DV_LINE_SIZE_4096 0x00000800
152#define DC3_DV_LINE_SIZE_8192 0x00000C00
153
154#define DF_VIDEO_CFG 0x0
155#define DF_VCFG_VID_EN (1 << 0)
156
157#define DF_DISPLAY_CFG 0x08
158
159#define DF_DCFG_CRT_EN (1 << 0)
160#define DF_DCFG_HSYNC_EN (1 << 1)
161#define DF_DCFG_VSYNC_EN (1 << 2)
162#define DF_DCFG_DAC_BL_EN (1 << 3)
163#define DF_DCFG_CRT_HSYNC_POL (1 << 8)
164#define DF_DCFG_CRT_VSYNC_POL (1 << 9)
165#define DF_DCFG_GV_PAL_BYP (1 << 21)
166 343
167#define DF_DCFG_CRT_SYNC_SKW_INIT 0x10000 344 FP_PM,
168#define DF_DCFG_CRT_SYNC_SKW_MASK 0x1c000 345 FP_DFC,
169 346
170#define DF_DCFG_PWR_SEQ_DLY_INIT 0x80000 347 FP_RSVD_0,
171#define DF_DCFG_PWR_SEQ_DLY_MASK 0xe0000 348 FP_RSVD_1,
172 349
173#define DF_MISC 0x50 350 FP_RSVD_2,
351 FP_RSVD_3,
352
353 FP_RSVD_4,
354 FP_DCA,
355
356 FP_DMD,
357 FP_CRC, /* 0x458 */
358};
359
360#define FP_PT2_SCRC (1 << 27) /* shfclk free */
361
362#define FP_PM_P (1 << 24) /* panel power ctl */
363#define FP_PM_PANEL_PWR_UP (1 << 3) /* r/o */
364#define FP_PM_PANEL_PWR_DOWN (1 << 2) /* r/o */
365#define FP_PM_PANEL_OFF (1 << 1) /* r/o */
366#define FP_PM_PANEL_ON (1 << 0) /* r/o */
367
368#define FP_DFC_BC ((1 << 4) | (1 << 5) | (1 << 6))
369
370
371/* register access functions */
372
373static inline uint32_t read_gp(struct lxfb_par *par, int reg)
374{
375 return readl(par->gp_regs + 4*reg);
376}
377
378static inline void write_gp(struct lxfb_par *par, int reg, uint32_t val)
379{
380 writel(val, par->gp_regs + 4*reg);
381}
382
383static inline uint32_t read_dc(struct lxfb_par *par, int reg)
384{
385 return readl(par->dc_regs + 4*reg);
386}
387
388static inline void write_dc(struct lxfb_par *par, int reg, uint32_t val)
389{
390 writel(val, par->dc_regs + 4*reg);
391}
392
393static inline uint32_t read_vp(struct lxfb_par *par, int reg)
394{
395 return readl(par->vp_regs + 8*reg);
396}
397
398static inline void write_vp(struct lxfb_par *par, int reg, uint32_t val)
399{
400 writel(val, par->vp_regs + 8*reg);
401}
402
403static inline uint32_t read_fp(struct lxfb_par *par, int reg)
404{
405 return readl(par->vp_regs + 8*reg + VP_FP_START);
406}
407
408static inline void write_fp(struct lxfb_par *par, int reg, uint32_t val)
409{
410 writel(val, par->vp_regs + 8*reg + VP_FP_START);
411}
174 412
175#define DF_MISC_GAM_BYPASS (1 << 0)
176#define DF_MISC_DAC_PWRDN (1 << 10)
177#define DF_MISC_A_PWRDN (1 << 11)
178 413
179#define DF_PAR 0x38 414/* MSRs are defined in asm/geode.h; their bitfields are here */
180#define DF_PDR 0x40
181#define DF_ALPHA_CONTROL_1 0xD8
182#define DF_VIDEO_REQUEST 0x120
183 415
184#define DF_PANEL_TIM1 0x400 416#define MSR_GLCP_DOTPLL_LOCK (1 << 25) /* r/o */
185#define DF_DEFAULT_TFT_PMTIM1 0x0 417#define MSR_GLCP_DOTPLL_HALFPIX (1 << 24)
418#define MSR_GLCP_DOTPLL_BYPASS (1 << 15)
419#define MSR_GLCP_DOTPLL_DOTRESET (1 << 0)
186 420
187#define DF_PANEL_TIM2 0x408 421/* note: this is actually the VP's GLD_MSR_CONFIG */
188#define DF_DEFAULT_TFT_PMTIM2 0x08000000 422#define MSR_LX_GLD_MSR_CONFIG_FMT ((1 << 3) | (1 << 4) | (1 << 5))
423#define MSR_LX_GLD_MSR_CONFIG_FMT_FP (1 << 3)
424#define MSR_LX_GLD_MSR_CONFIG_FMT_CRT (0)
425#define MSR_LX_GLD_MSR_CONFIG_FPC (1 << 15) /* FP *and* CRT */
189 426
190#define DF_FP_PM 0x410 427#define MSR_LX_MSR_PADSEL_TFT_SEL_LOW 0xDFFFFFFF /* ??? */
191#define DF_FP_PM_P (1 << 24) 428#define MSR_LX_MSR_PADSEL_TFT_SEL_HIGH 0x0000003F /* ??? */
192 429
193#define DF_DITHER_CONTROL 0x418 430#define MSR_LX_SPARE_MSR_DIS_CFIFO_HGO (1 << 11) /* undocumented */
194#define DF_DEFAULT_TFT_DITHCTL 0x00000070 431#define MSR_LX_SPARE_MSR_VFIFO_ARB_SEL (1 << 10) /* undocumented */
195#define GP_BLT_STATUS 0x44 432#define MSR_LX_SPARE_MSR_WM_LPEN_OVRD (1 << 9) /* undocumented */
196#define GP_BS_BLT_BUSY (1 << 0) 433#define MSR_LX_SPARE_MSR_LOAD_WM_LPEN_M (1 << 8) /* undocumented */
197#define GP_BS_CB_EMPTY (1 << 4) 434#define MSR_LX_SPARE_MSR_DIS_INIT_V_PRI (1 << 7) /* undocumented */
435#define MSR_LX_SPARE_MSR_DIS_VIFO_WM (1 << 6)
436#define MSR_LX_SPARE_MSR_DIS_CWD_CHECK (1 << 5) /* undocumented */
437#define MSR_LX_SPARE_MSR_PIX8_PAN_FIX (1 << 4) /* undocumented */
438#define MSR_LX_SPARE_MSR_FIRST_REQ_MASK (1 << 1) /* undocumented */
198 439
199#endif 440#endif
diff --git a/drivers/video/geode/lxfb_core.c b/drivers/video/geode/lxfb_core.c
index eb6b88171538..2cd9b74d2225 100644
--- a/drivers/video/geode/lxfb_core.c
+++ b/drivers/video/geode/lxfb_core.c
@@ -17,6 +17,7 @@
17#include <linux/console.h> 17#include <linux/console.h>
18#include <linux/mm.h> 18#include <linux/mm.h>
19#include <linux/slab.h> 19#include <linux/slab.h>
20#include <linux/suspend.h>
20#include <linux/delay.h> 21#include <linux/delay.h>
21#include <linux/fb.h> 22#include <linux/fb.h>
22#include <linux/init.h> 23#include <linux/init.h>
@@ -27,14 +28,15 @@
27 28
28static char *mode_option; 29static char *mode_option;
29static int noclear, nopanel, nocrt; 30static int noclear, nopanel, nocrt;
30static int fbsize; 31static int vram;
32static int vt_switch;
31 33
32/* Most of these modes are sorted in ascending order, but 34/* Most of these modes are sorted in ascending order, but
33 * since the first entry in this table is the "default" mode, 35 * since the first entry in this table is the "default" mode,
34 * we try to make it something sane - 640x480-60 is sane 36 * we try to make it something sane - 640x480-60 is sane
35 */ 37 */
36 38
37static const struct fb_videomode geode_modedb[] __initdata = { 39static struct fb_videomode geode_modedb[] __initdata = {
38 /* 640x480-60 */ 40 /* 640x480-60 */
39 { NULL, 60, 640, 480, 39682, 48, 8, 25, 2, 88, 2, 41 { NULL, 60, 640, 480, 39682, 48, 8, 25, 2, 88, 2,
40 FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, 42 FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
@@ -215,6 +217,35 @@ static const struct fb_videomode geode_modedb[] __initdata = {
215 0, FB_VMODE_NONINTERLACED, 0 }, 217 0, FB_VMODE_NONINTERLACED, 0 },
216}; 218};
217 219
220#ifdef CONFIG_OLPC
221#include <asm/olpc.h>
222
223static struct fb_videomode olpc_dcon_modedb[] __initdata = {
224 /* The only mode the DCON has is 1200x900 */
225 { NULL, 50, 1200, 900, 17460, 24, 8, 4, 5, 8, 3,
226 FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
227 FB_VMODE_NONINTERLACED, 0 }
228};
229
230static void __init get_modedb(struct fb_videomode **modedb, unsigned int *size)
231{
232 if (olpc_has_dcon()) {
233 *modedb = (struct fb_videomode *) olpc_dcon_modedb;
234 *size = ARRAY_SIZE(olpc_dcon_modedb);
235 } else {
236 *modedb = (struct fb_videomode *) geode_modedb;
237 *size = ARRAY_SIZE(geode_modedb);
238 }
239}
240
241#else
242static void __init get_modedb(struct fb_videomode **modedb, unsigned int *size)
243{
244 *modedb = (struct fb_videomode *) geode_modedb;
245 *size = ARRAY_SIZE(geode_modedb);
246}
247#endif
248
218static int lxfb_check_var(struct fb_var_screeninfo *var, struct fb_info *info) 249static int lxfb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
219{ 250{
220 if (var->xres > 1920 || var->yres > 1440) 251 if (var->xres > 1920 || var->yres > 1440)
@@ -333,13 +364,13 @@ static int __init lxfb_map_video_memory(struct fb_info *info,
333 if (ret) 364 if (ret)
334 return ret; 365 return ret;
335 366
336 ret = pci_request_region(dev, 3, "lxfb-vip"); 367 ret = pci_request_region(dev, 3, "lxfb-vp");
337 368
338 if (ret) 369 if (ret)
339 return ret; 370 return ret;
340 371
341 info->fix.smem_start = pci_resource_start(dev, 0); 372 info->fix.smem_start = pci_resource_start(dev, 0);
342 info->fix.smem_len = fbsize ? fbsize : lx_framebuffer_size(); 373 info->fix.smem_len = vram ? vram : lx_framebuffer_size();
343 374
344 info->screen_base = ioremap(info->fix.smem_start, info->fix.smem_len); 375 info->screen_base = ioremap(info->fix.smem_start, info->fix.smem_len);
345 376
@@ -360,18 +391,15 @@ static int __init lxfb_map_video_memory(struct fb_info *info,
360 if (par->dc_regs == NULL) 391 if (par->dc_regs == NULL)
361 return ret; 392 return ret;
362 393
363 par->df_regs = ioremap(pci_resource_start(dev, 3), 394 par->vp_regs = ioremap(pci_resource_start(dev, 3),
364 pci_resource_len(dev, 3)); 395 pci_resource_len(dev, 3));
365 396
366 if (par->df_regs == NULL) 397 if (par->vp_regs == NULL)
367 return ret; 398 return ret;
368 399
369 writel(DC_UNLOCK_CODE, par->dc_regs + DC_UNLOCK); 400 write_dc(par, DC_UNLOCK, DC_UNLOCK_UNLOCK);
370 401 write_dc(par, DC_GLIU0_MEM_OFFSET, info->fix.smem_start & 0xFF000000);
371 writel(info->fix.smem_start & 0xFF000000, 402 write_dc(par, DC_UNLOCK, DC_UNLOCK_LOCK);
372 par->dc_regs + DC_PHY_MEM_OFFSET);
373
374 writel(0, par->dc_regs + DC_UNLOCK);
375 403
376 dev_info(&dev->dev, "%d KB of video memory at 0x%lx\n", 404 dev_info(&dev->dev, "%d KB of video memory at 0x%lx\n",
377 info->fix.smem_len / 1024, info->fix.smem_start); 405 info->fix.smem_len / 1024, info->fix.smem_start);
@@ -431,6 +459,45 @@ static struct fb_info * __init lxfb_init_fbinfo(struct device *dev)
431 return info; 459 return info;
432} 460}
433 461
462#ifdef CONFIG_PM
463static int lxfb_suspend(struct pci_dev *pdev, pm_message_t state)
464{
465 struct fb_info *info = pci_get_drvdata(pdev);
466
467 if (state.event == PM_EVENT_SUSPEND) {
468 acquire_console_sem();
469 lx_powerdown(info);
470 fb_set_suspend(info, 1);
471 release_console_sem();
472 }
473
474 /* there's no point in setting PCI states; we emulate PCI, so
475 * we don't end up getting power savings anyways */
476
477 return 0;
478}
479
480static int lxfb_resume(struct pci_dev *pdev)
481{
482 struct fb_info *info = pci_get_drvdata(pdev);
483 int ret;
484
485 acquire_console_sem();
486 ret = lx_powerup(info);
487 if (ret) {
488 printk(KERN_ERR "lxfb: power up failed!\n");
489 return ret;
490 }
491
492 fb_set_suspend(info, 0);
493 release_console_sem();
494 return 0;
495}
496#else
497#define lxfb_suspend NULL
498#define lxfb_resume NULL
499#endif
500
434static int __init lxfb_probe(struct pci_dev *pdev, 501static int __init lxfb_probe(struct pci_dev *pdev,
435 const struct pci_device_id *id) 502 const struct pci_device_id *id)
436{ 503{
@@ -439,7 +506,7 @@ static int __init lxfb_probe(struct pci_dev *pdev,
439 int ret; 506 int ret;
440 507
441 struct fb_videomode *modedb_ptr; 508 struct fb_videomode *modedb_ptr;
442 int modedb_size; 509 unsigned int modedb_size;
443 510
444 info = lxfb_init_fbinfo(&pdev->dev); 511 info = lxfb_init_fbinfo(&pdev->dev);
445 512
@@ -464,9 +531,7 @@ static int __init lxfb_probe(struct pci_dev *pdev,
464 531
465 /* Set up the mode database */ 532 /* Set up the mode database */
466 533
467 modedb_ptr = (struct fb_videomode *) geode_modedb; 534 get_modedb(&modedb_ptr, &modedb_size);
468 modedb_size = ARRAY_SIZE(geode_modedb);
469
470 ret = fb_find_mode(&info->var, info, mode_option, 535 ret = fb_find_mode(&info->var, info, mode_option,
471 modedb_ptr, modedb_size, NULL, 16); 536 modedb_ptr, modedb_size, NULL, 16);
472 537
@@ -487,6 +552,8 @@ static int __init lxfb_probe(struct pci_dev *pdev,
487 lxfb_check_var(&info->var, info); 552 lxfb_check_var(&info->var, info);
488 lxfb_set_par(info); 553 lxfb_set_par(info);
489 554
555 pm_set_vt_switch(vt_switch);
556
490 if (register_framebuffer(info) < 0) { 557 if (register_framebuffer(info) < 0) {
491 ret = -EINVAL; 558 ret = -EINVAL;
492 goto err; 559 goto err;
@@ -510,8 +577,8 @@ err:
510 iounmap(par->dc_regs); 577 iounmap(par->dc_regs);
511 pci_release_region(pdev, 2); 578 pci_release_region(pdev, 2);
512 } 579 }
513 if (par->df_regs) { 580 if (par->vp_regs) {
514 iounmap(par->df_regs); 581 iounmap(par->vp_regs);
515 pci_release_region(pdev, 3); 582 pci_release_region(pdev, 3);
516 } 583 }
517 584
@@ -537,7 +604,7 @@ static void lxfb_remove(struct pci_dev *pdev)
537 iounmap(par->dc_regs); 604 iounmap(par->dc_regs);
538 pci_release_region(pdev, 2); 605 pci_release_region(pdev, 2);
539 606
540 iounmap(par->df_regs); 607 iounmap(par->vp_regs);
541 pci_release_region(pdev, 3); 608 pci_release_region(pdev, 3);
542 609
543 pci_set_drvdata(pdev, NULL); 610 pci_set_drvdata(pdev, NULL);
@@ -556,6 +623,8 @@ static struct pci_driver lxfb_driver = {
556 .id_table = lxfb_id_table, 623 .id_table = lxfb_id_table,
557 .probe = lxfb_probe, 624 .probe = lxfb_probe,
558 .remove = lxfb_remove, 625 .remove = lxfb_remove,
626 .suspend = lxfb_suspend,
627 .resume = lxfb_resume,
559}; 628};
560 629
561#ifndef MODULE 630#ifndef MODULE
@@ -570,9 +639,7 @@ static int __init lxfb_setup(char *options)
570 if (!*opt) 639 if (!*opt)
571 continue; 640 continue;
572 641
573 if (!strncmp(opt, "fbsize:", 7)) 642 if (!strcmp(opt, "noclear"))
574 fbsize = simple_strtoul(opt+7, NULL, 0);
575 else if (!strcmp(opt, "noclear"))
576 noclear = 1; 643 noclear = 1;
577 else if (!strcmp(opt, "nopanel")) 644 else if (!strcmp(opt, "nopanel"))
578 nopanel = 1; 645 nopanel = 1;
@@ -609,8 +676,11 @@ module_exit(lxfb_cleanup);
609module_param(mode_option, charp, 0); 676module_param(mode_option, charp, 0);
610MODULE_PARM_DESC(mode_option, "video mode (<x>x<y>[-<bpp>][@<refr>])"); 677MODULE_PARM_DESC(mode_option, "video mode (<x>x<y>[-<bpp>][@<refr>])");
611 678
612module_param(fbsize, int, 0); 679module_param(vram, int, 0);
613MODULE_PARM_DESC(fbsize, "video memory size"); 680MODULE_PARM_DESC(vram, "video memory size");
681
682module_param(vt_switch, int, 0);
683MODULE_PARM_DESC(vt_switch, "enable VT switch during suspend/resume");
614 684
615MODULE_DESCRIPTION("Framebuffer driver for the AMD Geode LX"); 685MODULE_DESCRIPTION("Framebuffer driver for the AMD Geode LX");
616MODULE_LICENSE("GPL"); 686MODULE_LICENSE("GPL");
diff --git a/drivers/video/geode/lxfb_ops.c b/drivers/video/geode/lxfb_ops.c
index 4fbc99be96ef..cd9d4cc26954 100644
--- a/drivers/video/geode/lxfb_ops.c
+++ b/drivers/video/geode/lxfb_ops.c
@@ -13,6 +13,7 @@
13#include <linux/fb.h> 13#include <linux/fb.h>
14#include <linux/uaccess.h> 14#include <linux/uaccess.h>
15#include <linux/delay.h> 15#include <linux/delay.h>
16#include <asm/geode.h>
16 17
17#include "lxfb.h" 18#include "lxfb.h"
18 19
@@ -34,35 +35,85 @@ static const struct {
34 unsigned int pllval; 35 unsigned int pllval;
35 unsigned int freq; 36 unsigned int freq;
36} pll_table[] = { 37} pll_table[] = {
37 { 0x000031AC, 24923 }, 38 { 0x000131AC, 6231 },
38 { 0x0000215D, 25175 }, 39 { 0x0001215D, 6294 },
39 { 0x00001087, 27000 }, 40 { 0x00011087, 6750 },
40 { 0x0000216C, 28322 }, 41 { 0x0001216C, 7081 },
41 { 0x0000218D, 28560 }, 42 { 0x0001218D, 7140 },
42 { 0x000010C9, 31200 }, 43 { 0x000110C9, 7800 },
43 { 0x00003147, 31500 }, 44 { 0x00013147, 7875 },
44 { 0x000010A7, 33032 }, 45 { 0x000110A7, 8258 },
45 { 0x00002159, 35112 }, 46 { 0x00012159, 8778 },
46 { 0x00004249, 35500 }, 47 { 0x00014249, 8875 },
47 { 0x00000057, 36000 }, 48 { 0x00010057, 9000 },
48 { 0x0000219A, 37889 }, 49 { 0x0001219A, 9472 },
49 { 0x00002158, 39168 }, 50 { 0x00012158, 9792 },
50 { 0x00000045, 40000 }, 51 { 0x00010045, 10000 },
51 { 0x00000089, 43163 }, 52 { 0x00010089, 10791 },
52 { 0x000010E7, 44900 }, 53 { 0x000110E7, 11225 },
53 { 0x00002136, 45720 }, 54 { 0x00012136, 11430 },
54 { 0x00003207, 49500 }, 55 { 0x00013207, 12375 },
55 { 0x00002187, 50000 }, 56 { 0x00012187, 12500 },
56 { 0x00004286, 56250 }, 57 { 0x00014286, 14063 },
57 { 0x000010E5, 60065 }, 58 { 0x000110E5, 15016 },
58 { 0x00004214, 65000 }, 59 { 0x00014214, 16250 },
59 { 0x00001105, 68179 }, 60 { 0x00011105, 17045 },
60 { 0x000031E4, 74250 }, 61 { 0x000131E4, 18563 },
61 { 0x00003183, 75000 }, 62 { 0x00013183, 18750 },
62 { 0x00004284, 78750 }, 63 { 0x00014284, 19688 },
63 { 0x00001104, 81600 }, 64 { 0x00011104, 20400 },
64 { 0x00006363, 94500 }, 65 { 0x00016363, 23625 },
65 { 0x00005303, 97520 }, 66 { 0x00015303, 24380 },
67 { 0x000031AC, 24923 },
68 { 0x0000215D, 25175 },
69 { 0x00001087, 27000 },
70 { 0x0000216C, 28322 },
71 { 0x0000218D, 28560 },
72 { 0x00010041, 29913 },
73 { 0x000010C9, 31200 },
74 { 0x00003147, 31500 },
75 { 0x000141A1, 32400 },
76 { 0x000010A7, 33032 },
77 { 0x00012182, 33375 },
78 { 0x000141B1, 33750 },
79 { 0x00002159, 35112 },
80 { 0x00004249, 35500 },
81 { 0x00000057, 36000 },
82 { 0x000141E1, 37125 },
83 { 0x0000219A, 37889 },
84 { 0x00002158, 39168 },
85 { 0x00000045, 40000 },
86 { 0x000131A1, 40500 },
87 { 0x00010061, 42301 },
88 { 0x00000089, 43163 },
89 { 0x00012151, 43875 },
90 { 0x000010E7, 44900 },
91 { 0x00002136, 45720 },
92 { 0x000152E1, 47250 },
93 { 0x00010071, 48000 },
94 { 0x00003207, 49500 },
95 { 0x00002187, 50000 },
96 { 0x00014291, 50625 },
97 { 0x00011101, 51188 },
98 { 0x00017481, 54563 },
99 { 0x00004286, 56250 },
100 { 0x00014170, 57375 },
101 { 0x00016210, 58500 },
102 { 0x000010E5, 60065 },
103 { 0x00013140, 62796 },
104 { 0x00004214, 65000 },
105 { 0x00016250, 65250 },
106 { 0x00001105, 68179 },
107 { 0x000141C0, 69600 },
108 { 0x00015220, 70160 },
109 { 0x00010050, 72000 },
110 { 0x000031E4, 74250 },
111 { 0x00003183, 75000 },
112 { 0x00004284, 78750 },
113 { 0x00012130, 80052 },
114 { 0x00001104, 81600 },
115 { 0x00006363, 94500 },
116 { 0x00005303, 97520 },
66 { 0x00002183, 100187 }, 117 { 0x00002183, 100187 },
67 { 0x00002122, 101420 }, 118 { 0x00002122, 101420 },
68 { 0x00001081, 108000 }, 119 { 0x00001081, 108000 },
@@ -101,16 +152,16 @@ static void lx_set_dotpll(u32 pllval)
101 u32 dotpll_lo, dotpll_hi; 152 u32 dotpll_lo, dotpll_hi;
102 int i; 153 int i;
103 154
104 rdmsr(MSR_LX_GLCP_DOTPLL, dotpll_lo, dotpll_hi); 155 rdmsr(MSR_GLCP_DOTPLL, dotpll_lo, dotpll_hi);
105 156
106 if ((dotpll_lo & GLCP_DOTPLL_LOCK) && (dotpll_hi == pllval)) 157 if ((dotpll_lo & MSR_GLCP_DOTPLL_LOCK) && (dotpll_hi == pllval))
107 return; 158 return;
108 159
109 dotpll_hi = pllval; 160 dotpll_hi = pllval;
110 dotpll_lo &= ~(GLCP_DOTPLL_BYPASS | GLCP_DOTPLL_HALFPIX); 161 dotpll_lo &= ~(MSR_GLCP_DOTPLL_BYPASS | MSR_GLCP_DOTPLL_HALFPIX);
111 dotpll_lo |= GLCP_DOTPLL_RESET; 162 dotpll_lo |= MSR_GLCP_DOTPLL_DOTRESET;
112 163
113 wrmsr(MSR_LX_GLCP_DOTPLL, dotpll_lo, dotpll_hi); 164 wrmsr(MSR_GLCP_DOTPLL, dotpll_lo, dotpll_hi);
114 165
115 /* Wait 100us for the PLL to lock */ 166 /* Wait 100us for the PLL to lock */
116 167
@@ -119,15 +170,15 @@ static void lx_set_dotpll(u32 pllval)
119 /* Now, loop for the lock bit */ 170 /* Now, loop for the lock bit */
120 171
121 for (i = 0; i < 1000; i++) { 172 for (i = 0; i < 1000; i++) {
122 rdmsr(MSR_LX_GLCP_DOTPLL, dotpll_lo, dotpll_hi); 173 rdmsr(MSR_GLCP_DOTPLL, dotpll_lo, dotpll_hi);
123 if (dotpll_lo & GLCP_DOTPLL_LOCK) 174 if (dotpll_lo & MSR_GLCP_DOTPLL_LOCK)
124 break; 175 break;
125 } 176 }
126 177
127 /* Clear the reset bit */ 178 /* Clear the reset bit */
128 179
129 dotpll_lo &= ~GLCP_DOTPLL_RESET; 180 dotpll_lo &= ~MSR_GLCP_DOTPLL_DOTRESET;
130 wrmsr(MSR_LX_GLCP_DOTPLL, dotpll_lo, dotpll_hi); 181 wrmsr(MSR_GLCP_DOTPLL, dotpll_lo, dotpll_hi);
131} 182}
132 183
133/* Set the clock based on the frequency specified by the current mode */ 184/* Set the clock based on the frequency specified by the current mode */
@@ -137,7 +188,7 @@ static void lx_set_clock(struct fb_info *info)
137 unsigned int diff, min, best = 0; 188 unsigned int diff, min, best = 0;
138 unsigned int freq, i; 189 unsigned int freq, i;
139 190
140 freq = (unsigned int) (0x3b9aca00 / info->var.pixclock); 191 freq = (unsigned int) (1000000000 / info->var.pixclock);
141 192
142 min = abs(pll_table[0].freq - freq); 193 min = abs(pll_table[0].freq - freq);
143 194
@@ -149,7 +200,7 @@ static void lx_set_clock(struct fb_info *info)
149 } 200 }
150 } 201 }
151 202
152 lx_set_dotpll(pll_table[best].pllval & 0x7FFF); 203 lx_set_dotpll(pll_table[best].pllval & 0x00017FFF);
153} 204}
154 205
155static void lx_graphics_disable(struct fb_info *info) 206static void lx_graphics_disable(struct fb_info *info)
@@ -159,63 +210,62 @@ static void lx_graphics_disable(struct fb_info *info)
159 210
160 /* Note: This assumes that the video is in a quitet state */ 211 /* Note: This assumes that the video is in a quitet state */
161 212
162 writel(0, par->df_regs + DF_ALPHA_CONTROL_1); 213 write_vp(par, VP_A1T, 0);
163 writel(0, par->df_regs + DF_ALPHA_CONTROL_1 + 32); 214 write_vp(par, VP_A2T, 0);
164 writel(0, par->df_regs + DF_ALPHA_CONTROL_1 + 64); 215 write_vp(par, VP_A3T, 0);
165 216
166 /* Turn off the VGA and video enable */ 217 /* Turn off the VGA and video enable */
167 val = readl (par->dc_regs + DC_GENERAL_CFG) & 218 val = read_dc(par, DC_GENERAL_CFG) & ~(DC_GENERAL_CFG_VGAE |
168 ~(DC_GCFG_VGAE | DC_GCFG_VIDE); 219 DC_GENERAL_CFG_VIDE);
169 220
170 writel(val, par->dc_regs + DC_GENERAL_CFG); 221 write_dc(par, DC_GENERAL_CFG, val);
171 222
172 val = readl(par->df_regs + DF_VIDEO_CFG) & ~DF_VCFG_VID_EN; 223 val = read_vp(par, VP_VCFG) & ~VP_VCFG_VID_EN;
173 writel(val, par->df_regs + DF_VIDEO_CFG); 224 write_vp(par, VP_VCFG, val);
174 225
175 writel( DC_IRQ_MASK | DC_VSYNC_IRQ_MASK | 226 write_dc(par, DC_IRQ, DC_IRQ_MASK | DC_IRQ_VIP_VSYNC_LOSS_IRQ_MASK |
176 DC_IRQ_STATUS | DC_VSYNC_IRQ_STATUS, 227 DC_IRQ_STATUS | DC_IRQ_VIP_VSYNC_IRQ_STATUS);
177 par->dc_regs + DC_IRQ);
178 228
179 val = readl(par->dc_regs + DC_GENLCK_CTRL) & ~DC_GENLCK_ENABLE; 229 val = read_dc(par, DC_GENLK_CTL) & ~DC_GENLK_CTL_GENLK_EN;
180 writel(val, par->dc_regs + DC_GENLCK_CTRL); 230 write_dc(par, DC_GENLK_CTL, val);
181 231
182 val = readl(par->dc_regs + DC_COLOR_KEY) & ~DC_CLR_KEY_ENABLE; 232 val = read_dc(par, DC_CLR_KEY);
183 writel(val & ~DC_CLR_KEY_ENABLE, par->dc_regs + DC_COLOR_KEY); 233 write_dc(par, DC_CLR_KEY, val & ~DC_CLR_KEY_CLR_KEY_EN);
184 234
185 /* We don't actually blank the panel, due to the long latency 235 /* turn off the panel */
186 involved with bringing it back */ 236 write_fp(par, FP_PM, read_fp(par, FP_PM) & ~FP_PM_P);
187 237
188 val = readl(par->df_regs + DF_MISC) | DF_MISC_DAC_PWRDN; 238 val = read_vp(par, VP_MISC) | VP_MISC_DACPWRDN;
189 writel(val, par->df_regs + DF_MISC); 239 write_vp(par, VP_MISC, val);
190 240
191 /* Turn off the display */ 241 /* Turn off the display */
192 242
193 val = readl(par->df_regs + DF_DISPLAY_CFG); 243 val = read_vp(par, VP_DCFG);
194 writel(val & ~(DF_DCFG_CRT_EN | DF_DCFG_HSYNC_EN | DF_DCFG_VSYNC_EN | 244 write_vp(par, VP_DCFG, val & ~(VP_DCFG_CRT_EN | VP_DCFG_HSYNC_EN |
195 DF_DCFG_DAC_BL_EN), par->df_regs + DF_DISPLAY_CFG); 245 VP_DCFG_VSYNC_EN | VP_DCFG_DAC_BL_EN));
196 246
197 gcfg = readl(par->dc_regs + DC_GENERAL_CFG); 247 gcfg = read_dc(par, DC_GENERAL_CFG);
198 gcfg &= ~(DC_GCFG_CMPE | DC_GCFG_DECE); 248 gcfg &= ~(DC_GENERAL_CFG_CMPE | DC_GENERAL_CFG_DECE);
199 writel(gcfg, par->dc_regs + DC_GENERAL_CFG); 249 write_dc(par, DC_GENERAL_CFG, gcfg);
200 250
201 /* Turn off the TGEN */ 251 /* Turn off the TGEN */
202 val = readl(par->dc_regs + DC_DISPLAY_CFG); 252 val = read_dc(par, DC_DISPLAY_CFG);
203 val &= ~DC_DCFG_TGEN; 253 val &= ~DC_DISPLAY_CFG_TGEN;
204 writel(val, par->dc_regs + DC_DISPLAY_CFG); 254 write_dc(par, DC_DISPLAY_CFG, val);
205 255
206 /* Wait 1000 usecs to ensure that the TGEN is clear */ 256 /* Wait 1000 usecs to ensure that the TGEN is clear */
207 udelay(1000); 257 udelay(1000);
208 258
209 /* Turn off the FIFO loader */ 259 /* Turn off the FIFO loader */
210 260
211 gcfg &= ~DC_GCFG_DFLE; 261 gcfg &= ~DC_GENERAL_CFG_DFLE;
212 writel(gcfg, par->dc_regs + DC_GENERAL_CFG); 262 write_dc(par, DC_GENERAL_CFG, gcfg);
213 263
214 /* Lastly, wait for the GP to go idle */ 264 /* Lastly, wait for the GP to go idle */
215 265
216 do { 266 do {
217 val = readl(par->gp_regs + GP_BLT_STATUS); 267 val = read_gp(par, GP_BLT_STATUS);
218 } while ((val & GP_BS_BLT_BUSY) || !(val & GP_BS_CB_EMPTY)); 268 } while ((val & GP_BLT_STATUS_PB) || !(val & GP_BLT_STATUS_CE));
219} 269}
220 270
221static void lx_graphics_enable(struct fb_info *info) 271static void lx_graphics_enable(struct fb_info *info)
@@ -224,80 +274,85 @@ static void lx_graphics_enable(struct fb_info *info)
224 u32 temp, config; 274 u32 temp, config;
225 275
226 /* Set the video request register */ 276 /* Set the video request register */
227 writel(0, par->df_regs + DF_VIDEO_REQUEST); 277 write_vp(par, VP_VRR, 0);
228 278
229 /* Set up the polarities */ 279 /* Set up the polarities */
230 280
231 config = readl(par->df_regs + DF_DISPLAY_CFG); 281 config = read_vp(par, VP_DCFG);
232 282
233 config &= ~(DF_DCFG_CRT_SYNC_SKW_MASK | DF_DCFG_PWR_SEQ_DLY_MASK | 283 config &= ~(VP_DCFG_CRT_SYNC_SKW | VP_DCFG_PWR_SEQ_DELAY |
234 DF_DCFG_CRT_HSYNC_POL | DF_DCFG_CRT_VSYNC_POL); 284 VP_DCFG_CRT_HSYNC_POL | VP_DCFG_CRT_VSYNC_POL);
235 285
236 config |= (DF_DCFG_CRT_SYNC_SKW_INIT | DF_DCFG_PWR_SEQ_DLY_INIT | 286 config |= (VP_DCFG_CRT_SYNC_SKW_DEFAULT | VP_DCFG_PWR_SEQ_DELAY_DEFAULT
237 DF_DCFG_GV_PAL_BYP); 287 | VP_DCFG_GV_GAM);
238 288
239 if (info->var.sync & FB_SYNC_HOR_HIGH_ACT) 289 if (info->var.sync & FB_SYNC_HOR_HIGH_ACT)
240 config |= DF_DCFG_CRT_HSYNC_POL; 290 config |= VP_DCFG_CRT_HSYNC_POL;
241 291
242 if (info->var.sync & FB_SYNC_VERT_HIGH_ACT) 292 if (info->var.sync & FB_SYNC_VERT_HIGH_ACT)
243 config |= DF_DCFG_CRT_VSYNC_POL; 293 config |= VP_DCFG_CRT_VSYNC_POL;
244 294
245 if (par->output & OUTPUT_PANEL) { 295 if (par->output & OUTPUT_PANEL) {
246 u32 msrlo, msrhi; 296 u32 msrlo, msrhi;
247 297
248 writel(DF_DEFAULT_TFT_PMTIM1, 298 write_fp(par, FP_PT1, 0);
249 par->df_regs + DF_PANEL_TIM1); 299 write_fp(par, FP_PT2, FP_PT2_SCRC);
250 writel(DF_DEFAULT_TFT_PMTIM2, 300 write_fp(par, FP_DFC, FP_DFC_BC);
251 par->df_regs + DF_PANEL_TIM2);
252 writel(DF_DEFAULT_TFT_DITHCTL,
253 par->df_regs + DF_DITHER_CONTROL);
254 301
255 msrlo = DF_DEFAULT_TFT_PAD_SEL_LOW; 302 msrlo = MSR_LX_MSR_PADSEL_TFT_SEL_LOW;
256 msrhi = DF_DEFAULT_TFT_PAD_SEL_HIGH; 303 msrhi = MSR_LX_MSR_PADSEL_TFT_SEL_HIGH;
257 304
258 wrmsr(MSR_LX_DF_PADSEL, msrlo, msrhi); 305 wrmsr(MSR_LX_MSR_PADSEL, msrlo, msrhi);
259 } 306 }
260 307
261 if (par->output & OUTPUT_CRT) { 308 if (par->output & OUTPUT_CRT) {
262 config |= DF_DCFG_CRT_EN | DF_DCFG_HSYNC_EN | 309 config |= VP_DCFG_CRT_EN | VP_DCFG_HSYNC_EN |
263 DF_DCFG_VSYNC_EN | DF_DCFG_DAC_BL_EN; 310 VP_DCFG_VSYNC_EN | VP_DCFG_DAC_BL_EN;
264 } 311 }
265 312
266 writel(config, par->df_regs + DF_DISPLAY_CFG); 313 write_vp(par, VP_DCFG, config);
267 314
268 /* Turn the CRT dacs back on */ 315 /* Turn the CRT dacs back on */
269 316
270 if (par->output & OUTPUT_CRT) { 317 if (par->output & OUTPUT_CRT) {
271 temp = readl(par->df_regs + DF_MISC); 318 temp = read_vp(par, VP_MISC);
272 temp &= ~(DF_MISC_DAC_PWRDN | DF_MISC_A_PWRDN); 319 temp &= ~(VP_MISC_DACPWRDN | VP_MISC_APWRDN);
273 writel(temp, par->df_regs + DF_MISC); 320 write_vp(par, VP_MISC, temp);
274 } 321 }
275 322
276 /* Turn the panel on (if it isn't already) */ 323 /* Turn the panel on (if it isn't already) */
277 324 if (par->output & OUTPUT_PANEL)
278 if (par->output & OUTPUT_PANEL) { 325 write_fp(par, FP_PM, read_fp(par, FP_PM) | FP_PM_P);
279 temp = readl(par->df_regs + DF_FP_PM);
280
281 if (!(temp & 0x09))
282 writel(temp | DF_FP_PM_P, par->df_regs + DF_FP_PM);
283 }
284
285 temp = readl(par->df_regs + DF_MISC);
286 temp = readl(par->df_regs + DF_DISPLAY_CFG);
287} 326}
288 327
289unsigned int lx_framebuffer_size(void) 328unsigned int lx_framebuffer_size(void)
290{ 329{
291 unsigned int val; 330 unsigned int val;
292 331
332 if (!geode_has_vsa2()) {
333 uint32_t hi, lo;
334
335 /* The number of pages is (PMAX - PMIN)+1 */
336 rdmsr(MSR_GLIU_P2D_RO0, lo, hi);
337
338 /* PMAX */
339 val = ((hi & 0xff) << 12) | ((lo & 0xfff00000) >> 20);
340 /* PMIN */
341 val -= (lo & 0x000fffff);
342 val += 1;
343
344 /* The page size is 4k */
345 return (val << 12);
346 }
347
293 /* The frame buffer size is reported by a VSM in VSA II */ 348 /* The frame buffer size is reported by a VSM in VSA II */
294 /* Virtual Register Class = 0x02 */ 349 /* Virtual Register Class = 0x02 */
295 /* VG_MEM_SIZE (1MB units) = 0x00 */ 350 /* VG_MEM_SIZE (1MB units) = 0x00 */
296 351
297 outw(0xFC53, 0xAC1C); 352 outw(VSA_VR_UNLOCK, VSA_VRC_INDEX);
298 outw(0x0200, 0xAC1C); 353 outw(VSA_VR_MEM_SIZE, VSA_VRC_INDEX);
299 354
300 val = (unsigned int)(inw(0xAC1E)) & 0xFE; 355 val = (unsigned int)(inw(VSA_VRC_DATA)) & 0xFE;
301 return (val << 20); 356 return (val << 20);
302} 357}
303 358
@@ -313,7 +368,7 @@ void lx_set_mode(struct fb_info *info)
313 int vactive, vblankstart, vsyncstart, vsyncend, vblankend, vtotal; 368 int vactive, vblankstart, vsyncstart, vsyncend, vblankend, vtotal;
314 369
315 /* Unlock the DC registers */ 370 /* Unlock the DC registers */
316 writel(DC_UNLOCK_CODE, par->dc_regs + DC_UNLOCK); 371 write_dc(par, DC_UNLOCK, DC_UNLOCK_UNLOCK);
317 372
318 lx_graphics_disable(info); 373 lx_graphics_disable(info);
319 374
@@ -321,102 +376,104 @@ void lx_set_mode(struct fb_info *info)
321 376
322 /* Set output mode */ 377 /* Set output mode */
323 378
324 rdmsrl(MSR_LX_DF_GLCONFIG, msrval); 379 rdmsrl(MSR_LX_GLD_MSR_CONFIG, msrval);
325 msrval &= ~DF_CONFIG_OUTPUT_MASK; 380 msrval &= ~MSR_LX_GLD_MSR_CONFIG_FMT;
326 381
327 if (par->output & OUTPUT_PANEL) { 382 if (par->output & OUTPUT_PANEL) {
328 msrval |= DF_OUTPUT_PANEL; 383 msrval |= MSR_LX_GLD_MSR_CONFIG_FMT_FP;
329 384
330 if (par->output & OUTPUT_CRT) 385 if (par->output & OUTPUT_CRT)
331 msrval |= DF_SIMULTANEOUS_CRT_AND_FP; 386 msrval |= MSR_LX_GLD_MSR_CONFIG_FPC;
332 else 387 else
333 msrval &= ~DF_SIMULTANEOUS_CRT_AND_FP; 388 msrval &= ~MSR_LX_GLD_MSR_CONFIG_FPC;
334 } else { 389 } else
335 msrval |= DF_OUTPUT_CRT; 390 msrval |= MSR_LX_GLD_MSR_CONFIG_FMT_CRT;
336 }
337 391
338 wrmsrl(MSR_LX_DF_GLCONFIG, msrval); 392 wrmsrl(MSR_LX_GLD_MSR_CONFIG, msrval);
339 393
340 /* Clear the various buffers */ 394 /* Clear the various buffers */
341 /* FIXME: Adjust for panning here */ 395 /* FIXME: Adjust for panning here */
342 396
343 writel(0, par->dc_regs + DC_FB_START); 397 write_dc(par, DC_FB_ST_OFFSET, 0);
344 writel(0, par->dc_regs + DC_CB_START); 398 write_dc(par, DC_CB_ST_OFFSET, 0);
345 writel(0, par->dc_regs + DC_CURSOR_START); 399 write_dc(par, DC_CURS_ST_OFFSET, 0);
346 400
347 /* FIXME: Add support for interlacing */ 401 /* FIXME: Add support for interlacing */
348 /* FIXME: Add support for scaling */ 402 /* FIXME: Add support for scaling */
349 403
350 val = readl(par->dc_regs + DC_GENLCK_CTRL); 404 val = read_dc(par, DC_GENLK_CTL);
351 val &= ~(DC_GC_ALPHA_FLICK_ENABLE | 405 val &= ~(DC_GENLK_CTL_ALPHA_FLICK_EN | DC_GENLK_CTL_FLICK_EN |
352 DC_GC_FLICKER_FILTER_ENABLE | DC_GC_FLICKER_FILTER_MASK); 406 DC_GENLK_CTL_FLICK_SEL_MASK);
353 407
354 /* Default scaling params */ 408 /* Default scaling params */
355 409
356 writel((0x4000 << 16) | 0x4000, par->dc_regs + DC_GFX_SCALE); 410 write_dc(par, DC_GFX_SCALE, (0x4000 << 16) | 0x4000);
357 writel(0, par->dc_regs + DC_IRQ_FILT_CTL); 411 write_dc(par, DC_IRQ_FILT_CTL, 0);
358 writel(val, par->dc_regs + DC_GENLCK_CTRL); 412 write_dc(par, DC_GENLK_CTL, val);
359 413
360 /* FIXME: Support compression */ 414 /* FIXME: Support compression */
361 415
362 if (info->fix.line_length > 4096) 416 if (info->fix.line_length > 4096)
363 dv = DC_DV_LINE_SIZE_8192; 417 dv = DC_DV_CTL_DV_LINE_SIZE_8K;
364 else if (info->fix.line_length > 2048) 418 else if (info->fix.line_length > 2048)
365 dv = DC_DV_LINE_SIZE_4096; 419 dv = DC_DV_CTL_DV_LINE_SIZE_4K;
366 else if (info->fix.line_length > 1024) 420 else if (info->fix.line_length > 1024)
367 dv = DC_DV_LINE_SIZE_2048; 421 dv = DC_DV_CTL_DV_LINE_SIZE_2K;
368 else 422 else
369 dv = DC_DV_LINE_SIZE_1024; 423 dv = DC_DV_CTL_DV_LINE_SIZE_1K;
370 424
371 max = info->fix.line_length * info->var.yres; 425 max = info->fix.line_length * info->var.yres;
372 max = (max + 0x3FF) & 0xFFFFFC00; 426 max = (max + 0x3FF) & 0xFFFFFC00;
373 427
374 writel(max | DC_DV_TOP_ENABLE, par->dc_regs + DC_DV_TOP); 428 write_dc(par, DC_DV_TOP, max | DC_DV_TOP_DV_TOP_EN);
375 429
376 val = readl(par->dc_regs + DC_DV_CTL) & ~DC_DV_LINE_SIZE_MASK; 430 val = read_dc(par, DC_DV_CTL) & ~DC_DV_CTL_DV_LINE_SIZE;
377 writel(val | dv, par->dc_regs + DC_DV_CTL); 431 write_dc(par, DC_DV_CTL, val | dv);
378 432
379 size = info->var.xres * (info->var.bits_per_pixel >> 3); 433 size = info->var.xres * (info->var.bits_per_pixel >> 3);
380 434
381 writel(info->fix.line_length >> 3, par->dc_regs + DC_GRAPHICS_PITCH); 435 write_dc(par, DC_GFX_PITCH, info->fix.line_length >> 3);
382 writel((size + 7) >> 3, par->dc_regs + DC_LINE_SIZE); 436 write_dc(par, DC_LINE_SIZE, (size + 7) >> 3);
383 437
384 /* Set default watermark values */ 438 /* Set default watermark values */
385 439
386 rdmsrl(MSR_LX_DC_SPARE, msrval); 440 rdmsrl(MSR_LX_SPARE_MSR, msrval);
387 441
388 msrval &= ~(DC_SPARE_DISABLE_CFIFO_HGO | DC_SPARE_VFIFO_ARB_SELECT | 442 msrval &= ~(MSR_LX_SPARE_MSR_DIS_CFIFO_HGO
389 DC_SPARE_LOAD_WM_LPEN_MASK | DC_SPARE_WM_LPEN_OVRD | 443 | MSR_LX_SPARE_MSR_VFIFO_ARB_SEL
390 DC_SPARE_DISABLE_INIT_VID_PRI | DC_SPARE_DISABLE_VFIFO_WM); 444 | MSR_LX_SPARE_MSR_LOAD_WM_LPEN_M
391 msrval |= DC_SPARE_DISABLE_VFIFO_WM | DC_SPARE_DISABLE_INIT_VID_PRI; 445 | MSR_LX_SPARE_MSR_WM_LPEN_OVRD);
392 wrmsrl(MSR_LX_DC_SPARE, msrval); 446 msrval |= MSR_LX_SPARE_MSR_DIS_VIFO_WM |
393 447 MSR_LX_SPARE_MSR_DIS_INIT_V_PRI;
394 gcfg = DC_GCFG_DFLE; /* Display fifo enable */ 448 wrmsrl(MSR_LX_SPARE_MSR, msrval);
395 gcfg |= 0xB600; /* Set default priority */ 449
396 gcfg |= DC_GCFG_FDTY; /* Set the frame dirty mode */ 450 gcfg = DC_GENERAL_CFG_DFLE; /* Display fifo enable */
397 451 gcfg |= (0x6 << DC_GENERAL_CFG_DFHPSL_SHIFT) | /* default priority */
398 dcfg = DC_DCFG_VDEN; /* Enable video data */ 452 (0xb << DC_GENERAL_CFG_DFHPEL_SHIFT);
399 dcfg |= DC_DCFG_GDEN; /* Enable graphics */ 453 gcfg |= DC_GENERAL_CFG_FDTY; /* Set the frame dirty mode */
400 dcfg |= DC_DCFG_TGEN; /* Turn on the timing generator */ 454
401 dcfg |= DC_DCFG_TRUP; /* Update timings immediately */ 455 dcfg = DC_DISPLAY_CFG_VDEN; /* Enable video data */
402 dcfg |= DC_DCFG_PALB; /* Palette bypass in > 8 bpp modes */ 456 dcfg |= DC_DISPLAY_CFG_GDEN; /* Enable graphics */
403 dcfg |= DC_DCFG_VISL; 457 dcfg |= DC_DISPLAY_CFG_TGEN; /* Turn on the timing generator */
404 dcfg |= DC_DCFG_DCEN; /* Always center the display */ 458 dcfg |= DC_DISPLAY_CFG_TRUP; /* Update timings immediately */
459 dcfg |= DC_DISPLAY_CFG_PALB; /* Palette bypass in > 8 bpp modes */
460 dcfg |= DC_DISPLAY_CFG_VISL;
461 dcfg |= DC_DISPLAY_CFG_DCEN; /* Always center the display */
405 462
406 /* Set the current BPP mode */ 463 /* Set the current BPP mode */
407 464
408 switch (info->var.bits_per_pixel) { 465 switch (info->var.bits_per_pixel) {
409 case 8: 466 case 8:
410 dcfg |= DC_DCFG_DISP_MODE_8BPP; 467 dcfg |= DC_DISPLAY_CFG_DISP_MODE_8BPP;
411 break; 468 break;
412 469
413 case 16: 470 case 16:
414 dcfg |= DC_DCFG_DISP_MODE_16BPP | DC_DCFG_16BPP; 471 dcfg |= DC_DISPLAY_CFG_DISP_MODE_16BPP;
415 break; 472 break;
416 473
417 case 32: 474 case 32:
418 case 24: 475 case 24:
419 dcfg |= DC_DCFG_DISP_MODE_24BPP; 476 dcfg |= DC_DISPLAY_CFG_DISP_MODE_24BPP;
420 break; 477 break;
421 } 478 }
422 479
@@ -436,35 +493,31 @@ void lx_set_mode(struct fb_info *info)
436 vblankend = vsyncend + info->var.upper_margin; 493 vblankend = vsyncend + info->var.upper_margin;
437 vtotal = vblankend; 494 vtotal = vblankend;
438 495
439 writel((hactive - 1) | ((htotal - 1) << 16), 496 write_dc(par, DC_H_ACTIVE_TIMING, (hactive - 1) | ((htotal - 1) << 16));
440 par->dc_regs + DC_H_ACTIVE_TIMING); 497 write_dc(par, DC_H_BLANK_TIMING,
441 writel((hblankstart - 1) | ((hblankend - 1) << 16), 498 (hblankstart - 1) | ((hblankend - 1) << 16));
442 par->dc_regs + DC_H_BLANK_TIMING); 499 write_dc(par, DC_H_SYNC_TIMING,
443 writel((hsyncstart - 1) | ((hsyncend - 1) << 16), 500 (hsyncstart - 1) | ((hsyncend - 1) << 16));
444 par->dc_regs + DC_H_SYNC_TIMING);
445
446 writel((vactive - 1) | ((vtotal - 1) << 16),
447 par->dc_regs + DC_V_ACTIVE_TIMING);
448 501
449 writel((vblankstart - 1) | ((vblankend - 1) << 16), 502 write_dc(par, DC_V_ACTIVE_TIMING, (vactive - 1) | ((vtotal - 1) << 16));
450 par->dc_regs + DC_V_BLANK_TIMING); 503 write_dc(par, DC_V_BLANK_TIMING,
504 (vblankstart - 1) | ((vblankend - 1) << 16));
505 write_dc(par, DC_V_SYNC_TIMING,
506 (vsyncstart - 1) | ((vsyncend - 1) << 16));
451 507
452 writel((vsyncstart - 1) | ((vsyncend - 1) << 16), 508 write_dc(par, DC_FB_ACTIVE,
453 par->dc_regs + DC_V_SYNC_TIMING); 509 (info->var.xres - 1) << 16 | (info->var.yres - 1));
454
455 writel( (info->var.xres - 1) << 16 | (info->var.yres - 1),
456 par->dc_regs + DC_FB_ACTIVE);
457 510
458 /* And re-enable the graphics output */ 511 /* And re-enable the graphics output */
459 lx_graphics_enable(info); 512 lx_graphics_enable(info);
460 513
461 /* Write the two main configuration registers */ 514 /* Write the two main configuration registers */
462 writel(dcfg, par->dc_regs + DC_DISPLAY_CFG); 515 write_dc(par, DC_DISPLAY_CFG, dcfg);
463 writel(0, par->dc_regs + DC_ARB_CFG); 516 write_dc(par, DC_ARB_CFG, 0);
464 writel(gcfg, par->dc_regs + DC_GENERAL_CFG); 517 write_dc(par, DC_GENERAL_CFG, gcfg);
465 518
466 /* Lock the DC registers */ 519 /* Lock the DC registers */
467 writel(0, par->dc_regs + DC_UNLOCK); 520 write_dc(par, DC_UNLOCK, DC_UNLOCK_LOCK);
468} 521}
469 522
470void lx_set_palette_reg(struct fb_info *info, unsigned regno, 523void lx_set_palette_reg(struct fb_info *info, unsigned regno,
@@ -479,58 +532,310 @@ void lx_set_palette_reg(struct fb_info *info, unsigned regno,
479 val |= (green) & 0x00ff00; 532 val |= (green) & 0x00ff00;
480 val |= (blue >> 8) & 0x0000ff; 533 val |= (blue >> 8) & 0x0000ff;
481 534
482 writel(regno, par->dc_regs + DC_PAL_ADDRESS); 535 write_dc(par, DC_PAL_ADDRESS, regno);
483 writel(val, par->dc_regs + DC_PAL_DATA); 536 write_dc(par, DC_PAL_DATA, val);
484} 537}
485 538
486int lx_blank_display(struct fb_info *info, int blank_mode) 539int lx_blank_display(struct fb_info *info, int blank_mode)
487{ 540{
488 struct lxfb_par *par = info->par; 541 struct lxfb_par *par = info->par;
489 u32 dcfg, fp_pm; 542 u32 dcfg, fp_pm;
490 int blank, hsync, vsync; 543 int blank, hsync, vsync, crt;
491 544
492 /* CRT power saving modes. */ 545 /* CRT power saving modes. */
493 switch (blank_mode) { 546 switch (blank_mode) {
494 case FB_BLANK_UNBLANK: 547 case FB_BLANK_UNBLANK:
495 blank = 0; hsync = 1; vsync = 1; 548 blank = 0; hsync = 1; vsync = 1; crt = 1;
496 break; 549 break;
497 case FB_BLANK_NORMAL: 550 case FB_BLANK_NORMAL:
498 blank = 1; hsync = 1; vsync = 1; 551 blank = 1; hsync = 1; vsync = 1; crt = 1;
499 break; 552 break;
500 case FB_BLANK_VSYNC_SUSPEND: 553 case FB_BLANK_VSYNC_SUSPEND:
501 blank = 1; hsync = 1; vsync = 0; 554 blank = 1; hsync = 1; vsync = 0; crt = 1;
502 break; 555 break;
503 case FB_BLANK_HSYNC_SUSPEND: 556 case FB_BLANK_HSYNC_SUSPEND:
504 blank = 1; hsync = 0; vsync = 1; 557 blank = 1; hsync = 0; vsync = 1; crt = 1;
505 break; 558 break;
506 case FB_BLANK_POWERDOWN: 559 case FB_BLANK_POWERDOWN:
507 blank = 1; hsync = 0; vsync = 0; 560 blank = 1; hsync = 0; vsync = 0; crt = 0;
508 break; 561 break;
509 default: 562 default:
510 return -EINVAL; 563 return -EINVAL;
511 } 564 }
512 565
513 dcfg = readl(par->df_regs + DF_DISPLAY_CFG); 566 dcfg = read_vp(par, VP_DCFG);
514 dcfg &= ~(DF_DCFG_DAC_BL_EN 567 dcfg &= ~(VP_DCFG_DAC_BL_EN | VP_DCFG_HSYNC_EN | VP_DCFG_VSYNC_EN |
515 | DF_DCFG_HSYNC_EN | DF_DCFG_VSYNC_EN); 568 VP_DCFG_CRT_EN);
516 if (!blank) 569 if (!blank)
517 dcfg |= DF_DCFG_DAC_BL_EN; 570 dcfg |= VP_DCFG_DAC_BL_EN;
518 if (hsync) 571 if (hsync)
519 dcfg |= DF_DCFG_HSYNC_EN; 572 dcfg |= VP_DCFG_HSYNC_EN;
520 if (vsync) 573 if (vsync)
521 dcfg |= DF_DCFG_VSYNC_EN; 574 dcfg |= VP_DCFG_VSYNC_EN;
522 writel(dcfg, par->df_regs + DF_DISPLAY_CFG); 575 if (crt)
576 dcfg |= VP_DCFG_CRT_EN;
577 write_vp(par, VP_DCFG, dcfg);
523 578
524 /* Power on/off flat panel */ 579 /* Power on/off flat panel */
525 580
526 if (par->output & OUTPUT_PANEL) { 581 if (par->output & OUTPUT_PANEL) {
527 fp_pm = readl(par->df_regs + DF_FP_PM); 582 fp_pm = read_fp(par, FP_PM);
528 if (blank_mode == FB_BLANK_POWERDOWN) 583 if (blank_mode == FB_BLANK_POWERDOWN)
529 fp_pm &= ~DF_FP_PM_P; 584 fp_pm &= ~FP_PM_P;
530 else 585 else
531 fp_pm |= DF_FP_PM_P; 586 fp_pm |= FP_PM_P;
532 writel(fp_pm, par->df_regs + DF_FP_PM); 587 write_fp(par, FP_PM, fp_pm);
533 } 588 }
534 589
535 return 0; 590 return 0;
536} 591}
592
593#ifdef CONFIG_PM
594
595static void lx_save_regs(struct lxfb_par *par)
596{
597 uint32_t filt;
598 int i;
599
600 /* wait for the BLT engine to stop being busy */
601 do {
602 i = read_gp(par, GP_BLT_STATUS);
603 } while ((i & GP_BLT_STATUS_PB) || !(i & GP_BLT_STATUS_CE));
604
605 /* save MSRs */
606 rdmsrl(MSR_LX_MSR_PADSEL, par->msr.padsel);
607 rdmsrl(MSR_GLCP_DOTPLL, par->msr.dotpll);
608 rdmsrl(MSR_LX_GLD_MSR_CONFIG, par->msr.dfglcfg);
609 rdmsrl(MSR_LX_SPARE_MSR, par->msr.dcspare);
610
611 write_dc(par, DC_UNLOCK, DC_UNLOCK_UNLOCK);
612
613 /* save registers */
614 memcpy(par->gp, par->gp_regs, sizeof(par->gp));
615 memcpy(par->dc, par->dc_regs, sizeof(par->dc));
616 memcpy(par->vp, par->vp_regs, sizeof(par->vp));
617 memcpy(par->fp, par->vp_regs + VP_FP_START, sizeof(par->fp));
618
619 /* save the palette */
620 write_dc(par, DC_PAL_ADDRESS, 0);
621 for (i = 0; i < ARRAY_SIZE(par->pal); i++)
622 par->pal[i] = read_dc(par, DC_PAL_DATA);
623
624 /* save the horizontal filter coefficients */
625 filt = par->dc[DC_IRQ_FILT_CTL] | DC_IRQ_FILT_CTL_H_FILT_SEL;
626 for (i = 0; i < ARRAY_SIZE(par->hcoeff); i += 2) {
627 write_dc(par, DC_IRQ_FILT_CTL, (filt & 0xffffff00) | i);
628 par->hcoeff[i] = read_dc(par, DC_FILT_COEFF1);
629 par->hcoeff[i + 1] = read_dc(par, DC_FILT_COEFF2);
630 }
631
632 /* save the vertical filter coefficients */
633 filt &= ~DC_IRQ_FILT_CTL_H_FILT_SEL;
634 for (i = 0; i < ARRAY_SIZE(par->vcoeff); i++) {
635 write_dc(par, DC_IRQ_FILT_CTL, (filt & 0xffffff00) | i);
636 par->vcoeff[i] = read_dc(par, DC_FILT_COEFF1);
637 }
638
639 /* save video coeff ram */
640 memcpy(par->vp_coeff, par->vp_regs + VP_VCR, sizeof(par->vp_coeff));
641}
642
643static void lx_restore_gfx_proc(struct lxfb_par *par)
644{
645 int i;
646
647 /* a bunch of registers require GP_RASTER_MODE to be set first */
648 write_gp(par, GP_RASTER_MODE, par->gp[GP_RASTER_MODE]);
649
650 for (i = 0; i < ARRAY_SIZE(par->gp); i++) {
651 switch (i) {
652 case GP_RASTER_MODE:
653 case GP_VECTOR_MODE:
654 case GP_BLT_MODE:
655 case GP_BLT_STATUS:
656 case GP_HST_SRC:
657 /* FIXME: restore LUT data */
658 case GP_LUT_INDEX:
659 case GP_LUT_DATA:
660 /* don't restore these registers */
661 break;
662
663 default:
664 write_gp(par, i, par->gp[i]);
665 }
666 }
667}
668
669static void lx_restore_display_ctlr(struct lxfb_par *par)
670{
671 uint32_t filt;
672 int i;
673
674 wrmsrl(MSR_LX_SPARE_MSR, par->msr.dcspare);
675
676 for (i = 0; i < ARRAY_SIZE(par->dc); i++) {
677 switch (i) {
678 case DC_UNLOCK:
679 /* unlock the DC; runs first */
680 write_dc(par, DC_UNLOCK, DC_UNLOCK_UNLOCK);
681 break;
682
683 case DC_GENERAL_CFG:
684 case DC_DISPLAY_CFG:
685 /* disable all while restoring */
686 write_dc(par, i, 0);
687 break;
688
689 case DC_DV_CTL:
690 /* set all ram to dirty */
691 write_dc(par, i, par->dc[i] | DC_DV_CTL_CLEAR_DV_RAM);
692
693 case DC_RSVD_1:
694 case DC_RSVD_2:
695 case DC_RSVD_3:
696 case DC_LINE_CNT:
697 case DC_PAL_ADDRESS:
698 case DC_PAL_DATA:
699 case DC_DFIFO_DIAG:
700 case DC_CFIFO_DIAG:
701 case DC_FILT_COEFF1:
702 case DC_FILT_COEFF2:
703 case DC_RSVD_4:
704 case DC_RSVD_5:
705 /* don't restore these registers */
706 break;
707
708 default:
709 write_dc(par, i, par->dc[i]);
710 }
711 }
712
713 /* restore the palette */
714 write_dc(par, DC_PAL_ADDRESS, 0);
715 for (i = 0; i < ARRAY_SIZE(par->pal); i++)
716 write_dc(par, DC_PAL_DATA, par->pal[i]);
717
718 /* restore the horizontal filter coefficients */
719 filt = par->dc[DC_IRQ_FILT_CTL] | DC_IRQ_FILT_CTL_H_FILT_SEL;
720 for (i = 0; i < ARRAY_SIZE(par->hcoeff); i += 2) {
721 write_dc(par, DC_IRQ_FILT_CTL, (filt & 0xffffff00) | i);
722 write_dc(par, DC_FILT_COEFF1, par->hcoeff[i]);
723 write_dc(par, DC_FILT_COEFF2, par->hcoeff[i + 1]);
724 }
725
726 /* restore the vertical filter coefficients */
727 filt &= ~DC_IRQ_FILT_CTL_H_FILT_SEL;
728 for (i = 0; i < ARRAY_SIZE(par->vcoeff); i++) {
729 write_dc(par, DC_IRQ_FILT_CTL, (filt & 0xffffff00) | i);
730 write_dc(par, DC_FILT_COEFF1, par->vcoeff[i]);
731 }
732}
733
734static void lx_restore_video_proc(struct lxfb_par *par)
735{
736 int i;
737
738 wrmsrl(MSR_LX_GLD_MSR_CONFIG, par->msr.dfglcfg);
739 wrmsrl(MSR_LX_MSR_PADSEL, par->msr.padsel);
740
741 for (i = 0; i < ARRAY_SIZE(par->vp); i++) {
742 switch (i) {
743 case VP_VCFG:
744 case VP_DCFG:
745 case VP_PAR:
746 case VP_PDR:
747 case VP_CCS:
748 case VP_RSVD_0:
749 /* case VP_VDC: */ /* why should this not be restored? */
750 case VP_RSVD_1:
751 case VP_CRC32:
752 /* don't restore these registers */
753 break;
754
755 default:
756 write_vp(par, i, par->vp[i]);
757 }
758 }
759
760 /* restore video coeff ram */
761 memcpy(par->vp_regs + VP_VCR, par->vp_coeff, sizeof(par->vp_coeff));
762}
763
764static void lx_restore_regs(struct lxfb_par *par)
765{
766 int i;
767
768 lx_set_dotpll((u32) (par->msr.dotpll >> 32));
769 lx_restore_gfx_proc(par);
770 lx_restore_display_ctlr(par);
771 lx_restore_video_proc(par);
772
773 /* Flat Panel */
774 for (i = 0; i < ARRAY_SIZE(par->fp); i++) {
775 switch (i) {
776 case FP_PM:
777 case FP_RSVD_0:
778 case FP_RSVD_1:
779 case FP_RSVD_2:
780 case FP_RSVD_3:
781 case FP_RSVD_4:
782 /* don't restore these registers */
783 break;
784
785 default:
786 write_fp(par, i, par->fp[i]);
787 }
788 }
789
790 /* control the panel */
791 if (par->fp[FP_PM] & FP_PM_P) {
792 /* power on the panel if not already power{ed,ing} on */
793 if (!(read_fp(par, FP_PM) &
794 (FP_PM_PANEL_ON|FP_PM_PANEL_PWR_UP)))
795 write_fp(par, FP_PM, par->fp[FP_PM]);
796 } else {
797 /* power down the panel if not already power{ed,ing} down */
798 if (!(read_fp(par, FP_PM) &
799 (FP_PM_PANEL_OFF|FP_PM_PANEL_PWR_DOWN)))
800 write_fp(par, FP_PM, par->fp[FP_PM]);
801 }
802
803 /* turn everything on */
804 write_vp(par, VP_VCFG, par->vp[VP_VCFG]);
805 write_vp(par, VP_DCFG, par->vp[VP_DCFG]);
806 write_dc(par, DC_DISPLAY_CFG, par->dc[DC_DISPLAY_CFG]);
807 /* do this last; it will enable the FIFO load */
808 write_dc(par, DC_GENERAL_CFG, par->dc[DC_GENERAL_CFG]);
809
810 /* lock the door behind us */
811 write_dc(par, DC_UNLOCK, DC_UNLOCK_LOCK);
812}
813
814int lx_powerdown(struct fb_info *info)
815{
816 struct lxfb_par *par = info->par;
817
818 if (par->powered_down)
819 return 0;
820
821 lx_save_regs(par);
822 lx_graphics_disable(info);
823
824 par->powered_down = 1;
825 return 0;
826}
827
828int lx_powerup(struct fb_info *info)
829{
830 struct lxfb_par *par = info->par;
831
832 if (!par->powered_down)
833 return 0;
834
835 lx_restore_regs(par);
836
837 par->powered_down = 0;
838 return 0;
839}
840
841#endif
diff --git a/drivers/video/geode/suspend_gx.c b/drivers/video/geode/suspend_gx.c
new file mode 100644
index 000000000000..9aff32ef8bb6
--- /dev/null
+++ b/drivers/video/geode/suspend_gx.c
@@ -0,0 +1,267 @@
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
diff --git a/drivers/video/geode/video_gx.c b/drivers/video/geode/video_gx.c
index febf09c63492..b8d52a8360db 100644
--- a/drivers/video/geode/video_gx.c
+++ b/drivers/video/geode/video_gx.c
@@ -16,9 +16,9 @@
16#include <asm/io.h> 16#include <asm/io.h>
17#include <asm/delay.h> 17#include <asm/delay.h>
18#include <asm/msr.h> 18#include <asm/msr.h>
19#include <asm/geode.h>
19 20
20#include "geodefb.h" 21#include "gxfb.h"
21#include "video_gx.h"
22 22
23 23
24/* 24/*
@@ -117,7 +117,7 @@ static const struct gx_pll_entry gx_pll_table_14MHz[] = {
117 { 4357, 0, 0x0000057D }, /* 229.5000 */ 117 { 4357, 0, 0x0000057D }, /* 229.5000 */
118}; 118};
119 119
120static void gx_set_dclk_frequency(struct fb_info *info) 120void gx_set_dclk_frequency(struct fb_info *info)
121{ 121{
122 const struct gx_pll_entry *pll_table; 122 const struct gx_pll_entry *pll_table;
123 int pll_table_len; 123 int pll_table_len;
@@ -178,110 +178,116 @@ static void gx_set_dclk_frequency(struct fb_info *info)
178static void 178static void
179gx_configure_tft(struct fb_info *info) 179gx_configure_tft(struct fb_info *info)
180{ 180{
181 struct geodefb_par *par = info->par; 181 struct gxfb_par *par = info->par;
182 unsigned long val; 182 unsigned long val;
183 unsigned long fp; 183 unsigned long fp;
184 184
185 /* Set up the DF pad select MSR */ 185 /* Set up the DF pad select MSR */
186 186
187 rdmsrl(GX_VP_MSR_PAD_SELECT, val); 187 rdmsrl(MSR_GX_MSR_PADSEL, val);
188 val &= ~GX_VP_PAD_SELECT_MASK; 188 val &= ~MSR_GX_MSR_PADSEL_MASK;
189 val |= GX_VP_PAD_SELECT_TFT; 189 val |= MSR_GX_MSR_PADSEL_TFT;
190 wrmsrl(GX_VP_MSR_PAD_SELECT, val); 190 wrmsrl(MSR_GX_MSR_PADSEL, val);
191 191
192 /* Turn off the panel */ 192 /* Turn off the panel */
193 193
194 fp = readl(par->vid_regs + GX_FP_PM); 194 fp = read_fp(par, FP_PM);
195 fp &= ~GX_FP_PM_P; 195 fp &= ~FP_PM_P;
196 writel(fp, par->vid_regs + GX_FP_PM); 196 write_fp(par, FP_PM, fp);
197 197
198 /* Set timing 1 */ 198 /* Set timing 1 */
199 199
200 fp = readl(par->vid_regs + GX_FP_PT1); 200 fp = read_fp(par, FP_PT1);
201 fp &= GX_FP_PT1_VSIZE_MASK; 201 fp &= FP_PT1_VSIZE_MASK;
202 fp |= info->var.yres << GX_FP_PT1_VSIZE_SHIFT; 202 fp |= info->var.yres << FP_PT1_VSIZE_SHIFT;
203 writel(fp, par->vid_regs + GX_FP_PT1); 203 write_fp(par, FP_PT1, fp);
204 204
205 /* Timing 2 */ 205 /* Timing 2 */
206 /* Set bits that are always on for TFT */ 206 /* Set bits that are always on for TFT */
207 207
208 fp = 0x0F100000; 208 fp = 0x0F100000;
209 209
210 /* Add sync polarity */ 210 /* Configure sync polarity */
211 211
212 if (!(info->var.sync & FB_SYNC_VERT_HIGH_ACT)) 212 if (!(info->var.sync & FB_SYNC_VERT_HIGH_ACT))
213 fp |= GX_FP_PT2_VSP; 213 fp |= FP_PT2_VSP;
214 214
215 if (!(info->var.sync & FB_SYNC_HOR_HIGH_ACT)) 215 if (!(info->var.sync & FB_SYNC_HOR_HIGH_ACT))
216 fp |= GX_FP_PT2_HSP; 216 fp |= FP_PT2_HSP;
217 217
218 writel(fp, par->vid_regs + GX_FP_PT2); 218 write_fp(par, FP_PT2, fp);
219 219
220 /* Set the dither control */ 220 /* Set the dither control */
221 writel(0x70, par->vid_regs + GX_FP_DFC); 221 write_fp(par, FP_DFC, FP_DFC_NFI);
222 222
223 /* Enable the FP data and power (in case the BIOS didn't) */ 223 /* Enable the FP data and power (in case the BIOS didn't) */
224 224
225 fp = readl(par->vid_regs + GX_DCFG); 225 fp = read_vp(par, VP_DCFG);
226 fp |= GX_DCFG_FP_PWR_EN | GX_DCFG_FP_DATA_EN; 226 fp |= VP_DCFG_FP_PWR_EN | VP_DCFG_FP_DATA_EN;
227 writel(fp, par->vid_regs + GX_DCFG); 227 write_vp(par, VP_DCFG, fp);
228 228
229 /* Unblank the panel */ 229 /* Unblank the panel */
230 230
231 fp = readl(par->vid_regs + GX_FP_PM); 231 fp = read_fp(par, FP_PM);
232 fp |= GX_FP_PM_P; 232 fp |= FP_PM_P;
233 writel(fp, par->vid_regs + GX_FP_PM); 233 write_fp(par, FP_PM, fp);
234} 234}
235 235
236static void gx_configure_display(struct fb_info *info) 236void gx_configure_display(struct fb_info *info)
237{ 237{
238 struct geodefb_par *par = info->par; 238 struct gxfb_par *par = info->par;
239 u32 dcfg, misc; 239 u32 dcfg, misc;
240 240
241 /* Set up the MISC register */
242
243 misc = readl(par->vid_regs + GX_MISC);
244
245 /* Power up the DAC */
246 misc &= ~(GX_MISC_A_PWRDN | GX_MISC_DAC_PWRDN);
247
248 /* Disable gamma correction */
249 misc |= GX_MISC_GAM_EN;
250
251 writel(misc, par->vid_regs + GX_MISC);
252
253 /* Write the display configuration */ 241 /* Write the display configuration */
254 dcfg = readl(par->vid_regs + GX_DCFG); 242 dcfg = read_vp(par, VP_DCFG);
255 243
256 /* Disable hsync and vsync */ 244 /* Disable hsync and vsync */
257 dcfg &= ~(GX_DCFG_VSYNC_EN | GX_DCFG_HSYNC_EN); 245 dcfg &= ~(VP_DCFG_VSYNC_EN | VP_DCFG_HSYNC_EN);
258 writel(dcfg, par->vid_regs + GX_DCFG); 246 write_vp(par, VP_DCFG, dcfg);
259 247
260 /* Clear bits from existing mode. */ 248 /* Clear bits from existing mode. */
261 dcfg &= ~(GX_DCFG_CRT_SYNC_SKW_MASK 249 dcfg &= ~(VP_DCFG_CRT_SYNC_SKW
262 | GX_DCFG_CRT_HSYNC_POL | GX_DCFG_CRT_VSYNC_POL 250 | VP_DCFG_CRT_HSYNC_POL | VP_DCFG_CRT_VSYNC_POL
263 | GX_DCFG_VSYNC_EN | GX_DCFG_HSYNC_EN); 251 | VP_DCFG_VSYNC_EN | VP_DCFG_HSYNC_EN);
264 252
265 /* Set default sync skew. */ 253 /* Set default sync skew. */
266 dcfg |= GX_DCFG_CRT_SYNC_SKW_DFLT; 254 dcfg |= VP_DCFG_CRT_SYNC_SKW_DEFAULT;
267 255
268 /* Enable hsync and vsync. */ 256 /* Enable hsync and vsync. */
269 dcfg |= GX_DCFG_HSYNC_EN | GX_DCFG_VSYNC_EN; 257 dcfg |= VP_DCFG_HSYNC_EN | VP_DCFG_VSYNC_EN;
270 258
271 /* Sync polarities. */ 259 misc = read_vp(par, VP_MISC);
272 if (info->var.sync & FB_SYNC_HOR_HIGH_ACT) 260
273 dcfg |= GX_DCFG_CRT_HSYNC_POL; 261 /* Disable gamma correction */
274 if (info->var.sync & FB_SYNC_VERT_HIGH_ACT) 262 misc |= VP_MISC_GAM_EN;
275 dcfg |= GX_DCFG_CRT_VSYNC_POL; 263
264 if (par->enable_crt) {
265
266 /* Power up the CRT DACs */
267 misc &= ~(VP_MISC_APWRDN | VP_MISC_DACPWRDN);
268 write_vp(par, VP_MISC, misc);
269
270 /* Only change the sync polarities if we are running
271 * in CRT mode. The FP polarities will be handled in
272 * gxfb_configure_tft */
273 if (!(info->var.sync & FB_SYNC_HOR_HIGH_ACT))
274 dcfg |= VP_DCFG_CRT_HSYNC_POL;
275 if (!(info->var.sync & FB_SYNC_VERT_HIGH_ACT))
276 dcfg |= VP_DCFG_CRT_VSYNC_POL;
277 } else {
278 /* Power down the CRT DACs if in FP mode */
279 misc |= (VP_MISC_APWRDN | VP_MISC_DACPWRDN);
280 write_vp(par, VP_MISC, misc);
281 }
276 282
277 /* Enable the display logic */ 283 /* Enable the display logic */
278 /* Set up the DACS to blank normally */ 284 /* Set up the DACS to blank normally */
279 285
280 dcfg |= GX_DCFG_CRT_EN | GX_DCFG_DAC_BL_EN; 286 dcfg |= VP_DCFG_CRT_EN | VP_DCFG_DAC_BL_EN;
281 287
282 /* Enable the external DAC VREF? */ 288 /* Enable the external DAC VREF? */
283 289
284 writel(dcfg, par->vid_regs + GX_DCFG); 290 write_vp(par, VP_DCFG, dcfg);
285 291
286 /* Set up the flat panel (if it is enabled) */ 292 /* Set up the flat panel (if it is enabled) */
287 293
@@ -289,59 +295,55 @@ static void gx_configure_display(struct fb_info *info)
289 gx_configure_tft(info); 295 gx_configure_tft(info);
290} 296}
291 297
292static int gx_blank_display(struct fb_info *info, int blank_mode) 298int gx_blank_display(struct fb_info *info, int blank_mode)
293{ 299{
294 struct geodefb_par *par = info->par; 300 struct gxfb_par *par = info->par;
295 u32 dcfg, fp_pm; 301 u32 dcfg, fp_pm;
296 int blank, hsync, vsync; 302 int blank, hsync, vsync, crt;
297 303
298 /* CRT power saving modes. */ 304 /* CRT power saving modes. */
299 switch (blank_mode) { 305 switch (blank_mode) {
300 case FB_BLANK_UNBLANK: 306 case FB_BLANK_UNBLANK:
301 blank = 0; hsync = 1; vsync = 1; 307 blank = 0; hsync = 1; vsync = 1; crt = 1;
302 break; 308 break;
303 case FB_BLANK_NORMAL: 309 case FB_BLANK_NORMAL:
304 blank = 1; hsync = 1; vsync = 1; 310 blank = 1; hsync = 1; vsync = 1; crt = 1;
305 break; 311 break;
306 case FB_BLANK_VSYNC_SUSPEND: 312 case FB_BLANK_VSYNC_SUSPEND:
307 blank = 1; hsync = 1; vsync = 0; 313 blank = 1; hsync = 1; vsync = 0; crt = 1;
308 break; 314 break;
309 case FB_BLANK_HSYNC_SUSPEND: 315 case FB_BLANK_HSYNC_SUSPEND:
310 blank = 1; hsync = 0; vsync = 1; 316 blank = 1; hsync = 0; vsync = 1; crt = 1;
311 break; 317 break;
312 case FB_BLANK_POWERDOWN: 318 case FB_BLANK_POWERDOWN:
313 blank = 1; hsync = 0; vsync = 0; 319 blank = 1; hsync = 0; vsync = 0; crt = 0;
314 break; 320 break;
315 default: 321 default:
316 return -EINVAL; 322 return -EINVAL;
317 } 323 }
318 dcfg = readl(par->vid_regs + GX_DCFG); 324 dcfg = read_vp(par, VP_DCFG);
319 dcfg &= ~(GX_DCFG_DAC_BL_EN 325 dcfg &= ~(VP_DCFG_DAC_BL_EN | VP_DCFG_HSYNC_EN | VP_DCFG_VSYNC_EN |
320 | GX_DCFG_HSYNC_EN | GX_DCFG_VSYNC_EN); 326 VP_DCFG_CRT_EN);
321 if (!blank) 327 if (!blank)
322 dcfg |= GX_DCFG_DAC_BL_EN; 328 dcfg |= VP_DCFG_DAC_BL_EN;
323 if (hsync) 329 if (hsync)
324 dcfg |= GX_DCFG_HSYNC_EN; 330 dcfg |= VP_DCFG_HSYNC_EN;
325 if (vsync) 331 if (vsync)
326 dcfg |= GX_DCFG_VSYNC_EN; 332 dcfg |= VP_DCFG_VSYNC_EN;
327 writel(dcfg, par->vid_regs + GX_DCFG); 333 if (crt)
334 dcfg |= VP_DCFG_CRT_EN;
335 write_vp(par, VP_DCFG, dcfg);
328 336
329 /* Power on/off flat panel. */ 337 /* Power on/off flat panel. */
330 338
331 if (par->enable_crt == 0) { 339 if (par->enable_crt == 0) {
332 fp_pm = readl(par->vid_regs + GX_FP_PM); 340 fp_pm = read_fp(par, FP_PM);
333 if (blank_mode == FB_BLANK_POWERDOWN) 341 if (blank_mode == FB_BLANK_POWERDOWN)
334 fp_pm &= ~GX_FP_PM_P; 342 fp_pm &= ~FP_PM_P;
335 else 343 else
336 fp_pm |= GX_FP_PM_P; 344 fp_pm |= FP_PM_P;
337 writel(fp_pm, par->vid_regs + GX_FP_PM); 345 write_fp(par, FP_PM, fp_pm);
338 } 346 }
339 347
340 return 0; 348 return 0;
341} 349}
342
343struct geode_vid_ops gx_vid_ops = {
344 .set_dclk = gx_set_dclk_frequency,
345 .configure_display = gx_configure_display,
346 .blank_display = gx_blank_display,
347};
diff --git a/drivers/video/geode/video_gx.h b/drivers/video/geode/video_gx.h
deleted file mode 100644
index ce28d8f382dc..000000000000
--- a/drivers/video/geode/video_gx.h
+++ /dev/null
@@ -1,72 +0,0 @@
1/*
2 * Geode GX video device
3 *
4 * Copyright (C) 2006 Arcom Control Systems Ltd.
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 */
11#ifndef __VIDEO_GX_H__
12#define __VIDEO_GX_H__
13
14extern struct geode_vid_ops gx_vid_ops;
15
16/* GX Flatpanel control MSR */
17#define GX_VP_MSR_PAD_SELECT 0xC0002011
18#define GX_VP_PAD_SELECT_MASK 0x3FFFFFFF
19#define GX_VP_PAD_SELECT_TFT 0x1FFFFFFF
20
21/* Geode GX video processor registers */
22
23#define GX_DCFG 0x0008
24# define GX_DCFG_CRT_EN 0x00000001
25# define GX_DCFG_HSYNC_EN 0x00000002
26# define GX_DCFG_VSYNC_EN 0x00000004
27# define GX_DCFG_DAC_BL_EN 0x00000008
28# define GX_DCFG_FP_PWR_EN 0x00000040
29# define GX_DCFG_FP_DATA_EN 0x00000080
30# define GX_DCFG_CRT_HSYNC_POL 0x00000100
31# define GX_DCFG_CRT_VSYNC_POL 0x00000200
32# define GX_DCFG_CRT_SYNC_SKW_MASK 0x0001C000
33# define GX_DCFG_CRT_SYNC_SKW_DFLT 0x00010000
34# define GX_DCFG_VG_CK 0x00100000
35# define GX_DCFG_GV_GAM 0x00200000
36# define GX_DCFG_DAC_VREF 0x04000000
37
38/* Geode GX MISC video configuration */
39
40#define GX_MISC 0x50
41#define GX_MISC_GAM_EN 0x00000001
42#define GX_MISC_DAC_PWRDN 0x00000400
43#define GX_MISC_A_PWRDN 0x00000800
44
45/* Geode GX flat panel display control registers */
46
47#define GX_FP_PT1 0x0400
48#define GX_FP_PT1_VSIZE_MASK 0x7FF0000
49#define GX_FP_PT1_VSIZE_SHIFT 16
50
51#define GX_FP_PT2 0x408
52#define GX_FP_PT2_VSP (1 << 23)
53#define GX_FP_PT2_HSP (1 << 22)
54
55#define GX_FP_PM 0x410
56# define GX_FP_PM_P 0x01000000
57
58#define GX_FP_DFC 0x418
59
60/* Geode GX clock control MSRs */
61
62#define MSR_GLCP_SYS_RSTPLL 0x4c000014
63# define MSR_GLCP_SYS_RSTPLL_DOTPREDIV2 (0x0000000000000002ull)
64# define MSR_GLCP_SYS_RSTPLL_DOTPREMULT2 (0x0000000000000004ull)
65# define MSR_GLCP_SYS_RSTPLL_DOTPOSTDIV3 (0x0000000000000008ull)
66
67#define MSR_GLCP_DOTPLL 0x4c000015
68# define MSR_GLCP_DOTPLL_DOTRESET (0x0000000000000001ull)
69# define MSR_GLCP_DOTPLL_BYPASS (0x0000000000008000ull)
70# define MSR_GLCP_DOTPLL_LOCK (0x0000000002000000ull)
71
72#endif /* !__VIDEO_GX_H__ */