Commit 3a59026ba111d85b1a86af0f1c4e5a8ef1242d82
Committed by
Linus Torvalds
1 parent
b8c49ef6ae
Exists in
master
and in
7 other branches
[PATCH] intelfb: extend partial support of i915G to include i915GM
Add partial support for GMA900 within the i915GM chipset. Signed-off-by: Scott MacKenzie <irrational@poboxes.com> Cc: "Antonino A. Daplas" <adaplas@pol.net> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Showing 3 changed files with 14 additions and 5 deletions Inline Diff
drivers/video/intelfb/intelfb.h
1 | #ifndef _INTELFB_H | 1 | #ifndef _INTELFB_H |
2 | #define _INTELFB_H | 2 | #define _INTELFB_H |
3 | 3 | ||
4 | /* $DHD: intelfb/intelfb.h,v 1.40 2003/06/27 15:06:25 dawes Exp $ */ | 4 | /* $DHD: intelfb/intelfb.h,v 1.40 2003/06/27 15:06:25 dawes Exp $ */ |
5 | 5 | ||
6 | #include <linux/agp_backend.h> | 6 | #include <linux/agp_backend.h> |
7 | #include <linux/fb.h> | 7 | #include <linux/fb.h> |
8 | 8 | ||
9 | 9 | ||
10 | /*** Version/name ***/ | 10 | /*** Version/name ***/ |
11 | #define INTELFB_VERSION "0.9.2" | 11 | #define INTELFB_VERSION "0.9.2" |
12 | #define INTELFB_MODULE_NAME "intelfb" | 12 | #define INTELFB_MODULE_NAME "intelfb" |
13 | #define SUPPORTED_CHIPSETS "830M/845G/852GM/855GM/865G/915G" | 13 | #define SUPPORTED_CHIPSETS "830M/845G/852GM/855GM/865G/915G/915GM" |
14 | 14 | ||
15 | 15 | ||
16 | /*** Debug/feature defines ***/ | 16 | /*** Debug/feature defines ***/ |
17 | 17 | ||
18 | #ifndef DEBUG | 18 | #ifndef DEBUG |
19 | #define DEBUG 0 | 19 | #define DEBUG 0 |
20 | #endif | 20 | #endif |
21 | 21 | ||
22 | #ifndef VERBOSE | 22 | #ifndef VERBOSE |
23 | #define VERBOSE 0 | 23 | #define VERBOSE 0 |
24 | #endif | 24 | #endif |
25 | 25 | ||
26 | #ifndef REGDUMP | 26 | #ifndef REGDUMP |
27 | #define REGDUMP 0 | 27 | #define REGDUMP 0 |
28 | #endif | 28 | #endif |
29 | 29 | ||
30 | #ifndef DETECT_VGA_CLASS_ONLY | 30 | #ifndef DETECT_VGA_CLASS_ONLY |
31 | #define DETECT_VGA_CLASS_ONLY 1 | 31 | #define DETECT_VGA_CLASS_ONLY 1 |
32 | #endif | 32 | #endif |
33 | 33 | ||
34 | #ifndef ALLOCATE_FOR_PANNING | 34 | #ifndef ALLOCATE_FOR_PANNING |
35 | #define ALLOCATE_FOR_PANNING 1 | 35 | #define ALLOCATE_FOR_PANNING 1 |
36 | #endif | 36 | #endif |
37 | 37 | ||
38 | #ifndef PREFERRED_MODE | 38 | #ifndef PREFERRED_MODE |
39 | #define PREFERRED_MODE "1024x768-32@70" | 39 | #define PREFERRED_MODE "1024x768-32@70" |
40 | #endif | 40 | #endif |
41 | 41 | ||
42 | /*** hw-related values ***/ | 42 | /*** hw-related values ***/ |
43 | 43 | ||
44 | /* PCI ids for supported devices */ | 44 | /* PCI ids for supported devices */ |
45 | #define PCI_DEVICE_ID_INTEL_830M 0x3577 | 45 | #define PCI_DEVICE_ID_INTEL_830M 0x3577 |
46 | #define PCI_DEVICE_ID_INTEL_845G 0x2562 | 46 | #define PCI_DEVICE_ID_INTEL_845G 0x2562 |
47 | #define PCI_DEVICE_ID_INTEL_85XGM 0x3582 | 47 | #define PCI_DEVICE_ID_INTEL_85XGM 0x3582 |
48 | #define PCI_DEVICE_ID_INTEL_865G 0x2572 | 48 | #define PCI_DEVICE_ID_INTEL_865G 0x2572 |
49 | #define PCI_DEVICE_ID_INTEL_915G 0x2582 | 49 | #define PCI_DEVICE_ID_INTEL_915G 0x2582 |
50 | #define PCI_DEVICE_ID_INTEL_915GM 0x2592 | ||
50 | 51 | ||
51 | /* Size of MMIO region */ | 52 | /* Size of MMIO region */ |
52 | #define INTEL_REG_SIZE 0x80000 | 53 | #define INTEL_REG_SIZE 0x80000 |
53 | 54 | ||
54 | #define STRIDE_ALIGNMENT 16 | 55 | #define STRIDE_ALIGNMENT 16 |
55 | 56 | ||
56 | #define PALETTE_8_ENTRIES 256 | 57 | #define PALETTE_8_ENTRIES 256 |
57 | 58 | ||
58 | 59 | ||
59 | /*** Macros ***/ | 60 | /*** Macros ***/ |
60 | 61 | ||
61 | /* basic arithmetic */ | 62 | /* basic arithmetic */ |
62 | #define KB(x) ((x) * 1024) | 63 | #define KB(x) ((x) * 1024) |
63 | #define MB(x) ((x) * 1024 * 1024) | 64 | #define MB(x) ((x) * 1024 * 1024) |
64 | #define BtoKB(x) ((x) / 1024) | 65 | #define BtoKB(x) ((x) / 1024) |
65 | #define BtoMB(x) ((x) / 1024 / 1024) | 66 | #define BtoMB(x) ((x) / 1024 / 1024) |
66 | 67 | ||
67 | #define GTT_PAGE_SIZE KB(4) | 68 | #define GTT_PAGE_SIZE KB(4) |
68 | 69 | ||
69 | #define ROUND_UP_TO(x, y) (((x) + (y) - 1) / (y) * (y)) | 70 | #define ROUND_UP_TO(x, y) (((x) + (y) - 1) / (y) * (y)) |
70 | #define ROUND_DOWN_TO(x, y) ((x) / (y) * (y)) | 71 | #define ROUND_DOWN_TO(x, y) ((x) / (y) * (y)) |
71 | #define ROUND_UP_TO_PAGE(x) ROUND_UP_TO((x), GTT_PAGE_SIZE) | 72 | #define ROUND_UP_TO_PAGE(x) ROUND_UP_TO((x), GTT_PAGE_SIZE) |
72 | #define ROUND_DOWN_TO_PAGE(x) ROUND_DOWN_TO((x), GTT_PAGE_SIZE) | 73 | #define ROUND_DOWN_TO_PAGE(x) ROUND_DOWN_TO((x), GTT_PAGE_SIZE) |
73 | 74 | ||
74 | /* messages */ | 75 | /* messages */ |
75 | #define PFX INTELFB_MODULE_NAME ": " | 76 | #define PFX INTELFB_MODULE_NAME ": " |
76 | 77 | ||
77 | #define ERR_MSG(fmt, args...) printk(KERN_ERR PFX fmt, ## args) | 78 | #define ERR_MSG(fmt, args...) printk(KERN_ERR PFX fmt, ## args) |
78 | #define WRN_MSG(fmt, args...) printk(KERN_WARNING PFX fmt, ## args) | 79 | #define WRN_MSG(fmt, args...) printk(KERN_WARNING PFX fmt, ## args) |
79 | #define NOT_MSG(fmt, args...) printk(KERN_NOTICE PFX fmt, ## args) | 80 | #define NOT_MSG(fmt, args...) printk(KERN_NOTICE PFX fmt, ## args) |
80 | #define INF_MSG(fmt, args...) printk(KERN_INFO PFX fmt, ## args) | 81 | #define INF_MSG(fmt, args...) printk(KERN_INFO PFX fmt, ## args) |
81 | #if DEBUG | 82 | #if DEBUG |
82 | #define DBG_MSG(fmt, args...) printk(KERN_DEBUG PFX fmt, ## args) | 83 | #define DBG_MSG(fmt, args...) printk(KERN_DEBUG PFX fmt, ## args) |
83 | #else | 84 | #else |
84 | #define DBG_MSG(fmt, args...) while (0) printk(fmt, ## args) | 85 | #define DBG_MSG(fmt, args...) while (0) printk(fmt, ## args) |
85 | #endif | 86 | #endif |
86 | 87 | ||
87 | /* get commonly used pointers */ | 88 | /* get commonly used pointers */ |
88 | #define GET_DINFO(info) (info)->par | 89 | #define GET_DINFO(info) (info)->par |
89 | 90 | ||
90 | /* misc macros */ | 91 | /* misc macros */ |
91 | #define ACCEL(d, i) \ | 92 | #define ACCEL(d, i) \ |
92 | ((d)->accel && !(d)->ring_lockup && \ | 93 | ((d)->accel && !(d)->ring_lockup && \ |
93 | ((i)->var.accel_flags & FB_ACCELF_TEXT)) | 94 | ((i)->var.accel_flags & FB_ACCELF_TEXT)) |
94 | 95 | ||
95 | /*#define NOACCEL_CHIPSET(d) \ | 96 | /*#define NOACCEL_CHIPSET(d) \ |
96 | ((d)->chipset != INTEL_865G)*/ | 97 | ((d)->chipset != INTEL_865G)*/ |
97 | #define NOACCEL_CHIPSET(d) \ | 98 | #define NOACCEL_CHIPSET(d) \ |
98 | (0) | 99 | (0) |
99 | 100 | ||
100 | #define FIXED_MODE(d) ((d)->fixed_mode) | 101 | #define FIXED_MODE(d) ((d)->fixed_mode) |
101 | 102 | ||
102 | /*** Driver paramters ***/ | 103 | /*** Driver paramters ***/ |
103 | 104 | ||
104 | #define RINGBUFFER_SIZE KB(64) | 105 | #define RINGBUFFER_SIZE KB(64) |
105 | #define HW_CURSOR_SIZE KB(4) | 106 | #define HW_CURSOR_SIZE KB(4) |
106 | 107 | ||
107 | /* Intel agpgart driver */ | 108 | /* Intel agpgart driver */ |
108 | #define AGP_PHYSICAL_MEMORY 2 | 109 | #define AGP_PHYSICAL_MEMORY 2 |
109 | 110 | ||
110 | /*** Data Types ***/ | 111 | /*** Data Types ***/ |
111 | 112 | ||
112 | /* supported chipsets */ | 113 | /* supported chipsets */ |
113 | enum intel_chips { | 114 | enum intel_chips { |
114 | INTEL_830M, | 115 | INTEL_830M, |
115 | INTEL_845G, | 116 | INTEL_845G, |
116 | INTEL_85XGM, | 117 | INTEL_85XGM, |
117 | INTEL_852GM, | 118 | INTEL_852GM, |
118 | INTEL_852GME, | 119 | INTEL_852GME, |
119 | INTEL_855GM, | 120 | INTEL_855GM, |
120 | INTEL_855GME, | 121 | INTEL_855GME, |
121 | INTEL_865G, | 122 | INTEL_865G, |
122 | INTEL_915G | 123 | INTEL_915G, |
124 | INTEL_915GM | ||
123 | }; | 125 | }; |
124 | 126 | ||
125 | struct intelfb_hwstate { | 127 | struct intelfb_hwstate { |
126 | u32 vga0_divisor; | 128 | u32 vga0_divisor; |
127 | u32 vga1_divisor; | 129 | u32 vga1_divisor; |
128 | u32 vga_pd; | 130 | u32 vga_pd; |
129 | u32 dpll_a; | 131 | u32 dpll_a; |
130 | u32 dpll_b; | 132 | u32 dpll_b; |
131 | u32 fpa0; | 133 | u32 fpa0; |
132 | u32 fpa1; | 134 | u32 fpa1; |
133 | u32 fpb0; | 135 | u32 fpb0; |
134 | u32 fpb1; | 136 | u32 fpb1; |
135 | u32 palette_a[PALETTE_8_ENTRIES]; | 137 | u32 palette_a[PALETTE_8_ENTRIES]; |
136 | u32 palette_b[PALETTE_8_ENTRIES]; | 138 | u32 palette_b[PALETTE_8_ENTRIES]; |
137 | u32 htotal_a; | 139 | u32 htotal_a; |
138 | u32 hblank_a; | 140 | u32 hblank_a; |
139 | u32 hsync_a; | 141 | u32 hsync_a; |
140 | u32 vtotal_a; | 142 | u32 vtotal_a; |
141 | u32 vblank_a; | 143 | u32 vblank_a; |
142 | u32 vsync_a; | 144 | u32 vsync_a; |
143 | u32 src_size_a; | 145 | u32 src_size_a; |
144 | u32 bclrpat_a; | 146 | u32 bclrpat_a; |
145 | u32 htotal_b; | 147 | u32 htotal_b; |
146 | u32 hblank_b; | 148 | u32 hblank_b; |
147 | u32 hsync_b; | 149 | u32 hsync_b; |
148 | u32 vtotal_b; | 150 | u32 vtotal_b; |
149 | u32 vblank_b; | 151 | u32 vblank_b; |
150 | u32 vsync_b; | 152 | u32 vsync_b; |
151 | u32 src_size_b; | 153 | u32 src_size_b; |
152 | u32 bclrpat_b; | 154 | u32 bclrpat_b; |
153 | u32 adpa; | 155 | u32 adpa; |
154 | u32 dvoa; | 156 | u32 dvoa; |
155 | u32 dvob; | 157 | u32 dvob; |
156 | u32 dvoc; | 158 | u32 dvoc; |
157 | u32 dvoa_srcdim; | 159 | u32 dvoa_srcdim; |
158 | u32 dvob_srcdim; | 160 | u32 dvob_srcdim; |
159 | u32 dvoc_srcdim; | 161 | u32 dvoc_srcdim; |
160 | u32 lvds; | 162 | u32 lvds; |
161 | u32 pipe_a_conf; | 163 | u32 pipe_a_conf; |
162 | u32 pipe_b_conf; | 164 | u32 pipe_b_conf; |
163 | u32 disp_arb; | 165 | u32 disp_arb; |
164 | u32 cursor_a_control; | 166 | u32 cursor_a_control; |
165 | u32 cursor_b_control; | 167 | u32 cursor_b_control; |
166 | u32 cursor_a_base; | 168 | u32 cursor_a_base; |
167 | u32 cursor_b_base; | 169 | u32 cursor_b_base; |
168 | u32 cursor_size; | 170 | u32 cursor_size; |
169 | u32 disp_a_ctrl; | 171 | u32 disp_a_ctrl; |
170 | u32 disp_b_ctrl; | 172 | u32 disp_b_ctrl; |
171 | u32 disp_a_base; | 173 | u32 disp_a_base; |
172 | u32 disp_b_base; | 174 | u32 disp_b_base; |
173 | u32 cursor_a_palette[4]; | 175 | u32 cursor_a_palette[4]; |
174 | u32 cursor_b_palette[4]; | 176 | u32 cursor_b_palette[4]; |
175 | u32 disp_a_stride; | 177 | u32 disp_a_stride; |
176 | u32 disp_b_stride; | 178 | u32 disp_b_stride; |
177 | u32 vgacntrl; | 179 | u32 vgacntrl; |
178 | u32 add_id; | 180 | u32 add_id; |
179 | u32 swf0x[7]; | 181 | u32 swf0x[7]; |
180 | u32 swf1x[7]; | 182 | u32 swf1x[7]; |
181 | u32 swf3x[3]; | 183 | u32 swf3x[3]; |
182 | u32 fence[8]; | 184 | u32 fence[8]; |
183 | u32 instpm; | 185 | u32 instpm; |
184 | u32 mem_mode; | 186 | u32 mem_mode; |
185 | u32 fw_blc_0; | 187 | u32 fw_blc_0; |
186 | u32 fw_blc_1; | 188 | u32 fw_blc_1; |
187 | }; | 189 | }; |
188 | 190 | ||
189 | struct intelfb_heap_data { | 191 | struct intelfb_heap_data { |
190 | u32 physical; | 192 | u32 physical; |
191 | u8 __iomem *virtual; | 193 | u8 __iomem *virtual; |
192 | u32 offset; // in GATT pages | 194 | u32 offset; // in GATT pages |
193 | u32 size; // in bytes | 195 | u32 size; // in bytes |
194 | }; | 196 | }; |
195 | 197 | ||
196 | struct intelfb_info { | 198 | struct intelfb_info { |
197 | struct fb_info *info; | 199 | struct fb_info *info; |
198 | struct fb_ops *fbops; | 200 | struct fb_ops *fbops; |
199 | struct pci_dev *pdev; | 201 | struct pci_dev *pdev; |
200 | 202 | ||
201 | struct intelfb_hwstate save_state; | 203 | struct intelfb_hwstate save_state; |
202 | 204 | ||
203 | /* agpgart structs */ | 205 | /* agpgart structs */ |
204 | struct agp_memory *gtt_fb_mem; // use all stolen memory or vram | 206 | struct agp_memory *gtt_fb_mem; // use all stolen memory or vram |
205 | struct agp_memory *gtt_ring_mem; // ring buffer | 207 | struct agp_memory *gtt_ring_mem; // ring buffer |
206 | struct agp_memory *gtt_cursor_mem; // hw cursor | 208 | struct agp_memory *gtt_cursor_mem; // hw cursor |
207 | 209 | ||
208 | /* use a gart reserved fb mem */ | 210 | /* use a gart reserved fb mem */ |
209 | u8 fbmem_gart; | 211 | u8 fbmem_gart; |
210 | 212 | ||
211 | /* mtrr support */ | 213 | /* mtrr support */ |
212 | u32 mtrr_reg; | 214 | u32 mtrr_reg; |
213 | u32 has_mtrr; | 215 | u32 has_mtrr; |
214 | 216 | ||
215 | /* heap data */ | 217 | /* heap data */ |
216 | struct intelfb_heap_data aperture; | 218 | struct intelfb_heap_data aperture; |
217 | struct intelfb_heap_data fb; | 219 | struct intelfb_heap_data fb; |
218 | struct intelfb_heap_data ring; | 220 | struct intelfb_heap_data ring; |
219 | struct intelfb_heap_data cursor; | 221 | struct intelfb_heap_data cursor; |
220 | 222 | ||
221 | /* mmio regs */ | 223 | /* mmio regs */ |
222 | u32 mmio_base_phys; | 224 | u32 mmio_base_phys; |
223 | u8 __iomem *mmio_base; | 225 | u8 __iomem *mmio_base; |
224 | 226 | ||
225 | /* fb start offset (in bytes) */ | 227 | /* fb start offset (in bytes) */ |
226 | u32 fb_start; | 228 | u32 fb_start; |
227 | 229 | ||
228 | /* ring buffer */ | 230 | /* ring buffer */ |
229 | u8 __iomem *ring_head; | 231 | u8 __iomem *ring_head; |
230 | u32 ring_tail; | 232 | u32 ring_tail; |
231 | u32 ring_tail_mask; | 233 | u32 ring_tail_mask; |
232 | u32 ring_space; | 234 | u32 ring_space; |
233 | u32 ring_lockup; | 235 | u32 ring_lockup; |
234 | 236 | ||
235 | /* palette */ | 237 | /* palette */ |
236 | u32 pseudo_palette[17]; | 238 | u32 pseudo_palette[17]; |
237 | 239 | ||
238 | /* chip info */ | 240 | /* chip info */ |
239 | int pci_chipset; | 241 | int pci_chipset; |
240 | int chipset; | 242 | int chipset; |
241 | const char *name; | 243 | const char *name; |
242 | int mobile; | 244 | int mobile; |
243 | 245 | ||
244 | /* current mode */ | 246 | /* current mode */ |
245 | int bpp, depth; | 247 | int bpp, depth; |
246 | u32 visual; | 248 | u32 visual; |
247 | int xres, yres, pitch; | 249 | int xres, yres, pitch; |
248 | int pixclock; | 250 | int pixclock; |
249 | 251 | ||
250 | /* current pipe */ | 252 | /* current pipe */ |
251 | int pipe; | 253 | int pipe; |
252 | 254 | ||
253 | /* some flags */ | 255 | /* some flags */ |
254 | int accel; | 256 | int accel; |
255 | int hwcursor; | 257 | int hwcursor; |
256 | int fixed_mode; | 258 | int fixed_mode; |
257 | int ring_active; | 259 | int ring_active; |
258 | 260 | ||
259 | /* hw cursor */ | 261 | /* hw cursor */ |
260 | int cursor_on; | 262 | int cursor_on; |
261 | int cursor_blanked; | 263 | int cursor_blanked; |
262 | u8 cursor_src[64]; | 264 | u8 cursor_src[64]; |
263 | 265 | ||
264 | /* initial parameters */ | 266 | /* initial parameters */ |
265 | int initial_vga; | 267 | int initial_vga; |
266 | struct fb_var_screeninfo initial_var; | 268 | struct fb_var_screeninfo initial_var; |
267 | u32 initial_fb_base; | 269 | u32 initial_fb_base; |
268 | u32 initial_video_ram; | 270 | u32 initial_video_ram; |
269 | u32 initial_pitch; | 271 | u32 initial_pitch; |
270 | 272 | ||
271 | /* driver registered */ | 273 | /* driver registered */ |
272 | int registered; | 274 | int registered; |
273 | }; | 275 | }; |
274 | 276 | ||
275 | /*** function prototypes ***/ | 277 | /*** function prototypes ***/ |
276 | 278 | ||
277 | extern int intelfb_var_to_depth(const struct fb_var_screeninfo *var); | 279 | extern int intelfb_var_to_depth(const struct fb_var_screeninfo *var); |
278 | 280 | ||
279 | #endif /* _INTELFB_H */ | 281 | #endif /* _INTELFB_H */ |
280 | 282 |
drivers/video/intelfb/intelfbdrv.c
1 | /* | 1 | /* |
2 | * intelfb | 2 | * intelfb |
3 | * | 3 | * |
4 | * Linux framebuffer driver for Intel(R) 830M/845G/852GM/855GM/865G/915G | 4 | * Linux framebuffer driver for Intel(R) 830M/845G/852GM/855GM/865G/915G/915GM |
5 | * integrated graphics chips. | 5 | * integrated graphics chips. |
6 | * | 6 | * |
7 | * Copyright ยฉ 2002, 2003 David Dawes <dawes@xfree86.org> | 7 | * Copyright ยฉ 2002, 2003 David Dawes <dawes@xfree86.org> |
8 | * 2004 Sylvain Meyer | 8 | * 2004 Sylvain Meyer |
9 | * | 9 | * |
10 | * This driver consists of two parts. The first part (intelfbdrv.c) provides | 10 | * This driver consists of two parts. The first part (intelfbdrv.c) provides |
11 | * the basic fbdev interfaces, is derived in part from the radeonfb and | 11 | * the basic fbdev interfaces, is derived in part from the radeonfb and |
12 | * vesafb drivers, and is covered by the GPL. The second part (intelfbhw.c) | 12 | * vesafb drivers, and is covered by the GPL. The second part (intelfbhw.c) |
13 | * provides the code to program the hardware. Most of it is derived from | 13 | * provides the code to program the hardware. Most of it is derived from |
14 | * the i810/i830 XFree86 driver. The HW-specific code is covered here | 14 | * the i810/i830 XFree86 driver. The HW-specific code is covered here |
15 | * under a dual license (GPL and MIT/XFree86 license). | 15 | * under a dual license (GPL and MIT/XFree86 license). |
16 | * | 16 | * |
17 | * Author: David Dawes | 17 | * Author: David Dawes |
18 | * | 18 | * |
19 | */ | 19 | */ |
20 | 20 | ||
21 | /* $DHD: intelfb/intelfbdrv.c,v 1.20 2003/06/27 15:17:40 dawes Exp $ */ | 21 | /* $DHD: intelfb/intelfbdrv.c,v 1.20 2003/06/27 15:17:40 dawes Exp $ */ |
22 | 22 | ||
23 | /* | 23 | /* |
24 | * Changes: | 24 | * Changes: |
25 | * 01/2003 - Initial driver (0.1.0), no mode switching, no acceleration. | 25 | * 01/2003 - Initial driver (0.1.0), no mode switching, no acceleration. |
26 | * This initial version is a basic core that works a lot like | 26 | * This initial version is a basic core that works a lot like |
27 | * the vesafb driver. It must be built-in to the kernel, | 27 | * the vesafb driver. It must be built-in to the kernel, |
28 | * and the initial video mode must be set with vga=XXX at | 28 | * and the initial video mode must be set with vga=XXX at |
29 | * boot time. (David Dawes) | 29 | * boot time. (David Dawes) |
30 | * | 30 | * |
31 | * 01/2003 - Version 0.2.0: Mode switching added, colormap support | 31 | * 01/2003 - Version 0.2.0: Mode switching added, colormap support |
32 | * implemented, Y panning, and soft screen blanking implemented. | 32 | * implemented, Y panning, and soft screen blanking implemented. |
33 | * No acceleration yet. (David Dawes) | 33 | * No acceleration yet. (David Dawes) |
34 | * | 34 | * |
35 | * 01/2003 - Version 0.3.0: fbcon acceleration support added. Module | 35 | * 01/2003 - Version 0.3.0: fbcon acceleration support added. Module |
36 | * option handling added. (David Dawes) | 36 | * option handling added. (David Dawes) |
37 | * | 37 | * |
38 | * 01/2003 - Version 0.4.0: fbcon HW cursor support added. (David Dawes) | 38 | * 01/2003 - Version 0.4.0: fbcon HW cursor support added. (David Dawes) |
39 | * | 39 | * |
40 | * 01/2003 - Version 0.4.1: Add auto-generation of built-in modes. | 40 | * 01/2003 - Version 0.4.1: Add auto-generation of built-in modes. |
41 | * (David Dawes) | 41 | * (David Dawes) |
42 | * | 42 | * |
43 | * 02/2003 - Version 0.4.2: Add check for active non-CRT devices, and | 43 | * 02/2003 - Version 0.4.2: Add check for active non-CRT devices, and |
44 | * mode validation checks. (David Dawes) | 44 | * mode validation checks. (David Dawes) |
45 | * | 45 | * |
46 | * 02/2003 - Version 0.4.3: Check when the VC is in graphics mode so that | 46 | * 02/2003 - Version 0.4.3: Check when the VC is in graphics mode so that |
47 | * acceleration is disabled while an XFree86 server is running. | 47 | * acceleration is disabled while an XFree86 server is running. |
48 | * (David Dawes) | 48 | * (David Dawes) |
49 | * | 49 | * |
50 | * 02/2003 - Version 0.4.4: Monitor DPMS support. (David Dawes) | 50 | * 02/2003 - Version 0.4.4: Monitor DPMS support. (David Dawes) |
51 | * | 51 | * |
52 | * 02/2003 - Version 0.4.5: Basic XFree86 + fbdev working. (David Dawes) | 52 | * 02/2003 - Version 0.4.5: Basic XFree86 + fbdev working. (David Dawes) |
53 | * | 53 | * |
54 | * 02/2003 - Version 0.5.0: Modify to work with the 2.5.32 kernel as well | 54 | * 02/2003 - Version 0.5.0: Modify to work with the 2.5.32 kernel as well |
55 | * as 2.4.x kernels. (David Dawes) | 55 | * as 2.4.x kernels. (David Dawes) |
56 | * | 56 | * |
57 | * 02/2003 - Version 0.6.0: Split out HW-specifics into a separate file. | 57 | * 02/2003 - Version 0.6.0: Split out HW-specifics into a separate file. |
58 | * (David Dawes) | 58 | * (David Dawes) |
59 | * | 59 | * |
60 | * 02/2003 - Version 0.7.0: Test on 852GM/855GM. Acceleration and HW | 60 | * 02/2003 - Version 0.7.0: Test on 852GM/855GM. Acceleration and HW |
61 | * cursor are disabled on this platform. (David Dawes) | 61 | * cursor are disabled on this platform. (David Dawes) |
62 | * | 62 | * |
63 | * 02/2003 - Version 0.7.1: Test on 845G. Acceleration is disabled | 63 | * 02/2003 - Version 0.7.1: Test on 845G. Acceleration is disabled |
64 | * on this platform. (David Dawes) | 64 | * on this platform. (David Dawes) |
65 | * | 65 | * |
66 | * 02/2003 - Version 0.7.2: Test on 830M. Acceleration and HW | 66 | * 02/2003 - Version 0.7.2: Test on 830M. Acceleration and HW |
67 | * cursor are disabled on this platform. (David Dawes) | 67 | * cursor are disabled on this platform. (David Dawes) |
68 | * | 68 | * |
69 | * 02/2003 - Version 0.7.3: Fix 8-bit modes for mobile platforms | 69 | * 02/2003 - Version 0.7.3: Fix 8-bit modes for mobile platforms |
70 | * (David Dawes) | 70 | * (David Dawes) |
71 | * | 71 | * |
72 | * 02/2003 - Version 0.7.4: Add checks for FB and FBCON_HAS_CFB* configured | 72 | * 02/2003 - Version 0.7.4: Add checks for FB and FBCON_HAS_CFB* configured |
73 | * in the kernel, and add mode bpp verification and default | 73 | * in the kernel, and add mode bpp verification and default |
74 | * bpp selection based on which FBCON_HAS_CFB* are configured. | 74 | * bpp selection based on which FBCON_HAS_CFB* are configured. |
75 | * (David Dawes) | 75 | * (David Dawes) |
76 | * | 76 | * |
77 | * 02/2003 - Version 0.7.5: Add basic package/install scripts based on the | 77 | * 02/2003 - Version 0.7.5: Add basic package/install scripts based on the |
78 | * DRI packaging scripts. (David Dawes) | 78 | * DRI packaging scripts. (David Dawes) |
79 | * | 79 | * |
80 | * 04/2003 - Version 0.7.6: Fix typo that affects builds with SMP-enabled | 80 | * 04/2003 - Version 0.7.6: Fix typo that affects builds with SMP-enabled |
81 | * kernels. (David Dawes, reported by Anupam). | 81 | * kernels. (David Dawes, reported by Anupam). |
82 | * | 82 | * |
83 | * 06/2003 - Version 0.7.7: | 83 | * 06/2003 - Version 0.7.7: |
84 | * Fix Makefile.kernel build problem (Tsutomu Yasuda). | 84 | * Fix Makefile.kernel build problem (Tsutomu Yasuda). |
85 | * Fix mis-placed #endif (2.4.21 kernel). | 85 | * Fix mis-placed #endif (2.4.21 kernel). |
86 | * | 86 | * |
87 | * 09/2004 - Version 0.9.0 - by Sylvain Meyer | 87 | * 09/2004 - Version 0.9.0 - by Sylvain Meyer |
88 | * Port to linux 2.6 kernel fbdev | 88 | * Port to linux 2.6 kernel fbdev |
89 | * Fix HW accel and HW cursor on i845G | 89 | * Fix HW accel and HW cursor on i845G |
90 | * Use of agpgart for fb memory reservation | 90 | * Use of agpgart for fb memory reservation |
91 | * Add mtrr support | 91 | * Add mtrr support |
92 | * | 92 | * |
93 | * 10/2004 - Version 0.9.1 | 93 | * 10/2004 - Version 0.9.1 |
94 | * Use module_param instead of old MODULE_PARM | 94 | * Use module_param instead of old MODULE_PARM |
95 | * Some cleanup | 95 | * Some cleanup |
96 | * | 96 | * |
97 | * 11/2004 - Version 0.9.2 | 97 | * 11/2004 - Version 0.9.2 |
98 | * Add vram option to reserve more memory than stolen by BIOS | 98 | * Add vram option to reserve more memory than stolen by BIOS |
99 | * Fix intelfbhw_pan_display typo | 99 | * Fix intelfbhw_pan_display typo |
100 | * Add __initdata annotations | 100 | * Add __initdata annotations |
101 | * | 101 | * |
102 | * TODO: | 102 | * TODO: |
103 | * | 103 | * |
104 | * | 104 | * |
105 | * Wish List: | 105 | * Wish List: |
106 | * | 106 | * |
107 | * | 107 | * |
108 | */ | 108 | */ |
109 | 109 | ||
110 | #include <linux/config.h> | 110 | #include <linux/config.h> |
111 | #include <linux/module.h> | 111 | #include <linux/module.h> |
112 | #include <linux/kernel.h> | 112 | #include <linux/kernel.h> |
113 | #include <linux/errno.h> | 113 | #include <linux/errno.h> |
114 | #include <linux/string.h> | 114 | #include <linux/string.h> |
115 | #include <linux/mm.h> | 115 | #include <linux/mm.h> |
116 | #include <linux/tty.h> | 116 | #include <linux/tty.h> |
117 | #include <linux/slab.h> | 117 | #include <linux/slab.h> |
118 | #include <linux/delay.h> | 118 | #include <linux/delay.h> |
119 | #include <linux/fb.h> | 119 | #include <linux/fb.h> |
120 | #include <linux/ioport.h> | 120 | #include <linux/ioport.h> |
121 | #include <linux/init.h> | 121 | #include <linux/init.h> |
122 | #include <linux/pci.h> | 122 | #include <linux/pci.h> |
123 | #include <linux/vmalloc.h> | 123 | #include <linux/vmalloc.h> |
124 | #include <linux/pagemap.h> | 124 | #include <linux/pagemap.h> |
125 | #include <linux/version.h> | 125 | #include <linux/version.h> |
126 | 126 | ||
127 | #include <asm/io.h> | 127 | #include <asm/io.h> |
128 | 128 | ||
129 | #ifdef CONFIG_MTRR | 129 | #ifdef CONFIG_MTRR |
130 | #include <asm/mtrr.h> | 130 | #include <asm/mtrr.h> |
131 | #endif | 131 | #endif |
132 | 132 | ||
133 | #include "intelfb.h" | 133 | #include "intelfb.h" |
134 | #include "intelfbhw.h" | 134 | #include "intelfbhw.h" |
135 | 135 | ||
136 | static void __devinit get_initial_mode(struct intelfb_info *dinfo); | 136 | static void __devinit get_initial_mode(struct intelfb_info *dinfo); |
137 | static void update_dinfo(struct intelfb_info *dinfo, | 137 | static void update_dinfo(struct intelfb_info *dinfo, |
138 | struct fb_var_screeninfo *var); | 138 | struct fb_var_screeninfo *var); |
139 | static int intelfb_get_fix(struct fb_fix_screeninfo *fix, | 139 | static int intelfb_get_fix(struct fb_fix_screeninfo *fix, |
140 | struct fb_info *info); | 140 | struct fb_info *info); |
141 | 141 | ||
142 | static int intelfb_check_var(struct fb_var_screeninfo *var, | 142 | static int intelfb_check_var(struct fb_var_screeninfo *var, |
143 | struct fb_info *info); | 143 | struct fb_info *info); |
144 | static int intelfb_set_par(struct fb_info *info); | 144 | static int intelfb_set_par(struct fb_info *info); |
145 | static int intelfb_setcolreg(unsigned regno, unsigned red, unsigned green, | 145 | static int intelfb_setcolreg(unsigned regno, unsigned red, unsigned green, |
146 | unsigned blue, unsigned transp, | 146 | unsigned blue, unsigned transp, |
147 | struct fb_info *info); | 147 | struct fb_info *info); |
148 | 148 | ||
149 | static int intelfb_blank(int blank, struct fb_info *info); | 149 | static int intelfb_blank(int blank, struct fb_info *info); |
150 | static int intelfb_pan_display(struct fb_var_screeninfo *var, | 150 | static int intelfb_pan_display(struct fb_var_screeninfo *var, |
151 | struct fb_info *info); | 151 | struct fb_info *info); |
152 | 152 | ||
153 | static void intelfb_fillrect(struct fb_info *info, | 153 | static void intelfb_fillrect(struct fb_info *info, |
154 | const struct fb_fillrect *rect); | 154 | const struct fb_fillrect *rect); |
155 | static void intelfb_copyarea(struct fb_info *info, | 155 | static void intelfb_copyarea(struct fb_info *info, |
156 | const struct fb_copyarea *region); | 156 | const struct fb_copyarea *region); |
157 | static void intelfb_imageblit(struct fb_info *info, | 157 | static void intelfb_imageblit(struct fb_info *info, |
158 | const struct fb_image *image); | 158 | const struct fb_image *image); |
159 | static int intelfb_cursor(struct fb_info *info, | 159 | static int intelfb_cursor(struct fb_info *info, |
160 | struct fb_cursor *cursor); | 160 | struct fb_cursor *cursor); |
161 | 161 | ||
162 | static int intelfb_sync(struct fb_info *info); | 162 | static int intelfb_sync(struct fb_info *info); |
163 | 163 | ||
164 | static int intelfb_ioctl(struct inode *inode, struct file *file, | 164 | static int intelfb_ioctl(struct inode *inode, struct file *file, |
165 | unsigned int cmd, unsigned long arg, | 165 | unsigned int cmd, unsigned long arg, |
166 | struct fb_info *info); | 166 | struct fb_info *info); |
167 | 167 | ||
168 | static int __devinit intelfb_pci_register(struct pci_dev *pdev, | 168 | static int __devinit intelfb_pci_register(struct pci_dev *pdev, |
169 | const struct pci_device_id *ent); | 169 | const struct pci_device_id *ent); |
170 | static void __devexit intelfb_pci_unregister(struct pci_dev *pdev); | 170 | static void __devexit intelfb_pci_unregister(struct pci_dev *pdev); |
171 | static int __devinit intelfb_set_fbinfo(struct intelfb_info *dinfo); | 171 | static int __devinit intelfb_set_fbinfo(struct intelfb_info *dinfo); |
172 | 172 | ||
173 | /* | 173 | /* |
174 | * Limiting the class to PCI_CLASS_DISPLAY_VGA prevents function 1 of the | 174 | * Limiting the class to PCI_CLASS_DISPLAY_VGA prevents function 1 of the |
175 | * mobile chipsets from being registered. | 175 | * mobile chipsets from being registered. |
176 | */ | 176 | */ |
177 | #if DETECT_VGA_CLASS_ONLY | 177 | #if DETECT_VGA_CLASS_ONLY |
178 | #define INTELFB_CLASS_MASK ~0 << 8 | 178 | #define INTELFB_CLASS_MASK ~0 << 8 |
179 | #else | 179 | #else |
180 | #define INTELFB_CLASS_MASK 0 | 180 | #define INTELFB_CLASS_MASK 0 |
181 | #endif | 181 | #endif |
182 | 182 | ||
183 | static struct pci_device_id intelfb_pci_table[] __devinitdata = { | 183 | static struct pci_device_id intelfb_pci_table[] __devinitdata = { |
184 | { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_830M, PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_DISPLAY_VGA << 8, INTELFB_CLASS_MASK, INTEL_830M }, | 184 | { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_830M, PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_DISPLAY_VGA << 8, INTELFB_CLASS_MASK, INTEL_830M }, |
185 | { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_845G, PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_DISPLAY_VGA << 8, INTELFB_CLASS_MASK, INTEL_845G }, | 185 | { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_845G, PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_DISPLAY_VGA << 8, INTELFB_CLASS_MASK, INTEL_845G }, |
186 | { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_85XGM, PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_DISPLAY_VGA << 8, INTELFB_CLASS_MASK, INTEL_85XGM }, | 186 | { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_85XGM, PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_DISPLAY_VGA << 8, INTELFB_CLASS_MASK, INTEL_85XGM }, |
187 | { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_865G, PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_DISPLAY_VGA << 8, INTELFB_CLASS_MASK, INTEL_865G }, | 187 | { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_865G, PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_DISPLAY_VGA << 8, INTELFB_CLASS_MASK, INTEL_865G }, |
188 | { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_915G, PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_DISPLAY_VGA << 8, INTELFB_CLASS_MASK, INTEL_915G }, | 188 | { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_915G, PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_DISPLAY_VGA << 8, INTELFB_CLASS_MASK, INTEL_915G }, |
189 | { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_915GM, PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_DISPLAY_VGA << 8, INTELFB_CLASS_MASK, INTEL_915GM }, | ||
189 | { 0, } | 190 | { 0, } |
190 | }; | 191 | }; |
191 | 192 | ||
192 | /* Global data */ | 193 | /* Global data */ |
193 | static int num_registered = 0; | 194 | static int num_registered = 0; |
194 | 195 | ||
195 | /* fb ops */ | 196 | /* fb ops */ |
196 | static struct fb_ops intel_fb_ops = { | 197 | static struct fb_ops intel_fb_ops = { |
197 | .owner = THIS_MODULE, | 198 | .owner = THIS_MODULE, |
198 | .fb_check_var = intelfb_check_var, | 199 | .fb_check_var = intelfb_check_var, |
199 | .fb_set_par = intelfb_set_par, | 200 | .fb_set_par = intelfb_set_par, |
200 | .fb_setcolreg = intelfb_setcolreg, | 201 | .fb_setcolreg = intelfb_setcolreg, |
201 | .fb_blank = intelfb_blank, | 202 | .fb_blank = intelfb_blank, |
202 | .fb_pan_display = intelfb_pan_display, | 203 | .fb_pan_display = intelfb_pan_display, |
203 | .fb_fillrect = intelfb_fillrect, | 204 | .fb_fillrect = intelfb_fillrect, |
204 | .fb_copyarea = intelfb_copyarea, | 205 | .fb_copyarea = intelfb_copyarea, |
205 | .fb_imageblit = intelfb_imageblit, | 206 | .fb_imageblit = intelfb_imageblit, |
206 | .fb_cursor = intelfb_cursor, | 207 | .fb_cursor = intelfb_cursor, |
207 | .fb_sync = intelfb_sync, | 208 | .fb_sync = intelfb_sync, |
208 | .fb_ioctl = intelfb_ioctl | 209 | .fb_ioctl = intelfb_ioctl |
209 | }; | 210 | }; |
210 | 211 | ||
211 | /* PCI driver module table */ | 212 | /* PCI driver module table */ |
212 | static struct pci_driver intelfb_driver = { | 213 | static struct pci_driver intelfb_driver = { |
213 | .name = "intelfb", | 214 | .name = "intelfb", |
214 | .id_table = intelfb_pci_table, | 215 | .id_table = intelfb_pci_table, |
215 | .probe = intelfb_pci_register, | 216 | .probe = intelfb_pci_register, |
216 | .remove = __devexit_p(intelfb_pci_unregister) | 217 | .remove = __devexit_p(intelfb_pci_unregister) |
217 | }; | 218 | }; |
218 | 219 | ||
219 | /* Module description/parameters */ | 220 | /* Module description/parameters */ |
220 | MODULE_AUTHOR("David Dawes <dawes@tungstengraphics.com>, " | 221 | MODULE_AUTHOR("David Dawes <dawes@tungstengraphics.com>, " |
221 | "Sylvain Meyer <sylvain.meyer@worldonline.fr>"); | 222 | "Sylvain Meyer <sylvain.meyer@worldonline.fr>"); |
222 | MODULE_DESCRIPTION( | 223 | MODULE_DESCRIPTION( |
223 | "Framebuffer driver for Intel(R) " SUPPORTED_CHIPSETS " chipsets"); | 224 | "Framebuffer driver for Intel(R) " SUPPORTED_CHIPSETS " chipsets"); |
224 | MODULE_LICENSE("Dual BSD/GPL"); | 225 | MODULE_LICENSE("Dual BSD/GPL"); |
225 | MODULE_DEVICE_TABLE(pci, intelfb_pci_table); | 226 | MODULE_DEVICE_TABLE(pci, intelfb_pci_table); |
226 | 227 | ||
227 | static int accel = 1; | 228 | static int accel = 1; |
228 | static int vram = 4; | 229 | static int vram = 4; |
229 | static int hwcursor = 0; | 230 | static int hwcursor = 0; |
230 | static int mtrr = 1; | 231 | static int mtrr = 1; |
231 | static int fixed = 0; | 232 | static int fixed = 0; |
232 | static int noinit = 0; | 233 | static int noinit = 0; |
233 | static int noregister = 0; | 234 | static int noregister = 0; |
234 | static int probeonly = 0; | 235 | static int probeonly = 0; |
235 | static int idonly = 0; | 236 | static int idonly = 0; |
236 | static int bailearly = 0; | 237 | static int bailearly = 0; |
237 | static int voffset = 48; | 238 | static int voffset = 48; |
238 | static char *mode = NULL; | 239 | static char *mode = NULL; |
239 | 240 | ||
240 | module_param(accel, bool, S_IRUGO); | 241 | module_param(accel, bool, S_IRUGO); |
241 | MODULE_PARM_DESC(accel, "Enable hardware acceleration"); | 242 | MODULE_PARM_DESC(accel, "Enable hardware acceleration"); |
242 | module_param(vram, int, S_IRUGO); | 243 | module_param(vram, int, S_IRUGO); |
243 | MODULE_PARM_DESC(vram, "System RAM to allocate to framebuffer in MiB"); | 244 | MODULE_PARM_DESC(vram, "System RAM to allocate to framebuffer in MiB"); |
244 | module_param(voffset, int, S_IRUGO); | 245 | module_param(voffset, int, S_IRUGO); |
245 | MODULE_PARM_DESC(voffset, "Offset of framebuffer in MiB"); | 246 | MODULE_PARM_DESC(voffset, "Offset of framebuffer in MiB"); |
246 | module_param(hwcursor, bool, S_IRUGO); | 247 | module_param(hwcursor, bool, S_IRUGO); |
247 | MODULE_PARM_DESC(hwcursor, "Enable HW cursor"); | 248 | MODULE_PARM_DESC(hwcursor, "Enable HW cursor"); |
248 | module_param(mtrr, bool, S_IRUGO); | 249 | module_param(mtrr, bool, S_IRUGO); |
249 | MODULE_PARM_DESC(mtrr, "Enable MTRR support"); | 250 | MODULE_PARM_DESC(mtrr, "Enable MTRR support"); |
250 | module_param(fixed, bool, S_IRUGO); | 251 | module_param(fixed, bool, S_IRUGO); |
251 | MODULE_PARM_DESC(fixed, "Disable mode switching"); | 252 | MODULE_PARM_DESC(fixed, "Disable mode switching"); |
252 | module_param(noinit, bool, 0); | 253 | module_param(noinit, bool, 0); |
253 | MODULE_PARM_DESC(noinit, "Don't initialise graphics mode when loading"); | 254 | MODULE_PARM_DESC(noinit, "Don't initialise graphics mode when loading"); |
254 | module_param(noregister, bool, 0); | 255 | module_param(noregister, bool, 0); |
255 | MODULE_PARM_DESC(noregister, "Don't register, just probe and exit (debug)"); | 256 | MODULE_PARM_DESC(noregister, "Don't register, just probe and exit (debug)"); |
256 | module_param(probeonly, bool, 0); | 257 | module_param(probeonly, bool, 0); |
257 | MODULE_PARM_DESC(probeonly, "Do a minimal probe (debug)"); | 258 | MODULE_PARM_DESC(probeonly, "Do a minimal probe (debug)"); |
258 | module_param(idonly, bool, 0); | 259 | module_param(idonly, bool, 0); |
259 | MODULE_PARM_DESC(idonly, "Just identify without doing anything else (debug)"); | 260 | MODULE_PARM_DESC(idonly, "Just identify without doing anything else (debug)"); |
260 | module_param(bailearly, bool, 0); | 261 | module_param(bailearly, bool, 0); |
261 | MODULE_PARM_DESC(bailearly, "Bail out early, depending on value (debug)"); | 262 | MODULE_PARM_DESC(bailearly, "Bail out early, depending on value (debug)"); |
262 | module_param(mode, charp, S_IRUGO); | 263 | module_param(mode, charp, S_IRUGO); |
263 | MODULE_PARM_DESC(mode, | 264 | MODULE_PARM_DESC(mode, |
264 | "Initial video mode \"<xres>x<yres>[-<depth>][@<refresh>]\""); | 265 | "Initial video mode \"<xres>x<yres>[-<depth>][@<refresh>]\""); |
265 | 266 | ||
266 | #ifndef MODULE | 267 | #ifndef MODULE |
267 | #define OPT_EQUAL(opt, name) (!strncmp(opt, name, strlen(name))) | 268 | #define OPT_EQUAL(opt, name) (!strncmp(opt, name, strlen(name))) |
268 | #define OPT_INTVAL(opt, name) simple_strtoul(opt + strlen(name), NULL, 0) | 269 | #define OPT_INTVAL(opt, name) simple_strtoul(opt + strlen(name), NULL, 0) |
269 | #define OPT_STRVAL(opt, name) (opt + strlen(name)) | 270 | #define OPT_STRVAL(opt, name) (opt + strlen(name)) |
270 | 271 | ||
271 | static __inline__ char * | 272 | static __inline__ char * |
272 | get_opt_string(const char *this_opt, const char *name) | 273 | get_opt_string(const char *this_opt, const char *name) |
273 | { | 274 | { |
274 | const char *p; | 275 | const char *p; |
275 | int i; | 276 | int i; |
276 | char *ret; | 277 | char *ret; |
277 | 278 | ||
278 | p = OPT_STRVAL(this_opt, name); | 279 | p = OPT_STRVAL(this_opt, name); |
279 | i = 0; | 280 | i = 0; |
280 | while (p[i] && p[i] != ' ' && p[i] != ',') | 281 | while (p[i] && p[i] != ' ' && p[i] != ',') |
281 | i++; | 282 | i++; |
282 | ret = kmalloc(i + 1, GFP_KERNEL); | 283 | ret = kmalloc(i + 1, GFP_KERNEL); |
283 | if (ret) { | 284 | if (ret) { |
284 | strncpy(ret, p, i); | 285 | strncpy(ret, p, i); |
285 | ret[i] = '\0'; | 286 | ret[i] = '\0'; |
286 | } | 287 | } |
287 | return ret; | 288 | return ret; |
288 | } | 289 | } |
289 | 290 | ||
290 | static __inline__ int | 291 | static __inline__ int |
291 | get_opt_int(const char *this_opt, const char *name, int *ret) | 292 | get_opt_int(const char *this_opt, const char *name, int *ret) |
292 | { | 293 | { |
293 | if (!ret) | 294 | if (!ret) |
294 | return 0; | 295 | return 0; |
295 | 296 | ||
296 | if (!OPT_EQUAL(this_opt, name)) | 297 | if (!OPT_EQUAL(this_opt, name)) |
297 | return 0; | 298 | return 0; |
298 | 299 | ||
299 | *ret = OPT_INTVAL(this_opt, name); | 300 | *ret = OPT_INTVAL(this_opt, name); |
300 | return 1; | 301 | return 1; |
301 | } | 302 | } |
302 | 303 | ||
303 | static __inline__ int | 304 | static __inline__ int |
304 | get_opt_bool(const char *this_opt, const char *name, int *ret) | 305 | get_opt_bool(const char *this_opt, const char *name, int *ret) |
305 | { | 306 | { |
306 | if (!ret) | 307 | if (!ret) |
307 | return 0; | 308 | return 0; |
308 | 309 | ||
309 | if (OPT_EQUAL(this_opt, name)) { | 310 | if (OPT_EQUAL(this_opt, name)) { |
310 | if (this_opt[strlen(name)] == '=') | 311 | if (this_opt[strlen(name)] == '=') |
311 | *ret = simple_strtoul(this_opt + strlen(name) + 1, | 312 | *ret = simple_strtoul(this_opt + strlen(name) + 1, |
312 | NULL, 0); | 313 | NULL, 0); |
313 | else | 314 | else |
314 | *ret = 1; | 315 | *ret = 1; |
315 | } else { | 316 | } else { |
316 | if (OPT_EQUAL(this_opt, "no") && OPT_EQUAL(this_opt + 2, name)) | 317 | if (OPT_EQUAL(this_opt, "no") && OPT_EQUAL(this_opt + 2, name)) |
317 | *ret = 0; | 318 | *ret = 0; |
318 | else | 319 | else |
319 | return 0; | 320 | return 0; |
320 | } | 321 | } |
321 | return 1; | 322 | return 1; |
322 | } | 323 | } |
323 | 324 | ||
324 | static int __init | 325 | static int __init |
325 | intelfb_setup(char *options) | 326 | intelfb_setup(char *options) |
326 | { | 327 | { |
327 | char *this_opt; | 328 | char *this_opt; |
328 | 329 | ||
329 | DBG_MSG("intelfb_setup\n"); | 330 | DBG_MSG("intelfb_setup\n"); |
330 | 331 | ||
331 | if (!options || !*options) { | 332 | if (!options || !*options) { |
332 | DBG_MSG("no options\n"); | 333 | DBG_MSG("no options\n"); |
333 | return 0; | 334 | return 0; |
334 | } else | 335 | } else |
335 | DBG_MSG("options: %s\n", options); | 336 | DBG_MSG("options: %s\n", options); |
336 | 337 | ||
337 | /* | 338 | /* |
338 | * These are the built-in options analogous to the module parameters | 339 | * These are the built-in options analogous to the module parameters |
339 | * defined above. | 340 | * defined above. |
340 | * | 341 | * |
341 | * The syntax is: | 342 | * The syntax is: |
342 | * | 343 | * |
343 | * video=intelfb:[mode][,<param>=<val>] ... | 344 | * video=intelfb:[mode][,<param>=<val>] ... |
344 | * | 345 | * |
345 | * e.g., | 346 | * e.g., |
346 | * | 347 | * |
347 | * video=intelfb:1024x768-16@75,accel=0 | 348 | * video=intelfb:1024x768-16@75,accel=0 |
348 | */ | 349 | */ |
349 | 350 | ||
350 | while ((this_opt = strsep(&options, ","))) { | 351 | while ((this_opt = strsep(&options, ","))) { |
351 | if (!*this_opt) | 352 | if (!*this_opt) |
352 | continue; | 353 | continue; |
353 | if (get_opt_bool(this_opt, "accel", &accel)) | 354 | if (get_opt_bool(this_opt, "accel", &accel)) |
354 | ; | 355 | ; |
355 | else if (get_opt_int(this_opt, "vram", &vram)) | 356 | else if (get_opt_int(this_opt, "vram", &vram)) |
356 | ; | 357 | ; |
357 | else if (get_opt_bool(this_opt, "hwcursor", &hwcursor)) | 358 | else if (get_opt_bool(this_opt, "hwcursor", &hwcursor)) |
358 | ; | 359 | ; |
359 | else if (get_opt_bool(this_opt, "mtrr", &mtrr)) | 360 | else if (get_opt_bool(this_opt, "mtrr", &mtrr)) |
360 | ; | 361 | ; |
361 | else if (get_opt_bool(this_opt, "fixed", &fixed)) | 362 | else if (get_opt_bool(this_opt, "fixed", &fixed)) |
362 | ; | 363 | ; |
363 | else if (get_opt_bool(this_opt, "init", &noinit)) | 364 | else if (get_opt_bool(this_opt, "init", &noinit)) |
364 | noinit = !noinit; | 365 | noinit = !noinit; |
365 | else if (OPT_EQUAL(this_opt, "mode=")) | 366 | else if (OPT_EQUAL(this_opt, "mode=")) |
366 | mode = get_opt_string(this_opt, "mode="); | 367 | mode = get_opt_string(this_opt, "mode="); |
367 | else | 368 | else |
368 | mode = this_opt; | 369 | mode = this_opt; |
369 | } | 370 | } |
370 | 371 | ||
371 | return 0; | 372 | return 0; |
372 | } | 373 | } |
373 | 374 | ||
374 | #endif | 375 | #endif |
375 | 376 | ||
376 | static int __init | 377 | static int __init |
377 | intelfb_init(void) | 378 | intelfb_init(void) |
378 | { | 379 | { |
379 | #ifndef MODULE | 380 | #ifndef MODULE |
380 | char *option = NULL; | 381 | char *option = NULL; |
381 | #endif | 382 | #endif |
382 | 383 | ||
383 | DBG_MSG("intelfb_init\n"); | 384 | DBG_MSG("intelfb_init\n"); |
384 | 385 | ||
385 | INF_MSG("Framebuffer driver for " | 386 | INF_MSG("Framebuffer driver for " |
386 | "Intel(R) " SUPPORTED_CHIPSETS " chipsets\n"); | 387 | "Intel(R) " SUPPORTED_CHIPSETS " chipsets\n"); |
387 | INF_MSG("Version " INTELFB_VERSION "\n"); | 388 | INF_MSG("Version " INTELFB_VERSION "\n"); |
388 | 389 | ||
389 | if (idonly) | 390 | if (idonly) |
390 | return -ENODEV; | 391 | return -ENODEV; |
391 | 392 | ||
392 | #ifndef MODULE | 393 | #ifndef MODULE |
393 | if (fb_get_options("intelfb", &option)) | 394 | if (fb_get_options("intelfb", &option)) |
394 | return -ENODEV; | 395 | return -ENODEV; |
395 | intelfb_setup(option); | 396 | intelfb_setup(option); |
396 | #endif | 397 | #endif |
397 | 398 | ||
398 | return pci_register_driver(&intelfb_driver); | 399 | return pci_register_driver(&intelfb_driver); |
399 | } | 400 | } |
400 | 401 | ||
401 | static void __exit | 402 | static void __exit |
402 | intelfb_exit(void) | 403 | intelfb_exit(void) |
403 | { | 404 | { |
404 | DBG_MSG("intelfb_exit\n"); | 405 | DBG_MSG("intelfb_exit\n"); |
405 | pci_unregister_driver(&intelfb_driver); | 406 | pci_unregister_driver(&intelfb_driver); |
406 | } | 407 | } |
407 | 408 | ||
408 | module_init(intelfb_init); | 409 | module_init(intelfb_init); |
409 | module_exit(intelfb_exit); | 410 | module_exit(intelfb_exit); |
410 | 411 | ||
411 | /*************************************************************** | 412 | /*************************************************************** |
412 | * mtrr support functions * | 413 | * mtrr support functions * |
413 | ***************************************************************/ | 414 | ***************************************************************/ |
414 | 415 | ||
415 | #ifdef CONFIG_MTRR | 416 | #ifdef CONFIG_MTRR |
416 | static inline void __devinit set_mtrr(struct intelfb_info *dinfo) | 417 | static inline void __devinit set_mtrr(struct intelfb_info *dinfo) |
417 | { | 418 | { |
418 | dinfo->mtrr_reg = mtrr_add(dinfo->aperture.physical, | 419 | dinfo->mtrr_reg = mtrr_add(dinfo->aperture.physical, |
419 | dinfo->aperture.size, MTRR_TYPE_WRCOMB, 1); | 420 | dinfo->aperture.size, MTRR_TYPE_WRCOMB, 1); |
420 | if (dinfo->mtrr_reg < 0) { | 421 | if (dinfo->mtrr_reg < 0) { |
421 | ERR_MSG("unable to set MTRR\n"); | 422 | ERR_MSG("unable to set MTRR\n"); |
422 | return; | 423 | return; |
423 | } | 424 | } |
424 | dinfo->has_mtrr = 1; | 425 | dinfo->has_mtrr = 1; |
425 | } | 426 | } |
426 | static inline void unset_mtrr(struct intelfb_info *dinfo) | 427 | static inline void unset_mtrr(struct intelfb_info *dinfo) |
427 | { | 428 | { |
428 | if (dinfo->has_mtrr) | 429 | if (dinfo->has_mtrr) |
429 | mtrr_del(dinfo->mtrr_reg, dinfo->aperture.physical, | 430 | mtrr_del(dinfo->mtrr_reg, dinfo->aperture.physical, |
430 | dinfo->aperture.size); | 431 | dinfo->aperture.size); |
431 | } | 432 | } |
432 | #else | 433 | #else |
433 | #define set_mtrr(x) WRN_MSG("MTRR is disabled in the kernel\n") | 434 | #define set_mtrr(x) WRN_MSG("MTRR is disabled in the kernel\n") |
434 | 435 | ||
435 | #define unset_mtrr(x) do { } while (0) | 436 | #define unset_mtrr(x) do { } while (0) |
436 | #endif /* CONFIG_MTRR */ | 437 | #endif /* CONFIG_MTRR */ |
437 | 438 | ||
438 | /*************************************************************** | 439 | /*************************************************************** |
439 | * driver init / cleanup * | 440 | * driver init / cleanup * |
440 | ***************************************************************/ | 441 | ***************************************************************/ |
441 | 442 | ||
442 | static void | 443 | static void |
443 | cleanup(struct intelfb_info *dinfo) | 444 | cleanup(struct intelfb_info *dinfo) |
444 | { | 445 | { |
445 | DBG_MSG("cleanup\n"); | 446 | DBG_MSG("cleanup\n"); |
446 | 447 | ||
447 | if (!dinfo) | 448 | if (!dinfo) |
448 | return; | 449 | return; |
449 | 450 | ||
450 | fb_dealloc_cmap(&dinfo->info->cmap); | 451 | fb_dealloc_cmap(&dinfo->info->cmap); |
451 | kfree(dinfo->info->pixmap.addr); | 452 | kfree(dinfo->info->pixmap.addr); |
452 | 453 | ||
453 | if (dinfo->registered) | 454 | if (dinfo->registered) |
454 | unregister_framebuffer(dinfo->info); | 455 | unregister_framebuffer(dinfo->info); |
455 | 456 | ||
456 | unset_mtrr(dinfo); | 457 | unset_mtrr(dinfo); |
457 | 458 | ||
458 | if (dinfo->fbmem_gart && dinfo->gtt_fb_mem) { | 459 | if (dinfo->fbmem_gart && dinfo->gtt_fb_mem) { |
459 | agp_unbind_memory(dinfo->gtt_fb_mem); | 460 | agp_unbind_memory(dinfo->gtt_fb_mem); |
460 | agp_free_memory(dinfo->gtt_fb_mem); | 461 | agp_free_memory(dinfo->gtt_fb_mem); |
461 | } | 462 | } |
462 | if (dinfo->gtt_cursor_mem) { | 463 | if (dinfo->gtt_cursor_mem) { |
463 | agp_unbind_memory(dinfo->gtt_cursor_mem); | 464 | agp_unbind_memory(dinfo->gtt_cursor_mem); |
464 | agp_free_memory(dinfo->gtt_cursor_mem); | 465 | agp_free_memory(dinfo->gtt_cursor_mem); |
465 | } | 466 | } |
466 | if (dinfo->gtt_ring_mem) { | 467 | if (dinfo->gtt_ring_mem) { |
467 | agp_unbind_memory(dinfo->gtt_ring_mem); | 468 | agp_unbind_memory(dinfo->gtt_ring_mem); |
468 | agp_free_memory(dinfo->gtt_ring_mem); | 469 | agp_free_memory(dinfo->gtt_ring_mem); |
469 | } | 470 | } |
470 | 471 | ||
471 | if (dinfo->mmio_base) | 472 | if (dinfo->mmio_base) |
472 | iounmap((void __iomem *)dinfo->mmio_base); | 473 | iounmap((void __iomem *)dinfo->mmio_base); |
473 | if (dinfo->aperture.virtual) | 474 | if (dinfo->aperture.virtual) |
474 | iounmap((void __iomem *)dinfo->aperture.virtual); | 475 | iounmap((void __iomem *)dinfo->aperture.virtual); |
475 | 476 | ||
476 | if (dinfo->mmio_base_phys) | 477 | if (dinfo->mmio_base_phys) |
477 | release_mem_region(dinfo->mmio_base_phys, INTEL_REG_SIZE); | 478 | release_mem_region(dinfo->mmio_base_phys, INTEL_REG_SIZE); |
478 | if (dinfo->aperture.physical) | 479 | if (dinfo->aperture.physical) |
479 | release_mem_region(dinfo->aperture.physical, | 480 | release_mem_region(dinfo->aperture.physical, |
480 | dinfo->aperture.size); | 481 | dinfo->aperture.size); |
481 | framebuffer_release(dinfo->info); | 482 | framebuffer_release(dinfo->info); |
482 | } | 483 | } |
483 | 484 | ||
484 | #define bailout(dinfo) do { \ | 485 | #define bailout(dinfo) do { \ |
485 | DBG_MSG("bailout\n"); \ | 486 | DBG_MSG("bailout\n"); \ |
486 | cleanup(dinfo); \ | 487 | cleanup(dinfo); \ |
487 | INF_MSG("Not going to register framebuffer, exiting...\n"); \ | 488 | INF_MSG("Not going to register framebuffer, exiting...\n"); \ |
488 | return -ENODEV; \ | 489 | return -ENODEV; \ |
489 | } while (0) | 490 | } while (0) |
490 | 491 | ||
491 | 492 | ||
492 | static int __devinit | 493 | static int __devinit |
493 | intelfb_pci_register(struct pci_dev *pdev, const struct pci_device_id *ent) | 494 | intelfb_pci_register(struct pci_dev *pdev, const struct pci_device_id *ent) |
494 | { | 495 | { |
495 | struct fb_info *info; | 496 | struct fb_info *info; |
496 | struct intelfb_info *dinfo; | 497 | struct intelfb_info *dinfo; |
497 | int i, err, dvo; | 498 | int i, err, dvo; |
498 | int aperture_size, stolen_size; | 499 | int aperture_size, stolen_size; |
499 | struct agp_kern_info gtt_info; | 500 | struct agp_kern_info gtt_info; |
500 | int agp_memtype; | 501 | int agp_memtype; |
501 | const char *s; | 502 | const char *s; |
502 | struct agp_bridge_data *bridge; | 503 | struct agp_bridge_data *bridge; |
503 | int aperture_bar = 0; | 504 | int aperture_bar = 0; |
504 | int mmio_bar = 1; | 505 | int mmio_bar = 1; |
505 | int offset; | 506 | int offset; |
506 | 507 | ||
507 | DBG_MSG("intelfb_pci_register\n"); | 508 | DBG_MSG("intelfb_pci_register\n"); |
508 | 509 | ||
509 | num_registered++; | 510 | num_registered++; |
510 | if (num_registered != 1) { | 511 | if (num_registered != 1) { |
511 | ERR_MSG("Attempted to register %d devices " | 512 | ERR_MSG("Attempted to register %d devices " |
512 | "(should be only 1).\n", num_registered); | 513 | "(should be only 1).\n", num_registered); |
513 | return -ENODEV; | 514 | return -ENODEV; |
514 | } | 515 | } |
515 | 516 | ||
516 | info = framebuffer_alloc(sizeof(struct intelfb_info), &pdev->dev); | 517 | info = framebuffer_alloc(sizeof(struct intelfb_info), &pdev->dev); |
517 | if (!info) { | 518 | if (!info) { |
518 | ERR_MSG("Could not allocate memory for intelfb_info.\n"); | 519 | ERR_MSG("Could not allocate memory for intelfb_info.\n"); |
519 | return -ENODEV; | 520 | return -ENODEV; |
520 | } | 521 | } |
521 | if (fb_alloc_cmap(&info->cmap, 256, 1) < 0) { | 522 | if (fb_alloc_cmap(&info->cmap, 256, 1) < 0) { |
522 | ERR_MSG("Could not allocate cmap for intelfb_info.\n"); | 523 | ERR_MSG("Could not allocate cmap for intelfb_info.\n"); |
523 | goto err_out_cmap; | 524 | goto err_out_cmap; |
524 | return -ENODEV; | 525 | return -ENODEV; |
525 | } | 526 | } |
526 | 527 | ||
527 | dinfo = info->par; | 528 | dinfo = info->par; |
528 | dinfo->info = info; | 529 | dinfo->info = info; |
529 | dinfo->fbops = &intel_fb_ops; | 530 | dinfo->fbops = &intel_fb_ops; |
530 | dinfo->pdev = pdev; | 531 | dinfo->pdev = pdev; |
531 | 532 | ||
532 | /* Reserve pixmap space. */ | 533 | /* Reserve pixmap space. */ |
533 | info->pixmap.addr = kmalloc(64 * 1024, GFP_KERNEL); | 534 | info->pixmap.addr = kmalloc(64 * 1024, GFP_KERNEL); |
534 | if (info->pixmap.addr == NULL) { | 535 | if (info->pixmap.addr == NULL) { |
535 | ERR_MSG("Cannot reserve pixmap memory.\n"); | 536 | ERR_MSG("Cannot reserve pixmap memory.\n"); |
536 | goto err_out_pixmap; | 537 | goto err_out_pixmap; |
537 | } | 538 | } |
538 | memset(info->pixmap.addr, 0, 64 * 1024); | 539 | memset(info->pixmap.addr, 0, 64 * 1024); |
539 | 540 | ||
540 | /* set early this option because it could be changed by tv encoder | 541 | /* set early this option because it could be changed by tv encoder |
541 | driver */ | 542 | driver */ |
542 | dinfo->fixed_mode = fixed; | 543 | dinfo->fixed_mode = fixed; |
543 | 544 | ||
544 | /* Enable device. */ | 545 | /* Enable device. */ |
545 | if ((err = pci_enable_device(pdev))) { | 546 | if ((err = pci_enable_device(pdev))) { |
546 | ERR_MSG("Cannot enable device.\n"); | 547 | ERR_MSG("Cannot enable device.\n"); |
547 | cleanup(dinfo); | 548 | cleanup(dinfo); |
548 | return -ENODEV; | 549 | return -ENODEV; |
549 | } | 550 | } |
550 | 551 | ||
551 | /* Set base addresses. */ | 552 | /* Set base addresses. */ |
552 | if (ent->device == PCI_DEVICE_ID_INTEL_915G) { | 553 | if ((ent->device == PCI_DEVICE_ID_INTEL_915G) || |
554 | (ent->device == PCI_DEVICE_ID_INTEL_915GM)) { | ||
553 | aperture_bar = 2; | 555 | aperture_bar = 2; |
554 | mmio_bar = 0; | 556 | mmio_bar = 0; |
555 | /* Disable HW cursor on 915G (not implemented yet) */ | 557 | /* Disable HW cursor on 915G/M (not implemented yet) */ |
556 | hwcursor = 0; | 558 | hwcursor = 0; |
557 | } | 559 | } |
558 | dinfo->aperture.physical = pci_resource_start(pdev, aperture_bar); | 560 | dinfo->aperture.physical = pci_resource_start(pdev, aperture_bar); |
559 | dinfo->aperture.size = pci_resource_len(pdev, aperture_bar); | 561 | dinfo->aperture.size = pci_resource_len(pdev, aperture_bar); |
560 | dinfo->mmio_base_phys = pci_resource_start(pdev, mmio_bar); | 562 | dinfo->mmio_base_phys = pci_resource_start(pdev, mmio_bar); |
561 | DBG_MSG("fb aperture: 0x%llx/0x%llx, MMIO region: 0x%llx/0x%llx\n", | 563 | DBG_MSG("fb aperture: 0x%llx/0x%llx, MMIO region: 0x%llx/0x%llx\n", |
562 | (unsigned long long)pci_resource_start(pdev, aperture_bar), | 564 | (unsigned long long)pci_resource_start(pdev, aperture_bar), |
563 | (unsigned long long)pci_resource_len(pdev, aperture_bar), | 565 | (unsigned long long)pci_resource_len(pdev, aperture_bar), |
564 | (unsigned long long)pci_resource_start(pdev, mmio_bar), | 566 | (unsigned long long)pci_resource_start(pdev, mmio_bar), |
565 | (unsigned long long)pci_resource_len(pdev, mmio_bar)); | 567 | (unsigned long long)pci_resource_len(pdev, mmio_bar)); |
566 | 568 | ||
567 | /* Reserve the fb and MMIO regions */ | 569 | /* Reserve the fb and MMIO regions */ |
568 | if (!request_mem_region(dinfo->aperture.physical, dinfo->aperture.size, | 570 | if (!request_mem_region(dinfo->aperture.physical, dinfo->aperture.size, |
569 | INTELFB_MODULE_NAME)) { | 571 | INTELFB_MODULE_NAME)) { |
570 | ERR_MSG("Cannot reserve FB region.\n"); | 572 | ERR_MSG("Cannot reserve FB region.\n"); |
571 | cleanup(dinfo); | 573 | cleanup(dinfo); |
572 | return -ENODEV; | 574 | return -ENODEV; |
573 | } | 575 | } |
574 | if (!request_mem_region(dinfo->mmio_base_phys, | 576 | if (!request_mem_region(dinfo->mmio_base_phys, |
575 | INTEL_REG_SIZE, | 577 | INTEL_REG_SIZE, |
576 | INTELFB_MODULE_NAME)) { | 578 | INTELFB_MODULE_NAME)) { |
577 | ERR_MSG("Cannot reserve MMIO region.\n"); | 579 | ERR_MSG("Cannot reserve MMIO region.\n"); |
578 | cleanup(dinfo); | 580 | cleanup(dinfo); |
579 | return -ENODEV; | 581 | return -ENODEV; |
580 | } | 582 | } |
581 | 583 | ||
582 | /* Get the chipset info. */ | 584 | /* Get the chipset info. */ |
583 | dinfo->pci_chipset = pdev->device; | 585 | dinfo->pci_chipset = pdev->device; |
584 | 586 | ||
585 | if (intelfbhw_get_chipset(pdev, &dinfo->name, &dinfo->chipset, | 587 | if (intelfbhw_get_chipset(pdev, &dinfo->name, &dinfo->chipset, |
586 | &dinfo->mobile)) { | 588 | &dinfo->mobile)) { |
587 | cleanup(dinfo); | 589 | cleanup(dinfo); |
588 | return -ENODEV; | 590 | return -ENODEV; |
589 | } | 591 | } |
590 | 592 | ||
591 | if (intelfbhw_get_memory(pdev, &aperture_size,&stolen_size)) { | 593 | if (intelfbhw_get_memory(pdev, &aperture_size,&stolen_size)) { |
592 | cleanup(dinfo); | 594 | cleanup(dinfo); |
593 | return -ENODEV; | 595 | return -ENODEV; |
594 | } | 596 | } |
595 | 597 | ||
596 | INF_MSG("%02x:%02x.%d: %s, aperture size %dMB, " | 598 | INF_MSG("%02x:%02x.%d: %s, aperture size %dMB, " |
597 | "stolen memory %dkB\n", | 599 | "stolen memory %dkB\n", |
598 | pdev->bus->number, PCI_SLOT(pdev->devfn), | 600 | pdev->bus->number, PCI_SLOT(pdev->devfn), |
599 | PCI_FUNC(pdev->devfn), dinfo->name, | 601 | PCI_FUNC(pdev->devfn), dinfo->name, |
600 | BtoMB(aperture_size), BtoKB(stolen_size)); | 602 | BtoMB(aperture_size), BtoKB(stolen_size)); |
601 | 603 | ||
602 | /* Set these from the options. */ | 604 | /* Set these from the options. */ |
603 | dinfo->accel = accel; | 605 | dinfo->accel = accel; |
604 | dinfo->hwcursor = hwcursor; | 606 | dinfo->hwcursor = hwcursor; |
605 | 607 | ||
606 | if (NOACCEL_CHIPSET(dinfo) && dinfo->accel == 1) { | 608 | if (NOACCEL_CHIPSET(dinfo) && dinfo->accel == 1) { |
607 | INF_MSG("Acceleration is not supported for the %s chipset.\n", | 609 | INF_MSG("Acceleration is not supported for the %s chipset.\n", |
608 | dinfo->name); | 610 | dinfo->name); |
609 | dinfo->accel = 0; | 611 | dinfo->accel = 0; |
610 | } | 612 | } |
611 | 613 | ||
612 | /* Framebuffer parameters - Use all the stolen memory if >= vram */ | 614 | /* Framebuffer parameters - Use all the stolen memory if >= vram */ |
613 | if (ROUND_UP_TO_PAGE(stolen_size) >= MB(vram)) { | 615 | if (ROUND_UP_TO_PAGE(stolen_size) >= MB(vram)) { |
614 | dinfo->fb.size = ROUND_UP_TO_PAGE(stolen_size); | 616 | dinfo->fb.size = ROUND_UP_TO_PAGE(stolen_size); |
615 | dinfo->fbmem_gart = 0; | 617 | dinfo->fbmem_gart = 0; |
616 | } else { | 618 | } else { |
617 | dinfo->fb.size = MB(vram); | 619 | dinfo->fb.size = MB(vram); |
618 | dinfo->fbmem_gart = 1; | 620 | dinfo->fbmem_gart = 1; |
619 | } | 621 | } |
620 | 622 | ||
621 | /* Allocate space for the ring buffer and HW cursor if enabled. */ | 623 | /* Allocate space for the ring buffer and HW cursor if enabled. */ |
622 | if (dinfo->accel) { | 624 | if (dinfo->accel) { |
623 | dinfo->ring.size = RINGBUFFER_SIZE; | 625 | dinfo->ring.size = RINGBUFFER_SIZE; |
624 | dinfo->ring_tail_mask = dinfo->ring.size - 1; | 626 | dinfo->ring_tail_mask = dinfo->ring.size - 1; |
625 | } | 627 | } |
626 | if (dinfo->hwcursor) { | 628 | if (dinfo->hwcursor) { |
627 | dinfo->cursor.size = HW_CURSOR_SIZE; | 629 | dinfo->cursor.size = HW_CURSOR_SIZE; |
628 | } | 630 | } |
629 | 631 | ||
630 | /* Use agpgart to manage the GATT */ | 632 | /* Use agpgart to manage the GATT */ |
631 | if (!(bridge = agp_backend_acquire(pdev))) { | 633 | if (!(bridge = agp_backend_acquire(pdev))) { |
632 | ERR_MSG("cannot acquire agp\n"); | 634 | ERR_MSG("cannot acquire agp\n"); |
633 | cleanup(dinfo); | 635 | cleanup(dinfo); |
634 | return -ENODEV; | 636 | return -ENODEV; |
635 | } | 637 | } |
636 | 638 | ||
637 | /* get the current gatt info */ | 639 | /* get the current gatt info */ |
638 | if (agp_copy_info(bridge, >t_info)) { | 640 | if (agp_copy_info(bridge, >t_info)) { |
639 | ERR_MSG("cannot get agp info\n"); | 641 | ERR_MSG("cannot get agp info\n"); |
640 | agp_backend_release(bridge); | 642 | agp_backend_release(bridge); |
641 | cleanup(dinfo); | 643 | cleanup(dinfo); |
642 | return -ENODEV; | 644 | return -ENODEV; |
643 | } | 645 | } |
644 | 646 | ||
645 | if (MB(voffset) < stolen_size) | 647 | if (MB(voffset) < stolen_size) |
646 | offset = (stolen_size >> 12); | 648 | offset = (stolen_size >> 12); |
647 | else | 649 | else |
648 | offset = ROUND_UP_TO_PAGE(MB(voffset))/GTT_PAGE_SIZE; | 650 | offset = ROUND_UP_TO_PAGE(MB(voffset))/GTT_PAGE_SIZE; |
649 | 651 | ||
650 | /* set the mem offsets - set them after the already used pages */ | 652 | /* set the mem offsets - set them after the already used pages */ |
651 | if (dinfo->accel) { | 653 | if (dinfo->accel) { |
652 | dinfo->ring.offset = offset + gtt_info.current_memory; | 654 | dinfo->ring.offset = offset + gtt_info.current_memory; |
653 | } | 655 | } |
654 | if (dinfo->hwcursor) { | 656 | if (dinfo->hwcursor) { |
655 | dinfo->cursor.offset = offset + | 657 | dinfo->cursor.offset = offset + |
656 | + gtt_info.current_memory + (dinfo->ring.size >> 12); | 658 | + gtt_info.current_memory + (dinfo->ring.size >> 12); |
657 | } | 659 | } |
658 | if (dinfo->fbmem_gart) { | 660 | if (dinfo->fbmem_gart) { |
659 | dinfo->fb.offset = offset + | 661 | dinfo->fb.offset = offset + |
660 | + gtt_info.current_memory + (dinfo->ring.size >> 12) | 662 | + gtt_info.current_memory + (dinfo->ring.size >> 12) |
661 | + (dinfo->cursor.size >> 12); | 663 | + (dinfo->cursor.size >> 12); |
662 | } | 664 | } |
663 | 665 | ||
664 | /* Allocate memories (which aren't stolen) */ | 666 | /* Allocate memories (which aren't stolen) */ |
665 | /* Map the fb and MMIO regions */ | 667 | /* Map the fb and MMIO regions */ |
666 | /* ioremap only up to the end of used aperture */ | 668 | /* ioremap only up to the end of used aperture */ |
667 | dinfo->aperture.virtual = (u8 __iomem *)ioremap_nocache | 669 | dinfo->aperture.virtual = (u8 __iomem *)ioremap_nocache |
668 | (dinfo->aperture.physical, ((offset + dinfo->fb.offset) << 12) | 670 | (dinfo->aperture.physical, ((offset + dinfo->fb.offset) << 12) |
669 | + dinfo->fb.size); | 671 | + dinfo->fb.size); |
670 | if (!dinfo->aperture.virtual) { | 672 | if (!dinfo->aperture.virtual) { |
671 | ERR_MSG("Cannot remap FB region.\n"); | 673 | ERR_MSG("Cannot remap FB region.\n"); |
672 | cleanup(dinfo); | 674 | cleanup(dinfo); |
673 | return -ENODEV; | 675 | return -ENODEV; |
674 | } | 676 | } |
675 | 677 | ||
676 | dinfo->mmio_base = | 678 | dinfo->mmio_base = |
677 | (u8 __iomem *)ioremap_nocache(dinfo->mmio_base_phys, | 679 | (u8 __iomem *)ioremap_nocache(dinfo->mmio_base_phys, |
678 | INTEL_REG_SIZE); | 680 | INTEL_REG_SIZE); |
679 | if (!dinfo->mmio_base) { | 681 | if (!dinfo->mmio_base) { |
680 | ERR_MSG("Cannot remap MMIO region.\n"); | 682 | ERR_MSG("Cannot remap MMIO region.\n"); |
681 | cleanup(dinfo); | 683 | cleanup(dinfo); |
682 | return -ENODEV; | 684 | return -ENODEV; |
683 | } | 685 | } |
684 | 686 | ||
685 | if (dinfo->accel) { | 687 | if (dinfo->accel) { |
686 | if (!(dinfo->gtt_ring_mem = | 688 | if (!(dinfo->gtt_ring_mem = |
687 | agp_allocate_memory(bridge, dinfo->ring.size >> 12, | 689 | agp_allocate_memory(bridge, dinfo->ring.size >> 12, |
688 | AGP_NORMAL_MEMORY))) { | 690 | AGP_NORMAL_MEMORY))) { |
689 | ERR_MSG("cannot allocate ring buffer memory\n"); | 691 | ERR_MSG("cannot allocate ring buffer memory\n"); |
690 | agp_backend_release(bridge); | 692 | agp_backend_release(bridge); |
691 | cleanup(dinfo); | 693 | cleanup(dinfo); |
692 | return -ENOMEM; | 694 | return -ENOMEM; |
693 | } | 695 | } |
694 | if (agp_bind_memory(dinfo->gtt_ring_mem, | 696 | if (agp_bind_memory(dinfo->gtt_ring_mem, |
695 | dinfo->ring.offset)) { | 697 | dinfo->ring.offset)) { |
696 | ERR_MSG("cannot bind ring buffer memory\n"); | 698 | ERR_MSG("cannot bind ring buffer memory\n"); |
697 | agp_backend_release(bridge); | 699 | agp_backend_release(bridge); |
698 | cleanup(dinfo); | 700 | cleanup(dinfo); |
699 | return -EBUSY; | 701 | return -EBUSY; |
700 | } | 702 | } |
701 | dinfo->ring.physical = dinfo->aperture.physical | 703 | dinfo->ring.physical = dinfo->aperture.physical |
702 | + (dinfo->ring.offset << 12); | 704 | + (dinfo->ring.offset << 12); |
703 | dinfo->ring.virtual = dinfo->aperture.virtual | 705 | dinfo->ring.virtual = dinfo->aperture.virtual |
704 | + (dinfo->ring.offset << 12); | 706 | + (dinfo->ring.offset << 12); |
705 | dinfo->ring_head = dinfo->ring.virtual; | 707 | dinfo->ring_head = dinfo->ring.virtual; |
706 | } | 708 | } |
707 | if (dinfo->hwcursor) { | 709 | if (dinfo->hwcursor) { |
708 | agp_memtype = dinfo->mobile ? AGP_PHYSICAL_MEMORY | 710 | agp_memtype = dinfo->mobile ? AGP_PHYSICAL_MEMORY |
709 | : AGP_NORMAL_MEMORY; | 711 | : AGP_NORMAL_MEMORY; |
710 | if (!(dinfo->gtt_cursor_mem = | 712 | if (!(dinfo->gtt_cursor_mem = |
711 | agp_allocate_memory(bridge, dinfo->cursor.size >> 12, | 713 | agp_allocate_memory(bridge, dinfo->cursor.size >> 12, |
712 | agp_memtype))) { | 714 | agp_memtype))) { |
713 | ERR_MSG("cannot allocate cursor memory\n"); | 715 | ERR_MSG("cannot allocate cursor memory\n"); |
714 | agp_backend_release(bridge); | 716 | agp_backend_release(bridge); |
715 | cleanup(dinfo); | 717 | cleanup(dinfo); |
716 | return -ENOMEM; | 718 | return -ENOMEM; |
717 | } | 719 | } |
718 | if (agp_bind_memory(dinfo->gtt_cursor_mem, | 720 | if (agp_bind_memory(dinfo->gtt_cursor_mem, |
719 | dinfo->cursor.offset)) { | 721 | dinfo->cursor.offset)) { |
720 | ERR_MSG("cannot bind cursor memory\n"); | 722 | ERR_MSG("cannot bind cursor memory\n"); |
721 | agp_backend_release(bridge); | 723 | agp_backend_release(bridge); |
722 | cleanup(dinfo); | 724 | cleanup(dinfo); |
723 | return -EBUSY; | 725 | return -EBUSY; |
724 | } | 726 | } |
725 | if (dinfo->mobile) | 727 | if (dinfo->mobile) |
726 | dinfo->cursor.physical | 728 | dinfo->cursor.physical |
727 | = dinfo->gtt_cursor_mem->physical; | 729 | = dinfo->gtt_cursor_mem->physical; |
728 | else | 730 | else |
729 | dinfo->cursor.physical = dinfo->aperture.physical | 731 | dinfo->cursor.physical = dinfo->aperture.physical |
730 | + (dinfo->cursor.offset << 12); | 732 | + (dinfo->cursor.offset << 12); |
731 | dinfo->cursor.virtual = dinfo->aperture.virtual | 733 | dinfo->cursor.virtual = dinfo->aperture.virtual |
732 | + (dinfo->cursor.offset << 12); | 734 | + (dinfo->cursor.offset << 12); |
733 | } | 735 | } |
734 | if (dinfo->fbmem_gart) { | 736 | if (dinfo->fbmem_gart) { |
735 | if (!(dinfo->gtt_fb_mem = | 737 | if (!(dinfo->gtt_fb_mem = |
736 | agp_allocate_memory(bridge, dinfo->fb.size >> 12, | 738 | agp_allocate_memory(bridge, dinfo->fb.size >> 12, |
737 | AGP_NORMAL_MEMORY))) { | 739 | AGP_NORMAL_MEMORY))) { |
738 | WRN_MSG("cannot allocate framebuffer memory - use " | 740 | WRN_MSG("cannot allocate framebuffer memory - use " |
739 | "the stolen one\n"); | 741 | "the stolen one\n"); |
740 | dinfo->fbmem_gart = 0; | 742 | dinfo->fbmem_gart = 0; |
741 | } | 743 | } |
742 | if (agp_bind_memory(dinfo->gtt_fb_mem, | 744 | if (agp_bind_memory(dinfo->gtt_fb_mem, |
743 | dinfo->fb.offset)) { | 745 | dinfo->fb.offset)) { |
744 | WRN_MSG("cannot bind framebuffer memory - use " | 746 | WRN_MSG("cannot bind framebuffer memory - use " |
745 | "the stolen one\n"); | 747 | "the stolen one\n"); |
746 | dinfo->fbmem_gart = 0; | 748 | dinfo->fbmem_gart = 0; |
747 | } | 749 | } |
748 | } | 750 | } |
749 | 751 | ||
750 | /* update framebuffer memory parameters */ | 752 | /* update framebuffer memory parameters */ |
751 | if (!dinfo->fbmem_gart) | 753 | if (!dinfo->fbmem_gart) |
752 | dinfo->fb.offset = 0; /* starts at offset 0 */ | 754 | dinfo->fb.offset = 0; /* starts at offset 0 */ |
753 | dinfo->fb.physical = dinfo->aperture.physical | 755 | dinfo->fb.physical = dinfo->aperture.physical |
754 | + (dinfo->fb.offset << 12); | 756 | + (dinfo->fb.offset << 12); |
755 | dinfo->fb.virtual = dinfo->aperture.virtual + (dinfo->fb.offset << 12); | 757 | dinfo->fb.virtual = dinfo->aperture.virtual + (dinfo->fb.offset << 12); |
756 | dinfo->fb_start = dinfo->fb.offset << 12; | 758 | dinfo->fb_start = dinfo->fb.offset << 12; |
757 | 759 | ||
758 | /* release agpgart */ | 760 | /* release agpgart */ |
759 | agp_backend_release(bridge); | 761 | agp_backend_release(bridge); |
760 | 762 | ||
761 | if (mtrr) | 763 | if (mtrr) |
762 | set_mtrr(dinfo); | 764 | set_mtrr(dinfo); |
763 | 765 | ||
764 | DBG_MSG("fb: 0x%x(+ 0x%x)/0x%x (0x%x)\n", | 766 | DBG_MSG("fb: 0x%x(+ 0x%x)/0x%x (0x%x)\n", |
765 | dinfo->fb.physical, dinfo->fb.offset, dinfo->fb.size, | 767 | dinfo->fb.physical, dinfo->fb.offset, dinfo->fb.size, |
766 | (u32 __iomem ) dinfo->fb.virtual); | 768 | (u32 __iomem ) dinfo->fb.virtual); |
767 | DBG_MSG("MMIO: 0x%x/0x%x (0x%x)\n", | 769 | DBG_MSG("MMIO: 0x%x/0x%x (0x%x)\n", |
768 | dinfo->mmio_base_phys, INTEL_REG_SIZE, | 770 | dinfo->mmio_base_phys, INTEL_REG_SIZE, |
769 | (u32 __iomem) dinfo->mmio_base); | 771 | (u32 __iomem) dinfo->mmio_base); |
770 | DBG_MSG("ring buffer: 0x%x/0x%x (0x%x)\n", | 772 | DBG_MSG("ring buffer: 0x%x/0x%x (0x%x)\n", |
771 | dinfo->ring.physical, dinfo->ring.size, | 773 | dinfo->ring.physical, dinfo->ring.size, |
772 | (u32 __iomem ) dinfo->ring.virtual); | 774 | (u32 __iomem ) dinfo->ring.virtual); |
773 | DBG_MSG("HW cursor: 0x%x/0x%x (0x%x) (offset 0x%x) (phys 0x%x)\n", | 775 | DBG_MSG("HW cursor: 0x%x/0x%x (0x%x) (offset 0x%x) (phys 0x%x)\n", |
774 | dinfo->cursor.physical, dinfo->cursor.size, | 776 | dinfo->cursor.physical, dinfo->cursor.size, |
775 | (u32 __iomem ) dinfo->cursor.virtual, dinfo->cursor.offset, | 777 | (u32 __iomem ) dinfo->cursor.virtual, dinfo->cursor.offset, |
776 | dinfo->cursor.physical); | 778 | dinfo->cursor.physical); |
777 | 779 | ||
778 | DBG_MSG("options: vram = %d, accel = %d, hwcursor = %d, fixed = %d, " | 780 | DBG_MSG("options: vram = %d, accel = %d, hwcursor = %d, fixed = %d, " |
779 | "noinit = %d\n", vram, accel, hwcursor, fixed, noinit); | 781 | "noinit = %d\n", vram, accel, hwcursor, fixed, noinit); |
780 | DBG_MSG("options: mode = \"%s\"\n", mode ? mode : ""); | 782 | DBG_MSG("options: mode = \"%s\"\n", mode ? mode : ""); |
781 | 783 | ||
782 | if (probeonly) | 784 | if (probeonly) |
783 | bailout(dinfo); | 785 | bailout(dinfo); |
784 | 786 | ||
785 | /* | 787 | /* |
786 | * Check if the LVDS port or any DVO ports are enabled. If so, | 788 | * Check if the LVDS port or any DVO ports are enabled. If so, |
787 | * don't allow mode switching | 789 | * don't allow mode switching |
788 | */ | 790 | */ |
789 | dvo = intelfbhw_check_non_crt(dinfo); | 791 | dvo = intelfbhw_check_non_crt(dinfo); |
790 | if (dvo) { | 792 | if (dvo) { |
791 | dinfo->fixed_mode = 1; | 793 | dinfo->fixed_mode = 1; |
792 | WRN_MSG("Non-CRT device is enabled ( "); | 794 | WRN_MSG("Non-CRT device is enabled ( "); |
793 | i = 0; | 795 | i = 0; |
794 | while (dvo) { | 796 | while (dvo) { |
795 | if (dvo & 1) { | 797 | if (dvo & 1) { |
796 | s = intelfbhw_dvo_to_string(1 << i); | 798 | s = intelfbhw_dvo_to_string(1 << i); |
797 | if (s) | 799 | if (s) |
798 | printk("%s ", s); | 800 | printk("%s ", s); |
799 | } | 801 | } |
800 | dvo >>= 1; | 802 | dvo >>= 1; |
801 | ++i; | 803 | ++i; |
802 | } | 804 | } |
803 | printk("). Disabling mode switching.\n"); | 805 | printk("). Disabling mode switching.\n"); |
804 | } | 806 | } |
805 | 807 | ||
806 | if (bailearly == 1) | 808 | if (bailearly == 1) |
807 | bailout(dinfo); | 809 | bailout(dinfo); |
808 | 810 | ||
809 | if (FIXED_MODE(dinfo) && ORIG_VIDEO_ISVGA != VIDEO_TYPE_VLFB) { | 811 | if (FIXED_MODE(dinfo) && ORIG_VIDEO_ISVGA != VIDEO_TYPE_VLFB) { |
810 | ERR_MSG("Video mode must be programmed at boot time.\n"); | 812 | ERR_MSG("Video mode must be programmed at boot time.\n"); |
811 | cleanup(dinfo); | 813 | cleanup(dinfo); |
812 | return -ENODEV; | 814 | return -ENODEV; |
813 | } | 815 | } |
814 | 816 | ||
815 | if (bailearly == 2) | 817 | if (bailearly == 2) |
816 | bailout(dinfo); | 818 | bailout(dinfo); |
817 | 819 | ||
818 | /* Initialise dinfo and related data. */ | 820 | /* Initialise dinfo and related data. */ |
819 | /* If an initial mode was programmed at boot time, get its details. */ | 821 | /* If an initial mode was programmed at boot time, get its details. */ |
820 | if (ORIG_VIDEO_ISVGA == VIDEO_TYPE_VLFB) | 822 | if (ORIG_VIDEO_ISVGA == VIDEO_TYPE_VLFB) |
821 | get_initial_mode(dinfo); | 823 | get_initial_mode(dinfo); |
822 | 824 | ||
823 | if (bailearly == 3) | 825 | if (bailearly == 3) |
824 | bailout(dinfo); | 826 | bailout(dinfo); |
825 | 827 | ||
826 | if (FIXED_MODE(dinfo)) { | 828 | if (FIXED_MODE(dinfo)) { |
827 | /* remap fb address */ | 829 | /* remap fb address */ |
828 | update_dinfo(dinfo, &dinfo->initial_var); | 830 | update_dinfo(dinfo, &dinfo->initial_var); |
829 | } | 831 | } |
830 | 832 | ||
831 | if (bailearly == 4) | 833 | if (bailearly == 4) |
832 | bailout(dinfo); | 834 | bailout(dinfo); |
833 | 835 | ||
834 | 836 | ||
835 | if (intelfb_set_fbinfo(dinfo)) { | 837 | if (intelfb_set_fbinfo(dinfo)) { |
836 | cleanup(dinfo); | 838 | cleanup(dinfo); |
837 | return -ENODEV; | 839 | return -ENODEV; |
838 | } | 840 | } |
839 | 841 | ||
840 | if (bailearly == 5) | 842 | if (bailearly == 5) |
841 | bailout(dinfo); | 843 | bailout(dinfo); |
842 | 844 | ||
843 | if (bailearly == 6) | 845 | if (bailearly == 6) |
844 | bailout(dinfo); | 846 | bailout(dinfo); |
845 | 847 | ||
846 | pci_set_drvdata(pdev, dinfo); | 848 | pci_set_drvdata(pdev, dinfo); |
847 | 849 | ||
848 | /* Save the initial register state. */ | 850 | /* Save the initial register state. */ |
849 | i = intelfbhw_read_hw_state(dinfo, &dinfo->save_state, | 851 | i = intelfbhw_read_hw_state(dinfo, &dinfo->save_state, |
850 | bailearly > 6 ? bailearly - 6 : 0); | 852 | bailearly > 6 ? bailearly - 6 : 0); |
851 | if (i != 0) { | 853 | if (i != 0) { |
852 | DBG_MSG("intelfbhw_read_hw_state returned %d\n", i); | 854 | DBG_MSG("intelfbhw_read_hw_state returned %d\n", i); |
853 | bailout(dinfo); | 855 | bailout(dinfo); |
854 | } | 856 | } |
855 | 857 | ||
856 | intelfbhw_print_hw_state(dinfo, &dinfo->save_state); | 858 | intelfbhw_print_hw_state(dinfo, &dinfo->save_state); |
857 | 859 | ||
858 | if (bailearly == 18) | 860 | if (bailearly == 18) |
859 | bailout(dinfo); | 861 | bailout(dinfo); |
860 | 862 | ||
861 | /* Cursor initialisation */ | 863 | /* Cursor initialisation */ |
862 | if (dinfo->hwcursor) { | 864 | if (dinfo->hwcursor) { |
863 | intelfbhw_cursor_init(dinfo); | 865 | intelfbhw_cursor_init(dinfo); |
864 | intelfbhw_cursor_reset(dinfo); | 866 | intelfbhw_cursor_reset(dinfo); |
865 | } | 867 | } |
866 | 868 | ||
867 | if (bailearly == 19) | 869 | if (bailearly == 19) |
868 | bailout(dinfo); | 870 | bailout(dinfo); |
869 | 871 | ||
870 | /* 2d acceleration init */ | 872 | /* 2d acceleration init */ |
871 | if (dinfo->accel) | 873 | if (dinfo->accel) |
872 | intelfbhw_2d_start(dinfo); | 874 | intelfbhw_2d_start(dinfo); |
873 | 875 | ||
874 | if (bailearly == 20) | 876 | if (bailearly == 20) |
875 | bailout(dinfo); | 877 | bailout(dinfo); |
876 | 878 | ||
877 | if (noregister) | 879 | if (noregister) |
878 | bailout(dinfo); | 880 | bailout(dinfo); |
879 | 881 | ||
880 | if (register_framebuffer(dinfo->info) < 0) { | 882 | if (register_framebuffer(dinfo->info) < 0) { |
881 | ERR_MSG("Cannot register framebuffer.\n"); | 883 | ERR_MSG("Cannot register framebuffer.\n"); |
882 | cleanup(dinfo); | 884 | cleanup(dinfo); |
883 | return -ENODEV; | 885 | return -ENODEV; |
884 | } | 886 | } |
885 | 887 | ||
886 | dinfo->registered = 1; | 888 | dinfo->registered = 1; |
887 | 889 | ||
888 | return 0; | 890 | return 0; |
889 | 891 | ||
890 | err_out_pixmap: | 892 | err_out_pixmap: |
891 | fb_dealloc_cmap(&info->cmap); | 893 | fb_dealloc_cmap(&info->cmap); |
892 | err_out_cmap: | 894 | err_out_cmap: |
893 | framebuffer_release(info); | 895 | framebuffer_release(info); |
894 | return -ENODEV; | 896 | return -ENODEV; |
895 | } | 897 | } |
896 | 898 | ||
897 | static void __devexit | 899 | static void __devexit |
898 | intelfb_pci_unregister(struct pci_dev *pdev) | 900 | intelfb_pci_unregister(struct pci_dev *pdev) |
899 | { | 901 | { |
900 | struct intelfb_info *dinfo = pci_get_drvdata(pdev); | 902 | struct intelfb_info *dinfo = pci_get_drvdata(pdev); |
901 | 903 | ||
902 | DBG_MSG("intelfb_pci_unregister\n"); | 904 | DBG_MSG("intelfb_pci_unregister\n"); |
903 | 905 | ||
904 | if (!dinfo) | 906 | if (!dinfo) |
905 | return; | 907 | return; |
906 | 908 | ||
907 | cleanup(dinfo); | 909 | cleanup(dinfo); |
908 | 910 | ||
909 | pci_set_drvdata(pdev, NULL); | 911 | pci_set_drvdata(pdev, NULL); |
910 | } | 912 | } |
911 | 913 | ||
912 | /*************************************************************** | 914 | /*************************************************************** |
913 | * helper functions * | 915 | * helper functions * |
914 | ***************************************************************/ | 916 | ***************************************************************/ |
915 | 917 | ||
916 | int __inline__ | 918 | int __inline__ |
917 | intelfb_var_to_depth(const struct fb_var_screeninfo *var) | 919 | intelfb_var_to_depth(const struct fb_var_screeninfo *var) |
918 | { | 920 | { |
919 | DBG_MSG("intelfb_var_to_depth: bpp: %d, green.length is %d\n", | 921 | DBG_MSG("intelfb_var_to_depth: bpp: %d, green.length is %d\n", |
920 | var->bits_per_pixel, var->green.length); | 922 | var->bits_per_pixel, var->green.length); |
921 | 923 | ||
922 | switch (var->bits_per_pixel) { | 924 | switch (var->bits_per_pixel) { |
923 | case 16: | 925 | case 16: |
924 | return (var->green.length == 6) ? 16 : 15; | 926 | return (var->green.length == 6) ? 16 : 15; |
925 | case 32: | 927 | case 32: |
926 | return 24; | 928 | return 24; |
927 | default: | 929 | default: |
928 | return var->bits_per_pixel; | 930 | return var->bits_per_pixel; |
929 | } | 931 | } |
930 | } | 932 | } |
931 | 933 | ||
932 | 934 | ||
933 | static __inline__ int | 935 | static __inline__ int |
934 | var_to_refresh(const struct fb_var_screeninfo *var) | 936 | var_to_refresh(const struct fb_var_screeninfo *var) |
935 | { | 937 | { |
936 | int xtot = var->xres + var->left_margin + var->right_margin + | 938 | int xtot = var->xres + var->left_margin + var->right_margin + |
937 | var->hsync_len; | 939 | var->hsync_len; |
938 | int ytot = var->yres + var->upper_margin + var->lower_margin + | 940 | int ytot = var->yres + var->upper_margin + var->lower_margin + |
939 | var->vsync_len; | 941 | var->vsync_len; |
940 | 942 | ||
941 | return (1000000000 / var->pixclock * 1000 + 500) / xtot / ytot; | 943 | return (1000000000 / var->pixclock * 1000 + 500) / xtot / ytot; |
942 | } | 944 | } |
943 | 945 | ||
944 | /*************************************************************** | 946 | /*************************************************************** |
945 | * Various intialisation functions * | 947 | * Various intialisation functions * |
946 | ***************************************************************/ | 948 | ***************************************************************/ |
947 | 949 | ||
948 | static void __devinit | 950 | static void __devinit |
949 | get_initial_mode(struct intelfb_info *dinfo) | 951 | get_initial_mode(struct intelfb_info *dinfo) |
950 | { | 952 | { |
951 | struct fb_var_screeninfo *var; | 953 | struct fb_var_screeninfo *var; |
952 | int xtot, ytot; | 954 | int xtot, ytot; |
953 | 955 | ||
954 | DBG_MSG("get_initial_mode\n"); | 956 | DBG_MSG("get_initial_mode\n"); |
955 | 957 | ||
956 | dinfo->initial_vga = 1; | 958 | dinfo->initial_vga = 1; |
957 | dinfo->initial_fb_base = screen_info.lfb_base; | 959 | dinfo->initial_fb_base = screen_info.lfb_base; |
958 | dinfo->initial_video_ram = screen_info.lfb_size * KB(64); | 960 | dinfo->initial_video_ram = screen_info.lfb_size * KB(64); |
959 | dinfo->initial_pitch = screen_info.lfb_linelength; | 961 | dinfo->initial_pitch = screen_info.lfb_linelength; |
960 | 962 | ||
961 | var = &dinfo->initial_var; | 963 | var = &dinfo->initial_var; |
962 | memset(var, 0, sizeof(*var)); | 964 | memset(var, 0, sizeof(*var)); |
963 | var->xres = screen_info.lfb_width; | 965 | var->xres = screen_info.lfb_width; |
964 | var->yres = screen_info.lfb_height; | 966 | var->yres = screen_info.lfb_height; |
965 | var->bits_per_pixel = screen_info.lfb_depth; | 967 | var->bits_per_pixel = screen_info.lfb_depth; |
966 | switch (screen_info.lfb_depth) { | 968 | switch (screen_info.lfb_depth) { |
967 | case 15: | 969 | case 15: |
968 | var->bits_per_pixel = 16; | 970 | var->bits_per_pixel = 16; |
969 | break; | 971 | break; |
970 | case 24: | 972 | case 24: |
971 | var->bits_per_pixel = 32; | 973 | var->bits_per_pixel = 32; |
972 | break; | 974 | break; |
973 | } | 975 | } |
974 | 976 | ||
975 | DBG_MSG("Initial info: FB is 0x%x/0x%x (%d kByte)\n", | 977 | DBG_MSG("Initial info: FB is 0x%x/0x%x (%d kByte)\n", |
976 | dinfo->initial_fb_base, dinfo->initial_video_ram, | 978 | dinfo->initial_fb_base, dinfo->initial_video_ram, |
977 | BtoKB(dinfo->initial_video_ram)); | 979 | BtoKB(dinfo->initial_video_ram)); |
978 | 980 | ||
979 | DBG_MSG("Initial info: mode is %dx%d-%d (%d)\n", | 981 | DBG_MSG("Initial info: mode is %dx%d-%d (%d)\n", |
980 | var->xres, var->yres, var->bits_per_pixel, | 982 | var->xres, var->yres, var->bits_per_pixel, |
981 | dinfo->initial_pitch); | 983 | dinfo->initial_pitch); |
982 | 984 | ||
983 | /* Dummy timing values (assume 60Hz) */ | 985 | /* Dummy timing values (assume 60Hz) */ |
984 | var->left_margin = (var->xres / 8) & 0xf8; | 986 | var->left_margin = (var->xres / 8) & 0xf8; |
985 | var->right_margin = 32; | 987 | var->right_margin = 32; |
986 | var->upper_margin = 16; | 988 | var->upper_margin = 16; |
987 | var->lower_margin = 4; | 989 | var->lower_margin = 4; |
988 | var->hsync_len = (var->xres / 8) & 0xf8; | 990 | var->hsync_len = (var->xres / 8) & 0xf8; |
989 | var->vsync_len = 4; | 991 | var->vsync_len = 4; |
990 | 992 | ||
991 | xtot = var->xres + var->left_margin + | 993 | xtot = var->xres + var->left_margin + |
992 | var->right_margin + var->hsync_len; | 994 | var->right_margin + var->hsync_len; |
993 | ytot = var->yres + var->upper_margin + | 995 | ytot = var->yres + var->upper_margin + |
994 | var->lower_margin + var->vsync_len; | 996 | var->lower_margin + var->vsync_len; |
995 | var->pixclock = 10000000 / xtot * 1000 / ytot * 100 / 60; | 997 | var->pixclock = 10000000 / xtot * 1000 / ytot * 100 / 60; |
996 | 998 | ||
997 | var->height = -1; | 999 | var->height = -1; |
998 | var->width = -1; | 1000 | var->width = -1; |
999 | 1001 | ||
1000 | if (var->bits_per_pixel > 8) { | 1002 | if (var->bits_per_pixel > 8) { |
1001 | var->red.offset = screen_info.red_pos; | 1003 | var->red.offset = screen_info.red_pos; |
1002 | var->red.length = screen_info.red_size; | 1004 | var->red.length = screen_info.red_size; |
1003 | var->green.offset = screen_info.green_pos; | 1005 | var->green.offset = screen_info.green_pos; |
1004 | var->green.length = screen_info.green_size; | 1006 | var->green.length = screen_info.green_size; |
1005 | var->blue.offset = screen_info.blue_pos; | 1007 | var->blue.offset = screen_info.blue_pos; |
1006 | var->blue.length = screen_info.blue_size; | 1008 | var->blue.length = screen_info.blue_size; |
1007 | var->transp.offset = screen_info.rsvd_pos; | 1009 | var->transp.offset = screen_info.rsvd_pos; |
1008 | var->transp.length = screen_info.rsvd_size; | 1010 | var->transp.length = screen_info.rsvd_size; |
1009 | } else { | 1011 | } else { |
1010 | var->red.length = 8; | 1012 | var->red.length = 8; |
1011 | var->green.length = 8; | 1013 | var->green.length = 8; |
1012 | var->blue.length = 8; | 1014 | var->blue.length = 8; |
1013 | } | 1015 | } |
1014 | } | 1016 | } |
1015 | 1017 | ||
1016 | static int __devinit | 1018 | static int __devinit |
1017 | intelfb_init_var(struct intelfb_info *dinfo) | 1019 | intelfb_init_var(struct intelfb_info *dinfo) |
1018 | { | 1020 | { |
1019 | struct fb_var_screeninfo *var; | 1021 | struct fb_var_screeninfo *var; |
1020 | int msrc = 0; | 1022 | int msrc = 0; |
1021 | 1023 | ||
1022 | DBG_MSG("intelfb_init_var\n"); | 1024 | DBG_MSG("intelfb_init_var\n"); |
1023 | 1025 | ||
1024 | var = &dinfo->info->var; | 1026 | var = &dinfo->info->var; |
1025 | if (FIXED_MODE(dinfo)) { | 1027 | if (FIXED_MODE(dinfo)) { |
1026 | memcpy(var, &dinfo->initial_var, | 1028 | memcpy(var, &dinfo->initial_var, |
1027 | sizeof(struct fb_var_screeninfo)); | 1029 | sizeof(struct fb_var_screeninfo)); |
1028 | msrc = 5; | 1030 | msrc = 5; |
1029 | } else { | 1031 | } else { |
1030 | if (mode) { | 1032 | if (mode) { |
1031 | msrc = fb_find_mode(var, dinfo->info, mode, | 1033 | msrc = fb_find_mode(var, dinfo->info, mode, |
1032 | vesa_modes, VESA_MODEDB_SIZE, | 1034 | vesa_modes, VESA_MODEDB_SIZE, |
1033 | NULL, 0); | 1035 | NULL, 0); |
1034 | if (msrc) | 1036 | if (msrc) |
1035 | msrc |= 8; | 1037 | msrc |= 8; |
1036 | } | 1038 | } |
1037 | if (!msrc) { | 1039 | if (!msrc) { |
1038 | msrc = fb_find_mode(var, dinfo->info, PREFERRED_MODE, | 1040 | msrc = fb_find_mode(var, dinfo->info, PREFERRED_MODE, |
1039 | vesa_modes, VESA_MODEDB_SIZE, | 1041 | vesa_modes, VESA_MODEDB_SIZE, |
1040 | NULL, 0); | 1042 | NULL, 0); |
1041 | } | 1043 | } |
1042 | } | 1044 | } |
1043 | 1045 | ||
1044 | if (!msrc) { | 1046 | if (!msrc) { |
1045 | ERR_MSG("Cannot find a suitable video mode.\n"); | 1047 | ERR_MSG("Cannot find a suitable video mode.\n"); |
1046 | return 1; | 1048 | return 1; |
1047 | } | 1049 | } |
1048 | 1050 | ||
1049 | INF_MSG("Initial video mode is %dx%d-%d@%d.\n", var->xres, var->yres, | 1051 | INF_MSG("Initial video mode is %dx%d-%d@%d.\n", var->xres, var->yres, |
1050 | var->bits_per_pixel, var_to_refresh(var)); | 1052 | var->bits_per_pixel, var_to_refresh(var)); |
1051 | 1053 | ||
1052 | DBG_MSG("Initial video mode is from %d.\n", msrc); | 1054 | DBG_MSG("Initial video mode is from %d.\n", msrc); |
1053 | 1055 | ||
1054 | #if ALLOCATE_FOR_PANNING | 1056 | #if ALLOCATE_FOR_PANNING |
1055 | /* Allow use of half of the video ram for panning */ | 1057 | /* Allow use of half of the video ram for panning */ |
1056 | var->xres_virtual = var->xres; | 1058 | var->xres_virtual = var->xres; |
1057 | var->yres_virtual = | 1059 | var->yres_virtual = |
1058 | dinfo->fb.size / 2 / (var->bits_per_pixel * var->xres); | 1060 | dinfo->fb.size / 2 / (var->bits_per_pixel * var->xres); |
1059 | if (var->yres_virtual < var->yres) | 1061 | if (var->yres_virtual < var->yres) |
1060 | var->yres_virtual = var->yres; | 1062 | var->yres_virtual = var->yres; |
1061 | #else | 1063 | #else |
1062 | var->yres_virtual = var->yres; | 1064 | var->yres_virtual = var->yres; |
1063 | #endif | 1065 | #endif |
1064 | 1066 | ||
1065 | if (dinfo->accel) | 1067 | if (dinfo->accel) |
1066 | var->accel_flags |= FB_ACCELF_TEXT; | 1068 | var->accel_flags |= FB_ACCELF_TEXT; |
1067 | else | 1069 | else |
1068 | var->accel_flags &= ~FB_ACCELF_TEXT; | 1070 | var->accel_flags &= ~FB_ACCELF_TEXT; |
1069 | 1071 | ||
1070 | return 0; | 1072 | return 0; |
1071 | } | 1073 | } |
1072 | 1074 | ||
1073 | static int __devinit | 1075 | static int __devinit |
1074 | intelfb_set_fbinfo(struct intelfb_info *dinfo) | 1076 | intelfb_set_fbinfo(struct intelfb_info *dinfo) |
1075 | { | 1077 | { |
1076 | struct fb_info *info = dinfo->info; | 1078 | struct fb_info *info = dinfo->info; |
1077 | 1079 | ||
1078 | DBG_MSG("intelfb_set_fbinfo\n"); | 1080 | DBG_MSG("intelfb_set_fbinfo\n"); |
1079 | 1081 | ||
1080 | info->flags = FBINFO_FLAG_DEFAULT; | 1082 | info->flags = FBINFO_FLAG_DEFAULT; |
1081 | info->fbops = &intel_fb_ops; | 1083 | info->fbops = &intel_fb_ops; |
1082 | info->pseudo_palette = dinfo->pseudo_palette; | 1084 | info->pseudo_palette = dinfo->pseudo_palette; |
1083 | 1085 | ||
1084 | info->pixmap.size = 64*1024; | 1086 | info->pixmap.size = 64*1024; |
1085 | info->pixmap.buf_align = 8; | 1087 | info->pixmap.buf_align = 8; |
1086 | info->pixmap.access_align = 32; | 1088 | info->pixmap.access_align = 32; |
1087 | info->pixmap.flags = FB_PIXMAP_SYSTEM; | 1089 | info->pixmap.flags = FB_PIXMAP_SYSTEM; |
1088 | 1090 | ||
1089 | if (intelfb_init_var(dinfo)) | 1091 | if (intelfb_init_var(dinfo)) |
1090 | return 1; | 1092 | return 1; |
1091 | 1093 | ||
1092 | info->pixmap.scan_align = 1; | 1094 | info->pixmap.scan_align = 1; |
1093 | 1095 | ||
1094 | update_dinfo(dinfo, &info->var); | 1096 | update_dinfo(dinfo, &info->var); |
1095 | 1097 | ||
1096 | return 0; | 1098 | return 0; |
1097 | } | 1099 | } |
1098 | 1100 | ||
1099 | /* Update dinfo to match the active video mode. */ | 1101 | /* Update dinfo to match the active video mode. */ |
1100 | static void | 1102 | static void |
1101 | update_dinfo(struct intelfb_info *dinfo, struct fb_var_screeninfo *var) | 1103 | update_dinfo(struct intelfb_info *dinfo, struct fb_var_screeninfo *var) |
1102 | { | 1104 | { |
1103 | DBG_MSG("update_dinfo\n"); | 1105 | DBG_MSG("update_dinfo\n"); |
1104 | 1106 | ||
1105 | dinfo->bpp = var->bits_per_pixel; | 1107 | dinfo->bpp = var->bits_per_pixel; |
1106 | dinfo->depth = intelfb_var_to_depth(var); | 1108 | dinfo->depth = intelfb_var_to_depth(var); |
1107 | dinfo->xres = var->xres; | 1109 | dinfo->xres = var->xres; |
1108 | dinfo->yres = var->xres; | 1110 | dinfo->yres = var->xres; |
1109 | dinfo->pixclock = var->pixclock; | 1111 | dinfo->pixclock = var->pixclock; |
1110 | 1112 | ||
1111 | intelfb_get_fix(&dinfo->info->fix, dinfo->info); | 1113 | intelfb_get_fix(&dinfo->info->fix, dinfo->info); |
1112 | 1114 | ||
1113 | switch (dinfo->bpp) { | 1115 | switch (dinfo->bpp) { |
1114 | case 8: | 1116 | case 8: |
1115 | dinfo->visual = FB_VISUAL_PSEUDOCOLOR; | 1117 | dinfo->visual = FB_VISUAL_PSEUDOCOLOR; |
1116 | dinfo->pitch = var->xres_virtual; | 1118 | dinfo->pitch = var->xres_virtual; |
1117 | break; | 1119 | break; |
1118 | case 16: | 1120 | case 16: |
1119 | dinfo->visual = FB_VISUAL_TRUECOLOR; | 1121 | dinfo->visual = FB_VISUAL_TRUECOLOR; |
1120 | dinfo->pitch = var->xres_virtual * 2; | 1122 | dinfo->pitch = var->xres_virtual * 2; |
1121 | break; | 1123 | break; |
1122 | case 32: | 1124 | case 32: |
1123 | dinfo->visual = FB_VISUAL_TRUECOLOR; | 1125 | dinfo->visual = FB_VISUAL_TRUECOLOR; |
1124 | dinfo->pitch = var->xres_virtual * 4; | 1126 | dinfo->pitch = var->xres_virtual * 4; |
1125 | break; | 1127 | break; |
1126 | } | 1128 | } |
1127 | 1129 | ||
1128 | /* Make sure the line length is a aligned correctly. */ | 1130 | /* Make sure the line length is a aligned correctly. */ |
1129 | dinfo->pitch = ROUND_UP_TO(dinfo->pitch, STRIDE_ALIGNMENT); | 1131 | dinfo->pitch = ROUND_UP_TO(dinfo->pitch, STRIDE_ALIGNMENT); |
1130 | 1132 | ||
1131 | if (FIXED_MODE(dinfo)) | 1133 | if (FIXED_MODE(dinfo)) |
1132 | dinfo->pitch = dinfo->initial_pitch; | 1134 | dinfo->pitch = dinfo->initial_pitch; |
1133 | 1135 | ||
1134 | dinfo->info->screen_base = (char __iomem *)dinfo->fb.virtual; | 1136 | dinfo->info->screen_base = (char __iomem *)dinfo->fb.virtual; |
1135 | dinfo->info->fix.line_length = dinfo->pitch; | 1137 | dinfo->info->fix.line_length = dinfo->pitch; |
1136 | dinfo->info->fix.visual = dinfo->visual; | 1138 | dinfo->info->fix.visual = dinfo->visual; |
1137 | } | 1139 | } |
1138 | 1140 | ||
1139 | /* fbops functions */ | 1141 | /* fbops functions */ |
1140 | 1142 | ||
1141 | static int | 1143 | static int |
1142 | intelfb_get_fix(struct fb_fix_screeninfo *fix, struct fb_info *info) | 1144 | intelfb_get_fix(struct fb_fix_screeninfo *fix, struct fb_info *info) |
1143 | { | 1145 | { |
1144 | struct intelfb_info *dinfo = GET_DINFO(info); | 1146 | struct intelfb_info *dinfo = GET_DINFO(info); |
1145 | 1147 | ||
1146 | DBG_MSG("intelfb_get_fix\n"); | 1148 | DBG_MSG("intelfb_get_fix\n"); |
1147 | 1149 | ||
1148 | memset(fix, 0, sizeof(*fix)); | 1150 | memset(fix, 0, sizeof(*fix)); |
1149 | strcpy(fix->id, dinfo->name); | 1151 | strcpy(fix->id, dinfo->name); |
1150 | fix->smem_start = dinfo->fb.physical; | 1152 | fix->smem_start = dinfo->fb.physical; |
1151 | fix->smem_len = dinfo->fb.size; | 1153 | fix->smem_len = dinfo->fb.size; |
1152 | fix->type = FB_TYPE_PACKED_PIXELS; | 1154 | fix->type = FB_TYPE_PACKED_PIXELS; |
1153 | fix->type_aux = 0; | 1155 | fix->type_aux = 0; |
1154 | fix->visual = dinfo->visual; | 1156 | fix->visual = dinfo->visual; |
1155 | fix->xpanstep = 8; | 1157 | fix->xpanstep = 8; |
1156 | fix->ypanstep = 1; | 1158 | fix->ypanstep = 1; |
1157 | fix->ywrapstep = 0; | 1159 | fix->ywrapstep = 0; |
1158 | fix->line_length = dinfo->pitch; | 1160 | fix->line_length = dinfo->pitch; |
1159 | fix->mmio_start = dinfo->mmio_base_phys; | 1161 | fix->mmio_start = dinfo->mmio_base_phys; |
1160 | fix->mmio_len = INTEL_REG_SIZE; | 1162 | fix->mmio_len = INTEL_REG_SIZE; |
1161 | fix->accel = FB_ACCEL_I830; | 1163 | fix->accel = FB_ACCEL_I830; |
1162 | return 0; | 1164 | return 0; |
1163 | } | 1165 | } |
1164 | 1166 | ||
1165 | /*************************************************************** | 1167 | /*************************************************************** |
1166 | * fbdev interface * | 1168 | * fbdev interface * |
1167 | ***************************************************************/ | 1169 | ***************************************************************/ |
1168 | 1170 | ||
1169 | static int | 1171 | static int |
1170 | intelfb_check_var(struct fb_var_screeninfo *var, struct fb_info *info) | 1172 | intelfb_check_var(struct fb_var_screeninfo *var, struct fb_info *info) |
1171 | { | 1173 | { |
1172 | int change_var = 0; | 1174 | int change_var = 0; |
1173 | struct fb_var_screeninfo v; | 1175 | struct fb_var_screeninfo v; |
1174 | struct intelfb_info *dinfo; | 1176 | struct intelfb_info *dinfo; |
1175 | static int first = 1; | 1177 | static int first = 1; |
1176 | 1178 | ||
1177 | DBG_MSG("intelfb_check_var: accel_flags is %d\n", var->accel_flags); | 1179 | DBG_MSG("intelfb_check_var: accel_flags is %d\n", var->accel_flags); |
1178 | 1180 | ||
1179 | dinfo = GET_DINFO(info); | 1181 | dinfo = GET_DINFO(info); |
1180 | 1182 | ||
1181 | if (intelfbhw_validate_mode(dinfo, var) != 0) | 1183 | if (intelfbhw_validate_mode(dinfo, var) != 0) |
1182 | return -EINVAL; | 1184 | return -EINVAL; |
1183 | 1185 | ||
1184 | v = *var; | 1186 | v = *var; |
1185 | 1187 | ||
1186 | /* Check for a supported bpp. */ | 1188 | /* Check for a supported bpp. */ |
1187 | if (v.bits_per_pixel <= 8) { | 1189 | if (v.bits_per_pixel <= 8) { |
1188 | v.bits_per_pixel = 8; | 1190 | v.bits_per_pixel = 8; |
1189 | } else if (v.bits_per_pixel <= 16) { | 1191 | } else if (v.bits_per_pixel <= 16) { |
1190 | if (v.bits_per_pixel == 16) | 1192 | if (v.bits_per_pixel == 16) |
1191 | v.green.length = 6; | 1193 | v.green.length = 6; |
1192 | v.bits_per_pixel = 16; | 1194 | v.bits_per_pixel = 16; |
1193 | } else if (v.bits_per_pixel <= 32) { | 1195 | } else if (v.bits_per_pixel <= 32) { |
1194 | v.bits_per_pixel = 32; | 1196 | v.bits_per_pixel = 32; |
1195 | } else | 1197 | } else |
1196 | return -EINVAL; | 1198 | return -EINVAL; |
1197 | 1199 | ||
1198 | change_var = ((info->var.xres != var->xres) || | 1200 | change_var = ((info->var.xres != var->xres) || |
1199 | (info->var.yres != var->yres) || | 1201 | (info->var.yres != var->yres) || |
1200 | (info->var.xres_virtual != var->xres_virtual) || | 1202 | (info->var.xres_virtual != var->xres_virtual) || |
1201 | (info->var.yres_virtual != var->yres_virtual) || | 1203 | (info->var.yres_virtual != var->yres_virtual) || |
1202 | (info->var.bits_per_pixel != var->bits_per_pixel) || | 1204 | (info->var.bits_per_pixel != var->bits_per_pixel) || |
1203 | memcmp(&info->var.red, &var->red, sizeof(var->red)) || | 1205 | memcmp(&info->var.red, &var->red, sizeof(var->red)) || |
1204 | memcmp(&info->var.green, &var->green, | 1206 | memcmp(&info->var.green, &var->green, |
1205 | sizeof(var->green)) || | 1207 | sizeof(var->green)) || |
1206 | memcmp(&info->var.blue, &var->blue, sizeof(var->blue))); | 1208 | memcmp(&info->var.blue, &var->blue, sizeof(var->blue))); |
1207 | 1209 | ||
1208 | if (FIXED_MODE(dinfo) && | 1210 | if (FIXED_MODE(dinfo) && |
1209 | (change_var || | 1211 | (change_var || |
1210 | var->yres_virtual > dinfo->initial_var.yres_virtual || | 1212 | var->yres_virtual > dinfo->initial_var.yres_virtual || |
1211 | var->yres_virtual < dinfo->initial_var.yres || | 1213 | var->yres_virtual < dinfo->initial_var.yres || |
1212 | var->xoffset || var->nonstd)) { | 1214 | var->xoffset || var->nonstd)) { |
1213 | if (first) { | 1215 | if (first) { |
1214 | ERR_MSG("Changing the video mode is not supported.\n"); | 1216 | ERR_MSG("Changing the video mode is not supported.\n"); |
1215 | first = 0; | 1217 | first = 0; |
1216 | } | 1218 | } |
1217 | return -EINVAL; | 1219 | return -EINVAL; |
1218 | } | 1220 | } |
1219 | 1221 | ||
1220 | switch (intelfb_var_to_depth(&v)) { | 1222 | switch (intelfb_var_to_depth(&v)) { |
1221 | case 8: | 1223 | case 8: |
1222 | v.red.offset = v.green.offset = v.blue.offset = 0; | 1224 | v.red.offset = v.green.offset = v.blue.offset = 0; |
1223 | v.red.length = v.green.length = v.blue.length = 8; | 1225 | v.red.length = v.green.length = v.blue.length = 8; |
1224 | v.transp.offset = v.transp.length = 0; | 1226 | v.transp.offset = v.transp.length = 0; |
1225 | break; | 1227 | break; |
1226 | case 15: | 1228 | case 15: |
1227 | v.red.offset = 10; | 1229 | v.red.offset = 10; |
1228 | v.green.offset = 5; | 1230 | v.green.offset = 5; |
1229 | v.blue.offset = 0; | 1231 | v.blue.offset = 0; |
1230 | v.red.length = v.green.length = v.blue.length = 5; | 1232 | v.red.length = v.green.length = v.blue.length = 5; |
1231 | v.transp.offset = v.transp.length = 0; | 1233 | v.transp.offset = v.transp.length = 0; |
1232 | break; | 1234 | break; |
1233 | case 16: | 1235 | case 16: |
1234 | v.red.offset = 11; | 1236 | v.red.offset = 11; |
1235 | v.green.offset = 5; | 1237 | v.green.offset = 5; |
1236 | v.blue.offset = 0; | 1238 | v.blue.offset = 0; |
1237 | v.red.length = 5; | 1239 | v.red.length = 5; |
1238 | v.green.length = 6; | 1240 | v.green.length = 6; |
1239 | v.blue.length = 5; | 1241 | v.blue.length = 5; |
1240 | v.transp.offset = v.transp.length = 0; | 1242 | v.transp.offset = v.transp.length = 0; |
1241 | break; | 1243 | break; |
1242 | case 24: | 1244 | case 24: |
1243 | v.red.offset = 16; | 1245 | v.red.offset = 16; |
1244 | v.green.offset = 8; | 1246 | v.green.offset = 8; |
1245 | v.blue.offset = 0; | 1247 | v.blue.offset = 0; |
1246 | v.red.length = v.green.length = v.blue.length = 8; | 1248 | v.red.length = v.green.length = v.blue.length = 8; |
1247 | v.transp.offset = v.transp.length = 0; | 1249 | v.transp.offset = v.transp.length = 0; |
1248 | break; | 1250 | break; |
1249 | case 32: | 1251 | case 32: |
1250 | v.red.offset = 16; | 1252 | v.red.offset = 16; |
1251 | v.green.offset = 8; | 1253 | v.green.offset = 8; |
1252 | v.blue.offset = 0; | 1254 | v.blue.offset = 0; |
1253 | v.red.length = v.green.length = v.blue.length = 8; | 1255 | v.red.length = v.green.length = v.blue.length = 8; |
1254 | v.transp.offset = 24; | 1256 | v.transp.offset = 24; |
1255 | v.transp.length = 8; | 1257 | v.transp.length = 8; |
1256 | break; | 1258 | break; |
1257 | } | 1259 | } |
1258 | 1260 | ||
1259 | if (v.xoffset < 0) | 1261 | if (v.xoffset < 0) |
1260 | v.xoffset = 0; | 1262 | v.xoffset = 0; |
1261 | if (v.yoffset < 0) | 1263 | if (v.yoffset < 0) |
1262 | v.yoffset = 0; | 1264 | v.yoffset = 0; |
1263 | 1265 | ||
1264 | if (v.xoffset > v.xres_virtual - v.xres) | 1266 | if (v.xoffset > v.xres_virtual - v.xres) |
1265 | v.xoffset = v.xres_virtual - v.xres; | 1267 | v.xoffset = v.xres_virtual - v.xres; |
1266 | if (v.yoffset > v.yres_virtual - v.yres) | 1268 | if (v.yoffset > v.yres_virtual - v.yres) |
1267 | v.yoffset = v.yres_virtual - v.yres; | 1269 | v.yoffset = v.yres_virtual - v.yres; |
1268 | 1270 | ||
1269 | v.red.msb_right = v.green.msb_right = v.blue.msb_right = | 1271 | v.red.msb_right = v.green.msb_right = v.blue.msb_right = |
1270 | v.transp.msb_right = 0; | 1272 | v.transp.msb_right = 0; |
1271 | 1273 | ||
1272 | *var = v; | 1274 | *var = v; |
1273 | 1275 | ||
1274 | return 0; | 1276 | return 0; |
1275 | } | 1277 | } |
1276 | 1278 | ||
1277 | static int | 1279 | static int |
1278 | intelfb_set_par(struct fb_info *info) | 1280 | intelfb_set_par(struct fb_info *info) |
1279 | { | 1281 | { |
1280 | struct intelfb_hwstate *hw; | 1282 | struct intelfb_hwstate *hw; |
1281 | struct intelfb_info *dinfo = GET_DINFO(info); | 1283 | struct intelfb_info *dinfo = GET_DINFO(info); |
1282 | 1284 | ||
1283 | if (FIXED_MODE(dinfo)) { | 1285 | if (FIXED_MODE(dinfo)) { |
1284 | ERR_MSG("Changing the video mode is not supported.\n"); | 1286 | ERR_MSG("Changing the video mode is not supported.\n"); |
1285 | return -EINVAL; | 1287 | return -EINVAL; |
1286 | } | 1288 | } |
1287 | 1289 | ||
1288 | hw = kmalloc(sizeof(*hw), GFP_ATOMIC); | 1290 | hw = kmalloc(sizeof(*hw), GFP_ATOMIC); |
1289 | if (!hw) | 1291 | if (!hw) |
1290 | return -ENOMEM; | 1292 | return -ENOMEM; |
1291 | 1293 | ||
1292 | DBG_MSG("intelfb_set_par (%dx%d-%d)\n", info->var.xres, | 1294 | DBG_MSG("intelfb_set_par (%dx%d-%d)\n", info->var.xres, |
1293 | info->var.yres, info->var.bits_per_pixel); | 1295 | info->var.yres, info->var.bits_per_pixel); |
1294 | 1296 | ||
1295 | intelfb_blank(FB_BLANK_POWERDOWN, info); | 1297 | intelfb_blank(FB_BLANK_POWERDOWN, info); |
1296 | 1298 | ||
1297 | if (ACCEL(dinfo, info)) | 1299 | if (ACCEL(dinfo, info)) |
1298 | intelfbhw_2d_stop(dinfo); | 1300 | intelfbhw_2d_stop(dinfo); |
1299 | 1301 | ||
1300 | memcpy(hw, &dinfo->save_state, sizeof(*hw)); | 1302 | memcpy(hw, &dinfo->save_state, sizeof(*hw)); |
1301 | if (intelfbhw_mode_to_hw(dinfo, hw, &info->var)) | 1303 | if (intelfbhw_mode_to_hw(dinfo, hw, &info->var)) |
1302 | goto invalid_mode; | 1304 | goto invalid_mode; |
1303 | if (intelfbhw_program_mode(dinfo, hw, 0)) | 1305 | if (intelfbhw_program_mode(dinfo, hw, 0)) |
1304 | goto invalid_mode; | 1306 | goto invalid_mode; |
1305 | 1307 | ||
1306 | #if REGDUMP > 0 | 1308 | #if REGDUMP > 0 |
1307 | intelfbhw_read_hw_state(dinfo, hw, 0); | 1309 | intelfbhw_read_hw_state(dinfo, hw, 0); |
1308 | intelfbhw_print_hw_state(dinfo, hw); | 1310 | intelfbhw_print_hw_state(dinfo, hw); |
1309 | #endif | 1311 | #endif |
1310 | 1312 | ||
1311 | update_dinfo(dinfo, &info->var); | 1313 | update_dinfo(dinfo, &info->var); |
1312 | 1314 | ||
1313 | if (ACCEL(dinfo, info)) | 1315 | if (ACCEL(dinfo, info)) |
1314 | intelfbhw_2d_start(dinfo); | 1316 | intelfbhw_2d_start(dinfo); |
1315 | 1317 | ||
1316 | intelfb_pan_display(&info->var, info); | 1318 | intelfb_pan_display(&info->var, info); |
1317 | 1319 | ||
1318 | intelfb_blank(FB_BLANK_UNBLANK, info); | 1320 | intelfb_blank(FB_BLANK_UNBLANK, info); |
1319 | 1321 | ||
1320 | if (ACCEL(dinfo, info)) { | 1322 | if (ACCEL(dinfo, info)) { |
1321 | info->flags = FBINFO_DEFAULT | FBINFO_HWACCEL_YPAN | | 1323 | info->flags = FBINFO_DEFAULT | FBINFO_HWACCEL_YPAN | |
1322 | FBINFO_HWACCEL_COPYAREA | FBINFO_HWACCEL_FILLRECT | | 1324 | FBINFO_HWACCEL_COPYAREA | FBINFO_HWACCEL_FILLRECT | |
1323 | FBINFO_HWACCEL_IMAGEBLIT; | 1325 | FBINFO_HWACCEL_IMAGEBLIT; |
1324 | } else { | 1326 | } else { |
1325 | info->flags = FBINFO_DEFAULT | FBINFO_HWACCEL_YPAN; | 1327 | info->flags = FBINFO_DEFAULT | FBINFO_HWACCEL_YPAN; |
1326 | } | 1328 | } |
1327 | kfree(hw); | 1329 | kfree(hw); |
1328 | return 0; | 1330 | return 0; |
1329 | invalid_mode: | 1331 | invalid_mode: |
1330 | kfree(hw); | 1332 | kfree(hw); |
1331 | return -EINVAL; | 1333 | return -EINVAL; |
1332 | } | 1334 | } |
1333 | 1335 | ||
1334 | static int | 1336 | static int |
1335 | intelfb_setcolreg(unsigned regno, unsigned red, unsigned green, | 1337 | intelfb_setcolreg(unsigned regno, unsigned red, unsigned green, |
1336 | unsigned blue, unsigned transp, struct fb_info *info) | 1338 | unsigned blue, unsigned transp, struct fb_info *info) |
1337 | { | 1339 | { |
1338 | struct intelfb_info *dinfo = GET_DINFO(info); | 1340 | struct intelfb_info *dinfo = GET_DINFO(info); |
1339 | 1341 | ||
1340 | #if VERBOSE > 0 | 1342 | #if VERBOSE > 0 |
1341 | DBG_MSG("intelfb_setcolreg: regno %d, depth %d\n", regno, dinfo->depth); | 1343 | DBG_MSG("intelfb_setcolreg: regno %d, depth %d\n", regno, dinfo->depth); |
1342 | #endif | 1344 | #endif |
1343 | 1345 | ||
1344 | if (regno > 255) | 1346 | if (regno > 255) |
1345 | return 1; | 1347 | return 1; |
1346 | 1348 | ||
1347 | switch (dinfo->depth) { | 1349 | switch (dinfo->depth) { |
1348 | case 8: | 1350 | case 8: |
1349 | { | 1351 | { |
1350 | red >>= 8; | 1352 | red >>= 8; |
1351 | green >>= 8; | 1353 | green >>= 8; |
1352 | blue >>= 8; | 1354 | blue >>= 8; |
1353 | 1355 | ||
1354 | intelfbhw_setcolreg(dinfo, regno, red, green, blue, | 1356 | intelfbhw_setcolreg(dinfo, regno, red, green, blue, |
1355 | transp); | 1357 | transp); |
1356 | } | 1358 | } |
1357 | break; | 1359 | break; |
1358 | case 15: | 1360 | case 15: |
1359 | dinfo->pseudo_palette[regno] = ((red & 0xf800) >> 1) | | 1361 | dinfo->pseudo_palette[regno] = ((red & 0xf800) >> 1) | |
1360 | ((green & 0xf800) >> 6) | | 1362 | ((green & 0xf800) >> 6) | |
1361 | ((blue & 0xf800) >> 11); | 1363 | ((blue & 0xf800) >> 11); |
1362 | break; | 1364 | break; |
1363 | case 16: | 1365 | case 16: |
1364 | dinfo->pseudo_palette[regno] = (red & 0xf800) | | 1366 | dinfo->pseudo_palette[regno] = (red & 0xf800) | |
1365 | ((green & 0xfc00) >> 5) | | 1367 | ((green & 0xfc00) >> 5) | |
1366 | ((blue & 0xf800) >> 11); | 1368 | ((blue & 0xf800) >> 11); |
1367 | break; | 1369 | break; |
1368 | case 24: | 1370 | case 24: |
1369 | dinfo->pseudo_palette[regno] = ((red & 0xff00) << 8) | | 1371 | dinfo->pseudo_palette[regno] = ((red & 0xff00) << 8) | |
1370 | (green & 0xff00) | | 1372 | (green & 0xff00) | |
1371 | ((blue & 0xff00) >> 8); | 1373 | ((blue & 0xff00) >> 8); |
1372 | break; | 1374 | break; |
1373 | } | 1375 | } |
1374 | return 0; | 1376 | return 0; |
1375 | } | 1377 | } |
1376 | 1378 | ||
1377 | static int | 1379 | static int |
1378 | intelfb_blank(int blank, struct fb_info *info) | 1380 | intelfb_blank(int blank, struct fb_info *info) |
1379 | { | 1381 | { |
1380 | intelfbhw_do_blank(blank, info); | 1382 | intelfbhw_do_blank(blank, info); |
1381 | return 0; | 1383 | return 0; |
1382 | } | 1384 | } |
1383 | 1385 | ||
1384 | static int | 1386 | static int |
1385 | intelfb_pan_display(struct fb_var_screeninfo *var, struct fb_info *info) | 1387 | intelfb_pan_display(struct fb_var_screeninfo *var, struct fb_info *info) |
1386 | { | 1388 | { |
1387 | intelfbhw_pan_display(var, info); | 1389 | intelfbhw_pan_display(var, info); |
1388 | return 0; | 1390 | return 0; |
1389 | } | 1391 | } |
1390 | 1392 | ||
1391 | /* When/if we have our own ioctls. */ | 1393 | /* When/if we have our own ioctls. */ |
1392 | static int | 1394 | static int |
1393 | intelfb_ioctl(struct inode *inode, struct file *file, unsigned int cmd, | 1395 | intelfb_ioctl(struct inode *inode, struct file *file, unsigned int cmd, |
1394 | unsigned long arg, struct fb_info *info) | 1396 | unsigned long arg, struct fb_info *info) |
1395 | { | 1397 | { |
1396 | int retval = 0; | 1398 | int retval = 0; |
1397 | 1399 | ||
1398 | return retval; | 1400 | return retval; |
1399 | } | 1401 | } |
1400 | 1402 | ||
1401 | static void | 1403 | static void |
1402 | intelfb_fillrect (struct fb_info *info, const struct fb_fillrect *rect) | 1404 | intelfb_fillrect (struct fb_info *info, const struct fb_fillrect *rect) |
1403 | { | 1405 | { |
1404 | struct intelfb_info *dinfo = GET_DINFO(info); | 1406 | struct intelfb_info *dinfo = GET_DINFO(info); |
1405 | u32 rop, color; | 1407 | u32 rop, color; |
1406 | 1408 | ||
1407 | #if VERBOSE > 0 | 1409 | #if VERBOSE > 0 |
1408 | DBG_MSG("intelfb_fillrect\n"); | 1410 | DBG_MSG("intelfb_fillrect\n"); |
1409 | #endif | 1411 | #endif |
1410 | 1412 | ||
1411 | if (!ACCEL(dinfo, info) || dinfo->depth == 4) | 1413 | if (!ACCEL(dinfo, info) || dinfo->depth == 4) |
1412 | return cfb_fillrect(info, rect); | 1414 | return cfb_fillrect(info, rect); |
1413 | 1415 | ||
1414 | if (rect->rop == ROP_COPY) | 1416 | if (rect->rop == ROP_COPY) |
1415 | rop = PAT_ROP_GXCOPY; | 1417 | rop = PAT_ROP_GXCOPY; |
1416 | else // ROP_XOR | 1418 | else // ROP_XOR |
1417 | rop = PAT_ROP_GXXOR; | 1419 | rop = PAT_ROP_GXXOR; |
1418 | 1420 | ||
1419 | if (dinfo->depth != 8) | 1421 | if (dinfo->depth != 8) |
1420 | color = dinfo->pseudo_palette[rect->color]; | 1422 | color = dinfo->pseudo_palette[rect->color]; |
1421 | else | 1423 | else |
1422 | color = rect->color; | 1424 | color = rect->color; |
1423 | 1425 | ||
1424 | intelfbhw_do_fillrect(dinfo, rect->dx, rect->dy, | 1426 | intelfbhw_do_fillrect(dinfo, rect->dx, rect->dy, |
1425 | rect->width, rect->height, color, | 1427 | rect->width, rect->height, color, |
1426 | dinfo->pitch, info->var.bits_per_pixel, | 1428 | dinfo->pitch, info->var.bits_per_pixel, |
1427 | rop); | 1429 | rop); |
1428 | } | 1430 | } |
1429 | 1431 | ||
1430 | static void | 1432 | static void |
1431 | intelfb_copyarea(struct fb_info *info, const struct fb_copyarea *region) | 1433 | intelfb_copyarea(struct fb_info *info, const struct fb_copyarea *region) |
1432 | { | 1434 | { |
1433 | struct intelfb_info *dinfo = GET_DINFO(info); | 1435 | struct intelfb_info *dinfo = GET_DINFO(info); |
1434 | 1436 | ||
1435 | #if VERBOSE > 0 | 1437 | #if VERBOSE > 0 |
1436 | DBG_MSG("intelfb_copyarea\n"); | 1438 | DBG_MSG("intelfb_copyarea\n"); |
1437 | #endif | 1439 | #endif |
1438 | 1440 | ||
1439 | if (!ACCEL(dinfo, info) || dinfo->depth == 4) | 1441 | if (!ACCEL(dinfo, info) || dinfo->depth == 4) |
1440 | return cfb_copyarea(info, region); | 1442 | return cfb_copyarea(info, region); |
1441 | 1443 | ||
1442 | intelfbhw_do_bitblt(dinfo, region->sx, region->sy, region->dx, | 1444 | intelfbhw_do_bitblt(dinfo, region->sx, region->sy, region->dx, |
1443 | region->dy, region->width, region->height, | 1445 | region->dy, region->width, region->height, |
1444 | dinfo->pitch, info->var.bits_per_pixel); | 1446 | dinfo->pitch, info->var.bits_per_pixel); |
1445 | } | 1447 | } |
1446 | 1448 | ||
1447 | static void | 1449 | static void |
1448 | intelfb_imageblit(struct fb_info *info, const struct fb_image *image) | 1450 | intelfb_imageblit(struct fb_info *info, const struct fb_image *image) |
1449 | { | 1451 | { |
1450 | struct intelfb_info *dinfo = GET_DINFO(info); | 1452 | struct intelfb_info *dinfo = GET_DINFO(info); |
1451 | u32 fgcolor, bgcolor; | 1453 | u32 fgcolor, bgcolor; |
1452 | 1454 | ||
1453 | #if VERBOSE > 0 | 1455 | #if VERBOSE > 0 |
1454 | DBG_MSG("intelfb_imageblit\n"); | 1456 | DBG_MSG("intelfb_imageblit\n"); |
1455 | #endif | 1457 | #endif |
1456 | 1458 | ||
1457 | if (!ACCEL(dinfo, info) || dinfo->depth == 4 | 1459 | if (!ACCEL(dinfo, info) || dinfo->depth == 4 |
1458 | || image->depth != 1) | 1460 | || image->depth != 1) |
1459 | return cfb_imageblit(info, image); | 1461 | return cfb_imageblit(info, image); |
1460 | 1462 | ||
1461 | if (dinfo->depth != 8) { | 1463 | if (dinfo->depth != 8) { |
1462 | fgcolor = dinfo->pseudo_palette[image->fg_color]; | 1464 | fgcolor = dinfo->pseudo_palette[image->fg_color]; |
1463 | bgcolor = dinfo->pseudo_palette[image->bg_color]; | 1465 | bgcolor = dinfo->pseudo_palette[image->bg_color]; |
1464 | } else { | 1466 | } else { |
1465 | fgcolor = image->fg_color; | 1467 | fgcolor = image->fg_color; |
1466 | bgcolor = image->bg_color; | 1468 | bgcolor = image->bg_color; |
1467 | } | 1469 | } |
1468 | 1470 | ||
1469 | if (!intelfbhw_do_drawglyph(dinfo, fgcolor, bgcolor, image->width, | 1471 | if (!intelfbhw_do_drawglyph(dinfo, fgcolor, bgcolor, image->width, |
1470 | image->height, image->data, | 1472 | image->height, image->data, |
1471 | image->dx, image->dy, | 1473 | image->dx, image->dy, |
1472 | dinfo->pitch, info->var.bits_per_pixel)) | 1474 | dinfo->pitch, info->var.bits_per_pixel)) |
1473 | return cfb_imageblit(info, image); | 1475 | return cfb_imageblit(info, image); |
1474 | } | 1476 | } |
1475 | 1477 | ||
1476 | static int | 1478 | static int |
1477 | intelfb_cursor(struct fb_info *info, struct fb_cursor *cursor) | 1479 | intelfb_cursor(struct fb_info *info, struct fb_cursor *cursor) |
1478 | { | 1480 | { |
1479 | struct intelfb_info *dinfo = GET_DINFO(info); | 1481 | struct intelfb_info *dinfo = GET_DINFO(info); |
1480 | 1482 | ||
1481 | #if VERBOSE > 0 | 1483 | #if VERBOSE > 0 |
1482 | DBG_MSG("intelfb_cursor\n"); | 1484 | DBG_MSG("intelfb_cursor\n"); |
1483 | #endif | 1485 | #endif |
1484 | 1486 | ||
1485 | if (!dinfo->hwcursor) | 1487 | if (!dinfo->hwcursor) |
1486 | return soft_cursor(info, cursor); | 1488 | return soft_cursor(info, cursor); |
1487 | 1489 | ||
1488 | intelfbhw_cursor_hide(dinfo); | 1490 | intelfbhw_cursor_hide(dinfo); |
1489 | 1491 | ||
1490 | /* If XFree killed the cursor - restore it */ | 1492 | /* If XFree killed the cursor - restore it */ |
1491 | if (INREG(CURSOR_A_BASEADDR) != dinfo->cursor.offset << 12) { | 1493 | if (INREG(CURSOR_A_BASEADDR) != dinfo->cursor.offset << 12) { |
1492 | u32 fg, bg; | 1494 | u32 fg, bg; |
1493 | 1495 | ||
1494 | DBG_MSG("the cursor was killed - restore it !!\n"); | 1496 | DBG_MSG("the cursor was killed - restore it !!\n"); |
1495 | DBG_MSG("size %d, %d pos %d, %d\n", | 1497 | DBG_MSG("size %d, %d pos %d, %d\n", |
1496 | cursor->image.width, cursor->image.height, | 1498 | cursor->image.width, cursor->image.height, |
1497 | cursor->image.dx, cursor->image.dy); | 1499 | cursor->image.dx, cursor->image.dy); |
1498 | 1500 | ||
1499 | intelfbhw_cursor_init(dinfo); | 1501 | intelfbhw_cursor_init(dinfo); |
1500 | intelfbhw_cursor_reset(dinfo); | 1502 | intelfbhw_cursor_reset(dinfo); |
1501 | intelfbhw_cursor_setpos(dinfo, cursor->image.dx, | 1503 | intelfbhw_cursor_setpos(dinfo, cursor->image.dx, |
1502 | cursor->image.dy); | 1504 | cursor->image.dy); |
1503 | 1505 | ||
1504 | if (dinfo->depth != 8) { | 1506 | if (dinfo->depth != 8) { |
1505 | fg =dinfo->pseudo_palette[cursor->image.fg_color]; | 1507 | fg =dinfo->pseudo_palette[cursor->image.fg_color]; |
1506 | bg =dinfo->pseudo_palette[cursor->image.bg_color]; | 1508 | bg =dinfo->pseudo_palette[cursor->image.bg_color]; |
1507 | } else { | 1509 | } else { |
1508 | fg = cursor->image.fg_color; | 1510 | fg = cursor->image.fg_color; |
1509 | bg = cursor->image.bg_color; | 1511 | bg = cursor->image.bg_color; |
1510 | } | 1512 | } |
1511 | intelfbhw_cursor_setcolor(dinfo, bg, fg); | 1513 | intelfbhw_cursor_setcolor(dinfo, bg, fg); |
1512 | intelfbhw_cursor_load(dinfo, cursor->image.width, | 1514 | intelfbhw_cursor_load(dinfo, cursor->image.width, |
1513 | cursor->image.height, | 1515 | cursor->image.height, |
1514 | dinfo->cursor_src); | 1516 | dinfo->cursor_src); |
1515 | 1517 | ||
1516 | if (cursor->enable) | 1518 | if (cursor->enable) |
1517 | intelfbhw_cursor_show(dinfo); | 1519 | intelfbhw_cursor_show(dinfo); |
1518 | return 0; | 1520 | return 0; |
1519 | } | 1521 | } |
1520 | 1522 | ||
1521 | if (cursor->set & FB_CUR_SETPOS) { | 1523 | if (cursor->set & FB_CUR_SETPOS) { |
1522 | u32 dx, dy; | 1524 | u32 dx, dy; |
1523 | 1525 | ||
1524 | dx = cursor->image.dx - info->var.xoffset; | 1526 | dx = cursor->image.dx - info->var.xoffset; |
1525 | dy = cursor->image.dy - info->var.yoffset; | 1527 | dy = cursor->image.dy - info->var.yoffset; |
1526 | 1528 | ||
1527 | intelfbhw_cursor_setpos(dinfo, dx, dy); | 1529 | intelfbhw_cursor_setpos(dinfo, dx, dy); |
1528 | } | 1530 | } |
1529 | 1531 | ||
1530 | if (cursor->set & FB_CUR_SETSIZE) { | 1532 | if (cursor->set & FB_CUR_SETSIZE) { |
1531 | if (cursor->image.width > 64 || cursor->image.height > 64) | 1533 | if (cursor->image.width > 64 || cursor->image.height > 64) |
1532 | return -ENXIO; | 1534 | return -ENXIO; |
1533 | 1535 | ||
1534 | intelfbhw_cursor_reset(dinfo); | 1536 | intelfbhw_cursor_reset(dinfo); |
1535 | } | 1537 | } |
1536 | 1538 | ||
1537 | if (cursor->set & FB_CUR_SETCMAP) { | 1539 | if (cursor->set & FB_CUR_SETCMAP) { |
1538 | u32 fg, bg; | 1540 | u32 fg, bg; |
1539 | 1541 | ||
1540 | if (dinfo->depth != 8) { | 1542 | if (dinfo->depth != 8) { |
1541 | fg = dinfo->pseudo_palette[cursor->image.fg_color]; | 1543 | fg = dinfo->pseudo_palette[cursor->image.fg_color]; |
1542 | bg = dinfo->pseudo_palette[cursor->image.bg_color]; | 1544 | bg = dinfo->pseudo_palette[cursor->image.bg_color]; |
1543 | } else { | 1545 | } else { |
1544 | fg = cursor->image.fg_color; | 1546 | fg = cursor->image.fg_color; |
1545 | bg = cursor->image.bg_color; | 1547 | bg = cursor->image.bg_color; |
1546 | } | 1548 | } |
1547 | 1549 | ||
1548 | intelfbhw_cursor_setcolor(dinfo, bg, fg); | 1550 | intelfbhw_cursor_setcolor(dinfo, bg, fg); |
1549 | } | 1551 | } |
1550 | 1552 | ||
1551 | if (cursor->set & (FB_CUR_SETSHAPE | FB_CUR_SETIMAGE)) { | 1553 | if (cursor->set & (FB_CUR_SETSHAPE | FB_CUR_SETIMAGE)) { |
1552 | u32 s_pitch = (ROUND_UP_TO(cursor->image.width, 8) / 8); | 1554 | u32 s_pitch = (ROUND_UP_TO(cursor->image.width, 8) / 8); |
1553 | u32 size = s_pitch * cursor->image.height; | 1555 | u32 size = s_pitch * cursor->image.height; |
1554 | u8 *dat = (u8 *) cursor->image.data; | 1556 | u8 *dat = (u8 *) cursor->image.data; |
1555 | u8 *msk = (u8 *) cursor->mask; | 1557 | u8 *msk = (u8 *) cursor->mask; |
1556 | u8 src[64]; | 1558 | u8 src[64]; |
1557 | u32 i; | 1559 | u32 i; |
1558 | 1560 | ||
1559 | if (cursor->image.depth != 1) | 1561 | if (cursor->image.depth != 1) |
1560 | return -ENXIO; | 1562 | return -ENXIO; |
1561 | 1563 | ||
1562 | switch (cursor->rop) { | 1564 | switch (cursor->rop) { |
1563 | case ROP_XOR: | 1565 | case ROP_XOR: |
1564 | for (i = 0; i < size; i++) | 1566 | for (i = 0; i < size; i++) |
1565 | src[i] = dat[i] ^ msk[i]; | 1567 | src[i] = dat[i] ^ msk[i]; |
1566 | break; | 1568 | break; |
1567 | case ROP_COPY: | 1569 | case ROP_COPY: |
1568 | default: | 1570 | default: |
1569 | for (i = 0; i < size; i++) | 1571 | for (i = 0; i < size; i++) |
1570 | src[i] = dat[i] & msk[i]; | 1572 | src[i] = dat[i] & msk[i]; |
1571 | break; | 1573 | break; |
1572 | } | 1574 | } |
1573 | 1575 | ||
1574 | /* save the bitmap to restore it when XFree will | 1576 | /* save the bitmap to restore it when XFree will |
1575 | make the cursor dirty */ | 1577 | make the cursor dirty */ |
1576 | memcpy(dinfo->cursor_src, src, size); | 1578 | memcpy(dinfo->cursor_src, src, size); |
1577 | 1579 | ||
1578 | intelfbhw_cursor_load(dinfo, cursor->image.width, | 1580 | intelfbhw_cursor_load(dinfo, cursor->image.width, |
1579 | cursor->image.height, src); | 1581 | cursor->image.height, src); |
1580 | } | 1582 | } |
1581 | 1583 | ||
1582 | if (cursor->enable) | 1584 | if (cursor->enable) |
1583 | intelfbhw_cursor_show(dinfo); | 1585 | intelfbhw_cursor_show(dinfo); |
1584 | 1586 | ||
1585 | return 0; | 1587 | return 0; |
1586 | } | 1588 | } |
1587 | 1589 | ||
1588 | static int | 1590 | static int |
1589 | intelfb_sync(struct fb_info *info) | 1591 | intelfb_sync(struct fb_info *info) |
1590 | { | 1592 | { |
1591 | struct intelfb_info *dinfo = GET_DINFO(info); | 1593 | struct intelfb_info *dinfo = GET_DINFO(info); |
1592 | 1594 | ||
1593 | #if VERBOSE > 0 | 1595 | #if VERBOSE > 0 |
1594 | DBG_MSG("intelfb_sync\n"); | 1596 | DBG_MSG("intelfb_sync\n"); |
1595 | #endif | 1597 | #endif |
1596 | 1598 | ||
1597 | if (dinfo->ring_lockup) | 1599 | if (dinfo->ring_lockup) |
1598 | return 0; | 1600 | return 0; |
1599 | 1601 | ||
1600 | intelfbhw_do_sync(dinfo); | 1602 | intelfbhw_do_sync(dinfo); |
1601 | return 0; | 1603 | return 0; |
1602 | } | 1604 | } |
1603 | 1605 | ||
1604 | 1606 |
drivers/video/intelfb/intelfbhw.c
1 | /* | 1 | /* |
2 | * intelfb | 2 | * intelfb |
3 | * | 3 | * |
4 | * Linux framebuffer driver for Intel(R) 865G integrated graphics chips. | 4 | * Linux framebuffer driver for Intel(R) 865G integrated graphics chips. |
5 | * | 5 | * |
6 | * Copyright ยฉ 2002, 2003 David Dawes <dawes@xfree86.org> | 6 | * Copyright ยฉ 2002, 2003 David Dawes <dawes@xfree86.org> |
7 | * 2004 Sylvain Meyer | 7 | * 2004 Sylvain Meyer |
8 | * | 8 | * |
9 | * This driver consists of two parts. The first part (intelfbdrv.c) provides | 9 | * This driver consists of two parts. The first part (intelfbdrv.c) provides |
10 | * the basic fbdev interfaces, is derived in part from the radeonfb and | 10 | * the basic fbdev interfaces, is derived in part from the radeonfb and |
11 | * vesafb drivers, and is covered by the GPL. The second part (intelfbhw.c) | 11 | * vesafb drivers, and is covered by the GPL. The second part (intelfbhw.c) |
12 | * provides the code to program the hardware. Most of it is derived from | 12 | * provides the code to program the hardware. Most of it is derived from |
13 | * the i810/i830 XFree86 driver. The HW-specific code is covered here | 13 | * the i810/i830 XFree86 driver. The HW-specific code is covered here |
14 | * under a dual license (GPL and MIT/XFree86 license). | 14 | * under a dual license (GPL and MIT/XFree86 license). |
15 | * | 15 | * |
16 | * Author: David Dawes | 16 | * Author: David Dawes |
17 | * | 17 | * |
18 | */ | 18 | */ |
19 | 19 | ||
20 | /* $DHD: intelfb/intelfbhw.c,v 1.9 2003/06/27 15:06:25 dawes Exp $ */ | 20 | /* $DHD: intelfb/intelfbhw.c,v 1.9 2003/06/27 15:06:25 dawes Exp $ */ |
21 | 21 | ||
22 | #include <linux/config.h> | 22 | #include <linux/config.h> |
23 | #include <linux/module.h> | 23 | #include <linux/module.h> |
24 | #include <linux/kernel.h> | 24 | #include <linux/kernel.h> |
25 | #include <linux/errno.h> | 25 | #include <linux/errno.h> |
26 | #include <linux/string.h> | 26 | #include <linux/string.h> |
27 | #include <linux/mm.h> | 27 | #include <linux/mm.h> |
28 | #include <linux/tty.h> | 28 | #include <linux/tty.h> |
29 | #include <linux/slab.h> | 29 | #include <linux/slab.h> |
30 | #include <linux/delay.h> | 30 | #include <linux/delay.h> |
31 | #include <linux/fb.h> | 31 | #include <linux/fb.h> |
32 | #include <linux/ioport.h> | 32 | #include <linux/ioport.h> |
33 | #include <linux/init.h> | 33 | #include <linux/init.h> |
34 | #include <linux/pci.h> | 34 | #include <linux/pci.h> |
35 | #include <linux/vmalloc.h> | 35 | #include <linux/vmalloc.h> |
36 | #include <linux/pagemap.h> | 36 | #include <linux/pagemap.h> |
37 | #include <linux/version.h> | 37 | #include <linux/version.h> |
38 | 38 | ||
39 | #include <asm/io.h> | 39 | #include <asm/io.h> |
40 | 40 | ||
41 | #include "intelfb.h" | 41 | #include "intelfb.h" |
42 | #include "intelfbhw.h" | 42 | #include "intelfbhw.h" |
43 | 43 | ||
44 | int | 44 | int |
45 | intelfbhw_get_chipset(struct pci_dev *pdev, const char **name, int *chipset, | 45 | intelfbhw_get_chipset(struct pci_dev *pdev, const char **name, int *chipset, |
46 | int *mobile) | 46 | int *mobile) |
47 | { | 47 | { |
48 | u32 tmp; | 48 | u32 tmp; |
49 | 49 | ||
50 | if (!pdev || !name || !chipset || !mobile) | 50 | if (!pdev || !name || !chipset || !mobile) |
51 | return 1; | 51 | return 1; |
52 | 52 | ||
53 | switch (pdev->device) { | 53 | switch (pdev->device) { |
54 | case PCI_DEVICE_ID_INTEL_830M: | 54 | case PCI_DEVICE_ID_INTEL_830M: |
55 | *name = "Intel(R) 830M"; | 55 | *name = "Intel(R) 830M"; |
56 | *chipset = INTEL_830M; | 56 | *chipset = INTEL_830M; |
57 | *mobile = 1; | 57 | *mobile = 1; |
58 | return 0; | 58 | return 0; |
59 | case PCI_DEVICE_ID_INTEL_845G: | 59 | case PCI_DEVICE_ID_INTEL_845G: |
60 | *name = "Intel(R) 845G"; | 60 | *name = "Intel(R) 845G"; |
61 | *chipset = INTEL_845G; | 61 | *chipset = INTEL_845G; |
62 | *mobile = 0; | 62 | *mobile = 0; |
63 | return 0; | 63 | return 0; |
64 | case PCI_DEVICE_ID_INTEL_85XGM: | 64 | case PCI_DEVICE_ID_INTEL_85XGM: |
65 | tmp = 0; | 65 | tmp = 0; |
66 | *mobile = 1; | 66 | *mobile = 1; |
67 | pci_read_config_dword(pdev, INTEL_85X_CAPID, &tmp); | 67 | pci_read_config_dword(pdev, INTEL_85X_CAPID, &tmp); |
68 | switch ((tmp >> INTEL_85X_VARIANT_SHIFT) & | 68 | switch ((tmp >> INTEL_85X_VARIANT_SHIFT) & |
69 | INTEL_85X_VARIANT_MASK) { | 69 | INTEL_85X_VARIANT_MASK) { |
70 | case INTEL_VAR_855GME: | 70 | case INTEL_VAR_855GME: |
71 | *name = "Intel(R) 855GME"; | 71 | *name = "Intel(R) 855GME"; |
72 | *chipset = INTEL_855GME; | 72 | *chipset = INTEL_855GME; |
73 | return 0; | 73 | return 0; |
74 | case INTEL_VAR_855GM: | 74 | case INTEL_VAR_855GM: |
75 | *name = "Intel(R) 855GM"; | 75 | *name = "Intel(R) 855GM"; |
76 | *chipset = INTEL_855GM; | 76 | *chipset = INTEL_855GM; |
77 | return 0; | 77 | return 0; |
78 | case INTEL_VAR_852GME: | 78 | case INTEL_VAR_852GME: |
79 | *name = "Intel(R) 852GME"; | 79 | *name = "Intel(R) 852GME"; |
80 | *chipset = INTEL_852GME; | 80 | *chipset = INTEL_852GME; |
81 | return 0; | 81 | return 0; |
82 | case INTEL_VAR_852GM: | 82 | case INTEL_VAR_852GM: |
83 | *name = "Intel(R) 852GM"; | 83 | *name = "Intel(R) 852GM"; |
84 | *chipset = INTEL_852GM; | 84 | *chipset = INTEL_852GM; |
85 | return 0; | 85 | return 0; |
86 | default: | 86 | default: |
87 | *name = "Intel(R) 852GM/855GM"; | 87 | *name = "Intel(R) 852GM/855GM"; |
88 | *chipset = INTEL_85XGM; | 88 | *chipset = INTEL_85XGM; |
89 | return 0; | 89 | return 0; |
90 | } | 90 | } |
91 | break; | 91 | break; |
92 | case PCI_DEVICE_ID_INTEL_865G: | 92 | case PCI_DEVICE_ID_INTEL_865G: |
93 | *name = "Intel(R) 865G"; | 93 | *name = "Intel(R) 865G"; |
94 | *chipset = INTEL_865G; | 94 | *chipset = INTEL_865G; |
95 | *mobile = 0; | 95 | *mobile = 0; |
96 | return 0; | 96 | return 0; |
97 | case PCI_DEVICE_ID_INTEL_915G: | 97 | case PCI_DEVICE_ID_INTEL_915G: |
98 | *name = "Intel(R) 915G"; | 98 | *name = "Intel(R) 915G"; |
99 | *chipset = INTEL_915G; | 99 | *chipset = INTEL_915G; |
100 | *mobile = 0; | 100 | *mobile = 0; |
101 | return 0; | 101 | return 0; |
102 | case PCI_DEVICE_ID_INTEL_915GM: | ||
103 | *name = "Intel(R) 915GM"; | ||
104 | *chipset = INTEL_915GM; | ||
105 | *mobile = 1; | ||
106 | return 0; | ||
102 | default: | 107 | default: |
103 | return 1; | 108 | return 1; |
104 | } | 109 | } |
105 | } | 110 | } |
106 | 111 | ||
107 | int | 112 | int |
108 | intelfbhw_get_memory(struct pci_dev *pdev, int *aperture_size, | 113 | intelfbhw_get_memory(struct pci_dev *pdev, int *aperture_size, |
109 | int *stolen_size) | 114 | int *stolen_size) |
110 | { | 115 | { |
111 | struct pci_dev *bridge_dev; | 116 | struct pci_dev *bridge_dev; |
112 | u16 tmp; | 117 | u16 tmp; |
113 | 118 | ||
114 | if (!pdev || !aperture_size || !stolen_size) | 119 | if (!pdev || !aperture_size || !stolen_size) |
115 | return 1; | 120 | return 1; |
116 | 121 | ||
117 | /* Find the bridge device. It is always 0:0.0 */ | 122 | /* Find the bridge device. It is always 0:0.0 */ |
118 | if (!(bridge_dev = pci_find_slot(0, PCI_DEVFN(0, 0)))) { | 123 | if (!(bridge_dev = pci_find_slot(0, PCI_DEVFN(0, 0)))) { |
119 | ERR_MSG("cannot find bridge device\n"); | 124 | ERR_MSG("cannot find bridge device\n"); |
120 | return 1; | 125 | return 1; |
121 | } | 126 | } |
122 | 127 | ||
123 | /* Get the fb aperture size and "stolen" memory amount. */ | 128 | /* Get the fb aperture size and "stolen" memory amount. */ |
124 | tmp = 0; | 129 | tmp = 0; |
125 | pci_read_config_word(bridge_dev, INTEL_GMCH_CTRL, &tmp); | 130 | pci_read_config_word(bridge_dev, INTEL_GMCH_CTRL, &tmp); |
126 | switch (pdev->device) { | 131 | switch (pdev->device) { |
127 | case PCI_DEVICE_ID_INTEL_830M: | 132 | case PCI_DEVICE_ID_INTEL_830M: |
128 | case PCI_DEVICE_ID_INTEL_845G: | 133 | case PCI_DEVICE_ID_INTEL_845G: |
129 | if ((tmp & INTEL_GMCH_MEM_MASK) == INTEL_GMCH_MEM_64M) | 134 | if ((tmp & INTEL_GMCH_MEM_MASK) == INTEL_GMCH_MEM_64M) |
130 | *aperture_size = MB(64); | 135 | *aperture_size = MB(64); |
131 | else | 136 | else |
132 | *aperture_size = MB(128); | 137 | *aperture_size = MB(128); |
133 | switch (tmp & INTEL_830_GMCH_GMS_MASK) { | 138 | switch (tmp & INTEL_830_GMCH_GMS_MASK) { |
134 | case INTEL_830_GMCH_GMS_STOLEN_512: | 139 | case INTEL_830_GMCH_GMS_STOLEN_512: |
135 | *stolen_size = KB(512) - KB(132); | 140 | *stolen_size = KB(512) - KB(132); |
136 | return 0; | 141 | return 0; |
137 | case INTEL_830_GMCH_GMS_STOLEN_1024: | 142 | case INTEL_830_GMCH_GMS_STOLEN_1024: |
138 | *stolen_size = MB(1) - KB(132); | 143 | *stolen_size = MB(1) - KB(132); |
139 | return 0; | 144 | return 0; |
140 | case INTEL_830_GMCH_GMS_STOLEN_8192: | 145 | case INTEL_830_GMCH_GMS_STOLEN_8192: |
141 | *stolen_size = MB(8) - KB(132); | 146 | *stolen_size = MB(8) - KB(132); |
142 | return 0; | 147 | return 0; |
143 | case INTEL_830_GMCH_GMS_LOCAL: | 148 | case INTEL_830_GMCH_GMS_LOCAL: |
144 | ERR_MSG("only local memory found\n"); | 149 | ERR_MSG("only local memory found\n"); |
145 | return 1; | 150 | return 1; |
146 | case INTEL_830_GMCH_GMS_DISABLED: | 151 | case INTEL_830_GMCH_GMS_DISABLED: |
147 | ERR_MSG("video memory is disabled\n"); | 152 | ERR_MSG("video memory is disabled\n"); |
148 | return 1; | 153 | return 1; |
149 | default: | 154 | default: |
150 | ERR_MSG("unexpected GMCH_GMS value: 0x%02x\n", | 155 | ERR_MSG("unexpected GMCH_GMS value: 0x%02x\n", |
151 | tmp & INTEL_830_GMCH_GMS_MASK); | 156 | tmp & INTEL_830_GMCH_GMS_MASK); |
152 | return 1; | 157 | return 1; |
153 | } | 158 | } |
154 | break; | 159 | break; |
155 | default: | 160 | default: |
156 | *aperture_size = MB(128); | 161 | *aperture_size = MB(128); |
157 | switch (tmp & INTEL_855_GMCH_GMS_MASK) { | 162 | switch (tmp & INTEL_855_GMCH_GMS_MASK) { |
158 | case INTEL_855_GMCH_GMS_STOLEN_1M: | 163 | case INTEL_855_GMCH_GMS_STOLEN_1M: |
159 | *stolen_size = MB(1) - KB(132); | 164 | *stolen_size = MB(1) - KB(132); |
160 | return 0; | 165 | return 0; |
161 | case INTEL_855_GMCH_GMS_STOLEN_4M: | 166 | case INTEL_855_GMCH_GMS_STOLEN_4M: |
162 | *stolen_size = MB(4) - KB(132); | 167 | *stolen_size = MB(4) - KB(132); |
163 | return 0; | 168 | return 0; |
164 | case INTEL_855_GMCH_GMS_STOLEN_8M: | 169 | case INTEL_855_GMCH_GMS_STOLEN_8M: |
165 | *stolen_size = MB(8) - KB(132); | 170 | *stolen_size = MB(8) - KB(132); |
166 | return 0; | 171 | return 0; |
167 | case INTEL_855_GMCH_GMS_STOLEN_16M: | 172 | case INTEL_855_GMCH_GMS_STOLEN_16M: |
168 | *stolen_size = MB(16) - KB(132); | 173 | *stolen_size = MB(16) - KB(132); |
169 | return 0; | 174 | return 0; |
170 | case INTEL_855_GMCH_GMS_STOLEN_32M: | 175 | case INTEL_855_GMCH_GMS_STOLEN_32M: |
171 | *stolen_size = MB(32) - KB(132); | 176 | *stolen_size = MB(32) - KB(132); |
172 | return 0; | 177 | return 0; |
173 | case INTEL_915G_GMCH_GMS_STOLEN_48M: | 178 | case INTEL_915G_GMCH_GMS_STOLEN_48M: |
174 | *stolen_size = MB(48) - KB(132); | 179 | *stolen_size = MB(48) - KB(132); |
175 | return 0; | 180 | return 0; |
176 | case INTEL_915G_GMCH_GMS_STOLEN_64M: | 181 | case INTEL_915G_GMCH_GMS_STOLEN_64M: |
177 | *stolen_size = MB(64) - KB(132); | 182 | *stolen_size = MB(64) - KB(132); |
178 | return 0; | 183 | return 0; |
179 | case INTEL_855_GMCH_GMS_DISABLED: | 184 | case INTEL_855_GMCH_GMS_DISABLED: |
180 | ERR_MSG("video memory is disabled\n"); | 185 | ERR_MSG("video memory is disabled\n"); |
181 | return 0; | 186 | return 0; |
182 | default: | 187 | default: |
183 | ERR_MSG("unexpected GMCH_GMS value: 0x%02x\n", | 188 | ERR_MSG("unexpected GMCH_GMS value: 0x%02x\n", |
184 | tmp & INTEL_855_GMCH_GMS_MASK); | 189 | tmp & INTEL_855_GMCH_GMS_MASK); |
185 | return 1; | 190 | return 1; |
186 | } | 191 | } |
187 | } | 192 | } |
188 | } | 193 | } |
189 | 194 | ||
190 | int | 195 | int |
191 | intelfbhw_check_non_crt(struct intelfb_info *dinfo) | 196 | intelfbhw_check_non_crt(struct intelfb_info *dinfo) |
192 | { | 197 | { |
193 | int dvo = 0; | 198 | int dvo = 0; |
194 | 199 | ||
195 | if (INREG(LVDS) & PORT_ENABLE) | 200 | if (INREG(LVDS) & PORT_ENABLE) |
196 | dvo |= LVDS_PORT; | 201 | dvo |= LVDS_PORT; |
197 | if (INREG(DVOA) & PORT_ENABLE) | 202 | if (INREG(DVOA) & PORT_ENABLE) |
198 | dvo |= DVOA_PORT; | 203 | dvo |= DVOA_PORT; |
199 | if (INREG(DVOB) & PORT_ENABLE) | 204 | if (INREG(DVOB) & PORT_ENABLE) |
200 | dvo |= DVOB_PORT; | 205 | dvo |= DVOB_PORT; |
201 | if (INREG(DVOC) & PORT_ENABLE) | 206 | if (INREG(DVOC) & PORT_ENABLE) |
202 | dvo |= DVOC_PORT; | 207 | dvo |= DVOC_PORT; |
203 | 208 | ||
204 | return dvo; | 209 | return dvo; |
205 | } | 210 | } |
206 | 211 | ||
207 | const char * | 212 | const char * |
208 | intelfbhw_dvo_to_string(int dvo) | 213 | intelfbhw_dvo_to_string(int dvo) |
209 | { | 214 | { |
210 | if (dvo & DVOA_PORT) | 215 | if (dvo & DVOA_PORT) |
211 | return "DVO port A"; | 216 | return "DVO port A"; |
212 | else if (dvo & DVOB_PORT) | 217 | else if (dvo & DVOB_PORT) |
213 | return "DVO port B"; | 218 | return "DVO port B"; |
214 | else if (dvo & DVOC_PORT) | 219 | else if (dvo & DVOC_PORT) |
215 | return "DVO port C"; | 220 | return "DVO port C"; |
216 | else if (dvo & LVDS_PORT) | 221 | else if (dvo & LVDS_PORT) |
217 | return "LVDS port"; | 222 | return "LVDS port"; |
218 | else | 223 | else |
219 | return NULL; | 224 | return NULL; |
220 | } | 225 | } |
221 | 226 | ||
222 | 227 | ||
223 | int | 228 | int |
224 | intelfbhw_validate_mode(struct intelfb_info *dinfo, | 229 | intelfbhw_validate_mode(struct intelfb_info *dinfo, |
225 | struct fb_var_screeninfo *var) | 230 | struct fb_var_screeninfo *var) |
226 | { | 231 | { |
227 | int bytes_per_pixel; | 232 | int bytes_per_pixel; |
228 | int tmp; | 233 | int tmp; |
229 | 234 | ||
230 | #if VERBOSE > 0 | 235 | #if VERBOSE > 0 |
231 | DBG_MSG("intelfbhw_validate_mode\n"); | 236 | DBG_MSG("intelfbhw_validate_mode\n"); |
232 | #endif | 237 | #endif |
233 | 238 | ||
234 | bytes_per_pixel = var->bits_per_pixel / 8; | 239 | bytes_per_pixel = var->bits_per_pixel / 8; |
235 | if (bytes_per_pixel == 3) | 240 | if (bytes_per_pixel == 3) |
236 | bytes_per_pixel = 4; | 241 | bytes_per_pixel = 4; |
237 | 242 | ||
238 | /* Check if enough video memory. */ | 243 | /* Check if enough video memory. */ |
239 | tmp = var->yres_virtual * var->xres_virtual * bytes_per_pixel; | 244 | tmp = var->yres_virtual * var->xres_virtual * bytes_per_pixel; |
240 | if (tmp > dinfo->fb.size) { | 245 | if (tmp > dinfo->fb.size) { |
241 | WRN_MSG("Not enough video ram for mode " | 246 | WRN_MSG("Not enough video ram for mode " |
242 | "(%d KByte vs %d KByte).\n", | 247 | "(%d KByte vs %d KByte).\n", |
243 | BtoKB(tmp), BtoKB(dinfo->fb.size)); | 248 | BtoKB(tmp), BtoKB(dinfo->fb.size)); |
244 | return 1; | 249 | return 1; |
245 | } | 250 | } |
246 | 251 | ||
247 | /* Check if x/y limits are OK. */ | 252 | /* Check if x/y limits are OK. */ |
248 | if (var->xres - 1 > HACTIVE_MASK) { | 253 | if (var->xres - 1 > HACTIVE_MASK) { |
249 | WRN_MSG("X resolution too large (%d vs %d).\n", | 254 | WRN_MSG("X resolution too large (%d vs %d).\n", |
250 | var->xres, HACTIVE_MASK + 1); | 255 | var->xres, HACTIVE_MASK + 1); |
251 | return 1; | 256 | return 1; |
252 | } | 257 | } |
253 | if (var->yres - 1 > VACTIVE_MASK) { | 258 | if (var->yres - 1 > VACTIVE_MASK) { |
254 | WRN_MSG("Y resolution too large (%d vs %d).\n", | 259 | WRN_MSG("Y resolution too large (%d vs %d).\n", |
255 | var->yres, VACTIVE_MASK + 1); | 260 | var->yres, VACTIVE_MASK + 1); |
256 | return 1; | 261 | return 1; |
257 | } | 262 | } |
258 | 263 | ||
259 | /* Check for interlaced/doublescan modes. */ | 264 | /* Check for interlaced/doublescan modes. */ |
260 | if (var->vmode & FB_VMODE_INTERLACED) { | 265 | if (var->vmode & FB_VMODE_INTERLACED) { |
261 | WRN_MSG("Mode is interlaced.\n"); | 266 | WRN_MSG("Mode is interlaced.\n"); |
262 | return 1; | 267 | return 1; |
263 | } | 268 | } |
264 | if (var->vmode & FB_VMODE_DOUBLE) { | 269 | if (var->vmode & FB_VMODE_DOUBLE) { |
265 | WRN_MSG("Mode is double-scan.\n"); | 270 | WRN_MSG("Mode is double-scan.\n"); |
266 | return 1; | 271 | return 1; |
267 | } | 272 | } |
268 | 273 | ||
269 | /* Check if clock is OK. */ | 274 | /* Check if clock is OK. */ |
270 | tmp = 1000000000 / var->pixclock; | 275 | tmp = 1000000000 / var->pixclock; |
271 | if (tmp < MIN_CLOCK) { | 276 | if (tmp < MIN_CLOCK) { |
272 | WRN_MSG("Pixel clock is too low (%d MHz vs %d MHz).\n", | 277 | WRN_MSG("Pixel clock is too low (%d MHz vs %d MHz).\n", |
273 | (tmp + 500) / 1000, MIN_CLOCK / 1000); | 278 | (tmp + 500) / 1000, MIN_CLOCK / 1000); |
274 | return 1; | 279 | return 1; |
275 | } | 280 | } |
276 | if (tmp > MAX_CLOCK) { | 281 | if (tmp > MAX_CLOCK) { |
277 | WRN_MSG("Pixel clock is too high (%d MHz vs %d MHz).\n", | 282 | WRN_MSG("Pixel clock is too high (%d MHz vs %d MHz).\n", |
278 | (tmp + 500) / 1000, MAX_CLOCK / 1000); | 283 | (tmp + 500) / 1000, MAX_CLOCK / 1000); |
279 | return 1; | 284 | return 1; |
280 | } | 285 | } |
281 | 286 | ||
282 | return 0; | 287 | return 0; |
283 | } | 288 | } |
284 | 289 | ||
285 | int | 290 | int |
286 | intelfbhw_pan_display(struct fb_var_screeninfo *var, struct fb_info *info) | 291 | intelfbhw_pan_display(struct fb_var_screeninfo *var, struct fb_info *info) |
287 | { | 292 | { |
288 | struct intelfb_info *dinfo = GET_DINFO(info); | 293 | struct intelfb_info *dinfo = GET_DINFO(info); |
289 | u32 offset, xoffset, yoffset; | 294 | u32 offset, xoffset, yoffset; |
290 | 295 | ||
291 | #if VERBOSE > 0 | 296 | #if VERBOSE > 0 |
292 | DBG_MSG("intelfbhw_pan_display\n"); | 297 | DBG_MSG("intelfbhw_pan_display\n"); |
293 | #endif | 298 | #endif |
294 | 299 | ||
295 | xoffset = ROUND_DOWN_TO(var->xoffset, 8); | 300 | xoffset = ROUND_DOWN_TO(var->xoffset, 8); |
296 | yoffset = var->yoffset; | 301 | yoffset = var->yoffset; |
297 | 302 | ||
298 | if ((xoffset + var->xres > var->xres_virtual) || | 303 | if ((xoffset + var->xres > var->xres_virtual) || |
299 | (yoffset + var->yres > var->yres_virtual)) | 304 | (yoffset + var->yres > var->yres_virtual)) |
300 | return -EINVAL; | 305 | return -EINVAL; |
301 | 306 | ||
302 | offset = (yoffset * dinfo->pitch) + | 307 | offset = (yoffset * dinfo->pitch) + |
303 | (xoffset * var->bits_per_pixel) / 8; | 308 | (xoffset * var->bits_per_pixel) / 8; |
304 | 309 | ||
305 | offset += dinfo->fb.offset << 12; | 310 | offset += dinfo->fb.offset << 12; |
306 | 311 | ||
307 | OUTREG(DSPABASE, offset); | 312 | OUTREG(DSPABASE, offset); |
308 | 313 | ||
309 | return 0; | 314 | return 0; |
310 | } | 315 | } |
311 | 316 | ||
312 | /* Blank the screen. */ | 317 | /* Blank the screen. */ |
313 | void | 318 | void |
314 | intelfbhw_do_blank(int blank, struct fb_info *info) | 319 | intelfbhw_do_blank(int blank, struct fb_info *info) |
315 | { | 320 | { |
316 | struct intelfb_info *dinfo = GET_DINFO(info); | 321 | struct intelfb_info *dinfo = GET_DINFO(info); |
317 | u32 tmp; | 322 | u32 tmp; |
318 | 323 | ||
319 | #if VERBOSE > 0 | 324 | #if VERBOSE > 0 |
320 | DBG_MSG("intelfbhw_do_blank: blank is %d\n", blank); | 325 | DBG_MSG("intelfbhw_do_blank: blank is %d\n", blank); |
321 | #endif | 326 | #endif |
322 | 327 | ||
323 | /* Turn plane A on or off */ | 328 | /* Turn plane A on or off */ |
324 | tmp = INREG(DSPACNTR); | 329 | tmp = INREG(DSPACNTR); |
325 | if (blank) | 330 | if (blank) |
326 | tmp &= ~DISPPLANE_PLANE_ENABLE; | 331 | tmp &= ~DISPPLANE_PLANE_ENABLE; |
327 | else | 332 | else |
328 | tmp |= DISPPLANE_PLANE_ENABLE; | 333 | tmp |= DISPPLANE_PLANE_ENABLE; |
329 | OUTREG(DSPACNTR, tmp); | 334 | OUTREG(DSPACNTR, tmp); |
330 | /* Flush */ | 335 | /* Flush */ |
331 | tmp = INREG(DSPABASE); | 336 | tmp = INREG(DSPABASE); |
332 | OUTREG(DSPABASE, tmp); | 337 | OUTREG(DSPABASE, tmp); |
333 | 338 | ||
334 | /* Turn off/on the HW cursor */ | 339 | /* Turn off/on the HW cursor */ |
335 | #if VERBOSE > 0 | 340 | #if VERBOSE > 0 |
336 | DBG_MSG("cursor_on is %d\n", dinfo->cursor_on); | 341 | DBG_MSG("cursor_on is %d\n", dinfo->cursor_on); |
337 | #endif | 342 | #endif |
338 | if (dinfo->cursor_on) { | 343 | if (dinfo->cursor_on) { |
339 | if (blank) { | 344 | if (blank) { |
340 | intelfbhw_cursor_hide(dinfo); | 345 | intelfbhw_cursor_hide(dinfo); |
341 | } else { | 346 | } else { |
342 | intelfbhw_cursor_show(dinfo); | 347 | intelfbhw_cursor_show(dinfo); |
343 | } | 348 | } |
344 | dinfo->cursor_on = 1; | 349 | dinfo->cursor_on = 1; |
345 | } | 350 | } |
346 | dinfo->cursor_blanked = blank; | 351 | dinfo->cursor_blanked = blank; |
347 | 352 | ||
348 | /* Set DPMS level */ | 353 | /* Set DPMS level */ |
349 | tmp = INREG(ADPA) & ~ADPA_DPMS_CONTROL_MASK; | 354 | tmp = INREG(ADPA) & ~ADPA_DPMS_CONTROL_MASK; |
350 | switch (blank) { | 355 | switch (blank) { |
351 | case FB_BLANK_UNBLANK: | 356 | case FB_BLANK_UNBLANK: |
352 | case FB_BLANK_NORMAL: | 357 | case FB_BLANK_NORMAL: |
353 | tmp |= ADPA_DPMS_D0; | 358 | tmp |= ADPA_DPMS_D0; |
354 | break; | 359 | break; |
355 | case FB_BLANK_VSYNC_SUSPEND: | 360 | case FB_BLANK_VSYNC_SUSPEND: |
356 | tmp |= ADPA_DPMS_D1; | 361 | tmp |= ADPA_DPMS_D1; |
357 | break; | 362 | break; |
358 | case FB_BLANK_HSYNC_SUSPEND: | 363 | case FB_BLANK_HSYNC_SUSPEND: |
359 | tmp |= ADPA_DPMS_D2; | 364 | tmp |= ADPA_DPMS_D2; |
360 | break; | 365 | break; |
361 | case FB_BLANK_POWERDOWN: | 366 | case FB_BLANK_POWERDOWN: |
362 | tmp |= ADPA_DPMS_D3; | 367 | tmp |= ADPA_DPMS_D3; |
363 | break; | 368 | break; |
364 | } | 369 | } |
365 | OUTREG(ADPA, tmp); | 370 | OUTREG(ADPA, tmp); |
366 | 371 | ||
367 | return; | 372 | return; |
368 | } | 373 | } |
369 | 374 | ||
370 | 375 | ||
371 | void | 376 | void |
372 | intelfbhw_setcolreg(struct intelfb_info *dinfo, unsigned regno, | 377 | intelfbhw_setcolreg(struct intelfb_info *dinfo, unsigned regno, |
373 | unsigned red, unsigned green, unsigned blue, | 378 | unsigned red, unsigned green, unsigned blue, |
374 | unsigned transp) | 379 | unsigned transp) |
375 | { | 380 | { |
376 | #if VERBOSE > 0 | 381 | #if VERBOSE > 0 |
377 | DBG_MSG("intelfbhw_setcolreg: %d: (%d, %d, %d)\n", | 382 | DBG_MSG("intelfbhw_setcolreg: %d: (%d, %d, %d)\n", |
378 | regno, red, green, blue); | 383 | regno, red, green, blue); |
379 | #endif | 384 | #endif |
380 | 385 | ||
381 | u32 palette_reg = (dinfo->pipe == PIPE_A) ? | 386 | u32 palette_reg = (dinfo->pipe == PIPE_A) ? |
382 | PALETTE_A : PALETTE_B; | 387 | PALETTE_A : PALETTE_B; |
383 | 388 | ||
384 | OUTREG(palette_reg + (regno << 2), | 389 | OUTREG(palette_reg + (regno << 2), |
385 | (red << PALETTE_8_RED_SHIFT) | | 390 | (red << PALETTE_8_RED_SHIFT) | |
386 | (green << PALETTE_8_GREEN_SHIFT) | | 391 | (green << PALETTE_8_GREEN_SHIFT) | |
387 | (blue << PALETTE_8_BLUE_SHIFT)); | 392 | (blue << PALETTE_8_BLUE_SHIFT)); |
388 | } | 393 | } |
389 | 394 | ||
390 | 395 | ||
391 | int | 396 | int |
392 | intelfbhw_read_hw_state(struct intelfb_info *dinfo, struct intelfb_hwstate *hw, | 397 | intelfbhw_read_hw_state(struct intelfb_info *dinfo, struct intelfb_hwstate *hw, |
393 | int flag) | 398 | int flag) |
394 | { | 399 | { |
395 | int i; | 400 | int i; |
396 | 401 | ||
397 | #if VERBOSE > 0 | 402 | #if VERBOSE > 0 |
398 | DBG_MSG("intelfbhw_read_hw_state\n"); | 403 | DBG_MSG("intelfbhw_read_hw_state\n"); |
399 | #endif | 404 | #endif |
400 | 405 | ||
401 | if (!hw || !dinfo) | 406 | if (!hw || !dinfo) |
402 | return -1; | 407 | return -1; |
403 | 408 | ||
404 | /* Read in as much of the HW state as possible. */ | 409 | /* Read in as much of the HW state as possible. */ |
405 | hw->vga0_divisor = INREG(VGA0_DIVISOR); | 410 | hw->vga0_divisor = INREG(VGA0_DIVISOR); |
406 | hw->vga1_divisor = INREG(VGA1_DIVISOR); | 411 | hw->vga1_divisor = INREG(VGA1_DIVISOR); |
407 | hw->vga_pd = INREG(VGAPD); | 412 | hw->vga_pd = INREG(VGAPD); |
408 | hw->dpll_a = INREG(DPLL_A); | 413 | hw->dpll_a = INREG(DPLL_A); |
409 | hw->dpll_b = INREG(DPLL_B); | 414 | hw->dpll_b = INREG(DPLL_B); |
410 | hw->fpa0 = INREG(FPA0); | 415 | hw->fpa0 = INREG(FPA0); |
411 | hw->fpa1 = INREG(FPA1); | 416 | hw->fpa1 = INREG(FPA1); |
412 | hw->fpb0 = INREG(FPB0); | 417 | hw->fpb0 = INREG(FPB0); |
413 | hw->fpb1 = INREG(FPB1); | 418 | hw->fpb1 = INREG(FPB1); |
414 | 419 | ||
415 | if (flag == 1) | 420 | if (flag == 1) |
416 | return flag; | 421 | return flag; |
417 | 422 | ||
418 | #if 0 | 423 | #if 0 |
419 | /* This seems to be a problem with the 852GM/855GM */ | 424 | /* This seems to be a problem with the 852GM/855GM */ |
420 | for (i = 0; i < PALETTE_8_ENTRIES; i++) { | 425 | for (i = 0; i < PALETTE_8_ENTRIES; i++) { |
421 | hw->palette_a[i] = INREG(PALETTE_A + (i << 2)); | 426 | hw->palette_a[i] = INREG(PALETTE_A + (i << 2)); |
422 | hw->palette_b[i] = INREG(PALETTE_B + (i << 2)); | 427 | hw->palette_b[i] = INREG(PALETTE_B + (i << 2)); |
423 | } | 428 | } |
424 | #endif | 429 | #endif |
425 | 430 | ||
426 | if (flag == 2) | 431 | if (flag == 2) |
427 | return flag; | 432 | return flag; |
428 | 433 | ||
429 | hw->htotal_a = INREG(HTOTAL_A); | 434 | hw->htotal_a = INREG(HTOTAL_A); |
430 | hw->hblank_a = INREG(HBLANK_A); | 435 | hw->hblank_a = INREG(HBLANK_A); |
431 | hw->hsync_a = INREG(HSYNC_A); | 436 | hw->hsync_a = INREG(HSYNC_A); |
432 | hw->vtotal_a = INREG(VTOTAL_A); | 437 | hw->vtotal_a = INREG(VTOTAL_A); |
433 | hw->vblank_a = INREG(VBLANK_A); | 438 | hw->vblank_a = INREG(VBLANK_A); |
434 | hw->vsync_a = INREG(VSYNC_A); | 439 | hw->vsync_a = INREG(VSYNC_A); |
435 | hw->src_size_a = INREG(SRC_SIZE_A); | 440 | hw->src_size_a = INREG(SRC_SIZE_A); |
436 | hw->bclrpat_a = INREG(BCLRPAT_A); | 441 | hw->bclrpat_a = INREG(BCLRPAT_A); |
437 | hw->htotal_b = INREG(HTOTAL_B); | 442 | hw->htotal_b = INREG(HTOTAL_B); |
438 | hw->hblank_b = INREG(HBLANK_B); | 443 | hw->hblank_b = INREG(HBLANK_B); |
439 | hw->hsync_b = INREG(HSYNC_B); | 444 | hw->hsync_b = INREG(HSYNC_B); |
440 | hw->vtotal_b = INREG(VTOTAL_B); | 445 | hw->vtotal_b = INREG(VTOTAL_B); |
441 | hw->vblank_b = INREG(VBLANK_B); | 446 | hw->vblank_b = INREG(VBLANK_B); |
442 | hw->vsync_b = INREG(VSYNC_B); | 447 | hw->vsync_b = INREG(VSYNC_B); |
443 | hw->src_size_b = INREG(SRC_SIZE_B); | 448 | hw->src_size_b = INREG(SRC_SIZE_B); |
444 | hw->bclrpat_b = INREG(BCLRPAT_B); | 449 | hw->bclrpat_b = INREG(BCLRPAT_B); |
445 | 450 | ||
446 | if (flag == 3) | 451 | if (flag == 3) |
447 | return flag; | 452 | return flag; |
448 | 453 | ||
449 | hw->adpa = INREG(ADPA); | 454 | hw->adpa = INREG(ADPA); |
450 | hw->dvoa = INREG(DVOA); | 455 | hw->dvoa = INREG(DVOA); |
451 | hw->dvob = INREG(DVOB); | 456 | hw->dvob = INREG(DVOB); |
452 | hw->dvoc = INREG(DVOC); | 457 | hw->dvoc = INREG(DVOC); |
453 | hw->dvoa_srcdim = INREG(DVOA_SRCDIM); | 458 | hw->dvoa_srcdim = INREG(DVOA_SRCDIM); |
454 | hw->dvob_srcdim = INREG(DVOB_SRCDIM); | 459 | hw->dvob_srcdim = INREG(DVOB_SRCDIM); |
455 | hw->dvoc_srcdim = INREG(DVOC_SRCDIM); | 460 | hw->dvoc_srcdim = INREG(DVOC_SRCDIM); |
456 | hw->lvds = INREG(LVDS); | 461 | hw->lvds = INREG(LVDS); |
457 | 462 | ||
458 | if (flag == 4) | 463 | if (flag == 4) |
459 | return flag; | 464 | return flag; |
460 | 465 | ||
461 | hw->pipe_a_conf = INREG(PIPEACONF); | 466 | hw->pipe_a_conf = INREG(PIPEACONF); |
462 | hw->pipe_b_conf = INREG(PIPEBCONF); | 467 | hw->pipe_b_conf = INREG(PIPEBCONF); |
463 | hw->disp_arb = INREG(DISPARB); | 468 | hw->disp_arb = INREG(DISPARB); |
464 | 469 | ||
465 | if (flag == 5) | 470 | if (flag == 5) |
466 | return flag; | 471 | return flag; |
467 | 472 | ||
468 | hw->cursor_a_control = INREG(CURSOR_A_CONTROL); | 473 | hw->cursor_a_control = INREG(CURSOR_A_CONTROL); |
469 | hw->cursor_b_control = INREG(CURSOR_B_CONTROL); | 474 | hw->cursor_b_control = INREG(CURSOR_B_CONTROL); |
470 | hw->cursor_a_base = INREG(CURSOR_A_BASEADDR); | 475 | hw->cursor_a_base = INREG(CURSOR_A_BASEADDR); |
471 | hw->cursor_b_base = INREG(CURSOR_B_BASEADDR); | 476 | hw->cursor_b_base = INREG(CURSOR_B_BASEADDR); |
472 | 477 | ||
473 | if (flag == 6) | 478 | if (flag == 6) |
474 | return flag; | 479 | return flag; |
475 | 480 | ||
476 | for (i = 0; i < 4; i++) { | 481 | for (i = 0; i < 4; i++) { |
477 | hw->cursor_a_palette[i] = INREG(CURSOR_A_PALETTE0 + (i << 2)); | 482 | hw->cursor_a_palette[i] = INREG(CURSOR_A_PALETTE0 + (i << 2)); |
478 | hw->cursor_b_palette[i] = INREG(CURSOR_B_PALETTE0 + (i << 2)); | 483 | hw->cursor_b_palette[i] = INREG(CURSOR_B_PALETTE0 + (i << 2)); |
479 | } | 484 | } |
480 | 485 | ||
481 | if (flag == 7) | 486 | if (flag == 7) |
482 | return flag; | 487 | return flag; |
483 | 488 | ||
484 | hw->cursor_size = INREG(CURSOR_SIZE); | 489 | hw->cursor_size = INREG(CURSOR_SIZE); |
485 | 490 | ||
486 | if (flag == 8) | 491 | if (flag == 8) |
487 | return flag; | 492 | return flag; |
488 | 493 | ||
489 | hw->disp_a_ctrl = INREG(DSPACNTR); | 494 | hw->disp_a_ctrl = INREG(DSPACNTR); |
490 | hw->disp_b_ctrl = INREG(DSPBCNTR); | 495 | hw->disp_b_ctrl = INREG(DSPBCNTR); |
491 | hw->disp_a_base = INREG(DSPABASE); | 496 | hw->disp_a_base = INREG(DSPABASE); |
492 | hw->disp_b_base = INREG(DSPBBASE); | 497 | hw->disp_b_base = INREG(DSPBBASE); |
493 | hw->disp_a_stride = INREG(DSPASTRIDE); | 498 | hw->disp_a_stride = INREG(DSPASTRIDE); |
494 | hw->disp_b_stride = INREG(DSPBSTRIDE); | 499 | hw->disp_b_stride = INREG(DSPBSTRIDE); |
495 | 500 | ||
496 | if (flag == 9) | 501 | if (flag == 9) |
497 | return flag; | 502 | return flag; |
498 | 503 | ||
499 | hw->vgacntrl = INREG(VGACNTRL); | 504 | hw->vgacntrl = INREG(VGACNTRL); |
500 | 505 | ||
501 | if (flag == 10) | 506 | if (flag == 10) |
502 | return flag; | 507 | return flag; |
503 | 508 | ||
504 | hw->add_id = INREG(ADD_ID); | 509 | hw->add_id = INREG(ADD_ID); |
505 | 510 | ||
506 | if (flag == 11) | 511 | if (flag == 11) |
507 | return flag; | 512 | return flag; |
508 | 513 | ||
509 | for (i = 0; i < 7; i++) { | 514 | for (i = 0; i < 7; i++) { |
510 | hw->swf0x[i] = INREG(SWF00 + (i << 2)); | 515 | hw->swf0x[i] = INREG(SWF00 + (i << 2)); |
511 | hw->swf1x[i] = INREG(SWF10 + (i << 2)); | 516 | hw->swf1x[i] = INREG(SWF10 + (i << 2)); |
512 | if (i < 3) | 517 | if (i < 3) |
513 | hw->swf3x[i] = INREG(SWF30 + (i << 2)); | 518 | hw->swf3x[i] = INREG(SWF30 + (i << 2)); |
514 | } | 519 | } |
515 | 520 | ||
516 | for (i = 0; i < 8; i++) | 521 | for (i = 0; i < 8; i++) |
517 | hw->fence[i] = INREG(FENCE + (i << 2)); | 522 | hw->fence[i] = INREG(FENCE + (i << 2)); |
518 | 523 | ||
519 | hw->instpm = INREG(INSTPM); | 524 | hw->instpm = INREG(INSTPM); |
520 | hw->mem_mode = INREG(MEM_MODE); | 525 | hw->mem_mode = INREG(MEM_MODE); |
521 | hw->fw_blc_0 = INREG(FW_BLC_0); | 526 | hw->fw_blc_0 = INREG(FW_BLC_0); |
522 | hw->fw_blc_1 = INREG(FW_BLC_1); | 527 | hw->fw_blc_1 = INREG(FW_BLC_1); |
523 | 528 | ||
524 | return 0; | 529 | return 0; |
525 | } | 530 | } |
526 | 531 | ||
527 | 532 | ||
528 | void | 533 | void |
529 | intelfbhw_print_hw_state(struct intelfb_info *dinfo, struct intelfb_hwstate *hw) | 534 | intelfbhw_print_hw_state(struct intelfb_info *dinfo, struct intelfb_hwstate *hw) |
530 | { | 535 | { |
531 | #if REGDUMP | 536 | #if REGDUMP |
532 | int i, m1, m2, n, p1, p2; | 537 | int i, m1, m2, n, p1, p2; |
533 | 538 | ||
534 | DBG_MSG("intelfbhw_print_hw_state\n"); | 539 | DBG_MSG("intelfbhw_print_hw_state\n"); |
535 | 540 | ||
536 | if (!hw || !dinfo) | 541 | if (!hw || !dinfo) |
537 | return; | 542 | return; |
538 | /* Read in as much of the HW state as possible. */ | 543 | /* Read in as much of the HW state as possible. */ |
539 | printk("hw state dump start\n"); | 544 | printk("hw state dump start\n"); |
540 | printk(" VGA0_DIVISOR: 0x%08x\n", hw->vga0_divisor); | 545 | printk(" VGA0_DIVISOR: 0x%08x\n", hw->vga0_divisor); |
541 | printk(" VGA1_DIVISOR: 0x%08x\n", hw->vga1_divisor); | 546 | printk(" VGA1_DIVISOR: 0x%08x\n", hw->vga1_divisor); |
542 | printk(" VGAPD: 0x%08x\n", hw->vga_pd); | 547 | printk(" VGAPD: 0x%08x\n", hw->vga_pd); |
543 | n = (hw->vga0_divisor >> FP_N_DIVISOR_SHIFT) & FP_DIVISOR_MASK; | 548 | n = (hw->vga0_divisor >> FP_N_DIVISOR_SHIFT) & FP_DIVISOR_MASK; |
544 | m1 = (hw->vga0_divisor >> FP_M1_DIVISOR_SHIFT) & FP_DIVISOR_MASK; | 549 | m1 = (hw->vga0_divisor >> FP_M1_DIVISOR_SHIFT) & FP_DIVISOR_MASK; |
545 | m2 = (hw->vga0_divisor >> FP_M2_DIVISOR_SHIFT) & FP_DIVISOR_MASK; | 550 | m2 = (hw->vga0_divisor >> FP_M2_DIVISOR_SHIFT) & FP_DIVISOR_MASK; |
546 | if (hw->vga_pd & VGAPD_0_P1_FORCE_DIV2) | 551 | if (hw->vga_pd & VGAPD_0_P1_FORCE_DIV2) |
547 | p1 = 0; | 552 | p1 = 0; |
548 | else | 553 | else |
549 | p1 = (hw->vga_pd >> VGAPD_0_P1_SHIFT) & DPLL_P1_MASK; | 554 | p1 = (hw->vga_pd >> VGAPD_0_P1_SHIFT) & DPLL_P1_MASK; |
550 | p2 = (hw->vga_pd >> VGAPD_0_P2_SHIFT) & DPLL_P2_MASK; | 555 | p2 = (hw->vga_pd >> VGAPD_0_P2_SHIFT) & DPLL_P2_MASK; |
551 | printk(" VGA0: (m1, m2, n, p1, p2) = (%d, %d, %d, %d, %d)\n", | 556 | printk(" VGA0: (m1, m2, n, p1, p2) = (%d, %d, %d, %d, %d)\n", |
552 | m1, m2, n, p1, p2); | 557 | m1, m2, n, p1, p2); |
553 | printk(" VGA0: clock is %d\n", CALC_VCLOCK(m1, m2, n, p1, p2)); | 558 | printk(" VGA0: clock is %d\n", CALC_VCLOCK(m1, m2, n, p1, p2)); |
554 | 559 | ||
555 | n = (hw->vga1_divisor >> FP_N_DIVISOR_SHIFT) & FP_DIVISOR_MASK; | 560 | n = (hw->vga1_divisor >> FP_N_DIVISOR_SHIFT) & FP_DIVISOR_MASK; |
556 | m1 = (hw->vga1_divisor >> FP_M1_DIVISOR_SHIFT) & FP_DIVISOR_MASK; | 561 | m1 = (hw->vga1_divisor >> FP_M1_DIVISOR_SHIFT) & FP_DIVISOR_MASK; |
557 | m2 = (hw->vga1_divisor >> FP_M2_DIVISOR_SHIFT) & FP_DIVISOR_MASK; | 562 | m2 = (hw->vga1_divisor >> FP_M2_DIVISOR_SHIFT) & FP_DIVISOR_MASK; |
558 | if (hw->vga_pd & VGAPD_1_P1_FORCE_DIV2) | 563 | if (hw->vga_pd & VGAPD_1_P1_FORCE_DIV2) |
559 | p1 = 0; | 564 | p1 = 0; |
560 | else | 565 | else |
561 | p1 = (hw->vga_pd >> VGAPD_1_P1_SHIFT) & DPLL_P1_MASK; | 566 | p1 = (hw->vga_pd >> VGAPD_1_P1_SHIFT) & DPLL_P1_MASK; |
562 | p2 = (hw->vga_pd >> VGAPD_1_P2_SHIFT) & DPLL_P2_MASK; | 567 | p2 = (hw->vga_pd >> VGAPD_1_P2_SHIFT) & DPLL_P2_MASK; |
563 | printk(" VGA1: (m1, m2, n, p1, p2) = (%d, %d, %d, %d, %d)\n", | 568 | printk(" VGA1: (m1, m2, n, p1, p2) = (%d, %d, %d, %d, %d)\n", |
564 | m1, m2, n, p1, p2); | 569 | m1, m2, n, p1, p2); |
565 | printk(" VGA1: clock is %d\n", CALC_VCLOCK(m1, m2, n, p1, p2)); | 570 | printk(" VGA1: clock is %d\n", CALC_VCLOCK(m1, m2, n, p1, p2)); |
566 | 571 | ||
567 | printk(" DPLL_A: 0x%08x\n", hw->dpll_a); | 572 | printk(" DPLL_A: 0x%08x\n", hw->dpll_a); |
568 | printk(" DPLL_B: 0x%08x\n", hw->dpll_b); | 573 | printk(" DPLL_B: 0x%08x\n", hw->dpll_b); |
569 | printk(" FPA0: 0x%08x\n", hw->fpa0); | 574 | printk(" FPA0: 0x%08x\n", hw->fpa0); |
570 | printk(" FPA1: 0x%08x\n", hw->fpa1); | 575 | printk(" FPA1: 0x%08x\n", hw->fpa1); |
571 | printk(" FPB0: 0x%08x\n", hw->fpb0); | 576 | printk(" FPB0: 0x%08x\n", hw->fpb0); |
572 | printk(" FPB1: 0x%08x\n", hw->fpb1); | 577 | printk(" FPB1: 0x%08x\n", hw->fpb1); |
573 | 578 | ||
574 | n = (hw->fpa0 >> FP_N_DIVISOR_SHIFT) & FP_DIVISOR_MASK; | 579 | n = (hw->fpa0 >> FP_N_DIVISOR_SHIFT) & FP_DIVISOR_MASK; |
575 | m1 = (hw->fpa0 >> FP_M1_DIVISOR_SHIFT) & FP_DIVISOR_MASK; | 580 | m1 = (hw->fpa0 >> FP_M1_DIVISOR_SHIFT) & FP_DIVISOR_MASK; |
576 | m2 = (hw->fpa0 >> FP_M2_DIVISOR_SHIFT) & FP_DIVISOR_MASK; | 581 | m2 = (hw->fpa0 >> FP_M2_DIVISOR_SHIFT) & FP_DIVISOR_MASK; |
577 | if (hw->dpll_a & DPLL_P1_FORCE_DIV2) | 582 | if (hw->dpll_a & DPLL_P1_FORCE_DIV2) |
578 | p1 = 0; | 583 | p1 = 0; |
579 | else | 584 | else |
580 | p1 = (hw->dpll_a >> DPLL_P1_SHIFT) & DPLL_P1_MASK; | 585 | p1 = (hw->dpll_a >> DPLL_P1_SHIFT) & DPLL_P1_MASK; |
581 | p2 = (hw->dpll_a >> DPLL_P2_SHIFT) & DPLL_P2_MASK; | 586 | p2 = (hw->dpll_a >> DPLL_P2_SHIFT) & DPLL_P2_MASK; |
582 | printk(" PLLA0: (m1, m2, n, p1, p2) = (%d, %d, %d, %d, %d)\n", | 587 | printk(" PLLA0: (m1, m2, n, p1, p2) = (%d, %d, %d, %d, %d)\n", |
583 | m1, m2, n, p1, p2); | 588 | m1, m2, n, p1, p2); |
584 | printk(" PLLA0: clock is %d\n", CALC_VCLOCK(m1, m2, n, p1, p2)); | 589 | printk(" PLLA0: clock is %d\n", CALC_VCLOCK(m1, m2, n, p1, p2)); |
585 | 590 | ||
586 | n = (hw->fpa1 >> FP_N_DIVISOR_SHIFT) & FP_DIVISOR_MASK; | 591 | n = (hw->fpa1 >> FP_N_DIVISOR_SHIFT) & FP_DIVISOR_MASK; |
587 | m1 = (hw->fpa1 >> FP_M1_DIVISOR_SHIFT) & FP_DIVISOR_MASK; | 592 | m1 = (hw->fpa1 >> FP_M1_DIVISOR_SHIFT) & FP_DIVISOR_MASK; |
588 | m2 = (hw->fpa1 >> FP_M2_DIVISOR_SHIFT) & FP_DIVISOR_MASK; | 593 | m2 = (hw->fpa1 >> FP_M2_DIVISOR_SHIFT) & FP_DIVISOR_MASK; |
589 | if (hw->dpll_a & DPLL_P1_FORCE_DIV2) | 594 | if (hw->dpll_a & DPLL_P1_FORCE_DIV2) |
590 | p1 = 0; | 595 | p1 = 0; |
591 | else | 596 | else |
592 | p1 = (hw->dpll_a >> DPLL_P1_SHIFT) & DPLL_P1_MASK; | 597 | p1 = (hw->dpll_a >> DPLL_P1_SHIFT) & DPLL_P1_MASK; |
593 | p2 = (hw->dpll_a >> DPLL_P2_SHIFT) & DPLL_P2_MASK; | 598 | p2 = (hw->dpll_a >> DPLL_P2_SHIFT) & DPLL_P2_MASK; |
594 | printk(" PLLA1: (m1, m2, n, p1, p2) = (%d, %d, %d, %d, %d)\n", | 599 | printk(" PLLA1: (m1, m2, n, p1, p2) = (%d, %d, %d, %d, %d)\n", |
595 | m1, m2, n, p1, p2); | 600 | m1, m2, n, p1, p2); |
596 | printk(" PLLA1: clock is %d\n", CALC_VCLOCK(m1, m2, n, p1, p2)); | 601 | printk(" PLLA1: clock is %d\n", CALC_VCLOCK(m1, m2, n, p1, p2)); |
597 | 602 | ||
598 | #if 0 | 603 | #if 0 |
599 | printk(" PALETTE_A:\n"); | 604 | printk(" PALETTE_A:\n"); |
600 | for (i = 0; i < PALETTE_8_ENTRIES) | 605 | for (i = 0; i < PALETTE_8_ENTRIES) |
601 | printk(" %3d: 0x%08x\n", i, hw->palette_a[i]; | 606 | printk(" %3d: 0x%08x\n", i, hw->palette_a[i]; |
602 | printk(" PALETTE_B:\n"); | 607 | printk(" PALETTE_B:\n"); |
603 | for (i = 0; i < PALETTE_8_ENTRIES) | 608 | for (i = 0; i < PALETTE_8_ENTRIES) |
604 | printk(" %3d: 0x%08x\n", i, hw->palette_b[i]; | 609 | printk(" %3d: 0x%08x\n", i, hw->palette_b[i]; |
605 | #endif | 610 | #endif |
606 | 611 | ||
607 | printk(" HTOTAL_A: 0x%08x\n", hw->htotal_a); | 612 | printk(" HTOTAL_A: 0x%08x\n", hw->htotal_a); |
608 | printk(" HBLANK_A: 0x%08x\n", hw->hblank_a); | 613 | printk(" HBLANK_A: 0x%08x\n", hw->hblank_a); |
609 | printk(" HSYNC_A: 0x%08x\n", hw->hsync_a); | 614 | printk(" HSYNC_A: 0x%08x\n", hw->hsync_a); |
610 | printk(" VTOTAL_A: 0x%08x\n", hw->vtotal_a); | 615 | printk(" VTOTAL_A: 0x%08x\n", hw->vtotal_a); |
611 | printk(" VBLANK_A: 0x%08x\n", hw->vblank_a); | 616 | printk(" VBLANK_A: 0x%08x\n", hw->vblank_a); |
612 | printk(" VSYNC_A: 0x%08x\n", hw->vsync_a); | 617 | printk(" VSYNC_A: 0x%08x\n", hw->vsync_a); |
613 | printk(" SRC_SIZE_A: 0x%08x\n", hw->src_size_a); | 618 | printk(" SRC_SIZE_A: 0x%08x\n", hw->src_size_a); |
614 | printk(" BCLRPAT_A: 0x%08x\n", hw->bclrpat_a); | 619 | printk(" BCLRPAT_A: 0x%08x\n", hw->bclrpat_a); |
615 | printk(" HTOTAL_B: 0x%08x\n", hw->htotal_b); | 620 | printk(" HTOTAL_B: 0x%08x\n", hw->htotal_b); |
616 | printk(" HBLANK_B: 0x%08x\n", hw->hblank_b); | 621 | printk(" HBLANK_B: 0x%08x\n", hw->hblank_b); |
617 | printk(" HSYNC_B: 0x%08x\n", hw->hsync_b); | 622 | printk(" HSYNC_B: 0x%08x\n", hw->hsync_b); |
618 | printk(" VTOTAL_B: 0x%08x\n", hw->vtotal_b); | 623 | printk(" VTOTAL_B: 0x%08x\n", hw->vtotal_b); |
619 | printk(" VBLANK_B: 0x%08x\n", hw->vblank_b); | 624 | printk(" VBLANK_B: 0x%08x\n", hw->vblank_b); |
620 | printk(" VSYNC_B: 0x%08x\n", hw->vsync_b); | 625 | printk(" VSYNC_B: 0x%08x\n", hw->vsync_b); |
621 | printk(" SRC_SIZE_B: 0x%08x\n", hw->src_size_b); | 626 | printk(" SRC_SIZE_B: 0x%08x\n", hw->src_size_b); |
622 | printk(" BCLRPAT_B: 0x%08x\n", hw->bclrpat_b); | 627 | printk(" BCLRPAT_B: 0x%08x\n", hw->bclrpat_b); |
623 | 628 | ||
624 | printk(" ADPA: 0x%08x\n", hw->adpa); | 629 | printk(" ADPA: 0x%08x\n", hw->adpa); |
625 | printk(" DVOA: 0x%08x\n", hw->dvoa); | 630 | printk(" DVOA: 0x%08x\n", hw->dvoa); |
626 | printk(" DVOB: 0x%08x\n", hw->dvob); | 631 | printk(" DVOB: 0x%08x\n", hw->dvob); |
627 | printk(" DVOC: 0x%08x\n", hw->dvoc); | 632 | printk(" DVOC: 0x%08x\n", hw->dvoc); |
628 | printk(" DVOA_SRCDIM: 0x%08x\n", hw->dvoa_srcdim); | 633 | printk(" DVOA_SRCDIM: 0x%08x\n", hw->dvoa_srcdim); |
629 | printk(" DVOB_SRCDIM: 0x%08x\n", hw->dvob_srcdim); | 634 | printk(" DVOB_SRCDIM: 0x%08x\n", hw->dvob_srcdim); |
630 | printk(" DVOC_SRCDIM: 0x%08x\n", hw->dvoc_srcdim); | 635 | printk(" DVOC_SRCDIM: 0x%08x\n", hw->dvoc_srcdim); |
631 | printk(" LVDS: 0x%08x\n", hw->lvds); | 636 | printk(" LVDS: 0x%08x\n", hw->lvds); |
632 | 637 | ||
633 | printk(" PIPEACONF: 0x%08x\n", hw->pipe_a_conf); | 638 | printk(" PIPEACONF: 0x%08x\n", hw->pipe_a_conf); |
634 | printk(" PIPEBCONF: 0x%08x\n", hw->pipe_b_conf); | 639 | printk(" PIPEBCONF: 0x%08x\n", hw->pipe_b_conf); |
635 | printk(" DISPARB: 0x%08x\n", hw->disp_arb); | 640 | printk(" DISPARB: 0x%08x\n", hw->disp_arb); |
636 | 641 | ||
637 | printk(" CURSOR_A_CONTROL: 0x%08x\n", hw->cursor_a_control); | 642 | printk(" CURSOR_A_CONTROL: 0x%08x\n", hw->cursor_a_control); |
638 | printk(" CURSOR_B_CONTROL: 0x%08x\n", hw->cursor_b_control); | 643 | printk(" CURSOR_B_CONTROL: 0x%08x\n", hw->cursor_b_control); |
639 | printk(" CURSOR_A_BASEADDR: 0x%08x\n", hw->cursor_a_base); | 644 | printk(" CURSOR_A_BASEADDR: 0x%08x\n", hw->cursor_a_base); |
640 | printk(" CURSOR_B_BASEADDR: 0x%08x\n", hw->cursor_b_base); | 645 | printk(" CURSOR_B_BASEADDR: 0x%08x\n", hw->cursor_b_base); |
641 | 646 | ||
642 | printk(" CURSOR_A_PALETTE: "); | 647 | printk(" CURSOR_A_PALETTE: "); |
643 | for (i = 0; i < 4; i++) { | 648 | for (i = 0; i < 4; i++) { |
644 | printk("0x%08x", hw->cursor_a_palette[i]); | 649 | printk("0x%08x", hw->cursor_a_palette[i]); |
645 | if (i < 3) | 650 | if (i < 3) |
646 | printk(", "); | 651 | printk(", "); |
647 | } | 652 | } |
648 | printk("\n"); | 653 | printk("\n"); |
649 | printk(" CURSOR_B_PALETTE: "); | 654 | printk(" CURSOR_B_PALETTE: "); |
650 | for (i = 0; i < 4; i++) { | 655 | for (i = 0; i < 4; i++) { |
651 | printk("0x%08x", hw->cursor_b_palette[i]); | 656 | printk("0x%08x", hw->cursor_b_palette[i]); |
652 | if (i < 3) | 657 | if (i < 3) |
653 | printk(", "); | 658 | printk(", "); |
654 | } | 659 | } |
655 | printk("\n"); | 660 | printk("\n"); |
656 | 661 | ||
657 | printk(" CURSOR_SIZE: 0x%08x\n", hw->cursor_size); | 662 | printk(" CURSOR_SIZE: 0x%08x\n", hw->cursor_size); |
658 | 663 | ||
659 | printk(" DSPACNTR: 0x%08x\n", hw->disp_a_ctrl); | 664 | printk(" DSPACNTR: 0x%08x\n", hw->disp_a_ctrl); |
660 | printk(" DSPBCNTR: 0x%08x\n", hw->disp_b_ctrl); | 665 | printk(" DSPBCNTR: 0x%08x\n", hw->disp_b_ctrl); |
661 | printk(" DSPABASE: 0x%08x\n", hw->disp_a_base); | 666 | printk(" DSPABASE: 0x%08x\n", hw->disp_a_base); |
662 | printk(" DSPBBASE: 0x%08x\n", hw->disp_b_base); | 667 | printk(" DSPBBASE: 0x%08x\n", hw->disp_b_base); |
663 | printk(" DSPASTRIDE: 0x%08x\n", hw->disp_a_stride); | 668 | printk(" DSPASTRIDE: 0x%08x\n", hw->disp_a_stride); |
664 | printk(" DSPBSTRIDE: 0x%08x\n", hw->disp_b_stride); | 669 | printk(" DSPBSTRIDE: 0x%08x\n", hw->disp_b_stride); |
665 | 670 | ||
666 | printk(" VGACNTRL: 0x%08x\n", hw->vgacntrl); | 671 | printk(" VGACNTRL: 0x%08x\n", hw->vgacntrl); |
667 | printk(" ADD_ID: 0x%08x\n", hw->add_id); | 672 | printk(" ADD_ID: 0x%08x\n", hw->add_id); |
668 | 673 | ||
669 | for (i = 0; i < 7; i++) { | 674 | for (i = 0; i < 7; i++) { |
670 | printk(" SWF0%d 0x%08x\n", i, | 675 | printk(" SWF0%d 0x%08x\n", i, |
671 | hw->swf0x[i]); | 676 | hw->swf0x[i]); |
672 | } | 677 | } |
673 | for (i = 0; i < 7; i++) { | 678 | for (i = 0; i < 7; i++) { |
674 | printk(" SWF1%d 0x%08x\n", i, | 679 | printk(" SWF1%d 0x%08x\n", i, |
675 | hw->swf1x[i]); | 680 | hw->swf1x[i]); |
676 | } | 681 | } |
677 | for (i = 0; i < 3; i++) { | 682 | for (i = 0; i < 3; i++) { |
678 | printk(" SWF3%d 0x%08x\n", i, | 683 | printk(" SWF3%d 0x%08x\n", i, |
679 | hw->swf3x[i]); | 684 | hw->swf3x[i]); |
680 | } | 685 | } |
681 | for (i = 0; i < 8; i++) | 686 | for (i = 0; i < 8; i++) |
682 | printk(" FENCE%d 0x%08x\n", i, | 687 | printk(" FENCE%d 0x%08x\n", i, |
683 | hw->fence[i]); | 688 | hw->fence[i]); |
684 | 689 | ||
685 | printk(" INSTPM 0x%08x\n", hw->instpm); | 690 | printk(" INSTPM 0x%08x\n", hw->instpm); |
686 | printk(" MEM_MODE 0x%08x\n", hw->mem_mode); | 691 | printk(" MEM_MODE 0x%08x\n", hw->mem_mode); |
687 | printk(" FW_BLC_0 0x%08x\n", hw->fw_blc_0); | 692 | printk(" FW_BLC_0 0x%08x\n", hw->fw_blc_0); |
688 | printk(" FW_BLC_1 0x%08x\n", hw->fw_blc_1); | 693 | printk(" FW_BLC_1 0x%08x\n", hw->fw_blc_1); |
689 | 694 | ||
690 | printk("hw state dump end\n"); | 695 | printk("hw state dump end\n"); |
691 | #endif | 696 | #endif |
692 | } | 697 | } |
693 | 698 | ||
694 | /* Split the M parameter into M1 and M2. */ | 699 | /* Split the M parameter into M1 and M2. */ |
695 | static int | 700 | static int |
696 | splitm(unsigned int m, unsigned int *retm1, unsigned int *retm2) | 701 | splitm(unsigned int m, unsigned int *retm1, unsigned int *retm2) |
697 | { | 702 | { |
698 | int m1, m2; | 703 | int m1, m2; |
699 | 704 | ||
700 | m1 = (m - 2 - (MIN_M2 + MAX_M2) / 2) / 5 - 2; | 705 | m1 = (m - 2 - (MIN_M2 + MAX_M2) / 2) / 5 - 2; |
701 | if (m1 < MIN_M1) | 706 | if (m1 < MIN_M1) |
702 | m1 = MIN_M1; | 707 | m1 = MIN_M1; |
703 | if (m1 > MAX_M1) | 708 | if (m1 > MAX_M1) |
704 | m1 = MAX_M1; | 709 | m1 = MAX_M1; |
705 | m2 = m - 5 * (m1 + 2) - 2; | 710 | m2 = m - 5 * (m1 + 2) - 2; |
706 | if (m2 < MIN_M2 || m2 > MAX_M2 || m2 >= m1) { | 711 | if (m2 < MIN_M2 || m2 > MAX_M2 || m2 >= m1) { |
707 | return 1; | 712 | return 1; |
708 | } else { | 713 | } else { |
709 | *retm1 = (unsigned int)m1; | 714 | *retm1 = (unsigned int)m1; |
710 | *retm2 = (unsigned int)m2; | 715 | *retm2 = (unsigned int)m2; |
711 | return 0; | 716 | return 0; |
712 | } | 717 | } |
713 | } | 718 | } |
714 | 719 | ||
715 | /* Split the P parameter into P1 and P2. */ | 720 | /* Split the P parameter into P1 and P2. */ |
716 | static int | 721 | static int |
717 | splitp(unsigned int p, unsigned int *retp1, unsigned int *retp2) | 722 | splitp(unsigned int p, unsigned int *retp1, unsigned int *retp2) |
718 | { | 723 | { |
719 | int p1, p2; | 724 | int p1, p2; |
720 | 725 | ||
721 | if (p % 4 == 0) | 726 | if (p % 4 == 0) |
722 | p2 = 1; | 727 | p2 = 1; |
723 | else | 728 | else |
724 | p2 = 0; | 729 | p2 = 0; |
725 | p1 = (p / (1 << (p2 + 1))) - 2; | 730 | p1 = (p / (1 << (p2 + 1))) - 2; |
726 | if (p % 4 == 0 && p1 < MIN_P1) { | 731 | if (p % 4 == 0 && p1 < MIN_P1) { |
727 | p2 = 0; | 732 | p2 = 0; |
728 | p1 = (p / (1 << (p2 + 1))) - 2; | 733 | p1 = (p / (1 << (p2 + 1))) - 2; |
729 | } | 734 | } |
730 | if (p1 < MIN_P1 || p1 > MAX_P1 || (p1 + 2) * (1 << (p2 + 1)) != p) { | 735 | if (p1 < MIN_P1 || p1 > MAX_P1 || (p1 + 2) * (1 << (p2 + 1)) != p) { |
731 | return 1; | 736 | return 1; |
732 | } else { | 737 | } else { |
733 | *retp1 = (unsigned int)p1; | 738 | *retp1 = (unsigned int)p1; |
734 | *retp2 = (unsigned int)p2; | 739 | *retp2 = (unsigned int)p2; |
735 | return 0; | 740 | return 0; |
736 | } | 741 | } |
737 | } | 742 | } |
738 | 743 | ||
739 | static int | 744 | static int |
740 | calc_pll_params(int clock, u32 *retm1, u32 *retm2, u32 *retn, u32 *retp1, | 745 | calc_pll_params(int clock, u32 *retm1, u32 *retm2, u32 *retn, u32 *retp1, |
741 | u32 *retp2, u32 *retclock) | 746 | u32 *retp2, u32 *retclock) |
742 | { | 747 | { |
743 | u32 m1, m2, n, p1, p2, n1; | 748 | u32 m1, m2, n, p1, p2, n1; |
744 | u32 f_vco, p, p_best = 0, m, f_out; | 749 | u32 f_vco, p, p_best = 0, m, f_out; |
745 | u32 err_max, err_target, err_best = 10000000; | 750 | u32 err_max, err_target, err_best = 10000000; |
746 | u32 n_best = 0, m_best = 0, f_best, f_err; | 751 | u32 n_best = 0, m_best = 0, f_best, f_err; |
747 | u32 p_min, p_max, p_inc, div_min, div_max; | 752 | u32 p_min, p_max, p_inc, div_min, div_max; |
748 | 753 | ||
749 | /* Accept 0.5% difference, but aim for 0.1% */ | 754 | /* Accept 0.5% difference, but aim for 0.1% */ |
750 | err_max = 5 * clock / 1000; | 755 | err_max = 5 * clock / 1000; |
751 | err_target = clock / 1000; | 756 | err_target = clock / 1000; |
752 | 757 | ||
753 | DBG_MSG("Clock is %d\n", clock); | 758 | DBG_MSG("Clock is %d\n", clock); |
754 | 759 | ||
755 | div_max = MAX_VCO_FREQ / clock; | 760 | div_max = MAX_VCO_FREQ / clock; |
756 | div_min = ROUND_UP_TO(MIN_VCO_FREQ, clock) / clock; | 761 | div_min = ROUND_UP_TO(MIN_VCO_FREQ, clock) / clock; |
757 | 762 | ||
758 | if (clock <= P_TRANSITION_CLOCK) | 763 | if (clock <= P_TRANSITION_CLOCK) |
759 | p_inc = 4; | 764 | p_inc = 4; |
760 | else | 765 | else |
761 | p_inc = 2; | 766 | p_inc = 2; |
762 | p_min = ROUND_UP_TO(div_min, p_inc); | 767 | p_min = ROUND_UP_TO(div_min, p_inc); |
763 | p_max = ROUND_DOWN_TO(div_max, p_inc); | 768 | p_max = ROUND_DOWN_TO(div_max, p_inc); |
764 | if (p_min < MIN_P) | 769 | if (p_min < MIN_P) |
765 | p_min = 4; | 770 | p_min = 4; |
766 | if (p_max > MAX_P) | 771 | if (p_max > MAX_P) |
767 | p_max = 128; | 772 | p_max = 128; |
768 | 773 | ||
769 | DBG_MSG("p range is %d-%d (%d)\n", p_min, p_max, p_inc); | 774 | DBG_MSG("p range is %d-%d (%d)\n", p_min, p_max, p_inc); |
770 | 775 | ||
771 | p = p_min; | 776 | p = p_min; |
772 | do { | 777 | do { |
773 | if (splitp(p, &p1, &p2)) { | 778 | if (splitp(p, &p1, &p2)) { |
774 | WRN_MSG("cannot split p = %d\n", p); | 779 | WRN_MSG("cannot split p = %d\n", p); |
775 | p += p_inc; | 780 | p += p_inc; |
776 | continue; | 781 | continue; |
777 | } | 782 | } |
778 | n = MIN_N; | 783 | n = MIN_N; |
779 | f_vco = clock * p; | 784 | f_vco = clock * p; |
780 | 785 | ||
781 | do { | 786 | do { |
782 | m = ROUND_UP_TO(f_vco * n, PLL_REFCLK) / PLL_REFCLK; | 787 | m = ROUND_UP_TO(f_vco * n, PLL_REFCLK) / PLL_REFCLK; |
783 | if (m < MIN_M) | 788 | if (m < MIN_M) |
784 | m = MIN_M; | 789 | m = MIN_M; |
785 | if (m > MAX_M) | 790 | if (m > MAX_M) |
786 | m = MAX_M; | 791 | m = MAX_M; |
787 | f_out = CALC_VCLOCK3(m, n, p); | 792 | f_out = CALC_VCLOCK3(m, n, p); |
788 | if (splitm(m, &m1, &m2)) { | 793 | if (splitm(m, &m1, &m2)) { |
789 | WRN_MSG("cannot split m = %d\n", m); | 794 | WRN_MSG("cannot split m = %d\n", m); |
790 | n++; | 795 | n++; |
791 | continue; | 796 | continue; |
792 | } | 797 | } |
793 | if (clock > f_out) | 798 | if (clock > f_out) |
794 | f_err = clock - f_out; | 799 | f_err = clock - f_out; |
795 | else | 800 | else |
796 | f_err = f_out - clock; | 801 | f_err = f_out - clock; |
797 | 802 | ||
798 | if (f_err < err_best) { | 803 | if (f_err < err_best) { |
799 | m_best = m; | 804 | m_best = m; |
800 | n_best = n; | 805 | n_best = n; |
801 | p_best = p; | 806 | p_best = p; |
802 | f_best = f_out; | 807 | f_best = f_out; |
803 | err_best = f_err; | 808 | err_best = f_err; |
804 | } | 809 | } |
805 | n++; | 810 | n++; |
806 | } while ((n <= MAX_N) && (f_out >= clock)); | 811 | } while ((n <= MAX_N) && (f_out >= clock)); |
807 | p += p_inc; | 812 | p += p_inc; |
808 | } while ((p <= p_max)); | 813 | } while ((p <= p_max)); |
809 | 814 | ||
810 | if (!m_best) { | 815 | if (!m_best) { |
811 | WRN_MSG("cannot find parameters for clock %d\n", clock); | 816 | WRN_MSG("cannot find parameters for clock %d\n", clock); |
812 | return 1; | 817 | return 1; |
813 | } | 818 | } |
814 | m = m_best; | 819 | m = m_best; |
815 | n = n_best; | 820 | n = n_best; |
816 | p = p_best; | 821 | p = p_best; |
817 | splitm(m, &m1, &m2); | 822 | splitm(m, &m1, &m2); |
818 | splitp(p, &p1, &p2); | 823 | splitp(p, &p1, &p2); |
819 | n1 = n - 2; | 824 | n1 = n - 2; |
820 | 825 | ||
821 | DBG_MSG("m, n, p: %d (%d,%d), %d (%d), %d (%d,%d), " | 826 | DBG_MSG("m, n, p: %d (%d,%d), %d (%d), %d (%d,%d), " |
822 | "f: %d (%d), VCO: %d\n", | 827 | "f: %d (%d), VCO: %d\n", |
823 | m, m1, m2, n, n1, p, p1, p2, | 828 | m, m1, m2, n, n1, p, p1, p2, |
824 | CALC_VCLOCK3(m, n, p), CALC_VCLOCK(m1, m2, n1, p1, p2), | 829 | CALC_VCLOCK3(m, n, p), CALC_VCLOCK(m1, m2, n1, p1, p2), |
825 | CALC_VCLOCK3(m, n, p) * p); | 830 | CALC_VCLOCK3(m, n, p) * p); |
826 | *retm1 = m1; | 831 | *retm1 = m1; |
827 | *retm2 = m2; | 832 | *retm2 = m2; |
828 | *retn = n1; | 833 | *retn = n1; |
829 | *retp1 = p1; | 834 | *retp1 = p1; |
830 | *retp2 = p2; | 835 | *retp2 = p2; |
831 | *retclock = CALC_VCLOCK(m1, m2, n1, p1, p2); | 836 | *retclock = CALC_VCLOCK(m1, m2, n1, p1, p2); |
832 | 837 | ||
833 | return 0; | 838 | return 0; |
834 | } | 839 | } |
835 | 840 | ||
836 | static __inline__ int | 841 | static __inline__ int |
837 | check_overflow(u32 value, u32 limit, const char *description) | 842 | check_overflow(u32 value, u32 limit, const char *description) |
838 | { | 843 | { |
839 | if (value > limit) { | 844 | if (value > limit) { |
840 | WRN_MSG("%s value %d exceeds limit %d\n", | 845 | WRN_MSG("%s value %d exceeds limit %d\n", |
841 | description, value, limit); | 846 | description, value, limit); |
842 | return 1; | 847 | return 1; |
843 | } | 848 | } |
844 | return 0; | 849 | return 0; |
845 | } | 850 | } |
846 | 851 | ||
847 | /* It is assumed that hw is filled in with the initial state information. */ | 852 | /* It is assumed that hw is filled in with the initial state information. */ |
848 | int | 853 | int |
849 | intelfbhw_mode_to_hw(struct intelfb_info *dinfo, struct intelfb_hwstate *hw, | 854 | intelfbhw_mode_to_hw(struct intelfb_info *dinfo, struct intelfb_hwstate *hw, |
850 | struct fb_var_screeninfo *var) | 855 | struct fb_var_screeninfo *var) |
851 | { | 856 | { |
852 | int pipe = PIPE_A; | 857 | int pipe = PIPE_A; |
853 | u32 *dpll, *fp0, *fp1; | 858 | u32 *dpll, *fp0, *fp1; |
854 | u32 m1, m2, n, p1, p2, clock_target, clock; | 859 | u32 m1, m2, n, p1, p2, clock_target, clock; |
855 | u32 hsync_start, hsync_end, hblank_start, hblank_end, htotal, hactive; | 860 | u32 hsync_start, hsync_end, hblank_start, hblank_end, htotal, hactive; |
856 | u32 vsync_start, vsync_end, vblank_start, vblank_end, vtotal, vactive; | 861 | u32 vsync_start, vsync_end, vblank_start, vblank_end, vtotal, vactive; |
857 | u32 vsync_pol, hsync_pol; | 862 | u32 vsync_pol, hsync_pol; |
858 | u32 *vs, *vb, *vt, *hs, *hb, *ht, *ss, *pipe_conf; | 863 | u32 *vs, *vb, *vt, *hs, *hb, *ht, *ss, *pipe_conf; |
859 | 864 | ||
860 | DBG_MSG("intelfbhw_mode_to_hw\n"); | 865 | DBG_MSG("intelfbhw_mode_to_hw\n"); |
861 | 866 | ||
862 | /* Disable VGA */ | 867 | /* Disable VGA */ |
863 | hw->vgacntrl |= VGA_DISABLE; | 868 | hw->vgacntrl |= VGA_DISABLE; |
864 | 869 | ||
865 | /* Check whether pipe A or pipe B is enabled. */ | 870 | /* Check whether pipe A or pipe B is enabled. */ |
866 | if (hw->pipe_a_conf & PIPECONF_ENABLE) | 871 | if (hw->pipe_a_conf & PIPECONF_ENABLE) |
867 | pipe = PIPE_A; | 872 | pipe = PIPE_A; |
868 | else if (hw->pipe_b_conf & PIPECONF_ENABLE) | 873 | else if (hw->pipe_b_conf & PIPECONF_ENABLE) |
869 | pipe = PIPE_B; | 874 | pipe = PIPE_B; |
870 | 875 | ||
871 | /* Set which pipe's registers will be set. */ | 876 | /* Set which pipe's registers will be set. */ |
872 | if (pipe == PIPE_B) { | 877 | if (pipe == PIPE_B) { |
873 | dpll = &hw->dpll_b; | 878 | dpll = &hw->dpll_b; |
874 | fp0 = &hw->fpb0; | 879 | fp0 = &hw->fpb0; |
875 | fp1 = &hw->fpb1; | 880 | fp1 = &hw->fpb1; |
876 | hs = &hw->hsync_b; | 881 | hs = &hw->hsync_b; |
877 | hb = &hw->hblank_b; | 882 | hb = &hw->hblank_b; |
878 | ht = &hw->htotal_b; | 883 | ht = &hw->htotal_b; |
879 | vs = &hw->vsync_b; | 884 | vs = &hw->vsync_b; |
880 | vb = &hw->vblank_b; | 885 | vb = &hw->vblank_b; |
881 | vt = &hw->vtotal_b; | 886 | vt = &hw->vtotal_b; |
882 | ss = &hw->src_size_b; | 887 | ss = &hw->src_size_b; |
883 | pipe_conf = &hw->pipe_b_conf; | 888 | pipe_conf = &hw->pipe_b_conf; |
884 | } else { | 889 | } else { |
885 | dpll = &hw->dpll_a; | 890 | dpll = &hw->dpll_a; |
886 | fp0 = &hw->fpa0; | 891 | fp0 = &hw->fpa0; |
887 | fp1 = &hw->fpa1; | 892 | fp1 = &hw->fpa1; |
888 | hs = &hw->hsync_a; | 893 | hs = &hw->hsync_a; |
889 | hb = &hw->hblank_a; | 894 | hb = &hw->hblank_a; |
890 | ht = &hw->htotal_a; | 895 | ht = &hw->htotal_a; |
891 | vs = &hw->vsync_a; | 896 | vs = &hw->vsync_a; |
892 | vb = &hw->vblank_a; | 897 | vb = &hw->vblank_a; |
893 | vt = &hw->vtotal_a; | 898 | vt = &hw->vtotal_a; |
894 | ss = &hw->src_size_a; | 899 | ss = &hw->src_size_a; |
895 | pipe_conf = &hw->pipe_a_conf; | 900 | pipe_conf = &hw->pipe_a_conf; |
896 | } | 901 | } |
897 | 902 | ||
898 | /* Use ADPA register for sync control. */ | 903 | /* Use ADPA register for sync control. */ |
899 | hw->adpa &= ~ADPA_USE_VGA_HVPOLARITY; | 904 | hw->adpa &= ~ADPA_USE_VGA_HVPOLARITY; |
900 | 905 | ||
901 | /* sync polarity */ | 906 | /* sync polarity */ |
902 | hsync_pol = (var->sync & FB_SYNC_HOR_HIGH_ACT) ? | 907 | hsync_pol = (var->sync & FB_SYNC_HOR_HIGH_ACT) ? |
903 | ADPA_SYNC_ACTIVE_HIGH : ADPA_SYNC_ACTIVE_LOW; | 908 | ADPA_SYNC_ACTIVE_HIGH : ADPA_SYNC_ACTIVE_LOW; |
904 | vsync_pol = (var->sync & FB_SYNC_VERT_HIGH_ACT) ? | 909 | vsync_pol = (var->sync & FB_SYNC_VERT_HIGH_ACT) ? |
905 | ADPA_SYNC_ACTIVE_HIGH : ADPA_SYNC_ACTIVE_LOW; | 910 | ADPA_SYNC_ACTIVE_HIGH : ADPA_SYNC_ACTIVE_LOW; |
906 | hw->adpa &= ~((ADPA_SYNC_ACTIVE_MASK << ADPA_VSYNC_ACTIVE_SHIFT) | | 911 | hw->adpa &= ~((ADPA_SYNC_ACTIVE_MASK << ADPA_VSYNC_ACTIVE_SHIFT) | |
907 | (ADPA_SYNC_ACTIVE_MASK << ADPA_HSYNC_ACTIVE_SHIFT)); | 912 | (ADPA_SYNC_ACTIVE_MASK << ADPA_HSYNC_ACTIVE_SHIFT)); |
908 | hw->adpa |= (hsync_pol << ADPA_HSYNC_ACTIVE_SHIFT) | | 913 | hw->adpa |= (hsync_pol << ADPA_HSYNC_ACTIVE_SHIFT) | |
909 | (vsync_pol << ADPA_VSYNC_ACTIVE_SHIFT); | 914 | (vsync_pol << ADPA_VSYNC_ACTIVE_SHIFT); |
910 | 915 | ||
911 | /* Connect correct pipe to the analog port DAC */ | 916 | /* Connect correct pipe to the analog port DAC */ |
912 | hw->adpa &= ~(PIPE_MASK << ADPA_PIPE_SELECT_SHIFT); | 917 | hw->adpa &= ~(PIPE_MASK << ADPA_PIPE_SELECT_SHIFT); |
913 | hw->adpa |= (pipe << ADPA_PIPE_SELECT_SHIFT); | 918 | hw->adpa |= (pipe << ADPA_PIPE_SELECT_SHIFT); |
914 | 919 | ||
915 | /* Set DPMS state to D0 (on) */ | 920 | /* Set DPMS state to D0 (on) */ |
916 | hw->adpa &= ~ADPA_DPMS_CONTROL_MASK; | 921 | hw->adpa &= ~ADPA_DPMS_CONTROL_MASK; |
917 | hw->adpa |= ADPA_DPMS_D0; | 922 | hw->adpa |= ADPA_DPMS_D0; |
918 | 923 | ||
919 | hw->adpa |= ADPA_DAC_ENABLE; | 924 | hw->adpa |= ADPA_DAC_ENABLE; |
920 | 925 | ||
921 | *dpll |= (DPLL_VCO_ENABLE | DPLL_VGA_MODE_DISABLE); | 926 | *dpll |= (DPLL_VCO_ENABLE | DPLL_VGA_MODE_DISABLE); |
922 | *dpll &= ~(DPLL_RATE_SELECT_MASK | DPLL_REFERENCE_SELECT_MASK); | 927 | *dpll &= ~(DPLL_RATE_SELECT_MASK | DPLL_REFERENCE_SELECT_MASK); |
923 | *dpll |= (DPLL_REFERENCE_DEFAULT | DPLL_RATE_SELECT_FP0); | 928 | *dpll |= (DPLL_REFERENCE_DEFAULT | DPLL_RATE_SELECT_FP0); |
924 | 929 | ||
925 | /* Desired clock in kHz */ | 930 | /* Desired clock in kHz */ |
926 | clock_target = 1000000000 / var->pixclock; | 931 | clock_target = 1000000000 / var->pixclock; |
927 | 932 | ||
928 | if (calc_pll_params(clock_target, &m1, &m2, &n, &p1, &p2, &clock)) { | 933 | if (calc_pll_params(clock_target, &m1, &m2, &n, &p1, &p2, &clock)) { |
929 | WRN_MSG("calc_pll_params failed\n"); | 934 | WRN_MSG("calc_pll_params failed\n"); |
930 | return 1; | 935 | return 1; |
931 | } | 936 | } |
932 | 937 | ||
933 | /* Check for overflow. */ | 938 | /* Check for overflow. */ |
934 | if (check_overflow(p1, DPLL_P1_MASK, "PLL P1 parameter")) | 939 | if (check_overflow(p1, DPLL_P1_MASK, "PLL P1 parameter")) |
935 | return 1; | 940 | return 1; |
936 | if (check_overflow(p2, DPLL_P2_MASK, "PLL P2 parameter")) | 941 | if (check_overflow(p2, DPLL_P2_MASK, "PLL P2 parameter")) |
937 | return 1; | 942 | return 1; |
938 | if (check_overflow(m1, FP_DIVISOR_MASK, "PLL M1 parameter")) | 943 | if (check_overflow(m1, FP_DIVISOR_MASK, "PLL M1 parameter")) |
939 | return 1; | 944 | return 1; |
940 | if (check_overflow(m2, FP_DIVISOR_MASK, "PLL M2 parameter")) | 945 | if (check_overflow(m2, FP_DIVISOR_MASK, "PLL M2 parameter")) |
941 | return 1; | 946 | return 1; |
942 | if (check_overflow(n, FP_DIVISOR_MASK, "PLL N parameter")) | 947 | if (check_overflow(n, FP_DIVISOR_MASK, "PLL N parameter")) |
943 | return 1; | 948 | return 1; |
944 | 949 | ||
945 | *dpll &= ~DPLL_P1_FORCE_DIV2; | 950 | *dpll &= ~DPLL_P1_FORCE_DIV2; |
946 | *dpll &= ~((DPLL_P2_MASK << DPLL_P2_SHIFT) | | 951 | *dpll &= ~((DPLL_P2_MASK << DPLL_P2_SHIFT) | |
947 | (DPLL_P1_MASK << DPLL_P1_SHIFT)); | 952 | (DPLL_P1_MASK << DPLL_P1_SHIFT)); |
948 | *dpll |= (p2 << DPLL_P2_SHIFT) | (p1 << DPLL_P1_SHIFT); | 953 | *dpll |= (p2 << DPLL_P2_SHIFT) | (p1 << DPLL_P1_SHIFT); |
949 | *fp0 = (n << FP_N_DIVISOR_SHIFT) | | 954 | *fp0 = (n << FP_N_DIVISOR_SHIFT) | |
950 | (m1 << FP_M1_DIVISOR_SHIFT) | | 955 | (m1 << FP_M1_DIVISOR_SHIFT) | |
951 | (m2 << FP_M2_DIVISOR_SHIFT); | 956 | (m2 << FP_M2_DIVISOR_SHIFT); |
952 | *fp1 = *fp0; | 957 | *fp1 = *fp0; |
953 | 958 | ||
954 | hw->dvob &= ~PORT_ENABLE; | 959 | hw->dvob &= ~PORT_ENABLE; |
955 | hw->dvoc &= ~PORT_ENABLE; | 960 | hw->dvoc &= ~PORT_ENABLE; |
956 | 961 | ||
957 | /* Use display plane A. */ | 962 | /* Use display plane A. */ |
958 | hw->disp_a_ctrl |= DISPPLANE_PLANE_ENABLE; | 963 | hw->disp_a_ctrl |= DISPPLANE_PLANE_ENABLE; |
959 | hw->disp_a_ctrl &= ~DISPPLANE_GAMMA_ENABLE; | 964 | hw->disp_a_ctrl &= ~DISPPLANE_GAMMA_ENABLE; |
960 | hw->disp_a_ctrl &= ~DISPPLANE_PIXFORMAT_MASK; | 965 | hw->disp_a_ctrl &= ~DISPPLANE_PIXFORMAT_MASK; |
961 | switch (intelfb_var_to_depth(var)) { | 966 | switch (intelfb_var_to_depth(var)) { |
962 | case 8: | 967 | case 8: |
963 | hw->disp_a_ctrl |= DISPPLANE_8BPP | DISPPLANE_GAMMA_ENABLE; | 968 | hw->disp_a_ctrl |= DISPPLANE_8BPP | DISPPLANE_GAMMA_ENABLE; |
964 | break; | 969 | break; |
965 | case 15: | 970 | case 15: |
966 | hw->disp_a_ctrl |= DISPPLANE_15_16BPP; | 971 | hw->disp_a_ctrl |= DISPPLANE_15_16BPP; |
967 | break; | 972 | break; |
968 | case 16: | 973 | case 16: |
969 | hw->disp_a_ctrl |= DISPPLANE_16BPP; | 974 | hw->disp_a_ctrl |= DISPPLANE_16BPP; |
970 | break; | 975 | break; |
971 | case 24: | 976 | case 24: |
972 | hw->disp_a_ctrl |= DISPPLANE_32BPP_NO_ALPHA; | 977 | hw->disp_a_ctrl |= DISPPLANE_32BPP_NO_ALPHA; |
973 | break; | 978 | break; |
974 | } | 979 | } |
975 | hw->disp_a_ctrl &= ~(PIPE_MASK << DISPPLANE_SEL_PIPE_SHIFT); | 980 | hw->disp_a_ctrl &= ~(PIPE_MASK << DISPPLANE_SEL_PIPE_SHIFT); |
976 | hw->disp_a_ctrl |= (pipe << DISPPLANE_SEL_PIPE_SHIFT); | 981 | hw->disp_a_ctrl |= (pipe << DISPPLANE_SEL_PIPE_SHIFT); |
977 | 982 | ||
978 | /* Set CRTC registers. */ | 983 | /* Set CRTC registers. */ |
979 | hactive = var->xres; | 984 | hactive = var->xres; |
980 | hsync_start = hactive + var->right_margin; | 985 | hsync_start = hactive + var->right_margin; |
981 | hsync_end = hsync_start + var->hsync_len; | 986 | hsync_end = hsync_start + var->hsync_len; |
982 | htotal = hsync_end + var->left_margin; | 987 | htotal = hsync_end + var->left_margin; |
983 | hblank_start = hactive; | 988 | hblank_start = hactive; |
984 | hblank_end = htotal; | 989 | hblank_end = htotal; |
985 | 990 | ||
986 | DBG_MSG("H: act %d, ss %d, se %d, tot %d bs %d, be %d\n", | 991 | DBG_MSG("H: act %d, ss %d, se %d, tot %d bs %d, be %d\n", |
987 | hactive, hsync_start, hsync_end, htotal, hblank_start, | 992 | hactive, hsync_start, hsync_end, htotal, hblank_start, |
988 | hblank_end); | 993 | hblank_end); |
989 | 994 | ||
990 | vactive = var->yres; | 995 | vactive = var->yres; |
991 | vsync_start = vactive + var->lower_margin; | 996 | vsync_start = vactive + var->lower_margin; |
992 | vsync_end = vsync_start + var->vsync_len; | 997 | vsync_end = vsync_start + var->vsync_len; |
993 | vtotal = vsync_end + var->upper_margin; | 998 | vtotal = vsync_end + var->upper_margin; |
994 | vblank_start = vactive; | 999 | vblank_start = vactive; |
995 | vblank_end = vtotal; | 1000 | vblank_end = vtotal; |
996 | vblank_end = vsync_end + 1; | 1001 | vblank_end = vsync_end + 1; |
997 | 1002 | ||
998 | DBG_MSG("V: act %d, ss %d, se %d, tot %d bs %d, be %d\n", | 1003 | DBG_MSG("V: act %d, ss %d, se %d, tot %d bs %d, be %d\n", |
999 | vactive, vsync_start, vsync_end, vtotal, vblank_start, | 1004 | vactive, vsync_start, vsync_end, vtotal, vblank_start, |
1000 | vblank_end); | 1005 | vblank_end); |
1001 | 1006 | ||
1002 | /* Adjust for register values, and check for overflow. */ | 1007 | /* Adjust for register values, and check for overflow. */ |
1003 | hactive--; | 1008 | hactive--; |
1004 | if (check_overflow(hactive, HACTIVE_MASK, "CRTC hactive")) | 1009 | if (check_overflow(hactive, HACTIVE_MASK, "CRTC hactive")) |
1005 | return 1; | 1010 | return 1; |
1006 | hsync_start--; | 1011 | hsync_start--; |
1007 | if (check_overflow(hsync_start, HSYNCSTART_MASK, "CRTC hsync_start")) | 1012 | if (check_overflow(hsync_start, HSYNCSTART_MASK, "CRTC hsync_start")) |
1008 | return 1; | 1013 | return 1; |
1009 | hsync_end--; | 1014 | hsync_end--; |
1010 | if (check_overflow(hsync_end, HSYNCEND_MASK, "CRTC hsync_end")) | 1015 | if (check_overflow(hsync_end, HSYNCEND_MASK, "CRTC hsync_end")) |
1011 | return 1; | 1016 | return 1; |
1012 | htotal--; | 1017 | htotal--; |
1013 | if (check_overflow(htotal, HTOTAL_MASK, "CRTC htotal")) | 1018 | if (check_overflow(htotal, HTOTAL_MASK, "CRTC htotal")) |
1014 | return 1; | 1019 | return 1; |
1015 | hblank_start--; | 1020 | hblank_start--; |
1016 | if (check_overflow(hblank_start, HBLANKSTART_MASK, "CRTC hblank_start")) | 1021 | if (check_overflow(hblank_start, HBLANKSTART_MASK, "CRTC hblank_start")) |
1017 | return 1; | 1022 | return 1; |
1018 | hblank_end--; | 1023 | hblank_end--; |
1019 | if (check_overflow(hblank_end, HBLANKEND_MASK, "CRTC hblank_end")) | 1024 | if (check_overflow(hblank_end, HBLANKEND_MASK, "CRTC hblank_end")) |
1020 | return 1; | 1025 | return 1; |
1021 | 1026 | ||
1022 | vactive--; | 1027 | vactive--; |
1023 | if (check_overflow(vactive, VACTIVE_MASK, "CRTC vactive")) | 1028 | if (check_overflow(vactive, VACTIVE_MASK, "CRTC vactive")) |
1024 | return 1; | 1029 | return 1; |
1025 | vsync_start--; | 1030 | vsync_start--; |
1026 | if (check_overflow(vsync_start, VSYNCSTART_MASK, "CRTC vsync_start")) | 1031 | if (check_overflow(vsync_start, VSYNCSTART_MASK, "CRTC vsync_start")) |
1027 | return 1; | 1032 | return 1; |
1028 | vsync_end--; | 1033 | vsync_end--; |
1029 | if (check_overflow(vsync_end, VSYNCEND_MASK, "CRTC vsync_end")) | 1034 | if (check_overflow(vsync_end, VSYNCEND_MASK, "CRTC vsync_end")) |
1030 | return 1; | 1035 | return 1; |
1031 | vtotal--; | 1036 | vtotal--; |
1032 | if (check_overflow(vtotal, VTOTAL_MASK, "CRTC vtotal")) | 1037 | if (check_overflow(vtotal, VTOTAL_MASK, "CRTC vtotal")) |
1033 | return 1; | 1038 | return 1; |
1034 | vblank_start--; | 1039 | vblank_start--; |
1035 | if (check_overflow(vblank_start, VBLANKSTART_MASK, "CRTC vblank_start")) | 1040 | if (check_overflow(vblank_start, VBLANKSTART_MASK, "CRTC vblank_start")) |
1036 | return 1; | 1041 | return 1; |
1037 | vblank_end--; | 1042 | vblank_end--; |
1038 | if (check_overflow(vblank_end, VBLANKEND_MASK, "CRTC vblank_end")) | 1043 | if (check_overflow(vblank_end, VBLANKEND_MASK, "CRTC vblank_end")) |
1039 | return 1; | 1044 | return 1; |
1040 | 1045 | ||
1041 | *ht = (htotal << HTOTAL_SHIFT) | (hactive << HACTIVE_SHIFT); | 1046 | *ht = (htotal << HTOTAL_SHIFT) | (hactive << HACTIVE_SHIFT); |
1042 | *hb = (hblank_start << HBLANKSTART_SHIFT) | | 1047 | *hb = (hblank_start << HBLANKSTART_SHIFT) | |
1043 | (hblank_end << HSYNCEND_SHIFT); | 1048 | (hblank_end << HSYNCEND_SHIFT); |
1044 | *hs = (hsync_start << HSYNCSTART_SHIFT) | (hsync_end << HSYNCEND_SHIFT); | 1049 | *hs = (hsync_start << HSYNCSTART_SHIFT) | (hsync_end << HSYNCEND_SHIFT); |
1045 | 1050 | ||
1046 | *vt = (vtotal << VTOTAL_SHIFT) | (vactive << VACTIVE_SHIFT); | 1051 | *vt = (vtotal << VTOTAL_SHIFT) | (vactive << VACTIVE_SHIFT); |
1047 | *vb = (vblank_start << VBLANKSTART_SHIFT) | | 1052 | *vb = (vblank_start << VBLANKSTART_SHIFT) | |
1048 | (vblank_end << VSYNCEND_SHIFT); | 1053 | (vblank_end << VSYNCEND_SHIFT); |
1049 | *vs = (vsync_start << VSYNCSTART_SHIFT) | (vsync_end << VSYNCEND_SHIFT); | 1054 | *vs = (vsync_start << VSYNCSTART_SHIFT) | (vsync_end << VSYNCEND_SHIFT); |
1050 | *ss = (hactive << SRC_SIZE_HORIZ_SHIFT) | | 1055 | *ss = (hactive << SRC_SIZE_HORIZ_SHIFT) | |
1051 | (vactive << SRC_SIZE_VERT_SHIFT); | 1056 | (vactive << SRC_SIZE_VERT_SHIFT); |
1052 | 1057 | ||
1053 | hw->disp_a_stride = var->xres_virtual * var->bits_per_pixel / 8; | 1058 | hw->disp_a_stride = var->xres_virtual * var->bits_per_pixel / 8; |
1054 | DBG_MSG("pitch is %d\n", hw->disp_a_stride); | 1059 | DBG_MSG("pitch is %d\n", hw->disp_a_stride); |
1055 | 1060 | ||
1056 | hw->disp_a_base = hw->disp_a_stride * var->yoffset + | 1061 | hw->disp_a_base = hw->disp_a_stride * var->yoffset + |
1057 | var->xoffset * var->bits_per_pixel / 8; | 1062 | var->xoffset * var->bits_per_pixel / 8; |
1058 | 1063 | ||
1059 | hw->disp_a_base += dinfo->fb.offset << 12; | 1064 | hw->disp_a_base += dinfo->fb.offset << 12; |
1060 | 1065 | ||
1061 | /* Check stride alignment. */ | 1066 | /* Check stride alignment. */ |
1062 | if (hw->disp_a_stride % STRIDE_ALIGNMENT != 0) { | 1067 | if (hw->disp_a_stride % STRIDE_ALIGNMENT != 0) { |
1063 | WRN_MSG("display stride %d has bad alignment %d\n", | 1068 | WRN_MSG("display stride %d has bad alignment %d\n", |
1064 | hw->disp_a_stride, STRIDE_ALIGNMENT); | 1069 | hw->disp_a_stride, STRIDE_ALIGNMENT); |
1065 | return 1; | 1070 | return 1; |
1066 | } | 1071 | } |
1067 | 1072 | ||
1068 | /* Set the palette to 8-bit mode. */ | 1073 | /* Set the palette to 8-bit mode. */ |
1069 | *pipe_conf &= ~PIPECONF_GAMMA; | 1074 | *pipe_conf &= ~PIPECONF_GAMMA; |
1070 | return 0; | 1075 | return 0; |
1071 | } | 1076 | } |
1072 | 1077 | ||
1073 | /* Program a (non-VGA) video mode. */ | 1078 | /* Program a (non-VGA) video mode. */ |
1074 | int | 1079 | int |
1075 | intelfbhw_program_mode(struct intelfb_info *dinfo, | 1080 | intelfbhw_program_mode(struct intelfb_info *dinfo, |
1076 | const struct intelfb_hwstate *hw, int blank) | 1081 | const struct intelfb_hwstate *hw, int blank) |
1077 | { | 1082 | { |
1078 | int pipe = PIPE_A; | 1083 | int pipe = PIPE_A; |
1079 | u32 tmp; | 1084 | u32 tmp; |
1080 | const u32 *dpll, *fp0, *fp1, *pipe_conf; | 1085 | const u32 *dpll, *fp0, *fp1, *pipe_conf; |
1081 | const u32 *hs, *ht, *hb, *vs, *vt, *vb, *ss; | 1086 | const u32 *hs, *ht, *hb, *vs, *vt, *vb, *ss; |
1082 | u32 dpll_reg, fp0_reg, fp1_reg, pipe_conf_reg; | 1087 | u32 dpll_reg, fp0_reg, fp1_reg, pipe_conf_reg; |
1083 | u32 hsync_reg, htotal_reg, hblank_reg; | 1088 | u32 hsync_reg, htotal_reg, hblank_reg; |
1084 | u32 vsync_reg, vtotal_reg, vblank_reg; | 1089 | u32 vsync_reg, vtotal_reg, vblank_reg; |
1085 | u32 src_size_reg; | 1090 | u32 src_size_reg; |
1086 | 1091 | ||
1087 | /* Assume single pipe, display plane A, analog CRT. */ | 1092 | /* Assume single pipe, display plane A, analog CRT. */ |
1088 | 1093 | ||
1089 | #if VERBOSE > 0 | 1094 | #if VERBOSE > 0 |
1090 | DBG_MSG("intelfbhw_program_mode\n"); | 1095 | DBG_MSG("intelfbhw_program_mode\n"); |
1091 | #endif | 1096 | #endif |
1092 | 1097 | ||
1093 | /* Disable VGA */ | 1098 | /* Disable VGA */ |
1094 | tmp = INREG(VGACNTRL); | 1099 | tmp = INREG(VGACNTRL); |
1095 | tmp |= VGA_DISABLE; | 1100 | tmp |= VGA_DISABLE; |
1096 | OUTREG(VGACNTRL, tmp); | 1101 | OUTREG(VGACNTRL, tmp); |
1097 | 1102 | ||
1098 | /* Check whether pipe A or pipe B is enabled. */ | 1103 | /* Check whether pipe A or pipe B is enabled. */ |
1099 | if (hw->pipe_a_conf & PIPECONF_ENABLE) | 1104 | if (hw->pipe_a_conf & PIPECONF_ENABLE) |
1100 | pipe = PIPE_A; | 1105 | pipe = PIPE_A; |
1101 | else if (hw->pipe_b_conf & PIPECONF_ENABLE) | 1106 | else if (hw->pipe_b_conf & PIPECONF_ENABLE) |
1102 | pipe = PIPE_B; | 1107 | pipe = PIPE_B; |
1103 | 1108 | ||
1104 | dinfo->pipe = pipe; | 1109 | dinfo->pipe = pipe; |
1105 | 1110 | ||
1106 | if (pipe == PIPE_B) { | 1111 | if (pipe == PIPE_B) { |
1107 | dpll = &hw->dpll_b; | 1112 | dpll = &hw->dpll_b; |
1108 | fp0 = &hw->fpb0; | 1113 | fp0 = &hw->fpb0; |
1109 | fp1 = &hw->fpb1; | 1114 | fp1 = &hw->fpb1; |
1110 | pipe_conf = &hw->pipe_b_conf; | 1115 | pipe_conf = &hw->pipe_b_conf; |
1111 | hs = &hw->hsync_b; | 1116 | hs = &hw->hsync_b; |
1112 | hb = &hw->hblank_b; | 1117 | hb = &hw->hblank_b; |
1113 | ht = &hw->htotal_b; | 1118 | ht = &hw->htotal_b; |
1114 | vs = &hw->vsync_b; | 1119 | vs = &hw->vsync_b; |
1115 | vb = &hw->vblank_b; | 1120 | vb = &hw->vblank_b; |
1116 | vt = &hw->vtotal_b; | 1121 | vt = &hw->vtotal_b; |
1117 | ss = &hw->src_size_b; | 1122 | ss = &hw->src_size_b; |
1118 | dpll_reg = DPLL_B; | 1123 | dpll_reg = DPLL_B; |
1119 | fp0_reg = FPB0; | 1124 | fp0_reg = FPB0; |
1120 | fp1_reg = FPB1; | 1125 | fp1_reg = FPB1; |
1121 | pipe_conf_reg = PIPEBCONF; | 1126 | pipe_conf_reg = PIPEBCONF; |
1122 | hsync_reg = HSYNC_B; | 1127 | hsync_reg = HSYNC_B; |
1123 | htotal_reg = HTOTAL_B; | 1128 | htotal_reg = HTOTAL_B; |
1124 | hblank_reg = HBLANK_B; | 1129 | hblank_reg = HBLANK_B; |
1125 | vsync_reg = VSYNC_B; | 1130 | vsync_reg = VSYNC_B; |
1126 | vtotal_reg = VTOTAL_B; | 1131 | vtotal_reg = VTOTAL_B; |
1127 | vblank_reg = VBLANK_B; | 1132 | vblank_reg = VBLANK_B; |
1128 | src_size_reg = SRC_SIZE_B; | 1133 | src_size_reg = SRC_SIZE_B; |
1129 | } else { | 1134 | } else { |
1130 | dpll = &hw->dpll_a; | 1135 | dpll = &hw->dpll_a; |
1131 | fp0 = &hw->fpa0; | 1136 | fp0 = &hw->fpa0; |
1132 | fp1 = &hw->fpa1; | 1137 | fp1 = &hw->fpa1; |
1133 | pipe_conf = &hw->pipe_a_conf; | 1138 | pipe_conf = &hw->pipe_a_conf; |
1134 | hs = &hw->hsync_a; | 1139 | hs = &hw->hsync_a; |
1135 | hb = &hw->hblank_a; | 1140 | hb = &hw->hblank_a; |
1136 | ht = &hw->htotal_a; | 1141 | ht = &hw->htotal_a; |
1137 | vs = &hw->vsync_a; | 1142 | vs = &hw->vsync_a; |
1138 | vb = &hw->vblank_a; | 1143 | vb = &hw->vblank_a; |
1139 | vt = &hw->vtotal_a; | 1144 | vt = &hw->vtotal_a; |
1140 | ss = &hw->src_size_a; | 1145 | ss = &hw->src_size_a; |
1141 | dpll_reg = DPLL_A; | 1146 | dpll_reg = DPLL_A; |
1142 | fp0_reg = FPA0; | 1147 | fp0_reg = FPA0; |
1143 | fp1_reg = FPA1; | 1148 | fp1_reg = FPA1; |
1144 | pipe_conf_reg = PIPEACONF; | 1149 | pipe_conf_reg = PIPEACONF; |
1145 | hsync_reg = HSYNC_A; | 1150 | hsync_reg = HSYNC_A; |
1146 | htotal_reg = HTOTAL_A; | 1151 | htotal_reg = HTOTAL_A; |
1147 | hblank_reg = HBLANK_A; | 1152 | hblank_reg = HBLANK_A; |
1148 | vsync_reg = VSYNC_A; | 1153 | vsync_reg = VSYNC_A; |
1149 | vtotal_reg = VTOTAL_A; | 1154 | vtotal_reg = VTOTAL_A; |
1150 | vblank_reg = VBLANK_A; | 1155 | vblank_reg = VBLANK_A; |
1151 | src_size_reg = SRC_SIZE_A; | 1156 | src_size_reg = SRC_SIZE_A; |
1152 | } | 1157 | } |
1153 | 1158 | ||
1154 | /* Disable planes A and B. */ | 1159 | /* Disable planes A and B. */ |
1155 | tmp = INREG(DSPACNTR); | 1160 | tmp = INREG(DSPACNTR); |
1156 | tmp &= ~DISPPLANE_PLANE_ENABLE; | 1161 | tmp &= ~DISPPLANE_PLANE_ENABLE; |
1157 | OUTREG(DSPACNTR, tmp); | 1162 | OUTREG(DSPACNTR, tmp); |
1158 | tmp = INREG(DSPBCNTR); | 1163 | tmp = INREG(DSPBCNTR); |
1159 | tmp &= ~DISPPLANE_PLANE_ENABLE; | 1164 | tmp &= ~DISPPLANE_PLANE_ENABLE; |
1160 | OUTREG(DSPBCNTR, tmp); | 1165 | OUTREG(DSPBCNTR, tmp); |
1161 | 1166 | ||
1162 | /* Wait for vblank. For now, just wait for a 50Hz cycle (20ms)) */ | 1167 | /* Wait for vblank. For now, just wait for a 50Hz cycle (20ms)) */ |
1163 | mdelay(20); | 1168 | mdelay(20); |
1164 | 1169 | ||
1165 | /* Disable Sync */ | 1170 | /* Disable Sync */ |
1166 | tmp = INREG(ADPA); | 1171 | tmp = INREG(ADPA); |
1167 | tmp &= ~ADPA_DPMS_CONTROL_MASK; | 1172 | tmp &= ~ADPA_DPMS_CONTROL_MASK; |
1168 | tmp |= ADPA_DPMS_D3; | 1173 | tmp |= ADPA_DPMS_D3; |
1169 | OUTREG(ADPA, tmp); | 1174 | OUTREG(ADPA, tmp); |
1170 | 1175 | ||
1171 | /* turn off pipe */ | 1176 | /* turn off pipe */ |
1172 | tmp = INREG(pipe_conf_reg); | 1177 | tmp = INREG(pipe_conf_reg); |
1173 | tmp &= ~PIPECONF_ENABLE; | 1178 | tmp &= ~PIPECONF_ENABLE; |
1174 | OUTREG(pipe_conf_reg, tmp); | 1179 | OUTREG(pipe_conf_reg, tmp); |
1175 | 1180 | ||
1176 | /* turn off PLL */ | 1181 | /* turn off PLL */ |
1177 | tmp = INREG(dpll_reg); | 1182 | tmp = INREG(dpll_reg); |
1178 | dpll_reg &= ~DPLL_VCO_ENABLE; | 1183 | dpll_reg &= ~DPLL_VCO_ENABLE; |
1179 | OUTREG(dpll_reg, tmp); | 1184 | OUTREG(dpll_reg, tmp); |
1180 | 1185 | ||
1181 | /* Set PLL parameters */ | 1186 | /* Set PLL parameters */ |
1182 | OUTREG(dpll_reg, *dpll & ~DPLL_VCO_ENABLE); | 1187 | OUTREG(dpll_reg, *dpll & ~DPLL_VCO_ENABLE); |
1183 | OUTREG(fp0_reg, *fp0); | 1188 | OUTREG(fp0_reg, *fp0); |
1184 | OUTREG(fp1_reg, *fp1); | 1189 | OUTREG(fp1_reg, *fp1); |
1185 | 1190 | ||
1186 | /* Set pipe parameters */ | 1191 | /* Set pipe parameters */ |
1187 | OUTREG(hsync_reg, *hs); | 1192 | OUTREG(hsync_reg, *hs); |
1188 | OUTREG(hblank_reg, *hb); | 1193 | OUTREG(hblank_reg, *hb); |
1189 | OUTREG(htotal_reg, *ht); | 1194 | OUTREG(htotal_reg, *ht); |
1190 | OUTREG(vsync_reg, *vs); | 1195 | OUTREG(vsync_reg, *vs); |
1191 | OUTREG(vblank_reg, *vb); | 1196 | OUTREG(vblank_reg, *vb); |
1192 | OUTREG(vtotal_reg, *vt); | 1197 | OUTREG(vtotal_reg, *vt); |
1193 | OUTREG(src_size_reg, *ss); | 1198 | OUTREG(src_size_reg, *ss); |
1194 | 1199 | ||
1195 | /* Set DVOs B/C */ | 1200 | /* Set DVOs B/C */ |
1196 | OUTREG(DVOB, hw->dvob); | 1201 | OUTREG(DVOB, hw->dvob); |
1197 | OUTREG(DVOC, hw->dvoc); | 1202 | OUTREG(DVOC, hw->dvoc); |
1198 | 1203 | ||
1199 | /* Set ADPA */ | 1204 | /* Set ADPA */ |
1200 | OUTREG(ADPA, (hw->adpa & ~(ADPA_DPMS_CONTROL_MASK)) | ADPA_DPMS_D3); | 1205 | OUTREG(ADPA, (hw->adpa & ~(ADPA_DPMS_CONTROL_MASK)) | ADPA_DPMS_D3); |
1201 | 1206 | ||
1202 | /* Enable PLL */ | 1207 | /* Enable PLL */ |
1203 | tmp = INREG(dpll_reg); | 1208 | tmp = INREG(dpll_reg); |
1204 | tmp |= DPLL_VCO_ENABLE; | 1209 | tmp |= DPLL_VCO_ENABLE; |
1205 | OUTREG(dpll_reg, tmp); | 1210 | OUTREG(dpll_reg, tmp); |
1206 | 1211 | ||
1207 | /* Enable pipe */ | 1212 | /* Enable pipe */ |
1208 | OUTREG(pipe_conf_reg, *pipe_conf | PIPECONF_ENABLE); | 1213 | OUTREG(pipe_conf_reg, *pipe_conf | PIPECONF_ENABLE); |
1209 | 1214 | ||
1210 | /* Enable sync */ | 1215 | /* Enable sync */ |
1211 | tmp = INREG(ADPA); | 1216 | tmp = INREG(ADPA); |
1212 | tmp &= ~ADPA_DPMS_CONTROL_MASK; | 1217 | tmp &= ~ADPA_DPMS_CONTROL_MASK; |
1213 | tmp |= ADPA_DPMS_D0; | 1218 | tmp |= ADPA_DPMS_D0; |
1214 | OUTREG(ADPA, tmp); | 1219 | OUTREG(ADPA, tmp); |
1215 | 1220 | ||
1216 | /* setup display plane */ | 1221 | /* setup display plane */ |
1217 | if (dinfo->pdev->device == PCI_DEVICE_ID_INTEL_830M) { | 1222 | if (dinfo->pdev->device == PCI_DEVICE_ID_INTEL_830M) { |
1218 | /* | 1223 | /* |
1219 | * i830M errata: the display plane must be enabled | 1224 | * i830M errata: the display plane must be enabled |
1220 | * to allow writes to the other bits in the plane | 1225 | * to allow writes to the other bits in the plane |
1221 | * control register. | 1226 | * control register. |
1222 | */ | 1227 | */ |
1223 | tmp = INREG(DSPACNTR); | 1228 | tmp = INREG(DSPACNTR); |
1224 | if ((tmp & DISPPLANE_PLANE_ENABLE) != DISPPLANE_PLANE_ENABLE) { | 1229 | if ((tmp & DISPPLANE_PLANE_ENABLE) != DISPPLANE_PLANE_ENABLE) { |
1225 | tmp |= DISPPLANE_PLANE_ENABLE; | 1230 | tmp |= DISPPLANE_PLANE_ENABLE; |
1226 | OUTREG(DSPACNTR, tmp); | 1231 | OUTREG(DSPACNTR, tmp); |
1227 | OUTREG(DSPACNTR, | 1232 | OUTREG(DSPACNTR, |
1228 | hw->disp_a_ctrl|DISPPLANE_PLANE_ENABLE); | 1233 | hw->disp_a_ctrl|DISPPLANE_PLANE_ENABLE); |
1229 | mdelay(1); | 1234 | mdelay(1); |
1230 | } | 1235 | } |
1231 | } | 1236 | } |
1232 | 1237 | ||
1233 | OUTREG(DSPACNTR, hw->disp_a_ctrl & ~DISPPLANE_PLANE_ENABLE); | 1238 | OUTREG(DSPACNTR, hw->disp_a_ctrl & ~DISPPLANE_PLANE_ENABLE); |
1234 | OUTREG(DSPASTRIDE, hw->disp_a_stride); | 1239 | OUTREG(DSPASTRIDE, hw->disp_a_stride); |
1235 | OUTREG(DSPABASE, hw->disp_a_base); | 1240 | OUTREG(DSPABASE, hw->disp_a_base); |
1236 | 1241 | ||
1237 | /* Enable plane */ | 1242 | /* Enable plane */ |
1238 | if (!blank) { | 1243 | if (!blank) { |
1239 | tmp = INREG(DSPACNTR); | 1244 | tmp = INREG(DSPACNTR); |
1240 | tmp |= DISPPLANE_PLANE_ENABLE; | 1245 | tmp |= DISPPLANE_PLANE_ENABLE; |
1241 | OUTREG(DSPACNTR, tmp); | 1246 | OUTREG(DSPACNTR, tmp); |
1242 | OUTREG(DSPABASE, hw->disp_a_base); | 1247 | OUTREG(DSPABASE, hw->disp_a_base); |
1243 | } | 1248 | } |
1244 | 1249 | ||
1245 | return 0; | 1250 | return 0; |
1246 | } | 1251 | } |
1247 | 1252 | ||
1248 | /* forward declarations */ | 1253 | /* forward declarations */ |
1249 | static void refresh_ring(struct intelfb_info *dinfo); | 1254 | static void refresh_ring(struct intelfb_info *dinfo); |
1250 | static void reset_state(struct intelfb_info *dinfo); | 1255 | static void reset_state(struct intelfb_info *dinfo); |
1251 | static void do_flush(struct intelfb_info *dinfo); | 1256 | static void do_flush(struct intelfb_info *dinfo); |
1252 | 1257 | ||
1253 | static int | 1258 | static int |
1254 | wait_ring(struct intelfb_info *dinfo, int n) | 1259 | wait_ring(struct intelfb_info *dinfo, int n) |
1255 | { | 1260 | { |
1256 | int i = 0; | 1261 | int i = 0; |
1257 | unsigned long end; | 1262 | unsigned long end; |
1258 | u32 last_head = INREG(PRI_RING_HEAD) & RING_HEAD_MASK; | 1263 | u32 last_head = INREG(PRI_RING_HEAD) & RING_HEAD_MASK; |
1259 | 1264 | ||
1260 | #if VERBOSE > 0 | 1265 | #if VERBOSE > 0 |
1261 | DBG_MSG("wait_ring: %d\n", n); | 1266 | DBG_MSG("wait_ring: %d\n", n); |
1262 | #endif | 1267 | #endif |
1263 | 1268 | ||
1264 | end = jiffies + (HZ * 3); | 1269 | end = jiffies + (HZ * 3); |
1265 | while (dinfo->ring_space < n) { | 1270 | while (dinfo->ring_space < n) { |
1266 | dinfo->ring_head = (u8 __iomem *)(INREG(PRI_RING_HEAD) & | 1271 | dinfo->ring_head = (u8 __iomem *)(INREG(PRI_RING_HEAD) & |
1267 | RING_HEAD_MASK); | 1272 | RING_HEAD_MASK); |
1268 | if (dinfo->ring_tail + RING_MIN_FREE < | 1273 | if (dinfo->ring_tail + RING_MIN_FREE < |
1269 | (u32 __iomem) dinfo->ring_head) | 1274 | (u32 __iomem) dinfo->ring_head) |
1270 | dinfo->ring_space = (u32 __iomem) dinfo->ring_head | 1275 | dinfo->ring_space = (u32 __iomem) dinfo->ring_head |
1271 | - (dinfo->ring_tail + RING_MIN_FREE); | 1276 | - (dinfo->ring_tail + RING_MIN_FREE); |
1272 | else | 1277 | else |
1273 | dinfo->ring_space = (dinfo->ring.size + | 1278 | dinfo->ring_space = (dinfo->ring.size + |
1274 | (u32 __iomem) dinfo->ring_head) | 1279 | (u32 __iomem) dinfo->ring_head) |
1275 | - (dinfo->ring_tail + RING_MIN_FREE); | 1280 | - (dinfo->ring_tail + RING_MIN_FREE); |
1276 | if ((u32 __iomem) dinfo->ring_head != last_head) { | 1281 | if ((u32 __iomem) dinfo->ring_head != last_head) { |
1277 | end = jiffies + (HZ * 3); | 1282 | end = jiffies + (HZ * 3); |
1278 | last_head = (u32 __iomem) dinfo->ring_head; | 1283 | last_head = (u32 __iomem) dinfo->ring_head; |
1279 | } | 1284 | } |
1280 | i++; | 1285 | i++; |
1281 | if (time_before(end, jiffies)) { | 1286 | if (time_before(end, jiffies)) { |
1282 | if (!i) { | 1287 | if (!i) { |
1283 | /* Try again */ | 1288 | /* Try again */ |
1284 | reset_state(dinfo); | 1289 | reset_state(dinfo); |
1285 | refresh_ring(dinfo); | 1290 | refresh_ring(dinfo); |
1286 | do_flush(dinfo); | 1291 | do_flush(dinfo); |
1287 | end = jiffies + (HZ * 3); | 1292 | end = jiffies + (HZ * 3); |
1288 | i = 1; | 1293 | i = 1; |
1289 | } else { | 1294 | } else { |
1290 | WRN_MSG("ring buffer : space: %d wanted %d\n", | 1295 | WRN_MSG("ring buffer : space: %d wanted %d\n", |
1291 | dinfo->ring_space, n); | 1296 | dinfo->ring_space, n); |
1292 | WRN_MSG("lockup - turning off hardware " | 1297 | WRN_MSG("lockup - turning off hardware " |
1293 | "acceleration\n"); | 1298 | "acceleration\n"); |
1294 | dinfo->ring_lockup = 1; | 1299 | dinfo->ring_lockup = 1; |
1295 | break; | 1300 | break; |
1296 | } | 1301 | } |
1297 | } | 1302 | } |
1298 | udelay(1); | 1303 | udelay(1); |
1299 | } | 1304 | } |
1300 | return i; | 1305 | return i; |
1301 | } | 1306 | } |
1302 | 1307 | ||
1303 | static void | 1308 | static void |
1304 | do_flush(struct intelfb_info *dinfo) { | 1309 | do_flush(struct intelfb_info *dinfo) { |
1305 | START_RING(2); | 1310 | START_RING(2); |
1306 | OUT_RING(MI_FLUSH | MI_WRITE_DIRTY_STATE | MI_INVALIDATE_MAP_CACHE); | 1311 | OUT_RING(MI_FLUSH | MI_WRITE_DIRTY_STATE | MI_INVALIDATE_MAP_CACHE); |
1307 | OUT_RING(MI_NOOP); | 1312 | OUT_RING(MI_NOOP); |
1308 | ADVANCE_RING(); | 1313 | ADVANCE_RING(); |
1309 | } | 1314 | } |
1310 | 1315 | ||
1311 | void | 1316 | void |
1312 | intelfbhw_do_sync(struct intelfb_info *dinfo) | 1317 | intelfbhw_do_sync(struct intelfb_info *dinfo) |
1313 | { | 1318 | { |
1314 | #if VERBOSE > 0 | 1319 | #if VERBOSE > 0 |
1315 | DBG_MSG("intelfbhw_do_sync\n"); | 1320 | DBG_MSG("intelfbhw_do_sync\n"); |
1316 | #endif | 1321 | #endif |
1317 | 1322 | ||
1318 | if (!dinfo->accel) | 1323 | if (!dinfo->accel) |
1319 | return; | 1324 | return; |
1320 | 1325 | ||
1321 | /* | 1326 | /* |
1322 | * Send a flush, then wait until the ring is empty. This is what | 1327 | * Send a flush, then wait until the ring is empty. This is what |
1323 | * the XFree86 driver does, and actually it doesn't seem a lot worse | 1328 | * the XFree86 driver does, and actually it doesn't seem a lot worse |
1324 | * than the recommended method (both have problems). | 1329 | * than the recommended method (both have problems). |
1325 | */ | 1330 | */ |
1326 | do_flush(dinfo); | 1331 | do_flush(dinfo); |
1327 | wait_ring(dinfo, dinfo->ring.size - RING_MIN_FREE); | 1332 | wait_ring(dinfo, dinfo->ring.size - RING_MIN_FREE); |
1328 | dinfo->ring_space = dinfo->ring.size - RING_MIN_FREE; | 1333 | dinfo->ring_space = dinfo->ring.size - RING_MIN_FREE; |
1329 | } | 1334 | } |
1330 | 1335 | ||
1331 | static void | 1336 | static void |
1332 | refresh_ring(struct intelfb_info *dinfo) | 1337 | refresh_ring(struct intelfb_info *dinfo) |
1333 | { | 1338 | { |
1334 | #if VERBOSE > 0 | 1339 | #if VERBOSE > 0 |
1335 | DBG_MSG("refresh_ring\n"); | 1340 | DBG_MSG("refresh_ring\n"); |
1336 | #endif | 1341 | #endif |
1337 | 1342 | ||
1338 | dinfo->ring_head = (u8 __iomem *) (INREG(PRI_RING_HEAD) & | 1343 | dinfo->ring_head = (u8 __iomem *) (INREG(PRI_RING_HEAD) & |
1339 | RING_HEAD_MASK); | 1344 | RING_HEAD_MASK); |
1340 | dinfo->ring_tail = INREG(PRI_RING_TAIL) & RING_TAIL_MASK; | 1345 | dinfo->ring_tail = INREG(PRI_RING_TAIL) & RING_TAIL_MASK; |
1341 | if (dinfo->ring_tail + RING_MIN_FREE < (u32 __iomem)dinfo->ring_head) | 1346 | if (dinfo->ring_tail + RING_MIN_FREE < (u32 __iomem)dinfo->ring_head) |
1342 | dinfo->ring_space = (u32 __iomem) dinfo->ring_head | 1347 | dinfo->ring_space = (u32 __iomem) dinfo->ring_head |
1343 | - (dinfo->ring_tail + RING_MIN_FREE); | 1348 | - (dinfo->ring_tail + RING_MIN_FREE); |
1344 | else | 1349 | else |
1345 | dinfo->ring_space = (dinfo->ring.size + | 1350 | dinfo->ring_space = (dinfo->ring.size + |
1346 | (u32 __iomem) dinfo->ring_head) | 1351 | (u32 __iomem) dinfo->ring_head) |
1347 | - (dinfo->ring_tail + RING_MIN_FREE); | 1352 | - (dinfo->ring_tail + RING_MIN_FREE); |
1348 | } | 1353 | } |
1349 | 1354 | ||
1350 | static void | 1355 | static void |
1351 | reset_state(struct intelfb_info *dinfo) | 1356 | reset_state(struct intelfb_info *dinfo) |
1352 | { | 1357 | { |
1353 | int i; | 1358 | int i; |
1354 | u32 tmp; | 1359 | u32 tmp; |
1355 | 1360 | ||
1356 | #if VERBOSE > 0 | 1361 | #if VERBOSE > 0 |
1357 | DBG_MSG("reset_state\n"); | 1362 | DBG_MSG("reset_state\n"); |
1358 | #endif | 1363 | #endif |
1359 | 1364 | ||
1360 | for (i = 0; i < FENCE_NUM; i++) | 1365 | for (i = 0; i < FENCE_NUM; i++) |
1361 | OUTREG(FENCE + (i << 2), 0); | 1366 | OUTREG(FENCE + (i << 2), 0); |
1362 | 1367 | ||
1363 | /* Flush the ring buffer if it's enabled. */ | 1368 | /* Flush the ring buffer if it's enabled. */ |
1364 | tmp = INREG(PRI_RING_LENGTH); | 1369 | tmp = INREG(PRI_RING_LENGTH); |
1365 | if (tmp & RING_ENABLE) { | 1370 | if (tmp & RING_ENABLE) { |
1366 | #if VERBOSE > 0 | 1371 | #if VERBOSE > 0 |
1367 | DBG_MSG("reset_state: ring was enabled\n"); | 1372 | DBG_MSG("reset_state: ring was enabled\n"); |
1368 | #endif | 1373 | #endif |
1369 | refresh_ring(dinfo); | 1374 | refresh_ring(dinfo); |
1370 | intelfbhw_do_sync(dinfo); | 1375 | intelfbhw_do_sync(dinfo); |
1371 | DO_RING_IDLE(); | 1376 | DO_RING_IDLE(); |
1372 | } | 1377 | } |
1373 | 1378 | ||
1374 | OUTREG(PRI_RING_LENGTH, 0); | 1379 | OUTREG(PRI_RING_LENGTH, 0); |
1375 | OUTREG(PRI_RING_HEAD, 0); | 1380 | OUTREG(PRI_RING_HEAD, 0); |
1376 | OUTREG(PRI_RING_TAIL, 0); | 1381 | OUTREG(PRI_RING_TAIL, 0); |
1377 | OUTREG(PRI_RING_START, 0); | 1382 | OUTREG(PRI_RING_START, 0); |
1378 | } | 1383 | } |
1379 | 1384 | ||
1380 | /* Stop the 2D engine, and turn off the ring buffer. */ | 1385 | /* Stop the 2D engine, and turn off the ring buffer. */ |
1381 | void | 1386 | void |
1382 | intelfbhw_2d_stop(struct intelfb_info *dinfo) | 1387 | intelfbhw_2d_stop(struct intelfb_info *dinfo) |
1383 | { | 1388 | { |
1384 | #if VERBOSE > 0 | 1389 | #if VERBOSE > 0 |
1385 | DBG_MSG("intelfbhw_2d_stop: accel: %d, ring_active: %d\n", dinfo->accel, | 1390 | DBG_MSG("intelfbhw_2d_stop: accel: %d, ring_active: %d\n", dinfo->accel, |
1386 | dinfo->ring_active); | 1391 | dinfo->ring_active); |
1387 | #endif | 1392 | #endif |
1388 | 1393 | ||
1389 | if (!dinfo->accel) | 1394 | if (!dinfo->accel) |
1390 | return; | 1395 | return; |
1391 | 1396 | ||
1392 | dinfo->ring_active = 0; | 1397 | dinfo->ring_active = 0; |
1393 | reset_state(dinfo); | 1398 | reset_state(dinfo); |
1394 | } | 1399 | } |
1395 | 1400 | ||
1396 | /* | 1401 | /* |
1397 | * Enable the ring buffer, and initialise the 2D engine. | 1402 | * Enable the ring buffer, and initialise the 2D engine. |
1398 | * It is assumed that the graphics engine has been stopped by previously | 1403 | * It is assumed that the graphics engine has been stopped by previously |
1399 | * calling intelfb_2d_stop(). | 1404 | * calling intelfb_2d_stop(). |
1400 | */ | 1405 | */ |
1401 | void | 1406 | void |
1402 | intelfbhw_2d_start(struct intelfb_info *dinfo) | 1407 | intelfbhw_2d_start(struct intelfb_info *dinfo) |
1403 | { | 1408 | { |
1404 | #if VERBOSE > 0 | 1409 | #if VERBOSE > 0 |
1405 | DBG_MSG("intelfbhw_2d_start: accel: %d, ring_active: %d\n", | 1410 | DBG_MSG("intelfbhw_2d_start: accel: %d, ring_active: %d\n", |
1406 | dinfo->accel, dinfo->ring_active); | 1411 | dinfo->accel, dinfo->ring_active); |
1407 | #endif | 1412 | #endif |
1408 | 1413 | ||
1409 | if (!dinfo->accel) | 1414 | if (!dinfo->accel) |
1410 | return; | 1415 | return; |
1411 | 1416 | ||
1412 | /* Initialise the primary ring buffer. */ | 1417 | /* Initialise the primary ring buffer. */ |
1413 | OUTREG(PRI_RING_LENGTH, 0); | 1418 | OUTREG(PRI_RING_LENGTH, 0); |
1414 | OUTREG(PRI_RING_TAIL, 0); | 1419 | OUTREG(PRI_RING_TAIL, 0); |
1415 | OUTREG(PRI_RING_HEAD, 0); | 1420 | OUTREG(PRI_RING_HEAD, 0); |
1416 | 1421 | ||
1417 | OUTREG(PRI_RING_START, dinfo->ring.physical & RING_START_MASK); | 1422 | OUTREG(PRI_RING_START, dinfo->ring.physical & RING_START_MASK); |
1418 | OUTREG(PRI_RING_LENGTH, | 1423 | OUTREG(PRI_RING_LENGTH, |
1419 | ((dinfo->ring.size - GTT_PAGE_SIZE) & RING_LENGTH_MASK) | | 1424 | ((dinfo->ring.size - GTT_PAGE_SIZE) & RING_LENGTH_MASK) | |
1420 | RING_NO_REPORT | RING_ENABLE); | 1425 | RING_NO_REPORT | RING_ENABLE); |
1421 | refresh_ring(dinfo); | 1426 | refresh_ring(dinfo); |
1422 | dinfo->ring_active = 1; | 1427 | dinfo->ring_active = 1; |
1423 | } | 1428 | } |
1424 | 1429 | ||
1425 | /* 2D fillrect (solid fill or invert) */ | 1430 | /* 2D fillrect (solid fill or invert) */ |
1426 | void | 1431 | void |
1427 | intelfbhw_do_fillrect(struct intelfb_info *dinfo, u32 x, u32 y, u32 w, u32 h, | 1432 | intelfbhw_do_fillrect(struct intelfb_info *dinfo, u32 x, u32 y, u32 w, u32 h, |
1428 | u32 color, u32 pitch, u32 bpp, u32 rop) | 1433 | u32 color, u32 pitch, u32 bpp, u32 rop) |
1429 | { | 1434 | { |
1430 | u32 br00, br09, br13, br14, br16; | 1435 | u32 br00, br09, br13, br14, br16; |
1431 | 1436 | ||
1432 | #if VERBOSE > 0 | 1437 | #if VERBOSE > 0 |
1433 | DBG_MSG("intelfbhw_do_fillrect: (%d,%d) %dx%d, c 0x%06x, p %d bpp %d, " | 1438 | DBG_MSG("intelfbhw_do_fillrect: (%d,%d) %dx%d, c 0x%06x, p %d bpp %d, " |
1434 | "rop 0x%02x\n", x, y, w, h, color, pitch, bpp, rop); | 1439 | "rop 0x%02x\n", x, y, w, h, color, pitch, bpp, rop); |
1435 | #endif | 1440 | #endif |
1436 | 1441 | ||
1437 | br00 = COLOR_BLT_CMD; | 1442 | br00 = COLOR_BLT_CMD; |
1438 | br09 = dinfo->fb_start + (y * pitch + x * (bpp / 8)); | 1443 | br09 = dinfo->fb_start + (y * pitch + x * (bpp / 8)); |
1439 | br13 = (rop << ROP_SHIFT) | pitch; | 1444 | br13 = (rop << ROP_SHIFT) | pitch; |
1440 | br14 = (h << HEIGHT_SHIFT) | ((w * (bpp / 8)) << WIDTH_SHIFT); | 1445 | br14 = (h << HEIGHT_SHIFT) | ((w * (bpp / 8)) << WIDTH_SHIFT); |
1441 | br16 = color; | 1446 | br16 = color; |
1442 | 1447 | ||
1443 | switch (bpp) { | 1448 | switch (bpp) { |
1444 | case 8: | 1449 | case 8: |
1445 | br13 |= COLOR_DEPTH_8; | 1450 | br13 |= COLOR_DEPTH_8; |
1446 | break; | 1451 | break; |
1447 | case 16: | 1452 | case 16: |
1448 | br13 |= COLOR_DEPTH_16; | 1453 | br13 |= COLOR_DEPTH_16; |
1449 | break; | 1454 | break; |
1450 | case 32: | 1455 | case 32: |
1451 | br13 |= COLOR_DEPTH_32; | 1456 | br13 |= COLOR_DEPTH_32; |
1452 | br00 |= WRITE_ALPHA | WRITE_RGB; | 1457 | br00 |= WRITE_ALPHA | WRITE_RGB; |
1453 | break; | 1458 | break; |
1454 | } | 1459 | } |
1455 | 1460 | ||
1456 | START_RING(6); | 1461 | START_RING(6); |
1457 | OUT_RING(br00); | 1462 | OUT_RING(br00); |
1458 | OUT_RING(br13); | 1463 | OUT_RING(br13); |
1459 | OUT_RING(br14); | 1464 | OUT_RING(br14); |
1460 | OUT_RING(br09); | 1465 | OUT_RING(br09); |
1461 | OUT_RING(br16); | 1466 | OUT_RING(br16); |
1462 | OUT_RING(MI_NOOP); | 1467 | OUT_RING(MI_NOOP); |
1463 | ADVANCE_RING(); | 1468 | ADVANCE_RING(); |
1464 | 1469 | ||
1465 | #if VERBOSE > 0 | 1470 | #if VERBOSE > 0 |
1466 | DBG_MSG("ring = 0x%08x, 0x%08x (%d)\n", dinfo->ring_head, | 1471 | DBG_MSG("ring = 0x%08x, 0x%08x (%d)\n", dinfo->ring_head, |
1467 | dinfo->ring_tail, dinfo->ring_space); | 1472 | dinfo->ring_tail, dinfo->ring_space); |
1468 | #endif | 1473 | #endif |
1469 | } | 1474 | } |
1470 | 1475 | ||
1471 | void | 1476 | void |
1472 | intelfbhw_do_bitblt(struct intelfb_info *dinfo, u32 curx, u32 cury, | 1477 | intelfbhw_do_bitblt(struct intelfb_info *dinfo, u32 curx, u32 cury, |
1473 | u32 dstx, u32 dsty, u32 w, u32 h, u32 pitch, u32 bpp) | 1478 | u32 dstx, u32 dsty, u32 w, u32 h, u32 pitch, u32 bpp) |
1474 | { | 1479 | { |
1475 | u32 br00, br09, br11, br12, br13, br22, br23, br26; | 1480 | u32 br00, br09, br11, br12, br13, br22, br23, br26; |
1476 | 1481 | ||
1477 | #if VERBOSE > 0 | 1482 | #if VERBOSE > 0 |
1478 | DBG_MSG("intelfbhw_do_bitblt: (%d,%d)->(%d,%d) %dx%d, p %d bpp %d\n", | 1483 | DBG_MSG("intelfbhw_do_bitblt: (%d,%d)->(%d,%d) %dx%d, p %d bpp %d\n", |
1479 | curx, cury, dstx, dsty, w, h, pitch, bpp); | 1484 | curx, cury, dstx, dsty, w, h, pitch, bpp); |
1480 | #endif | 1485 | #endif |
1481 | 1486 | ||
1482 | br00 = XY_SRC_COPY_BLT_CMD; | 1487 | br00 = XY_SRC_COPY_BLT_CMD; |
1483 | br09 = dinfo->fb_start; | 1488 | br09 = dinfo->fb_start; |
1484 | br11 = (pitch << PITCH_SHIFT); | 1489 | br11 = (pitch << PITCH_SHIFT); |
1485 | br12 = dinfo->fb_start; | 1490 | br12 = dinfo->fb_start; |
1486 | br13 = (SRC_ROP_GXCOPY << ROP_SHIFT) | (pitch << PITCH_SHIFT); | 1491 | br13 = (SRC_ROP_GXCOPY << ROP_SHIFT) | (pitch << PITCH_SHIFT); |
1487 | br22 = (dstx << WIDTH_SHIFT) | (dsty << HEIGHT_SHIFT); | 1492 | br22 = (dstx << WIDTH_SHIFT) | (dsty << HEIGHT_SHIFT); |
1488 | br23 = ((dstx + w) << WIDTH_SHIFT) | | 1493 | br23 = ((dstx + w) << WIDTH_SHIFT) | |
1489 | ((dsty + h) << HEIGHT_SHIFT); | 1494 | ((dsty + h) << HEIGHT_SHIFT); |
1490 | br26 = (curx << WIDTH_SHIFT) | (cury << HEIGHT_SHIFT); | 1495 | br26 = (curx << WIDTH_SHIFT) | (cury << HEIGHT_SHIFT); |
1491 | 1496 | ||
1492 | switch (bpp) { | 1497 | switch (bpp) { |
1493 | case 8: | 1498 | case 8: |
1494 | br13 |= COLOR_DEPTH_8; | 1499 | br13 |= COLOR_DEPTH_8; |
1495 | break; | 1500 | break; |
1496 | case 16: | 1501 | case 16: |
1497 | br13 |= COLOR_DEPTH_16; | 1502 | br13 |= COLOR_DEPTH_16; |
1498 | break; | 1503 | break; |
1499 | case 32: | 1504 | case 32: |
1500 | br13 |= COLOR_DEPTH_32; | 1505 | br13 |= COLOR_DEPTH_32; |
1501 | br00 |= WRITE_ALPHA | WRITE_RGB; | 1506 | br00 |= WRITE_ALPHA | WRITE_RGB; |
1502 | break; | 1507 | break; |
1503 | } | 1508 | } |
1504 | 1509 | ||
1505 | START_RING(8); | 1510 | START_RING(8); |
1506 | OUT_RING(br00); | 1511 | OUT_RING(br00); |
1507 | OUT_RING(br13); | 1512 | OUT_RING(br13); |
1508 | OUT_RING(br22); | 1513 | OUT_RING(br22); |
1509 | OUT_RING(br23); | 1514 | OUT_RING(br23); |
1510 | OUT_RING(br09); | 1515 | OUT_RING(br09); |
1511 | OUT_RING(br26); | 1516 | OUT_RING(br26); |
1512 | OUT_RING(br11); | 1517 | OUT_RING(br11); |
1513 | OUT_RING(br12); | 1518 | OUT_RING(br12); |
1514 | ADVANCE_RING(); | 1519 | ADVANCE_RING(); |
1515 | } | 1520 | } |
1516 | 1521 | ||
1517 | int | 1522 | int |
1518 | intelfbhw_do_drawglyph(struct intelfb_info *dinfo, u32 fg, u32 bg, u32 w, | 1523 | intelfbhw_do_drawglyph(struct intelfb_info *dinfo, u32 fg, u32 bg, u32 w, |
1519 | u32 h, const u8* cdat, u32 x, u32 y, u32 pitch, u32 bpp) | 1524 | u32 h, const u8* cdat, u32 x, u32 y, u32 pitch, u32 bpp) |
1520 | { | 1525 | { |
1521 | int nbytes, ndwords, pad, tmp; | 1526 | int nbytes, ndwords, pad, tmp; |
1522 | u32 br00, br09, br13, br18, br19, br22, br23; | 1527 | u32 br00, br09, br13, br18, br19, br22, br23; |
1523 | int dat, ix, iy, iw; | 1528 | int dat, ix, iy, iw; |
1524 | int i, j; | 1529 | int i, j; |
1525 | 1530 | ||
1526 | #if VERBOSE > 0 | 1531 | #if VERBOSE > 0 |
1527 | DBG_MSG("intelfbhw_do_drawglyph: (%d,%d) %dx%d\n", x, y, w, h); | 1532 | DBG_MSG("intelfbhw_do_drawglyph: (%d,%d) %dx%d\n", x, y, w, h); |
1528 | #endif | 1533 | #endif |
1529 | 1534 | ||
1530 | /* size in bytes of a padded scanline */ | 1535 | /* size in bytes of a padded scanline */ |
1531 | nbytes = ROUND_UP_TO(w, 16) / 8; | 1536 | nbytes = ROUND_UP_TO(w, 16) / 8; |
1532 | 1537 | ||
1533 | /* Total bytes of padded scanline data to write out. */ | 1538 | /* Total bytes of padded scanline data to write out. */ |
1534 | nbytes = nbytes * h; | 1539 | nbytes = nbytes * h; |
1535 | 1540 | ||
1536 | /* | 1541 | /* |
1537 | * Check if the glyph data exceeds the immediate mode limit. | 1542 | * Check if the glyph data exceeds the immediate mode limit. |
1538 | * It would take a large font (1K pixels) to hit this limit. | 1543 | * It would take a large font (1K pixels) to hit this limit. |
1539 | */ | 1544 | */ |
1540 | if (nbytes > MAX_MONO_IMM_SIZE) | 1545 | if (nbytes > MAX_MONO_IMM_SIZE) |
1541 | return 0; | 1546 | return 0; |
1542 | 1547 | ||
1543 | /* Src data is packaged a dword (32-bit) at a time. */ | 1548 | /* Src data is packaged a dword (32-bit) at a time. */ |
1544 | ndwords = ROUND_UP_TO(nbytes, 4) / 4; | 1549 | ndwords = ROUND_UP_TO(nbytes, 4) / 4; |
1545 | 1550 | ||
1546 | /* | 1551 | /* |
1547 | * Ring has to be padded to a quad word. But because the command starts | 1552 | * Ring has to be padded to a quad word. But because the command starts |
1548 | with 7 bytes, pad only if there is an even number of ndwords | 1553 | with 7 bytes, pad only if there is an even number of ndwords |
1549 | */ | 1554 | */ |
1550 | pad = !(ndwords % 2); | 1555 | pad = !(ndwords % 2); |
1551 | 1556 | ||
1552 | tmp = (XY_MONO_SRC_IMM_BLT_CMD & DW_LENGTH_MASK) + ndwords; | 1557 | tmp = (XY_MONO_SRC_IMM_BLT_CMD & DW_LENGTH_MASK) + ndwords; |
1553 | br00 = (XY_MONO_SRC_IMM_BLT_CMD & ~DW_LENGTH_MASK) | tmp; | 1558 | br00 = (XY_MONO_SRC_IMM_BLT_CMD & ~DW_LENGTH_MASK) | tmp; |
1554 | br09 = dinfo->fb_start; | 1559 | br09 = dinfo->fb_start; |
1555 | br13 = (SRC_ROP_GXCOPY << ROP_SHIFT) | (pitch << PITCH_SHIFT); | 1560 | br13 = (SRC_ROP_GXCOPY << ROP_SHIFT) | (pitch << PITCH_SHIFT); |
1556 | br18 = bg; | 1561 | br18 = bg; |
1557 | br19 = fg; | 1562 | br19 = fg; |
1558 | br22 = (x << WIDTH_SHIFT) | (y << HEIGHT_SHIFT); | 1563 | br22 = (x << WIDTH_SHIFT) | (y << HEIGHT_SHIFT); |
1559 | br23 = ((x + w) << WIDTH_SHIFT) | ((y + h) << HEIGHT_SHIFT); | 1564 | br23 = ((x + w) << WIDTH_SHIFT) | ((y + h) << HEIGHT_SHIFT); |
1560 | 1565 | ||
1561 | switch (bpp) { | 1566 | switch (bpp) { |
1562 | case 8: | 1567 | case 8: |
1563 | br13 |= COLOR_DEPTH_8; | 1568 | br13 |= COLOR_DEPTH_8; |
1564 | break; | 1569 | break; |
1565 | case 16: | 1570 | case 16: |
1566 | br13 |= COLOR_DEPTH_16; | 1571 | br13 |= COLOR_DEPTH_16; |
1567 | break; | 1572 | break; |
1568 | case 32: | 1573 | case 32: |
1569 | br13 |= COLOR_DEPTH_32; | 1574 | br13 |= COLOR_DEPTH_32; |
1570 | br00 |= WRITE_ALPHA | WRITE_RGB; | 1575 | br00 |= WRITE_ALPHA | WRITE_RGB; |
1571 | break; | 1576 | break; |
1572 | } | 1577 | } |
1573 | 1578 | ||
1574 | START_RING(8 + ndwords); | 1579 | START_RING(8 + ndwords); |
1575 | OUT_RING(br00); | 1580 | OUT_RING(br00); |
1576 | OUT_RING(br13); | 1581 | OUT_RING(br13); |
1577 | OUT_RING(br22); | 1582 | OUT_RING(br22); |
1578 | OUT_RING(br23); | 1583 | OUT_RING(br23); |
1579 | OUT_RING(br09); | 1584 | OUT_RING(br09); |
1580 | OUT_RING(br18); | 1585 | OUT_RING(br18); |
1581 | OUT_RING(br19); | 1586 | OUT_RING(br19); |
1582 | ix = iy = 0; | 1587 | ix = iy = 0; |
1583 | iw = ROUND_UP_TO(w, 8) / 8; | 1588 | iw = ROUND_UP_TO(w, 8) / 8; |
1584 | while (ndwords--) { | 1589 | while (ndwords--) { |
1585 | dat = 0; | 1590 | dat = 0; |
1586 | for (j = 0; j < 2; ++j) { | 1591 | for (j = 0; j < 2; ++j) { |
1587 | for (i = 0; i < 2; ++i) { | 1592 | for (i = 0; i < 2; ++i) { |
1588 | if (ix != iw || i == 0) | 1593 | if (ix != iw || i == 0) |
1589 | dat |= cdat[iy*iw + ix++] << (i+j*2)*8; | 1594 | dat |= cdat[iy*iw + ix++] << (i+j*2)*8; |
1590 | } | 1595 | } |
1591 | if (ix == iw && iy != (h-1)) { | 1596 | if (ix == iw && iy != (h-1)) { |
1592 | ix = 0; | 1597 | ix = 0; |
1593 | ++iy; | 1598 | ++iy; |
1594 | } | 1599 | } |
1595 | } | 1600 | } |
1596 | OUT_RING(dat); | 1601 | OUT_RING(dat); |
1597 | } | 1602 | } |
1598 | if (pad) | 1603 | if (pad) |
1599 | OUT_RING(MI_NOOP); | 1604 | OUT_RING(MI_NOOP); |
1600 | ADVANCE_RING(); | 1605 | ADVANCE_RING(); |
1601 | 1606 | ||
1602 | return 1; | 1607 | return 1; |
1603 | } | 1608 | } |
1604 | 1609 | ||
1605 | /* HW cursor functions. */ | 1610 | /* HW cursor functions. */ |
1606 | void | 1611 | void |
1607 | intelfbhw_cursor_init(struct intelfb_info *dinfo) | 1612 | intelfbhw_cursor_init(struct intelfb_info *dinfo) |
1608 | { | 1613 | { |
1609 | u32 tmp; | 1614 | u32 tmp; |
1610 | 1615 | ||
1611 | #if VERBOSE > 0 | 1616 | #if VERBOSE > 0 |
1612 | DBG_MSG("intelfbhw_cursor_init\n"); | 1617 | DBG_MSG("intelfbhw_cursor_init\n"); |
1613 | #endif | 1618 | #endif |
1614 | 1619 | ||
1615 | if (dinfo->mobile) { | 1620 | if (dinfo->mobile) { |
1616 | if (!dinfo->cursor.physical) | 1621 | if (!dinfo->cursor.physical) |
1617 | return; | 1622 | return; |
1618 | tmp = INREG(CURSOR_A_CONTROL); | 1623 | tmp = INREG(CURSOR_A_CONTROL); |
1619 | tmp &= ~(CURSOR_MODE_MASK | CURSOR_MOBILE_GAMMA_ENABLE | | 1624 | tmp &= ~(CURSOR_MODE_MASK | CURSOR_MOBILE_GAMMA_ENABLE | |
1620 | CURSOR_MEM_TYPE_LOCAL | | 1625 | CURSOR_MEM_TYPE_LOCAL | |
1621 | (1 << CURSOR_PIPE_SELECT_SHIFT)); | 1626 | (1 << CURSOR_PIPE_SELECT_SHIFT)); |
1622 | tmp |= CURSOR_MODE_DISABLE; | 1627 | tmp |= CURSOR_MODE_DISABLE; |
1623 | OUTREG(CURSOR_A_CONTROL, tmp); | 1628 | OUTREG(CURSOR_A_CONTROL, tmp); |
1624 | OUTREG(CURSOR_A_BASEADDR, dinfo->cursor.physical); | 1629 | OUTREG(CURSOR_A_BASEADDR, dinfo->cursor.physical); |
1625 | } else { | 1630 | } else { |
1626 | tmp = INREG(CURSOR_CONTROL); | 1631 | tmp = INREG(CURSOR_CONTROL); |
1627 | tmp &= ~(CURSOR_FORMAT_MASK | CURSOR_GAMMA_ENABLE | | 1632 | tmp &= ~(CURSOR_FORMAT_MASK | CURSOR_GAMMA_ENABLE | |
1628 | CURSOR_ENABLE | CURSOR_STRIDE_MASK); | 1633 | CURSOR_ENABLE | CURSOR_STRIDE_MASK); |
1629 | tmp = CURSOR_FORMAT_3C; | 1634 | tmp = CURSOR_FORMAT_3C; |
1630 | OUTREG(CURSOR_CONTROL, tmp); | 1635 | OUTREG(CURSOR_CONTROL, tmp); |
1631 | OUTREG(CURSOR_A_BASEADDR, dinfo->cursor.offset << 12); | 1636 | OUTREG(CURSOR_A_BASEADDR, dinfo->cursor.offset << 12); |
1632 | tmp = (64 << CURSOR_SIZE_H_SHIFT) | | 1637 | tmp = (64 << CURSOR_SIZE_H_SHIFT) | |
1633 | (64 << CURSOR_SIZE_V_SHIFT); | 1638 | (64 << CURSOR_SIZE_V_SHIFT); |
1634 | OUTREG(CURSOR_SIZE, tmp); | 1639 | OUTREG(CURSOR_SIZE, tmp); |
1635 | } | 1640 | } |
1636 | } | 1641 | } |
1637 | 1642 | ||
1638 | void | 1643 | void |
1639 | intelfbhw_cursor_hide(struct intelfb_info *dinfo) | 1644 | intelfbhw_cursor_hide(struct intelfb_info *dinfo) |
1640 | { | 1645 | { |
1641 | u32 tmp; | 1646 | u32 tmp; |
1642 | 1647 | ||
1643 | #if VERBOSE > 0 | 1648 | #if VERBOSE > 0 |
1644 | DBG_MSG("intelfbhw_cursor_hide\n"); | 1649 | DBG_MSG("intelfbhw_cursor_hide\n"); |
1645 | #endif | 1650 | #endif |
1646 | 1651 | ||
1647 | dinfo->cursor_on = 0; | 1652 | dinfo->cursor_on = 0; |
1648 | if (dinfo->mobile) { | 1653 | if (dinfo->mobile) { |
1649 | if (!dinfo->cursor.physical) | 1654 | if (!dinfo->cursor.physical) |
1650 | return; | 1655 | return; |
1651 | tmp = INREG(CURSOR_A_CONTROL); | 1656 | tmp = INREG(CURSOR_A_CONTROL); |
1652 | tmp &= ~CURSOR_MODE_MASK; | 1657 | tmp &= ~CURSOR_MODE_MASK; |
1653 | tmp |= CURSOR_MODE_DISABLE; | 1658 | tmp |= CURSOR_MODE_DISABLE; |
1654 | OUTREG(CURSOR_A_CONTROL, tmp); | 1659 | OUTREG(CURSOR_A_CONTROL, tmp); |
1655 | /* Flush changes */ | 1660 | /* Flush changes */ |
1656 | OUTREG(CURSOR_A_BASEADDR, dinfo->cursor.physical); | 1661 | OUTREG(CURSOR_A_BASEADDR, dinfo->cursor.physical); |
1657 | } else { | 1662 | } else { |
1658 | tmp = INREG(CURSOR_CONTROL); | 1663 | tmp = INREG(CURSOR_CONTROL); |
1659 | tmp &= ~CURSOR_ENABLE; | 1664 | tmp &= ~CURSOR_ENABLE; |
1660 | OUTREG(CURSOR_CONTROL, tmp); | 1665 | OUTREG(CURSOR_CONTROL, tmp); |
1661 | } | 1666 | } |
1662 | } | 1667 | } |
1663 | 1668 | ||
1664 | void | 1669 | void |
1665 | intelfbhw_cursor_show(struct intelfb_info *dinfo) | 1670 | intelfbhw_cursor_show(struct intelfb_info *dinfo) |
1666 | { | 1671 | { |
1667 | u32 tmp; | 1672 | u32 tmp; |
1668 | 1673 | ||
1669 | #if VERBOSE > 0 | 1674 | #if VERBOSE > 0 |
1670 | DBG_MSG("intelfbhw_cursor_show\n"); | 1675 | DBG_MSG("intelfbhw_cursor_show\n"); |
1671 | #endif | 1676 | #endif |
1672 | 1677 | ||
1673 | dinfo->cursor_on = 1; | 1678 | dinfo->cursor_on = 1; |
1674 | 1679 | ||
1675 | if (dinfo->cursor_blanked) | 1680 | if (dinfo->cursor_blanked) |
1676 | return; | 1681 | return; |
1677 | 1682 | ||
1678 | if (dinfo->mobile) { | 1683 | if (dinfo->mobile) { |
1679 | if (!dinfo->cursor.physical) | 1684 | if (!dinfo->cursor.physical) |
1680 | return; | 1685 | return; |
1681 | tmp = INREG(CURSOR_A_CONTROL); | 1686 | tmp = INREG(CURSOR_A_CONTROL); |
1682 | tmp &= ~CURSOR_MODE_MASK; | 1687 | tmp &= ~CURSOR_MODE_MASK; |
1683 | tmp |= CURSOR_MODE_64_4C_AX; | 1688 | tmp |= CURSOR_MODE_64_4C_AX; |
1684 | OUTREG(CURSOR_A_CONTROL, tmp); | 1689 | OUTREG(CURSOR_A_CONTROL, tmp); |
1685 | /* Flush changes */ | 1690 | /* Flush changes */ |
1686 | OUTREG(CURSOR_A_BASEADDR, dinfo->cursor.physical); | 1691 | OUTREG(CURSOR_A_BASEADDR, dinfo->cursor.physical); |
1687 | } else { | 1692 | } else { |
1688 | tmp = INREG(CURSOR_CONTROL); | 1693 | tmp = INREG(CURSOR_CONTROL); |
1689 | tmp |= CURSOR_ENABLE; | 1694 | tmp |= CURSOR_ENABLE; |
1690 | OUTREG(CURSOR_CONTROL, tmp); | 1695 | OUTREG(CURSOR_CONTROL, tmp); |
1691 | } | 1696 | } |
1692 | } | 1697 | } |
1693 | 1698 | ||
1694 | void | 1699 | void |
1695 | intelfbhw_cursor_setpos(struct intelfb_info *dinfo, int x, int y) | 1700 | intelfbhw_cursor_setpos(struct intelfb_info *dinfo, int x, int y) |
1696 | { | 1701 | { |
1697 | u32 tmp; | 1702 | u32 tmp; |
1698 | 1703 | ||
1699 | #if VERBOSE > 0 | 1704 | #if VERBOSE > 0 |
1700 | DBG_MSG("intelfbhw_cursor_setpos: (%d, %d)\n", x, y); | 1705 | DBG_MSG("intelfbhw_cursor_setpos: (%d, %d)\n", x, y); |
1701 | #endif | 1706 | #endif |
1702 | 1707 | ||
1703 | /* | 1708 | /* |
1704 | * Sets the position. The coordinates are assumed to already | 1709 | * Sets the position. The coordinates are assumed to already |
1705 | * have any offset adjusted. Assume that the cursor is never | 1710 | * have any offset adjusted. Assume that the cursor is never |
1706 | * completely off-screen, and that x, y are always >= 0. | 1711 | * completely off-screen, and that x, y are always >= 0. |
1707 | */ | 1712 | */ |
1708 | 1713 | ||
1709 | tmp = ((x & CURSOR_POS_MASK) << CURSOR_X_SHIFT) | | 1714 | tmp = ((x & CURSOR_POS_MASK) << CURSOR_X_SHIFT) | |
1710 | ((y & CURSOR_POS_MASK) << CURSOR_Y_SHIFT); | 1715 | ((y & CURSOR_POS_MASK) << CURSOR_Y_SHIFT); |
1711 | OUTREG(CURSOR_A_POSITION, tmp); | 1716 | OUTREG(CURSOR_A_POSITION, tmp); |
1712 | } | 1717 | } |
1713 | 1718 | ||
1714 | void | 1719 | void |
1715 | intelfbhw_cursor_setcolor(struct intelfb_info *dinfo, u32 bg, u32 fg) | 1720 | intelfbhw_cursor_setcolor(struct intelfb_info *dinfo, u32 bg, u32 fg) |
1716 | { | 1721 | { |
1717 | #if VERBOSE > 0 | 1722 | #if VERBOSE > 0 |
1718 | DBG_MSG("intelfbhw_cursor_setcolor\n"); | 1723 | DBG_MSG("intelfbhw_cursor_setcolor\n"); |
1719 | #endif | 1724 | #endif |
1720 | 1725 | ||
1721 | OUTREG(CURSOR_A_PALETTE0, bg & CURSOR_PALETTE_MASK); | 1726 | OUTREG(CURSOR_A_PALETTE0, bg & CURSOR_PALETTE_MASK); |
1722 | OUTREG(CURSOR_A_PALETTE1, fg & CURSOR_PALETTE_MASK); | 1727 | OUTREG(CURSOR_A_PALETTE1, fg & CURSOR_PALETTE_MASK); |
1723 | OUTREG(CURSOR_A_PALETTE2, fg & CURSOR_PALETTE_MASK); | 1728 | OUTREG(CURSOR_A_PALETTE2, fg & CURSOR_PALETTE_MASK); |
1724 | OUTREG(CURSOR_A_PALETTE3, bg & CURSOR_PALETTE_MASK); | 1729 | OUTREG(CURSOR_A_PALETTE3, bg & CURSOR_PALETTE_MASK); |
1725 | } | 1730 | } |
1726 | 1731 | ||
1727 | void | 1732 | void |
1728 | intelfbhw_cursor_load(struct intelfb_info *dinfo, int width, int height, | 1733 | intelfbhw_cursor_load(struct intelfb_info *dinfo, int width, int height, |
1729 | u8 *data) | 1734 | u8 *data) |
1730 | { | 1735 | { |
1731 | u8 __iomem *addr = (u8 __iomem *)dinfo->cursor.virtual; | 1736 | u8 __iomem *addr = (u8 __iomem *)dinfo->cursor.virtual; |
1732 | int i, j, w = width / 8; | 1737 | int i, j, w = width / 8; |
1733 | int mod = width % 8, t_mask, d_mask; | 1738 | int mod = width % 8, t_mask, d_mask; |
1734 | 1739 | ||
1735 | #if VERBOSE > 0 | 1740 | #if VERBOSE > 0 |
1736 | DBG_MSG("intelfbhw_cursor_load\n"); | 1741 | DBG_MSG("intelfbhw_cursor_load\n"); |
1737 | #endif | 1742 | #endif |
1738 | 1743 | ||
1739 | if (!dinfo->cursor.virtual) | 1744 | if (!dinfo->cursor.virtual) |
1740 | return; | 1745 | return; |
1741 | 1746 | ||
1742 | t_mask = 0xff >> mod; | 1747 | t_mask = 0xff >> mod; |
1743 | d_mask = ~(0xff >> mod); | 1748 | d_mask = ~(0xff >> mod); |
1744 | for (i = height; i--; ) { | 1749 | for (i = height; i--; ) { |
1745 | for (j = 0; j < w; j++) { | 1750 | for (j = 0; j < w; j++) { |
1746 | writeb(0x00, addr + j); | 1751 | writeb(0x00, addr + j); |
1747 | writeb(*(data++), addr + j+8); | 1752 | writeb(*(data++), addr + j+8); |
1748 | } | 1753 | } |
1749 | if (mod) { | 1754 | if (mod) { |
1750 | writeb(t_mask, addr + j); | 1755 | writeb(t_mask, addr + j); |
1751 | writeb(*(data++) & d_mask, addr + j+8); | 1756 | writeb(*(data++) & d_mask, addr + j+8); |
1752 | } | 1757 | } |
1753 | addr += 16; | 1758 | addr += 16; |
1754 | } | 1759 | } |
1755 | } | 1760 | } |
1756 | 1761 | ||
1757 | void | 1762 | void |
1758 | intelfbhw_cursor_reset(struct intelfb_info *dinfo) { | 1763 | intelfbhw_cursor_reset(struct intelfb_info *dinfo) { |
1759 | u8 __iomem *addr = (u8 __iomem *)dinfo->cursor.virtual; | 1764 | u8 __iomem *addr = (u8 __iomem *)dinfo->cursor.virtual; |
1760 | int i, j; | 1765 | int i, j; |
1761 | 1766 | ||
1762 | #if VERBOSE > 0 | 1767 | #if VERBOSE > 0 |
1763 | DBG_MSG("intelfbhw_cursor_reset\n"); | 1768 | DBG_MSG("intelfbhw_cursor_reset\n"); |
1764 | #endif | 1769 | #endif |
1765 | 1770 | ||
1766 | if (!dinfo->cursor.virtual) | 1771 | if (!dinfo->cursor.virtual) |
1767 | return; | 1772 | return; |
1768 | 1773 | ||
1769 | for (i = 64; i--; ) { | 1774 | for (i = 64; i--; ) { |
1770 | for (j = 0; j < 8; j++) { | 1775 | for (j = 0; j < 8; j++) { |
1771 | writeb(0xff, addr + j+0); | 1776 | writeb(0xff, addr + j+0); |
1772 | writeb(0x00, addr + j+8); | 1777 | writeb(0x00, addr + j+8); |
1773 | } | 1778 | } |
1774 | addr += 16; | 1779 | addr += 16; |
1775 | } | 1780 | } |
1776 | } | 1781 | } |
1777 | 1782 |