diff options
author | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-04-16 18:20:36 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-04-16 18:20:36 -0400 |
commit | 1da177e4c3f41524e886b7f1b8a0c1fc7321cac2 (patch) | |
tree | 0bba044c4ce775e45a88a51686b5d9f90697ea9d /drivers/video/virgefb.c |
Linux-2.6.12-rc2v2.6.12-rc2
Initial git repository build. I'm not bothering with the full history,
even though we have it. We can create a separate "historical" git
archive of that later if we want to, and in the meantime it's about
3.2GB when imported into git - space that would just make the early
git days unnecessarily complicated, when we don't have a lot of good
infrastructure for it.
Let it rip!
Diffstat (limited to 'drivers/video/virgefb.c')
-rw-r--r-- | drivers/video/virgefb.c | 2513 |
1 files changed, 2513 insertions, 0 deletions
diff --git a/drivers/video/virgefb.c b/drivers/video/virgefb.c new file mode 100644 index 000000000000..ed78747487e2 --- /dev/null +++ b/drivers/video/virgefb.c | |||
@@ -0,0 +1,2513 @@ | |||
1 | /* | ||
2 | * linux/drivers/video/virgefb.c -- CyberVision64/3D frame buffer device | ||
3 | * | ||
4 | * Copyright (C) 1997 André Heynatz | ||
5 | * | ||
6 | * | ||
7 | * This file is based on the CyberVision frame buffer device (cyberfb.c): | ||
8 | * | ||
9 | * Copyright (C) 1996 Martin Apel | ||
10 | * Geert Uytterhoeven | ||
11 | * | ||
12 | * Zorro II additions : | ||
13 | * | ||
14 | * Copyright (C) 1998-2000 Christian T. Steigies | ||
15 | * | ||
16 | * Initialization additions : | ||
17 | * | ||
18 | * Copyright (C) 1998-2000 Ken Tyler | ||
19 | * | ||
20 | * Parts of the Initialization code are based on Cyberfb.c by Allan Bair, | ||
21 | * and on the NetBSD CyberVision64 frame buffer driver by Michael Teske who gave | ||
22 | * permission for its use. | ||
23 | * | ||
24 | * Many thanks to Frank Mariak for his assistance with ZORRO 2 access and other | ||
25 | * mysteries. | ||
26 | * | ||
27 | * | ||
28 | * | ||
29 | * This file is subject to the terms and conditions of the GNU General Public | ||
30 | * License. See the file COPYING in the main directory of this archive | ||
31 | * for more details. | ||
32 | */ | ||
33 | |||
34 | #undef VIRGEFBDEBUG | ||
35 | #undef VIRGEFBDUMP | ||
36 | |||
37 | #include <linux/module.h> | ||
38 | #include <linux/kernel.h> | ||
39 | #include <linux/errno.h> | ||
40 | #include <linux/string.h> | ||
41 | #include <linux/mm.h> | ||
42 | #include <linux/tty.h> | ||
43 | #include <linux/slab.h> | ||
44 | #include <linux/delay.h> | ||
45 | #include <linux/zorro.h> | ||
46 | #include <linux/fb.h> | ||
47 | #include <linux/init.h> | ||
48 | #include <asm/uaccess.h> | ||
49 | #include <asm/system.h> | ||
50 | #include <asm/amigahw.h> | ||
51 | #include <asm/io.h> | ||
52 | #include <asm/irq.h> | ||
53 | #include <video/fbcon.h> | ||
54 | #include <video/fbcon-cfb8.h> | ||
55 | #include <video/fbcon-cfb16.h> | ||
56 | #include <video/fbcon-cfb32.h> | ||
57 | |||
58 | #include "virgefb.h" | ||
59 | |||
60 | #ifdef VIRGEFBDEBUG | ||
61 | #define DPRINTK(fmt, args...) printk(KERN_DEBUG "%s: " fmt, __FUNCTION__ , ## args) | ||
62 | #else | ||
63 | #define DPRINTK(fmt, args...) | ||
64 | #endif | ||
65 | |||
66 | #ifdef VIRGEFBDUMP | ||
67 | static void cv64_dump(void); | ||
68 | #define DUMP cv64_dump() | ||
69 | #else | ||
70 | #define DUMP | ||
71 | #endif | ||
72 | |||
73 | /* | ||
74 | * Macros for register access and zorro control | ||
75 | */ | ||
76 | |||
77 | static inline void mb_inline(void) { mb(); } /* for use in comma expressions */ | ||
78 | |||
79 | /* Set zorro 2 map */ | ||
80 | |||
81 | #define SelectIO \ | ||
82 | mb(); \ | ||
83 | if (on_zorro2) { \ | ||
84 | (*(volatile u16 *)((u8 *)(vcode_switch_base + 0x04)) = 0x01); \ | ||
85 | mb(); \ | ||
86 | } | ||
87 | |||
88 | #define SelectMMIO \ | ||
89 | mb(); \ | ||
90 | if (on_zorro2) { \ | ||
91 | (*(volatile u16 *)((u8 *)(vcode_switch_base + 0x04)) = 0x02); \ | ||
92 | mb(); \ | ||
93 | } | ||
94 | |||
95 | #define SelectCFG \ | ||
96 | mb(); \ | ||
97 | if (on_zorro2) { \ | ||
98 | (*(volatile u16 *)((u8 *)(vcode_switch_base + 0x04)) = 0x03); \ | ||
99 | mb(); \ | ||
100 | } | ||
101 | |||
102 | /* Set pass through, 0 = amiga, !=0 = cv64/3d */ | ||
103 | |||
104 | #define SetVSwitch(x) \ | ||
105 | mb(); \ | ||
106 | (*(volatile u16 *)((u8 *)(vcode_switch_base)) = \ | ||
107 | (u16)(x ? 0 : 1)); \ | ||
108 | mb(); | ||
109 | |||
110 | /* Zorro2 endian 'aperture' */ | ||
111 | |||
112 | #define ENDIAN_BYTE 2 | ||
113 | #define ENDIAN_WORD 1 | ||
114 | #define ENDIAN_LONG 0 | ||
115 | |||
116 | #define Select_Zorro2_FrameBuffer(x) \ | ||
117 | do { \ | ||
118 | if (on_zorro2) { \ | ||
119 | mb(); \ | ||
120 | (*(volatile u16 *)((u8 *)(vcode_switch_base + 0x08)) = \ | ||
121 | (x * 0x40)); \ | ||
122 | mb(); \ | ||
123 | } \ | ||
124 | } while (0) | ||
125 | |||
126 | /* SetPortVal - only used for interrupt enable (not yet implemented) */ | ||
127 | |||
128 | #if 0 | ||
129 | #define SetPortVal(x) \ | ||
130 | mb(); \ | ||
131 | (*(volatile u16 *)((u8 *)(vcode_switch_base + 0x0c)) = \ | ||
132 | (u16)x); \ | ||
133 | mb(); | ||
134 | #endif | ||
135 | |||
136 | /* IO access */ | ||
137 | |||
138 | #define byte_access_io(x) (((x) & 0x3ffc) | (((x) & 3)^3) | (((x) & 3) <<14)) | ||
139 | #define byte_access_mmio(x) (((x) & 0xfffc) | (((x) & 3)^3)) | ||
140 | |||
141 | /* Write 8 bit VGA register - used once for chip wakeup */ | ||
142 | |||
143 | #define wb_vgaio(reg, dat) \ | ||
144 | SelectIO; \ | ||
145 | (*(volatile u8 *)(vgaio_regs + ((u32)byte_access_io(reg) & 0xffff)) = \ | ||
146 | (dat & 0xff)); \ | ||
147 | SelectMMIO; | ||
148 | |||
149 | /* Read 8 bit VGA register - only used in dump (SelectIO not needed on read ?) */ | ||
150 | |||
151 | #ifdef VIRGEFBDUMP | ||
152 | #define rb_vgaio(reg) \ | ||
153 | ({ \ | ||
154 | u8 __zzyzx; \ | ||
155 | SelectIO; \ | ||
156 | __zzyzx = (*(volatile u8 *)((vgaio_regs)+(u32)byte_access_io(reg))); \ | ||
157 | SelectMMIO; \ | ||
158 | __zzyzx; \ | ||
159 | }) | ||
160 | #endif | ||
161 | |||
162 | /* MMIO access */ | ||
163 | |||
164 | /* Read 8 bit MMIO register */ | ||
165 | |||
166 | #define rb_mmio(reg) \ | ||
167 | (mb_inline(), \ | ||
168 | (*(volatile u8 *)(mmio_regs + 0x8000 + (u32)byte_access_mmio(reg)))) | ||
169 | |||
170 | /* Write 8 bit MMIO register */ | ||
171 | |||
172 | #define wb_mmio(reg,dat) \ | ||
173 | mb(); \ | ||
174 | (*(volatile u8 *)(mmio_regs + 0x8000 + (byte_access_mmio((reg) & 0xffff))) = \ | ||
175 | (dat & 0xff)); \ | ||
176 | mb(); | ||
177 | |||
178 | /* Read 32 bit MMIO register */ | ||
179 | |||
180 | #define rl_mmio(reg) \ | ||
181 | (mb_inline(), \ | ||
182 | (*((volatile u32 *)((u8 *)((mmio_regs + (on_zorro2 ? 0x20000 : 0)) + (reg)))))) | ||
183 | |||
184 | /* Write 32 bit MMIO register */ | ||
185 | |||
186 | #define wl_mmio(reg,dat) \ | ||
187 | mb(); \ | ||
188 | ((*(volatile u32 *)((u8 *)((mmio_regs + (on_zorro2 ? 0x20000 : 0)) + (reg)))) = \ | ||
189 | (u32)(dat)); \ | ||
190 | mb(); | ||
191 | |||
192 | /* Write to virge graphics register */ | ||
193 | |||
194 | #define wgfx(reg, dat) do { wb_mmio(GCT_ADDRESS, (reg)); wb_mmio(GCT_ADDRESS_W, (dat)); } while (0) | ||
195 | |||
196 | /* Write to virge sequencer register */ | ||
197 | |||
198 | #define wseq(reg, dat) do { wb_mmio(SEQ_ADDRESS, (reg)); wb_mmio(SEQ_ADDRESS_W, (dat)); } while (0) | ||
199 | |||
200 | /* Write to virge CRT controller register */ | ||
201 | |||
202 | #define wcrt(reg, dat) do { wb_mmio(CRT_ADDRESS, (reg)); wb_mmio(CRT_ADDRESS_W, (dat)); } while (0) | ||
203 | |||
204 | /* Write to virge attribute register */ | ||
205 | |||
206 | #define watr(reg, dat) \ | ||
207 | do { \ | ||
208 | volatile unsigned char watr_tmp; \ | ||
209 | watr_tmp = rb_mmio(ACT_ADDRESS_RESET); \ | ||
210 | wb_mmio(ACT_ADDRESS_W, (reg)); \ | ||
211 | wb_mmio(ACT_ADDRESS_W, (dat)); \ | ||
212 | udelay(10); \ | ||
213 | } while (0) | ||
214 | |||
215 | /* end of macros */ | ||
216 | |||
217 | struct virgefb_par { | ||
218 | struct fb_var_screeninfo var; | ||
219 | __u32 type; | ||
220 | __u32 type_aux; | ||
221 | __u32 visual; | ||
222 | __u32 line_length; | ||
223 | }; | ||
224 | |||
225 | static struct virgefb_par current_par; | ||
226 | |||
227 | static int current_par_valid = 0; | ||
228 | |||
229 | static struct display disp; | ||
230 | static struct fb_info fb_info; | ||
231 | |||
232 | static union { | ||
233 | #ifdef FBCON_HAS_CFB16 | ||
234 | u16 cfb16[16]; | ||
235 | #endif | ||
236 | #ifdef FBCON_HAS_CFB32 | ||
237 | u32 cfb32[16]; | ||
238 | #endif | ||
239 | } fbcon_cmap; | ||
240 | |||
241 | /* | ||
242 | * Switch for Chipset Independency | ||
243 | */ | ||
244 | |||
245 | static struct fb_hwswitch { | ||
246 | |||
247 | /* Initialisation */ | ||
248 | |||
249 | int (*init)(void); | ||
250 | |||
251 | /* Display Control */ | ||
252 | |||
253 | int (*encode_fix)(struct fb_fix_screeninfo *fix, struct virgefb_par *par); | ||
254 | int (*decode_var)(struct fb_var_screeninfo *var, struct virgefb_par *par); | ||
255 | int (*encode_var)(struct fb_var_screeninfo *var, struct virgefb_par *par); | ||
256 | int (*getcolreg)(u_int regno, u_int *red, u_int *green, u_int *blue, | ||
257 | u_int *transp, struct fb_info *info); | ||
258 | void (*blank)(int blank); | ||
259 | } *fbhw; | ||
260 | |||
261 | static unsigned char blit_maybe_busy = 0; | ||
262 | |||
263 | /* | ||
264 | * Frame Buffer Name | ||
265 | */ | ||
266 | |||
267 | static char virgefb_name[16] = "CyberVision/3D"; | ||
268 | |||
269 | /* | ||
270 | * CyberVision64/3d Graphics Board | ||
271 | */ | ||
272 | |||
273 | static unsigned char virgefb_colour_table [256][3]; | ||
274 | static unsigned long v_ram; | ||
275 | static unsigned long v_ram_size; | ||
276 | static volatile unsigned char *mmio_regs; | ||
277 | static volatile unsigned char *vgaio_regs; | ||
278 | |||
279 | static unsigned long v_ram_phys; | ||
280 | static unsigned long mmio_regs_phys; | ||
281 | static unsigned long vcode_switch_base; | ||
282 | static unsigned char on_zorro2; | ||
283 | |||
284 | /* | ||
285 | * Offsets from start of video ram to appropriate ZIII aperture | ||
286 | */ | ||
287 | |||
288 | #ifdef FBCON_HAS_CFB8 | ||
289 | #define CYBMEM_OFFSET_8 0x800000 /* BGRX */ | ||
290 | #endif | ||
291 | #ifdef FBCON_HAS_CFB16 | ||
292 | #define CYBMEM_OFFSET_16 0x400000 /* GBXR */ | ||
293 | #endif | ||
294 | #ifdef FBCON_HAS_CFB32 | ||
295 | #define CYBMEM_OFFSET_32 0x000000 /* XRGB */ | ||
296 | #endif | ||
297 | |||
298 | /* | ||
299 | * MEMCLOCK was 32MHz, 64MHz works, 72MHz doesn't (on my board) | ||
300 | */ | ||
301 | |||
302 | #define MEMCLOCK 50000000 | ||
303 | |||
304 | /* | ||
305 | * Predefined Video Modes | ||
306 | */ | ||
307 | |||
308 | static struct { | ||
309 | const char *name; | ||
310 | struct fb_var_screeninfo var; | ||
311 | } virgefb_predefined[] __initdata = { | ||
312 | #ifdef FBCON_HAS_CFB8 | ||
313 | { | ||
314 | "640x480-8", { /* Cybervision 8 bpp */ | ||
315 | 640, 480, 640, 480, 0, 0, 8, 0, | ||
316 | {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0}, | ||
317 | 0, 0, -1, -1, FB_ACCELF_TEXT, 31250, 160, 136, 82, 61, 88, 2, | ||
318 | 0, FB_VMODE_NONINTERLACED | ||
319 | } | ||
320 | }, { | ||
321 | "768x576-8", { /* Cybervision 8 bpp */ | ||
322 | 768, 576, 768, 576, 0, 0, 8, 0, | ||
323 | {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0}, | ||
324 | 0, 0, -1, -1, FB_ACCELF_TEXT, 29411, 144, 112, 32, 15, 64, 2, | ||
325 | 0, FB_VMODE_NONINTERLACED | ||
326 | } | ||
327 | }, { | ||
328 | "800x600-8", { /* Cybervision 8 bpp */ | ||
329 | 800, 600, 800, 600, 0, 0, 8, 0, | ||
330 | {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0}, | ||
331 | 0, 0, -1, -1, FB_ACCELF_TEXT, 28571, 168, 104, 22, 1, 48, 2, | ||
332 | 0, FB_VMODE_NONINTERLACED | ||
333 | } | ||
334 | }, { | ||
335 | #if 0 | ||
336 | "1024x768-8", { /* Cybervision 8 bpp */ | ||
337 | 1024, 768, 1024, 768, 0, 0, 8, 0, | ||
338 | {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0}, | ||
339 | 0, 0, -1, -1, FB_ACCELF_TEXT, 20833, 272, 168, 39, 2, 72, 1, | ||
340 | 0, FB_VMODE_NONINTERLACED | ||
341 | } | ||
342 | #else | ||
343 | "1024x768-8", { | ||
344 | 1024, 768, 1024, 768, 0, 0, 8, 0, | ||
345 | {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0}, | ||
346 | #if 0 | ||
347 | 0, 0, -1, -1, FB_ACCELF_TEXT, 12500, 184, 40, 40, 2, 96, 1, | ||
348 | FB_SYNC_COMP_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED | ||
349 | } | ||
350 | #else | ||
351 | 0, 0, -1, -1, FB_ACCELF_TEXT, 12699, 176, 16, 28, 1, 96, 3, | ||
352 | FB_SYNC_COMP_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED | ||
353 | } | ||
354 | #endif | ||
355 | #endif | ||
356 | }, { | ||
357 | "1152x886-8", { /* Cybervision 8 bpp */ | ||
358 | 1152, 886, 1152, 886, 0, 0, 8, 0, | ||
359 | {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0}, | ||
360 | 0, 0, -1, -1, FB_ACCELF_TEXT, 19230, 280, 168, 45, 1, 64, 10, | ||
361 | 0, FB_VMODE_NONINTERLACED | ||
362 | } | ||
363 | }, { | ||
364 | "1280x1024-8", { /* Cybervision 8 bpp */ | ||
365 | 1280, 1024, 1280, 1024, 0, 0, 8, 0, | ||
366 | {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0}, | ||
367 | #if 0 | ||
368 | 0, 0, -1, -1, FB_ACCELF_TEXT, 17857, 232, 232, 71, 15, 176, 12, | ||
369 | } | ||
370 | #else | ||
371 | 0, 0, -1, -1, FB_ACCELF_TEXT, 7414, 232, 64, 38, 1, 112, 3, | ||
372 | FB_SYNC_COMP_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED | ||
373 | } | ||
374 | #endif | ||
375 | }, { | ||
376 | "1600x1200-8", { /* Cybervision 8 bpp */ | ||
377 | 1600, 1200, 1600, 1200, 0, 0, 8, 0, | ||
378 | {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0}, | ||
379 | #if 0 | ||
380 | 0, 0, -1, -1, FB_ACCELF_TEXT, 13698, 336, 224, 77, 15, 176, 12, | ||
381 | 0, FB_VMODE_NONINTERLACED | ||
382 | } | ||
383 | #else | ||
384 | 0, 0, -1, -1, FB_ACCELF_TEXT, 6411, 256, 32, 52, 10, 160, 8, | ||
385 | FB_SYNC_COMP_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED | ||
386 | } | ||
387 | #endif | ||
388 | }, | ||
389 | #endif | ||
390 | |||
391 | #ifdef FBCON_HAS_CFB16 | ||
392 | { | ||
393 | "640x480-16", { /* Cybervision 16 bpp */ | ||
394 | 640, 480, 640, 480, 0, 0, 16, 0, | ||
395 | {11, 5, 0}, {5, 6, 0}, {0, 5, 0}, {0, 0, 0}, | ||
396 | 0, 0, -1, -1, FB_ACCELF_TEXT, 31250, 152, 144, 82, 61, 88, 2, | ||
397 | 0, FB_VMODE_NONINTERLACED | ||
398 | } | ||
399 | }, { | ||
400 | "768x576-16", { /* Cybervision 16 bpp */ | ||
401 | 768, 576, 768, 576, 0, 0, 16, 0, | ||
402 | {11, 5, 0}, {5, 6, 0}, {0, 5, 0}, {0, 0, 0}, | ||
403 | 0, 0, -1, -1, FB_ACCELF_TEXT, 29411, 144, 112, 32, 15, 64, 2, | ||
404 | 0, FB_VMODE_NONINTERLACED | ||
405 | } | ||
406 | }, { | ||
407 | "800x600-16", { /* Cybervision 16 bpp */ | ||
408 | 800, 600, 800, 600, 0, 0, 16, 0, | ||
409 | {11, 5, 0}, {5, 6, 0}, {0, 5, 0}, {0, 0, 0}, | ||
410 | 0, 0, -1, -1, FB_ACCELF_TEXT, 28571, 168, 104, 22, 1, 48, 2, | ||
411 | 0, FB_VMODE_NONINTERLACED | ||
412 | } | ||
413 | }, { | ||
414 | #if 0 | ||
415 | "1024x768-16", { /* Cybervision 16 bpp */ | ||
416 | 1024, 768, 1024, 768, 0, 0, 16, 0, | ||
417 | {11, 5, 0}, {5, 6, 0}, {0, 5, 0}, {0, 0, 0}, | ||
418 | 0, 0, -1, -1, FB_ACCELF_TEXT, 20833, 272, 168, 39, 2, 72, 1, | ||
419 | 0, FB_VMODE_NONINTERLACED | ||
420 | } | ||
421 | #else | ||
422 | "1024x768-16", { | ||
423 | 1024, 768, 1024, 768, 0, 0, 16, 0, | ||
424 | {11, 5, 0}, {5, 6, 0}, {0, 5, 0}, {0, 0, 0}, | ||
425 | 0, 0, -1, -1, FB_ACCELF_TEXT, 12500, 184, 40, 40, 2, 96, 1, | ||
426 | FB_SYNC_COMP_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED | ||
427 | } | ||
428 | #endif | ||
429 | }, { | ||
430 | "1152x886-16", { /* Cybervision 16 bpp */ | ||
431 | 1152, 886, 1152, 886, 0, 0, 16, 0, | ||
432 | {11, 5, 0}, {5, 6, 0}, {0, 5, 0}, {0, 0, 0}, | ||
433 | 0, 0, -1, -1, FB_ACCELF_TEXT, 19230, 280, 168, 45, 1, 64, 10, | ||
434 | 0, FB_VMODE_NONINTERLACED | ||
435 | } | ||
436 | }, { | ||
437 | "1280x1024-16", { /* Cybervision 16 bpp */ | ||
438 | 1280, 1024, 1280, 1024, 0, 0, 16, 0, | ||
439 | {11, 5, 0}, {5, 6, 0}, {0, 5, 0}, {0, 0, 0}, | ||
440 | 0, 0, -1, -1, FB_ACCELF_TEXT, 17857, 232, 232, 71, 15, 176, 12, | ||
441 | 0, FB_VMODE_NONINTERLACED | ||
442 | } | ||
443 | }, { | ||
444 | "1600x1200-16", { /* Cybervision 16 bpp */ | ||
445 | 1600, 1200, 1600, 1200, 0, 0, 16, 0, | ||
446 | {11, 5, 0}, {5, 6, 0}, {0, 5, 0}, {0, 0, 0}, | ||
447 | 0, 0, -1, -1, FB_ACCELF_TEXT, 13698, 336, 224, 77, 15, 176, 12, | ||
448 | 0, FB_VMODE_NONINTERLACED | ||
449 | } | ||
450 | }, | ||
451 | #endif | ||
452 | |||
453 | #ifdef FBCON_HAS_CFB32 | ||
454 | { | ||
455 | "640x480-32", { /* Cybervision 32 bpp */ | ||
456 | 640, 480, 640, 480, 0, 0, 32, 0, | ||
457 | {16, 8, 0}, {8, 8, 0}, {0, 8, 0}, {24, 0, 0}, | ||
458 | 0, 0, -1, -1, FB_ACCELF_TEXT, 31250, 160, 136, 82, 61, 88, 2, | ||
459 | 0, FB_VMODE_NONINTERLACED | ||
460 | } | ||
461 | }, { | ||
462 | "768x576-32", { /* Cybervision 32 bpp */ | ||
463 | 768, 576, 768, 576, 0, 0, 32, 0, | ||
464 | {16, 8, 0}, {8, 8, 0}, {0, 8, 0}, {24, 0, 0}, | ||
465 | 0, 0, -1, -1, FB_ACCELF_TEXT, 29411, 144, 112, 32, 15, 64, 2, | ||
466 | 0, FB_VMODE_NONINTERLACED | ||
467 | } | ||
468 | }, { | ||
469 | "800x600-32", { /* Cybervision 32 bpp */ | ||
470 | 800, 600, 800, 600, 0, 0, 32, 0, | ||
471 | {16, 8, 0}, {8, 8, 0}, {0, 8, 0}, {24, 0, 0}, | ||
472 | 0, 0, -1, -1, FB_ACCELF_TEXT, 28571, 168, 104, 22, 1, 48, 2, | ||
473 | 0, FB_VMODE_NONINTERLACED | ||
474 | } | ||
475 | }, { | ||
476 | "1024x768-32", { /* Cybervision 32 bpp */ | ||
477 | 1024, 768, 1024, 768, 0, 0, 32, 0, | ||
478 | {16, 8, 0}, {8, 8, 0}, {0, 8, 0}, {24, 0, 0}, | ||
479 | 0, 0, -1, -1, FB_ACCELF_TEXT, 20833, 272, 168, 39, 2, 72, 1, | ||
480 | 0, FB_VMODE_NONINTERLACED | ||
481 | } | ||
482 | }, { | ||
483 | "1152x886-32", { /* Cybervision 32 bpp */ | ||
484 | 1152, 886, 1152, 886, 0, 0, 32, 0, | ||
485 | {16, 8, 0}, {8, 8, 0}, {0, 8, 0}, {24, 0, 0}, | ||
486 | 0, 0, -1, -1, FB_ACCELF_TEXT, 19230, 280, 168, 45, 1, 64, 10, | ||
487 | 0, FB_VMODE_NONINTERLACED | ||
488 | } | ||
489 | }, { | ||
490 | "1280x1024-32", { /* Cybervision 32 bpp */ | ||
491 | 1280, 1024, 1280, 1024, 0, 0, 32, 0, | ||
492 | {16, 8, 0}, {8, 8, 0}, {0, 8, 0}, {24, 0, 0}, | ||
493 | 0, 0, -1, -1, FB_ACCELF_TEXT, 17857, 232, 232, 71, 15, 176, 12, | ||
494 | 0, FB_VMODE_NONINTERLACED | ||
495 | } | ||
496 | }, { | ||
497 | "1600x1200-32", { /* Cybervision 32 bpp */ | ||
498 | 1600, 1200, 1600, 1200, 0, 0, 32, 0, | ||
499 | {16, 8, 0}, {8, 8, 0}, {0, 8, 0}, {24, 0, 0}, | ||
500 | 0, 0, -1, -1, FB_ACCELF_TEXT, 13698, 336, 224, 77, 15, 176, 12, | ||
501 | 0, FB_VMODE_NONINTERLACED | ||
502 | } | ||
503 | }, | ||
504 | #endif | ||
505 | |||
506 | /* interlaced modes */ | ||
507 | |||
508 | #ifdef FBCON_HAS_CFB8 | ||
509 | { | ||
510 | "1024x768-8i", { /* Cybervision 8 bpp */ | ||
511 | 1024, 768, 1024, 768, 0, 0, 8, 0, | ||
512 | {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0}, | ||
513 | 0, 0, -1, -1, FB_ACCELF_TEXT, 20833, 272, 168, 39, 2, 72, 1, | ||
514 | 0, FB_VMODE_INTERLACED | ||
515 | } | ||
516 | }, { | ||
517 | "1280x1024-8i", { /* Cybervision 8 bpp */ | ||
518 | 1280, 1024, 1280, 1024, 0, 0, 8, 0, | ||
519 | {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0}, | ||
520 | 0, 0, -1, -1, FB_ACCELF_TEXT, 17857, 232, 232, 71, 15, 176, 12, | ||
521 | 0, FB_VMODE_INTERLACED | ||
522 | } | ||
523 | }, { | ||
524 | "1600x1200-8i", { /* Cybervision 8 bpp */ | ||
525 | 1600, 1200, 1600, 1200, 0, 0, 8, 0, | ||
526 | {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0}, | ||
527 | 0, 0, -1, -1, FB_ACCELF_TEXT, 13698, 336, 224, 77, 15, 176, 12, | ||
528 | 0, FB_VMODE_INTERLACED | ||
529 | } | ||
530 | }, | ||
531 | #endif | ||
532 | |||
533 | #ifdef FBCON_HAS_CFB16 | ||
534 | { | ||
535 | "1024x768-16i", { /* Cybervision 16 bpp */ | ||
536 | 1024, 768, 1024, 768, 0, 0, 16, 0, | ||
537 | {11, 5, 0}, {5, 6, 0}, {0, 5, 0}, {0, 0, 0}, | ||
538 | 0, 0, -1, -1, FB_ACCELF_TEXT, 20833, 272, 168, 39, 2, 72, 1, | ||
539 | 0, FB_VMODE_INTERLACED | ||
540 | } | ||
541 | }, { | ||
542 | "1280x1024-16i", { /* Cybervision 16 bpp */ | ||
543 | 1280, 1024, 1280, 1024, 0, 0, 16, 0, | ||
544 | {11, 5, 0}, {5, 6, 0}, {0, 5, 0}, {0, 0, 0}, | ||
545 | 0, 0, -1, -1, FB_ACCELF_TEXT, 17857, 232, 232, 71, 15, 176, 12, | ||
546 | 0, FB_VMODE_INTERLACED | ||
547 | } | ||
548 | }, { | ||
549 | "1600x1200-16i", { /* Cybervision 16 bpp */ | ||
550 | 1600, 1200, 1600, 1200, 0, 0, 16, 0, | ||
551 | {11, 5, 0}, {5, 6, 0}, {0, 5, 0}, {0, 0, 0}, | ||
552 | 0, 0, -1, -1, FB_ACCELF_TEXT, 13698, 336, 224, 77, 15, 176, 12, | ||
553 | 0, FB_VMODE_INTERLACED | ||
554 | } | ||
555 | }, | ||
556 | #endif | ||
557 | |||
558 | #ifdef FBCON_HAS_CFB32 | ||
559 | { | ||
560 | "1024x768-32i", { /* Cybervision 32 bpp */ | ||
561 | 1024, 768, 1024, 768, 0, 0, 32, 0, | ||
562 | {16, 8, 0}, {8, 8, 0}, {0, 8, 0}, {24, 0, 0}, | ||
563 | 0, 0, -1, -1, FB_ACCELF_TEXT, 22222, 216, 144, 39, 2, 72, 1, | ||
564 | 0, FB_VMODE_INTERLACED | ||
565 | } | ||
566 | }, { | ||
567 | "1280x1024-32i", { /* Cybervision 32 bpp */ | ||
568 | 1280, 1024, 1280, 1024, 0, 0, 32, 0, | ||
569 | {16, 8, 0}, {8, 8, 0}, {0, 8, 0}, {23, 0, 0}, | ||
570 | 0, 0, -1, -1, FB_ACCELF_TEXT, 17857, 232, 232, 71, 15, 176, 12, | ||
571 | 0, FB_VMODE_INTERLACED | ||
572 | } | ||
573 | }, { | ||
574 | "1600x1200-32i", { /* Cybervision 32 bpp */ | ||
575 | 1600, 1200, 1600, 1200, 0, 0, 32, 0, | ||
576 | {16, 8, 0}, {8, 8, 0}, {0, 8, 0}, {24, 0, 0}, | ||
577 | 0, 0, -1, -1, FB_ACCELF_TEXT, 13698, 336, 224, 77, 15, 176, 12, | ||
578 | 0, FB_VMODE_INTERLACED | ||
579 | } | ||
580 | }, | ||
581 | #endif | ||
582 | |||
583 | /* doublescan modes */ | ||
584 | |||
585 | #ifdef FBCON_HAS_CFB8 | ||
586 | { | ||
587 | "320x240-8d", { /* Cybervision 8 bpp */ | ||
588 | 320, 240, 320, 240, 0, 0, 8, 0, | ||
589 | {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0}, | ||
590 | 0, 0, -1, -1, FB_ACCELF_TEXT, 59259, 80, 80, 45, 26, 32, 1, | ||
591 | 0, FB_VMODE_DOUBLE | ||
592 | } | ||
593 | }, | ||
594 | #endif | ||
595 | |||
596 | #ifdef FBCON_HAS_CFB16 | ||
597 | { | ||
598 | "320x240-16d", { /* Cybervision 16 bpp */ | ||
599 | 320, 240, 320, 240, 0, 0, 16, 0, | ||
600 | {11, 5, 0}, {5, 6, 0}, {0, 5, 0}, {0, 0, 0}, | ||
601 | 0, 0, -1, -1, FB_ACCELF_TEXT, 59259, 80, 80, 45, 26, 32, 1, | ||
602 | 0, FB_VMODE_DOUBLE | ||
603 | } | ||
604 | }, | ||
605 | #endif | ||
606 | |||
607 | #ifdef FBCON_HAS_CFB32 | ||
608 | { | ||
609 | "320x240-32d", { /* Cybervision 32 bpp */ | ||
610 | 320, 240, 320, 240, 0, 0, 32, 0, | ||
611 | {16, 8, 0}, {8, 8, 0}, {0, 8, 0}, {24, 0, 0}, | ||
612 | 0, 0, -1, -1, FB_ACCELF_TEXT, 59259, 80, 80, 45, 26, 32, 1, | ||
613 | 0, FB_VMODE_DOUBLE | ||
614 | } | ||
615 | }, | ||
616 | #endif | ||
617 | }; | ||
618 | |||
619 | #define arraysize(x) (sizeof(x)/sizeof(*(x))) | ||
620 | #define NUM_TOTAL_MODES arraysize(virgefb_predefined) | ||
621 | |||
622 | /* | ||
623 | * Default to 800x600 for video=virge8:, virge16: or virge32: | ||
624 | */ | ||
625 | |||
626 | #ifdef FBCON_HAS_CFB8 | ||
627 | #define VIRGE8_DEFMODE (2) | ||
628 | #endif | ||
629 | |||
630 | #ifdef FBCON_HAS_CFB16 | ||
631 | #define VIRGE16_DEFMODE (9) | ||
632 | #endif | ||
633 | |||
634 | #ifdef FBCON_HAS_CFB32 | ||
635 | #define VIRGE32_DEFMODE (16) | ||
636 | #endif | ||
637 | |||
638 | static struct fb_var_screeninfo virgefb_default; | ||
639 | static int virgefb_inverse = 0; | ||
640 | |||
641 | /* | ||
642 | * Interface used by the world | ||
643 | */ | ||
644 | |||
645 | int virgefb_setup(char*); | ||
646 | static int virgefb_get_fix(struct fb_fix_screeninfo *fix, int con, | ||
647 | struct fb_info *info); | ||
648 | static int virgefb_get_var(struct fb_var_screeninfo *var, int con, | ||
649 | struct fb_info *info); | ||
650 | static int virgefb_set_var(struct fb_var_screeninfo *var, int con, | ||
651 | struct fb_info *info); | ||
652 | static int virgefb_get_cmap(struct fb_cmap *cmap, int kspc, int con, | ||
653 | struct fb_info *info); | ||
654 | static int virgefb_setcolreg(u_int regno, u_int red, u_int green, u_int blue, | ||
655 | u_int transp, struct fb_info *info); | ||
656 | static int virgefb_blank(int blank, struct fb_info *info); | ||
657 | |||
658 | /* | ||
659 | * Interface to the low level console driver | ||
660 | */ | ||
661 | |||
662 | int virgefb_init(void); | ||
663 | static int virgefb_switch(int con, struct fb_info *info); | ||
664 | static int virgefb_updatevar(int con, struct fb_info *info); | ||
665 | |||
666 | /* | ||
667 | * Text console acceleration | ||
668 | */ | ||
669 | |||
670 | #ifdef FBCON_HAS_CFB8 | ||
671 | static struct display_switch fbcon_virge8; | ||
672 | #endif | ||
673 | |||
674 | #ifdef FBCON_HAS_CFB16 | ||
675 | static struct display_switch fbcon_virge16; | ||
676 | #endif | ||
677 | |||
678 | #ifdef FBCON_HAS_CFB32 | ||
679 | static struct display_switch fbcon_virge32; | ||
680 | #endif | ||
681 | |||
682 | /* | ||
683 | * Hardware Specific Routines | ||
684 | */ | ||
685 | |||
686 | static int virge_init(void); | ||
687 | static int virgefb_encode_fix(struct fb_fix_screeninfo *fix, | ||
688 | struct virgefb_par *par); | ||
689 | static int virgefb_decode_var(struct fb_var_screeninfo *var, | ||
690 | struct virgefb_par *par); | ||
691 | static int virgefb_encode_var(struct fb_var_screeninfo *var, | ||
692 | struct virgefb_par *par); | ||
693 | static int virgefb_getcolreg(u_int regno, u_int *red, u_int *green, u_int *blue, | ||
694 | u_int *transp, struct fb_info *info); | ||
695 | static void virgefb_gfx_on_off(int blank); | ||
696 | static inline void virgefb_wait_for_idle(void); | ||
697 | static void virgefb_BitBLT(u_short curx, u_short cury, u_short destx, u_short desty, | ||
698 | u_short width, u_short height, u_short stride, u_short depth); | ||
699 | static void virgefb_RectFill(u_short x, u_short y, u_short width, u_short height, | ||
700 | u_short color, u_short stride, u_short depth); | ||
701 | |||
702 | /* | ||
703 | * Internal routines | ||
704 | */ | ||
705 | |||
706 | static void virgefb_get_par(struct virgefb_par *par); | ||
707 | static void virgefb_set_par(struct virgefb_par *par); | ||
708 | static int virgefb_do_fb_set_var(struct fb_var_screeninfo *var, int isactive); | ||
709 | static void virgefb_set_disp(int con, struct fb_info *info); | ||
710 | static int virgefb_get_video_mode(const char *name); | ||
711 | static void virgefb_set_video(struct fb_var_screeninfo *var); | ||
712 | |||
713 | /* | ||
714 | * Additions for Initialization | ||
715 | */ | ||
716 | |||
717 | static void virgefb_load_video_mode(struct fb_var_screeninfo *video_mode); | ||
718 | static int cv3d_has_4mb(void); | ||
719 | static unsigned short virgefb_compute_clock(unsigned long freq); | ||
720 | static inline unsigned char rattr(short); | ||
721 | static inline unsigned char rseq(short); | ||
722 | static inline unsigned char rcrt(short); | ||
723 | static inline unsigned char rgfx(short); | ||
724 | static inline void gfx_on_off(int toggle); | ||
725 | static void virgefb_pci_init(void); | ||
726 | |||
727 | /* -------------------- Hardware specific routines ------------------------- */ | ||
728 | |||
729 | /* | ||
730 | * Functions for register access | ||
731 | */ | ||
732 | |||
733 | /* Read attribute controller register */ | ||
734 | |||
735 | static inline unsigned char rattr(short idx) | ||
736 | { | ||
737 | volatile unsigned char rattr_tmp; | ||
738 | |||
739 | rattr_tmp = rb_mmio(ACT_ADDRESS_RESET); | ||
740 | wb_mmio(ACT_ADDRESS_W, idx); | ||
741 | return (rb_mmio(ACT_ADDRESS_R)); | ||
742 | } | ||
743 | |||
744 | /* Read sequencer register */ | ||
745 | |||
746 | static inline unsigned char rseq(short idx) | ||
747 | { | ||
748 | wb_mmio(SEQ_ADDRESS, idx); | ||
749 | return (rb_mmio(SEQ_ADDRESS_R)); | ||
750 | } | ||
751 | |||
752 | /* Read CRT controller register */ | ||
753 | |||
754 | static inline unsigned char rcrt(short idx) | ||
755 | { | ||
756 | wb_mmio(CRT_ADDRESS, idx); | ||
757 | return (rb_mmio(CRT_ADDRESS_R)); | ||
758 | } | ||
759 | |||
760 | /* Read graphics controller register */ | ||
761 | |||
762 | static inline unsigned char rgfx(short idx) | ||
763 | { | ||
764 | wb_mmio(GCT_ADDRESS, idx); | ||
765 | return (rb_mmio(GCT_ADDRESS_R)); | ||
766 | } | ||
767 | |||
768 | |||
769 | /* | ||
770 | * Initialization | ||
771 | */ | ||
772 | |||
773 | /* PCI init */ | ||
774 | |||
775 | void virgefb_pci_init(void) { | ||
776 | |||
777 | DPRINTK("ENTER\n"); | ||
778 | |||
779 | SelectCFG; | ||
780 | |||
781 | if (on_zorro2) { | ||
782 | *((short *)(vgaio_regs + 0x00000010)) = 0; | ||
783 | *((long *)(vgaio_regs + 0x00000004)) = 0x02000003; | ||
784 | } else { | ||
785 | *((short *)(vgaio_regs + 0x000e0010)) = 0; | ||
786 | *((long *)(vgaio_regs + 0x000e0004)) = 0x02000003; | ||
787 | } | ||
788 | |||
789 | /* SelectIO is in wb_vgaio macro */ | ||
790 | wb_vgaio(SREG_VIDEO_SUBS_ENABLE, 0x01); | ||
791 | /* SelectMMIO is in wb_vgaio macro */ | ||
792 | |||
793 | DPRINTK("EXIT\n"); | ||
794 | |||
795 | return; | ||
796 | } | ||
797 | |||
798 | /* | ||
799 | * Initalize all mode independent regs, find mem size and clear mem | ||
800 | */ | ||
801 | |||
802 | static int virge_init(void) | ||
803 | { | ||
804 | int i; | ||
805 | unsigned char tmp; | ||
806 | |||
807 | DPRINTK("ENTER\n"); | ||
808 | |||
809 | virgefb_pci_init(); | ||
810 | |||
811 | wb_mmio(GREG_MISC_OUTPUT_W, 0x07); /* colour, ram enable, clk sel */ | ||
812 | |||
813 | wseq(SEQ_ID_UNLOCK_EXT, 0x06); /* unlock extensions */ | ||
814 | tmp = rb_mmio(GREG_MISC_OUTPUT_R); | ||
815 | wcrt(CRT_ID_REGISTER_LOCK_1, 0x48); /* unlock CR2D to CR3F */ | ||
816 | |||
817 | wcrt(CRT_ID_BACKWAD_COMP_1, 0x00); /* irq disable */ | ||
818 | |||
819 | wcrt(CRT_ID_REGISTER_LOCK_2, 0xa5); /* unlock CR40 to CRFF and more */ | ||
820 | wcrt(CRT_ID_REGISTER_LOCK,0x00); /* unlock h and v timing */ | ||
821 | wcrt(CRT_ID_SYSTEM_CONFIG, 0x01); /* unlock enhanced programming registers */ | ||
822 | |||
823 | wb_mmio(GREG_FEATURE_CONTROL_W, 0x00); | ||
824 | |||
825 | wcrt(CRT_ID_EXT_MISC_CNTL, 0x00); /* b2 = 0 to allow VDAC mmio access */ | ||
826 | #if 0 | ||
827 | /* write strap options ... ? */ | ||
828 | wcrt(CRT_ID_CONFIG_1, 0x08); | ||
829 | wcrt(CRT_ID_CONFIG_2, 0xff); /* 0x0x2 bit needs to be set ?? */ | ||
830 | wcrt(CRT_ID_CONFIG_3, 0x0f); | ||
831 | wcrt(CRT_ID_CONFIG_4, 0x1a); | ||
832 | #endif | ||
833 | wcrt(CRT_ID_EXT_MISC_CNTL_1, 0x82); /* PCI DE and software reset S3D engine */ | ||
834 | /* EXT_MISC_CNTL_1, CR66 bit 0 should be the same as bit 0 MR_ADVANCED_FUNCTION_CONTROL - check */ | ||
835 | wl_mmio(MR_ADVANCED_FUNCTION_CONTROL, 0x00000011); /* enhanced mode, linear addressing */ | ||
836 | |||
837 | /* crtc registers */ | ||
838 | |||
839 | wcrt(CRT_ID_PRESET_ROW_SCAN, 0x00); | ||
840 | |||
841 | /* Disable h/w cursor */ | ||
842 | |||
843 | wcrt(CRT_ID_CURSOR_START, 0x00); | ||
844 | wcrt(CRT_ID_CURSOR_END, 0x00); | ||
845 | wcrt(CRT_ID_START_ADDR_HIGH, 0x00); | ||
846 | wcrt(CRT_ID_START_ADDR_LOW, 0x00); | ||
847 | wcrt(CRT_ID_CURSOR_LOC_HIGH, 0x00); | ||
848 | wcrt(CRT_ID_CURSOR_LOC_LOW, 0x00); | ||
849 | wcrt(CRT_ID_EXT_MODE, 0x00); | ||
850 | wcrt(CRT_ID_HWGC_MODE, 0x00); | ||
851 | wcrt(CRT_ID_HWGC_ORIGIN_X_HI, 0x00); | ||
852 | wcrt(CRT_ID_HWGC_ORIGIN_X_LO, 0x00); | ||
853 | wcrt(CRT_ID_HWGC_ORIGIN_Y_HI, 0x00); | ||
854 | wcrt(CRT_ID_HWGC_ORIGIN_Y_LO, 0x00); | ||
855 | i = rcrt(CRT_ID_HWGC_MODE); | ||
856 | wcrt(CRT_ID_HWGC_FG_STACK, 0x00); | ||
857 | wcrt(CRT_ID_HWGC_FG_STACK, 0x00); | ||
858 | wcrt(CRT_ID_HWGC_FG_STACK, 0x00); | ||
859 | wcrt(CRT_ID_HWGC_BG_STACK, 0x00); | ||
860 | wcrt(CRT_ID_HWGC_BG_STACK, 0x00); | ||
861 | wcrt(CRT_ID_HWGC_BG_STACK, 0x00); | ||
862 | wcrt(CRT_ID_HWGC_START_AD_HI, 0x00); | ||
863 | wcrt(CRT_ID_HWGC_START_AD_LO, 0x00); | ||
864 | wcrt(CRT_ID_HWGC_DSTART_X, 0x00); | ||
865 | wcrt(CRT_ID_HWGC_DSTART_Y, 0x00); | ||
866 | |||
867 | wcrt(CRT_ID_UNDERLINE_LOC, 0x00); | ||
868 | |||
869 | wcrt(CRT_ID_MODE_CONTROL, 0xe3); | ||
870 | wcrt(CRT_ID_BACKWAD_COMP_2, 0x22); /* blank bdr bit 5 blanking only on 8 bit */ | ||
871 | |||
872 | wcrt(CRT_ID_EX_SYNC_1, 0x00); | ||
873 | |||
874 | /* memory */ | ||
875 | |||
876 | wcrt(CRT_ID_EXT_SYS_CNTL_3, 0x00); | ||
877 | wcrt(CRT_ID_MEMORY_CONF, 0x08); /* config enhanced map */ | ||
878 | wcrt(CRT_ID_EXT_MEM_CNTL_1, 0x08); /* MMIO Select (0x0c works as well)*/ | ||
879 | wcrt(CRT_ID_EXT_MEM_CNTL_2, 0x02); /* why 02 big endian 00 works ? */ | ||
880 | wcrt(CRT_ID_EXT_MEM_CNTL_4, 0x9f); /* config big endian - 0x00 ? */ | ||
881 | wcrt(CRT_ID_LAW_POS_HI, 0x00); | ||
882 | wcrt(CRT_ID_LAW_POS_LO, 0x00); | ||
883 | wcrt(CRT_ID_EXT_MISC_CNTL_1, 0x81); | ||
884 | wcrt(CRT_ID_MISC_1, 0x90); /* must follow CRT_ID_EXT_MISC_CNTL_1 */ | ||
885 | wcrt(CRT_ID_LAW_CNTL, 0x13); /* force 4 Meg for test */ | ||
886 | if (cv3d_has_4mb()) { | ||
887 | v_ram_size = 0x00400000; | ||
888 | wcrt(CRT_ID_LAW_CNTL, 0x13); /* 4 MB */ | ||
889 | } else { | ||
890 | v_ram_size = 0x00200000; | ||
891 | wcrt(CRT_ID_LAW_CNTL, 0x12); /* 2 MB */ | ||
892 | } | ||
893 | |||
894 | if (on_zorro2) | ||
895 | v_ram_size -= 0x60000; /* we need some space for the registers */ | ||
896 | |||
897 | wcrt(CRT_ID_EXT_SYS_CNTL_4, 0x00); | ||
898 | wcrt(CRT_ID_EXT_DAC_CNTL, 0x00); /* 0x10 for X11 cursor mode */ | ||
899 | |||
900 | /* sequencer registers */ | ||
901 | |||
902 | wseq(SEQ_ID_CLOCKING_MODE, 0x01); /* 8 dot clock */ | ||
903 | wseq(SEQ_ID_MAP_MASK, 0xff); | ||
904 | wseq(SEQ_ID_CHAR_MAP_SELECT, 0x00); | ||
905 | wseq(SEQ_ID_MEMORY_MODE, 0x02); | ||
906 | wseq(SEQ_ID_RAMDAC_CNTL, 0x00); | ||
907 | wseq(SEQ_ID_SIGNAL_SELECT, 0x00); | ||
908 | wseq(SEQ_ID_EXT_SEQ_REG9, 0x00); /* MMIO and PIO reg access enabled */ | ||
909 | wseq(SEQ_ID_EXT_MISC_SEQ, 0x00); | ||
910 | wseq(SEQ_ID_CLKSYN_CNTL_1, 0x00); | ||
911 | wseq(SEQ_ID_EXT_SEQ, 0x00); | ||
912 | |||
913 | /* graphic registers */ | ||
914 | |||
915 | wgfx(GCT_ID_SET_RESET, 0x00); | ||
916 | wgfx(GCT_ID_ENABLE_SET_RESET, 0x00); | ||
917 | wgfx(GCT_ID_COLOR_COMPARE, 0x00); | ||
918 | wgfx(GCT_ID_DATA_ROTATE, 0x00); | ||
919 | wgfx(GCT_ID_READ_MAP_SELECT, 0x00); | ||
920 | wgfx(GCT_ID_GRAPHICS_MODE, 0x40); | ||
921 | wgfx(GCT_ID_MISC, 0x01); | ||
922 | wgfx(GCT_ID_COLOR_XCARE, 0x0f); | ||
923 | wgfx(GCT_ID_BITMASK, 0xff); | ||
924 | |||
925 | /* attribute registers */ | ||
926 | |||
927 | for(i = 0; i <= 15; i++) | ||
928 | watr(ACT_ID_PALETTE0 + i, i); | ||
929 | watr(ACT_ID_ATTR_MODE_CNTL, 0x41); | ||
930 | watr(ACT_ID_OVERSCAN_COLOR, 0xff); | ||
931 | watr(ACT_ID_COLOR_PLANE_ENA, 0x0f); | ||
932 | watr(ACT_ID_HOR_PEL_PANNING, 0x00); | ||
933 | watr(ACT_ID_COLOR_SELECT, 0x00); | ||
934 | |||
935 | wb_mmio(VDAC_MASK, 0xff); | ||
936 | |||
937 | /* init local cmap as greyscale levels */ | ||
938 | |||
939 | for (i = 0; i < 256; i++) { | ||
940 | virgefb_colour_table [i][0] = i; | ||
941 | virgefb_colour_table [i][1] = i; | ||
942 | virgefb_colour_table [i][2] = i; | ||
943 | } | ||
944 | |||
945 | /* clear framebuffer memory */ | ||
946 | |||
947 | memset((char*)v_ram, 0x00, v_ram_size); | ||
948 | |||
949 | DPRINTK("EXIT\n"); | ||
950 | return 0; | ||
951 | } | ||
952 | |||
953 | |||
954 | /* | ||
955 | * This function should fill in the `fix' structure based on the | ||
956 | * values in the `par' structure. | ||
957 | */ | ||
958 | |||
959 | static int virgefb_encode_fix(struct fb_fix_screeninfo *fix, | ||
960 | struct virgefb_par *par) | ||
961 | { | ||
962 | DPRINTK("ENTER set video phys addr\n"); | ||
963 | |||
964 | memset(fix, 0, sizeof(struct fb_fix_screeninfo)); | ||
965 | strcpy(fix->id, virgefb_name); | ||
966 | if (on_zorro2) | ||
967 | fix->smem_start = v_ram_phys; | ||
968 | switch (par->var.bits_per_pixel) { | ||
969 | #ifdef FBCON_HAS_CFB8 | ||
970 | case 8: | ||
971 | if (on_zorro2) | ||
972 | Select_Zorro2_FrameBuffer(ENDIAN_BYTE); | ||
973 | else | ||
974 | fix->smem_start = (v_ram_phys + CYBMEM_OFFSET_8); | ||
975 | break; | ||
976 | #endif | ||
977 | #ifdef FBCON_HAS_CFB16 | ||
978 | case 16: | ||
979 | if (on_zorro2) | ||
980 | Select_Zorro2_FrameBuffer(ENDIAN_WORD); | ||
981 | else | ||
982 | fix->smem_start = (v_ram_phys + CYBMEM_OFFSET_16); | ||
983 | break; | ||
984 | #endif | ||
985 | #ifdef FBCON_HAS_CFB32 | ||
986 | case 32: | ||
987 | if (on_zorro2) | ||
988 | Select_Zorro2_FrameBuffer(ENDIAN_LONG); | ||
989 | else | ||
990 | fix->smem_start = (v_ram_phys + CYBMEM_OFFSET_32); | ||
991 | break; | ||
992 | #endif | ||
993 | } | ||
994 | |||
995 | fix->smem_len = v_ram_size; | ||
996 | fix->mmio_start = mmio_regs_phys; | ||
997 | fix->mmio_len = 0x10000; /* TODO: verify this for the CV64/3D */ | ||
998 | |||
999 | fix->type = FB_TYPE_PACKED_PIXELS; | ||
1000 | fix->type_aux = 0; | ||
1001 | if (par->var.bits_per_pixel == 8) | ||
1002 | fix->visual = FB_VISUAL_PSEUDOCOLOR; | ||
1003 | else | ||
1004 | fix->visual = FB_VISUAL_TRUECOLOR; | ||
1005 | |||
1006 | fix->xpanstep = 0; | ||
1007 | fix->ypanstep = 0; | ||
1008 | fix->ywrapstep = 0; | ||
1009 | fix->line_length = par->var.xres_virtual*par->var.bits_per_pixel/8; | ||
1010 | fix->accel = FB_ACCEL_S3_VIRGE; | ||
1011 | DPRINTK("EXIT v_ram_phys = 0x%8.8lx\n", (unsigned long)fix->smem_start); | ||
1012 | return 0; | ||
1013 | } | ||
1014 | |||
1015 | |||
1016 | /* | ||
1017 | * Fill the `par' structure based on the values in `var'. | ||
1018 | * TODO: Verify and adjust values, return -EINVAL if bad. | ||
1019 | */ | ||
1020 | |||
1021 | static int virgefb_decode_var(struct fb_var_screeninfo *var, | ||
1022 | struct virgefb_par *par) | ||
1023 | { | ||
1024 | DPRINTK("ENTER\n"); | ||
1025 | par->var.xres = var->xres; | ||
1026 | par->var.yres = var->yres; | ||
1027 | par->var.xres_virtual = var->xres_virtual; | ||
1028 | par->var.yres_virtual = var->yres_virtual; | ||
1029 | /* roundup and validate */ | ||
1030 | par->var.xres = (par->var.xres+7) & ~7; | ||
1031 | par->var.xres_virtual = (par->var.xres_virtual+7) & ~7; | ||
1032 | if (par->var.xres_virtual < par->var.xres) | ||
1033 | par->var.xres_virtual = par->var.xres; | ||
1034 | if (par->var.yres_virtual < par->var.yres) | ||
1035 | par->var.yres_virtual = par->var.yres; | ||
1036 | par->var.xoffset = var->xoffset; | ||
1037 | par->var.yoffset = var->yoffset; | ||
1038 | par->var.bits_per_pixel = var->bits_per_pixel; | ||
1039 | if (par->var.bits_per_pixel <= 8) | ||
1040 | par->var.bits_per_pixel = 8; | ||
1041 | else if (par->var.bits_per_pixel <= 16) | ||
1042 | par->var.bits_per_pixel = 16; | ||
1043 | else | ||
1044 | par->var.bits_per_pixel = 32; | ||
1045 | #ifndef FBCON_HAS_CFB32 | ||
1046 | if (par->var.bits_per_pixel == 32) | ||
1047 | par->var.bits_per_pixel = 16; | ||
1048 | #endif | ||
1049 | #ifndef FBCON_HAS_CFB16 | ||
1050 | if (par->var.bits_per_pixel == 16) | ||
1051 | par->var.bits_per_pixel = 8; | ||
1052 | #endif | ||
1053 | par->var.grayscale = var->grayscale; | ||
1054 | par->var.red = var->red; | ||
1055 | par->var.green = var->green; | ||
1056 | par->var.blue = var->blue; | ||
1057 | par->var.transp = var->transp; | ||
1058 | par->var.nonstd = var->nonstd; | ||
1059 | par->var.activate = var->activate; | ||
1060 | par->var.height = var->height; | ||
1061 | par->var.width = var->width; | ||
1062 | if (var->accel_flags & FB_ACCELF_TEXT) { | ||
1063 | par->var.accel_flags = FB_ACCELF_TEXT; | ||
1064 | } else { | ||
1065 | par->var.accel_flags = 0; | ||
1066 | } | ||
1067 | par->var.pixclock = var->pixclock; | ||
1068 | par->var.left_margin = var->left_margin; | ||
1069 | par->var.right_margin = var->right_margin; | ||
1070 | par->var.upper_margin = var->upper_margin; | ||
1071 | par->var.lower_margin = var->lower_margin; | ||
1072 | par->var.hsync_len = var->hsync_len; | ||
1073 | par->var.vsync_len = var->vsync_len; | ||
1074 | par->var.sync = var->sync; | ||
1075 | par->var.vmode = var->vmode; | ||
1076 | DPRINTK("EXIT\n"); | ||
1077 | return 0; | ||
1078 | } | ||
1079 | |||
1080 | /* | ||
1081 | * Fill the `var' structure based on the values in `par' and maybe | ||
1082 | * other values read out of the hardware. | ||
1083 | */ | ||
1084 | |||
1085 | static int virgefb_encode_var(struct fb_var_screeninfo *var, | ||
1086 | struct virgefb_par *par) | ||
1087 | { | ||
1088 | DPRINTK("ENTER\n"); | ||
1089 | memset(var, 0, sizeof(struct fb_var_screeninfo)); /* need this ? */ | ||
1090 | var->xres = par->var.xres; | ||
1091 | var->yres = par->var.yres; | ||
1092 | var->xres_virtual = par->var.xres_virtual; | ||
1093 | var->yres_virtual = par->var.yres_virtual; | ||
1094 | var->xoffset = par->var.xoffset; | ||
1095 | var->yoffset = par->var.yoffset; | ||
1096 | var->bits_per_pixel = par->var.bits_per_pixel; | ||
1097 | var->grayscale = par->var.grayscale; | ||
1098 | var->red = par->var.red; | ||
1099 | var->green = par->var.green; | ||
1100 | var->blue = par->var.blue; | ||
1101 | var->transp = par->var.transp; | ||
1102 | var->nonstd = par->var.nonstd; | ||
1103 | var->activate = par->var.activate; | ||
1104 | var->height = par->var.height; | ||
1105 | var->width = par->var.width; | ||
1106 | var->accel_flags = par->var.accel_flags; | ||
1107 | var->pixclock = par->var.pixclock; | ||
1108 | var->left_margin = par->var.left_margin; | ||
1109 | var->right_margin = par->var.right_margin; | ||
1110 | var->upper_margin = par->var.upper_margin; | ||
1111 | var->lower_margin = par->var.lower_margin; | ||
1112 | var->hsync_len = par->var.hsync_len; | ||
1113 | var->vsync_len = par->var.vsync_len; | ||
1114 | var->sync = par->var.sync; | ||
1115 | var->vmode = par->var.vmode; | ||
1116 | DPRINTK("EXIT\n"); | ||
1117 | return 0; | ||
1118 | } | ||
1119 | |||
1120 | /* | ||
1121 | * Set a single color register. The values supplied are already | ||
1122 | * rounded down to the hardware's capabilities (according to the | ||
1123 | * entries in the var structure). Return != 0 for invalid regno. | ||
1124 | */ | ||
1125 | |||
1126 | static int virgefb_setcolreg(u_int regno, u_int red, u_int green, u_int blue, | ||
1127 | u_int transp, struct fb_info *info) | ||
1128 | { | ||
1129 | DPRINTK("ENTER\n"); | ||
1130 | if (((current_par.var.bits_per_pixel==8) && (regno>255)) || | ||
1131 | ((current_par.var.bits_per_pixel!=8) && (regno>15))) { | ||
1132 | DPRINTK("EXIT\n"); | ||
1133 | return 1; | ||
1134 | } | ||
1135 | if (((current_par.var.bits_per_pixel==8) && (regno<256)) || | ||
1136 | ((current_par.var.bits_per_pixel!=8) && (regno<16))) { | ||
1137 | virgefb_colour_table [regno][0] = red >> 10; | ||
1138 | virgefb_colour_table [regno][1] = green >> 10; | ||
1139 | virgefb_colour_table [regno][2] = blue >> 10; | ||
1140 | } | ||
1141 | |||
1142 | switch (current_par.var.bits_per_pixel) { | ||
1143 | #ifdef FBCON_HAS_CFB8 | ||
1144 | case 8: | ||
1145 | wb_mmio(VDAC_ADDRESS_W, (unsigned char)regno); | ||
1146 | wb_mmio(VDAC_DATA, ((unsigned char)(red >> 10))); | ||
1147 | wb_mmio(VDAC_DATA, ((unsigned char)(green >> 10))); | ||
1148 | wb_mmio(VDAC_DATA, ((unsigned char)(blue >> 10))); | ||
1149 | break; | ||
1150 | #endif | ||
1151 | #ifdef FBCON_HAS_CFB16 | ||
1152 | case 16: | ||
1153 | fbcon_cmap.cfb16[regno] = | ||
1154 | ((red & 0xf800) | | ||
1155 | ((green & 0xfc00) >> 5) | | ||
1156 | ((blue & 0xf800) >> 11)); | ||
1157 | break; | ||
1158 | #endif | ||
1159 | #ifdef FBCON_HAS_CFB32 | ||
1160 | case 32: | ||
1161 | fbcon_cmap.cfb32[regno] = | ||
1162 | /* transp = 0's or 1's ? */ | ||
1163 | (((red & 0xff00) << 8) | | ||
1164 | ((green & 0xff00) >> 0) | | ||
1165 | ((blue & 0xff00) >> 8)); | ||
1166 | break; | ||
1167 | #endif | ||
1168 | } | ||
1169 | DPRINTK("EXIT\n"); | ||
1170 | return 0; | ||
1171 | } | ||
1172 | |||
1173 | |||
1174 | /* | ||
1175 | * Read a single color register and split it into | ||
1176 | * colors/transparent. Return != 0 for invalid regno. | ||
1177 | */ | ||
1178 | |||
1179 | static int virgefb_getcolreg(u_int regno, u_int *red, u_int *green, u_int *blue, | ||
1180 | u_int *transp, struct fb_info *info) | ||
1181 | { | ||
1182 | int t; | ||
1183 | |||
1184 | DPRINTK("ENTER\n"); | ||
1185 | if (regno > 255) { | ||
1186 | DPRINTK("EXIT\n"); | ||
1187 | return 1; | ||
1188 | } | ||
1189 | if (((current_par.var.bits_per_pixel==8) && (regno<256)) || | ||
1190 | ((current_par.var.bits_per_pixel!=8) && (regno<16))) { | ||
1191 | |||
1192 | t = virgefb_colour_table [regno][0]; | ||
1193 | *red = (t<<10) | (t<<4) | (t>>2); | ||
1194 | t = virgefb_colour_table [regno][1]; | ||
1195 | *green = (t<<10) | (t<<4) | (t>>2); | ||
1196 | t = virgefb_colour_table [regno][2]; | ||
1197 | *blue = (t<<10) | (t<<4) | (t>>2); | ||
1198 | } | ||
1199 | *transp = 0; | ||
1200 | DPRINTK("EXIT\n"); | ||
1201 | return 0; | ||
1202 | } | ||
1203 | |||
1204 | |||
1205 | /* | ||
1206 | * (Un)Blank the screen | ||
1207 | */ | ||
1208 | |||
1209 | static void virgefb_gfx_on_off(int blank) | ||
1210 | { | ||
1211 | DPRINTK("ENTER\n"); | ||
1212 | gfx_on_off(blank); | ||
1213 | DPRINTK("EXIT\n"); | ||
1214 | } | ||
1215 | |||
1216 | /* | ||
1217 | * CV3D low-level support | ||
1218 | */ | ||
1219 | |||
1220 | |||
1221 | static inline void wait_3d_fifo_slots(int n) /* WaitQueue */ | ||
1222 | { | ||
1223 | do { | ||
1224 | mb(); | ||
1225 | } while (((rl_mmio(MR_SUBSYSTEM_STATUS_R) >> 8) & 0x1f) < (n + 2)); | ||
1226 | } | ||
1227 | |||
1228 | static inline void virgefb_wait_for_idle(void) /* WaitIdle */ | ||
1229 | { | ||
1230 | while(!(rl_mmio(MR_SUBSYSTEM_STATUS_R) & 0x2000)) ; | ||
1231 | blit_maybe_busy = 0; | ||
1232 | } | ||
1233 | |||
1234 | /* | ||
1235 | * BitBLT - Through the Plane | ||
1236 | */ | ||
1237 | |||
1238 | static void virgefb_BitBLT(u_short curx, u_short cury, u_short destx, u_short desty, | ||
1239 | u_short width, u_short height, u_short stride, u_short depth) | ||
1240 | { | ||
1241 | unsigned int blitcmd = S3V_BITBLT | S3V_DRAW | S3V_BLT_COPY; | ||
1242 | |||
1243 | switch (depth) { | ||
1244 | #ifdef FBCON_HAS_CFB8 | ||
1245 | case 8 : | ||
1246 | blitcmd |= S3V_DST_8BPP; | ||
1247 | break; | ||
1248 | #endif | ||
1249 | #ifdef FBCON_HAS_CFB16 | ||
1250 | case 16 : | ||
1251 | blitcmd |= S3V_DST_16BPP; | ||
1252 | break; | ||
1253 | #endif | ||
1254 | #ifdef FBCON_HAS_CFB32 | ||
1255 | case 32 : | ||
1256 | /* 32 bit uses 2 by 16 bit values, see fbcon_virge32_bmove */ | ||
1257 | blitcmd |= S3V_DST_16BPP; | ||
1258 | break; | ||
1259 | #endif | ||
1260 | } | ||
1261 | |||
1262 | /* Set drawing direction */ | ||
1263 | /* -Y, X maj, -X (default) */ | ||
1264 | if (curx > destx) { | ||
1265 | blitcmd |= (1 << 25); /* Drawing direction +X */ | ||
1266 | } else { | ||
1267 | curx += (width - 1); | ||
1268 | destx += (width - 1); | ||
1269 | } | ||
1270 | |||
1271 | if (cury > desty) { | ||
1272 | blitcmd |= (1 << 26); /* Drawing direction +Y */ | ||
1273 | } else { | ||
1274 | cury += (height - 1); | ||
1275 | desty += (height - 1); | ||
1276 | } | ||
1277 | |||
1278 | wait_3d_fifo_slots(8); /* wait on fifo slots for 8 writes */ | ||
1279 | |||
1280 | if (blit_maybe_busy) | ||
1281 | virgefb_wait_for_idle(); | ||
1282 | blit_maybe_busy = 1; | ||
1283 | |||
1284 | wl_mmio(BLT_PATTERN_COLOR, 1); /* pattern fb color */ | ||
1285 | wl_mmio(BLT_MONO_PATTERN_0, ~0); | ||
1286 | wl_mmio(BLT_MONO_PATTERN_1, ~0); | ||
1287 | wl_mmio(BLT_SIZE_X_Y, ((width << 16) | height)); | ||
1288 | wl_mmio(BLT_SRC_X_Y, ((curx << 16) | cury)); | ||
1289 | wl_mmio(BLT_DEST_X_Y, ((destx << 16) | desty)); | ||
1290 | wl_mmio(BLT_SRC_DEST_STRIDE, (((stride << 16) | stride) /* & 0x0ff80ff8 */)); /* why is this needed now ? */ | ||
1291 | wl_mmio(BLT_COMMAND_SET, blitcmd); | ||
1292 | } | ||
1293 | |||
1294 | /* | ||
1295 | * Rectangle Fill Solid | ||
1296 | */ | ||
1297 | |||
1298 | static void virgefb_RectFill(u_short x, u_short y, u_short width, u_short height, | ||
1299 | u_short color, u_short stride, u_short depth) | ||
1300 | { | ||
1301 | unsigned int blitcmd = S3V_RECTFILL | S3V_DRAW | | ||
1302 | S3V_BLT_CLEAR | S3V_MONO_PAT | (1 << 26) | (1 << 25); | ||
1303 | |||
1304 | switch (depth) { | ||
1305 | #ifdef FBCON_HAS_CFB8 | ||
1306 | case 8 : | ||
1307 | blitcmd |= S3V_DST_8BPP; | ||
1308 | break; | ||
1309 | #endif | ||
1310 | #ifdef FBCON_HAS_CFB16 | ||
1311 | case 16 : | ||
1312 | blitcmd |= S3V_DST_16BPP; | ||
1313 | break; | ||
1314 | #endif | ||
1315 | #ifdef FBCON_HAS_CFB32 | ||
1316 | case 32 : | ||
1317 | /* 32 bit uses 2 times 16 bit values, see fbcon_virge32_clear */ | ||
1318 | blitcmd |= S3V_DST_16BPP; | ||
1319 | break; | ||
1320 | #endif | ||
1321 | } | ||
1322 | |||
1323 | wait_3d_fifo_slots(5); /* wait on fifo slots for 5 writes */ | ||
1324 | |||
1325 | if (blit_maybe_busy) | ||
1326 | virgefb_wait_for_idle(); | ||
1327 | blit_maybe_busy = 1; | ||
1328 | |||
1329 | wl_mmio(BLT_PATTERN_COLOR, (color & 0xff)); | ||
1330 | wl_mmio(BLT_SIZE_X_Y, ((width << 16) | height)); | ||
1331 | wl_mmio(BLT_DEST_X_Y, ((x << 16) | y)); | ||
1332 | wl_mmio(BLT_SRC_DEST_STRIDE, (((stride << 16) | stride) /* & 0x0ff80ff8 */)); | ||
1333 | wl_mmio(BLT_COMMAND_SET, blitcmd); | ||
1334 | } | ||
1335 | |||
1336 | /* | ||
1337 | * Move cursor to x, y | ||
1338 | */ | ||
1339 | |||
1340 | #if 0 | ||
1341 | static void virgefb_move_cursor(u_short x, u_short y) | ||
1342 | { | ||
1343 | DPRINTK("Yuck .... MoveCursor on a 3D\n"); | ||
1344 | return 0; | ||
1345 | } | ||
1346 | #endif | ||
1347 | |||
1348 | /* -------------------- Interfaces to hardware functions -------------------- */ | ||
1349 | |||
1350 | static struct fb_hwswitch virgefb_hw_switch = { | ||
1351 | .init = virge_init, | ||
1352 | .encode_fix = virgefb_encode_fix, | ||
1353 | .decode_var = virgefb_decode_var, | ||
1354 | .encode_var = virgefb_encode_var, | ||
1355 | .getcolreg = virgefb_getcolreg, | ||
1356 | .blank = virgefb_gfx_on_off | ||
1357 | }; | ||
1358 | |||
1359 | |||
1360 | /* -------------------- Generic routines ------------------------------------ */ | ||
1361 | |||
1362 | |||
1363 | /* | ||
1364 | * Fill the hardware's `par' structure. | ||
1365 | */ | ||
1366 | |||
1367 | static void virgefb_get_par(struct virgefb_par *par) | ||
1368 | { | ||
1369 | DPRINTK("ENTER\n"); | ||
1370 | if (current_par_valid) { | ||
1371 | *par = current_par; | ||
1372 | } else { | ||
1373 | fbhw->decode_var(&virgefb_default, par); | ||
1374 | } | ||
1375 | DPRINTK("EXIT\n"); | ||
1376 | } | ||
1377 | |||
1378 | |||
1379 | static void virgefb_set_par(struct virgefb_par *par) | ||
1380 | { | ||
1381 | DPRINTK("ENTER\n"); | ||
1382 | current_par = *par; | ||
1383 | current_par_valid = 1; | ||
1384 | DPRINTK("EXIT\n"); | ||
1385 | } | ||
1386 | |||
1387 | |||
1388 | static void virgefb_set_video(struct fb_var_screeninfo *var) | ||
1389 | { | ||
1390 | /* Set clipping rectangle to current screen size */ | ||
1391 | |||
1392 | unsigned int clip; | ||
1393 | |||
1394 | DPRINTK("ENTER\n"); | ||
1395 | wait_3d_fifo_slots(4); | ||
1396 | clip = ((0 << 16) | (var->xres - 1)); | ||
1397 | wl_mmio(BLT_CLIP_LEFT_RIGHT, clip); | ||
1398 | clip = ((0 << 16) | (var->yres - 1)); | ||
1399 | wl_mmio(BLT_CLIP_TOP_BOTTOM, clip); | ||
1400 | wl_mmio(BLT_SRC_BASE, 0); /* seems we need to clear these two */ | ||
1401 | wl_mmio(BLT_DEST_BASE, 0); | ||
1402 | |||
1403 | /* Load the video mode defined by the 'var' data */ | ||
1404 | |||
1405 | virgefb_load_video_mode(var); | ||
1406 | DPRINTK("EXIT\n"); | ||
1407 | } | ||
1408 | |||
1409 | /* | ||
1410 | Merge these two functions, Geert's suggestion. | ||
1411 | static int virgefb_set_var(struct fb_var_screeninfo *var, int con, struct fb_info *info); | ||
1412 | static int virgefb_do_fb_set_var(struct fb_var_screeninfo *var, int isactive); | ||
1413 | */ | ||
1414 | |||
1415 | static int virgefb_do_fb_set_var(struct fb_var_screeninfo *var, int isactive) | ||
1416 | { | ||
1417 | int err, activate; | ||
1418 | struct virgefb_par par; | ||
1419 | |||
1420 | DPRINTK("ENTER\n"); | ||
1421 | if ((err = fbhw->decode_var(var, &par))) { | ||
1422 | DPRINTK("EXIT\n"); | ||
1423 | return (err); | ||
1424 | } | ||
1425 | |||
1426 | activate = var->activate; | ||
1427 | if ((var->activate & FB_ACTIVATE_MASK) == FB_ACTIVATE_NOW && isactive) | ||
1428 | virgefb_set_par(&par); | ||
1429 | fbhw->encode_var(var, &par); | ||
1430 | var->activate = activate; | ||
1431 | if ((var->activate & FB_ACTIVATE_MASK) == FB_ACTIVATE_NOW && isactive) | ||
1432 | virgefb_set_video(var); | ||
1433 | DPRINTK("EXIT\n"); | ||
1434 | return 0; | ||
1435 | } | ||
1436 | |||
1437 | |||
1438 | /* | ||
1439 | * Get the Fixed Part of the Display | ||
1440 | */ | ||
1441 | |||
1442 | static int virgefb_get_fix(struct fb_fix_screeninfo *fix, int con, | ||
1443 | struct fb_info *info) | ||
1444 | { | ||
1445 | struct virgefb_par par; | ||
1446 | int error = 0; | ||
1447 | |||
1448 | DPRINTK("ENTER\n"); | ||
1449 | if (con == -1) | ||
1450 | virgefb_get_par(&par); | ||
1451 | else | ||
1452 | error = fbhw->decode_var(&fb_display[con].var, &par); | ||
1453 | |||
1454 | if (!error) | ||
1455 | error = fbhw->encode_fix(fix, &par); | ||
1456 | DPRINTK("EXIT\n"); | ||
1457 | return(error); | ||
1458 | } | ||
1459 | |||
1460 | |||
1461 | /* | ||
1462 | * Get the User Defined Part of the Display | ||
1463 | */ | ||
1464 | |||
1465 | static int virgefb_get_var(struct fb_var_screeninfo *var, int con, | ||
1466 | struct fb_info *info) | ||
1467 | { | ||
1468 | struct virgefb_par par; | ||
1469 | int error = 0; | ||
1470 | |||
1471 | DPRINTK("ENTER\n"); | ||
1472 | if (con == -1) { | ||
1473 | virgefb_get_par(&par); | ||
1474 | error = fbhw->encode_var(var, &par); | ||
1475 | disp.var = *var; /* ++Andre: don't know if this is the right place */ | ||
1476 | } else { | ||
1477 | *var = fb_display[con].var; | ||
1478 | } | ||
1479 | DPRINTK("EXIT\n"); | ||
1480 | return(error); | ||
1481 | } | ||
1482 | |||
1483 | static void virgefb_set_disp(int con, struct fb_info *info) | ||
1484 | { | ||
1485 | struct fb_fix_screeninfo fix; | ||
1486 | struct display *display; | ||
1487 | |||
1488 | DPRINTK("ENTER\n"); | ||
1489 | if (con >= 0) | ||
1490 | display = &fb_display[con]; | ||
1491 | else | ||
1492 | display = &disp; /* used during initialization */ | ||
1493 | |||
1494 | virgefb_get_fix(&fix, con, info); | ||
1495 | if (con == -1) | ||
1496 | con = 0; | ||
1497 | if(on_zorro2) { | ||
1498 | info->screen_base = (char*)v_ram; | ||
1499 | } else { | ||
1500 | switch (display->var.bits_per_pixel) { | ||
1501 | #ifdef FBCON_HAS_CFB8 | ||
1502 | case 8: | ||
1503 | info->screen_base = (char*)(v_ram + CYBMEM_OFFSET_8); | ||
1504 | break; | ||
1505 | #endif | ||
1506 | #ifdef FBCON_HAS_CFB16 | ||
1507 | case 16: | ||
1508 | info->screen_base = (char*)(v_ram + CYBMEM_OFFSET_16); | ||
1509 | break; | ||
1510 | #endif | ||
1511 | #ifdef FBCON_HAS_CFB32 | ||
1512 | case 32: | ||
1513 | info->screen_base = (char*)(v_ram + CYBMEM_OFFSET_32); | ||
1514 | break; | ||
1515 | #endif | ||
1516 | } | ||
1517 | } | ||
1518 | display->visual = fix.visual; | ||
1519 | display->type = fix.type; | ||
1520 | display->type_aux = fix.type_aux; | ||
1521 | display->ypanstep = fix.ypanstep; | ||
1522 | display->ywrapstep = fix.ywrapstep; | ||
1523 | display->can_soft_blank = 1; | ||
1524 | display->inverse = virgefb_inverse; | ||
1525 | display->line_length = display->var.xres_virtual* | ||
1526 | display->var.bits_per_pixel/8; | ||
1527 | |||
1528 | switch (display->var.bits_per_pixel) { | ||
1529 | #ifdef FBCON_HAS_CFB8 | ||
1530 | case 8: | ||
1531 | if (display->var.accel_flags & FB_ACCELF_TEXT) { | ||
1532 | display->dispsw = &fbcon_virge8; | ||
1533 | #warning FIXME: We should reinit the graphics engine here | ||
1534 | } else | ||
1535 | display->dispsw = &fbcon_cfb8; | ||
1536 | break; | ||
1537 | #endif | ||
1538 | #ifdef FBCON_HAS_CFB16 | ||
1539 | case 16: | ||
1540 | if (display->var.accel_flags & FB_ACCELF_TEXT) { | ||
1541 | display->dispsw = &fbcon_virge16; | ||
1542 | } else | ||
1543 | display->dispsw = &fbcon_cfb16; | ||
1544 | display->dispsw_data = &fbcon_cmap.cfb16; | ||
1545 | break; | ||
1546 | #endif | ||
1547 | #ifdef FBCON_HAS_CFB32 | ||
1548 | case 32: | ||
1549 | if (display->var.accel_flags & FB_ACCELF_TEXT) { | ||
1550 | display->dispsw = &fbcon_virge32; | ||
1551 | } else | ||
1552 | display->dispsw = &fbcon_cfb32; | ||
1553 | display->dispsw_data = &fbcon_cmap.cfb32; | ||
1554 | break; | ||
1555 | #endif | ||
1556 | default: | ||
1557 | display->dispsw = &fbcon_dummy; | ||
1558 | break; | ||
1559 | } | ||
1560 | DPRINTK("EXIT v_ram virt = 0x%8.8lx\n",(unsigned long)display->screen_base); | ||
1561 | } | ||
1562 | |||
1563 | |||
1564 | /* | ||
1565 | * Set the User Defined Part of the Display | ||
1566 | */ | ||
1567 | |||
1568 | static int virgefb_set_var(struct fb_var_screeninfo *var, int con, | ||
1569 | struct fb_info *info) | ||
1570 | { | ||
1571 | int err, oldxres, oldyres, oldvxres, oldvyres, oldbpp, oldaccel; | ||
1572 | |||
1573 | DPRINTK("ENTER\n"); | ||
1574 | |||
1575 | if ((err = virgefb_do_fb_set_var(var, con == info->currcon))) { | ||
1576 | DPRINTK("EXIT\n"); | ||
1577 | return(err); | ||
1578 | } | ||
1579 | if ((var->activate & FB_ACTIVATE_MASK) == FB_ACTIVATE_NOW) { | ||
1580 | oldxres = fb_display[con].var.xres; | ||
1581 | oldyres = fb_display[con].var.yres; | ||
1582 | oldvxres = fb_display[con].var.xres_virtual; | ||
1583 | oldvyres = fb_display[con].var.yres_virtual; | ||
1584 | oldbpp = fb_display[con].var.bits_per_pixel; | ||
1585 | oldaccel = fb_display[con].var.accel_flags; | ||
1586 | fb_display[con].var = *var; | ||
1587 | if (oldxres != var->xres || oldyres != var->yres || | ||
1588 | oldvxres != var->xres_virtual || | ||
1589 | oldvyres != var->yres_virtual || | ||
1590 | oldbpp != var->bits_per_pixel || | ||
1591 | oldaccel != var->accel_flags) { | ||
1592 | virgefb_set_disp(con, info); | ||
1593 | if (fb_info.changevar) | ||
1594 | (*fb_info.changevar)(con); | ||
1595 | fb_alloc_cmap(&fb_display[con].cmap, 0, 0); | ||
1596 | do_install_cmap(con, info); | ||
1597 | } | ||
1598 | } | ||
1599 | var->activate = 0; | ||
1600 | DPRINTK("EXIT\n"); | ||
1601 | return 0; | ||
1602 | } | ||
1603 | |||
1604 | |||
1605 | /* | ||
1606 | * Get the Colormap | ||
1607 | */ | ||
1608 | |||
1609 | static int virgefb_get_cmap(struct fb_cmap *cmap, int kspc, int con, | ||
1610 | struct fb_info *info) | ||
1611 | { | ||
1612 | DPRINTK("ENTER\n"); | ||
1613 | if (con == info->currcon) { /* current console? */ | ||
1614 | DPRINTK("EXIT - console is current console, fb_get_cmap\n"); | ||
1615 | return(fb_get_cmap(cmap, kspc, fbhw->getcolreg, info)); | ||
1616 | } else if (fb_display[con].cmap.len) { /* non default colormap? */ | ||
1617 | DPRINTK("Use console cmap\n"); | ||
1618 | fb_copy_cmap(&fb_display[con].cmap, cmap, kspc ? 0 : 2); | ||
1619 | } else { | ||
1620 | DPRINTK("Use default cmap\n"); | ||
1621 | fb_copy_cmap(fb_default_cmap(fb_display[con].var.bits_per_pixel==8 ? 256 : 16), | ||
1622 | cmap, kspc ? 0 : 2); | ||
1623 | } | ||
1624 | DPRINTK("EXIT\n"); | ||
1625 | return 0; | ||
1626 | } | ||
1627 | |||
1628 | static struct fb_ops virgefb_ops = { | ||
1629 | .owner = THIS_MODULE, | ||
1630 | .fb_get_fix = virgefb_get_fix, | ||
1631 | .fb_get_var = virgefb_get_var, | ||
1632 | .fb_set_var = virgefb_set_var, | ||
1633 | .fb_get_cmap = virgefb_get_cmap, | ||
1634 | .fb_set_cmap = gen_set_cmap, | ||
1635 | .fb_setcolreg = virgefb_setcolreg, | ||
1636 | .fb_blank = virgefb_blank, | ||
1637 | }; | ||
1638 | |||
1639 | int __init virgefb_setup(char *options) | ||
1640 | { | ||
1641 | char *this_opt; | ||
1642 | fb_info.fontname[0] = '\0'; | ||
1643 | |||
1644 | DPRINTK("ENTER\n"); | ||
1645 | if (!options || !*options) { | ||
1646 | DPRINTK("EXIT\n"); | ||
1647 | return 0; | ||
1648 | } | ||
1649 | |||
1650 | while ((this_opt = strsep(&options, ",")) != NULL) { | ||
1651 | if (!*this_opt) | ||
1652 | continue; | ||
1653 | if (!strcmp(this_opt, "inverse")) { | ||
1654 | virgefb_inverse = 1; | ||
1655 | fb_invert_cmaps(); | ||
1656 | } else if (!strncmp(this_opt, "font:", 5)) | ||
1657 | strcpy(fb_info.fontname, this_opt+5); | ||
1658 | #ifdef FBCON_HAS_CFB8 | ||
1659 | else if (!strcmp (this_opt, "virge8")){ | ||
1660 | virgefb_default = virgefb_predefined[VIRGE8_DEFMODE].var; | ||
1661 | } | ||
1662 | #endif | ||
1663 | #ifdef FBCON_HAS_CFB16 | ||
1664 | else if (!strcmp (this_opt, "virge16")){ | ||
1665 | virgefb_default = virgefb_predefined[VIRGE16_DEFMODE].var; | ||
1666 | } | ||
1667 | #endif | ||
1668 | #ifdef FBCON_HAS_CFB32 | ||
1669 | else if (!strcmp (this_opt, "virge32")){ | ||
1670 | virgefb_default = virgefb_predefined[VIRGE32_DEFMODE].var; | ||
1671 | } | ||
1672 | #endif | ||
1673 | else | ||
1674 | virgefb_get_video_mode(this_opt); | ||
1675 | } | ||
1676 | |||
1677 | printk(KERN_INFO "mode : xres=%d, yres=%d, bpp=%d\n", virgefb_default.xres, | ||
1678 | virgefb_default.yres, virgefb_default.bits_per_pixel); | ||
1679 | DPRINTK("EXIT\n"); | ||
1680 | return 0; | ||
1681 | } | ||
1682 | |||
1683 | |||
1684 | /* | ||
1685 | * Get a Video Mode | ||
1686 | */ | ||
1687 | |||
1688 | static int __init virgefb_get_video_mode(const char *name) | ||
1689 | { | ||
1690 | int i; | ||
1691 | |||
1692 | DPRINTK("ENTER\n"); | ||
1693 | for (i = 0; i < NUM_TOTAL_MODES; i++) { | ||
1694 | if (!strcmp(name, virgefb_predefined[i].name)) { | ||
1695 | virgefb_default = virgefb_predefined[i].var; | ||
1696 | DPRINTK("EXIT\n"); | ||
1697 | return(i); | ||
1698 | } | ||
1699 | } | ||
1700 | /* ++Andre: set virgefb default mode */ | ||
1701 | |||
1702 | /* prefer 16 bit depth, 8 if no 16, if no 8 or 16 use 32 */ | ||
1703 | |||
1704 | #ifdef FBCON_HAS_CFB32 | ||
1705 | virgefb_default = virgefb_predefined[VIRGE32_DEFMODE].var; | ||
1706 | #endif | ||
1707 | #ifdef FBCON_HAS_CFB8 | ||
1708 | virgefb_default = virgefb_predefined[VIRGE8_DEFMODE].var; | ||
1709 | #endif | ||
1710 | #ifdef FBCON_HAS_CFB16 | ||
1711 | virgefb_default = virgefb_predefined[VIRGE16_DEFMODE].var; | ||
1712 | #endif | ||
1713 | DPRINTK("EXIT\n"); | ||
1714 | return 0; | ||
1715 | } | ||
1716 | |||
1717 | /* | ||
1718 | * Initialization | ||
1719 | */ | ||
1720 | |||
1721 | int __init virgefb_init(void) | ||
1722 | { | ||
1723 | struct virgefb_par par; | ||
1724 | unsigned long board_addr, board_size; | ||
1725 | struct zorro_dev *z = NULL; | ||
1726 | |||
1727 | DPRINTK("ENTER\n"); | ||
1728 | |||
1729 | z = zorro_find_device(ZORRO_PROD_PHASE5_CYBERVISION64_3D, NULL); | ||
1730 | if (!z) | ||
1731 | return -ENODEV; | ||
1732 | |||
1733 | board_addr = z->resource.start; | ||
1734 | if (board_addr < 0x01000000) { | ||
1735 | |||
1736 | /* board running in Z2 space. This includes the video memory | ||
1737 | as well as the S3 register set */ | ||
1738 | |||
1739 | on_zorro2 = 1; | ||
1740 | board_size = 0x00400000; | ||
1741 | |||
1742 | if (!request_mem_region(board_addr, board_size, "S3 ViRGE")) | ||
1743 | return -ENOMEM; | ||
1744 | |||
1745 | v_ram_phys = board_addr; | ||
1746 | v_ram = ZTWO_VADDR(v_ram_phys); | ||
1747 | mmio_regs_phys = (unsigned long)(board_addr + 0x003c0000); | ||
1748 | vgaio_regs = (unsigned char *) ZTWO_VADDR(board_addr + 0x003c0000); | ||
1749 | mmio_regs = (unsigned char *)ZTWO_VADDR(mmio_regs_phys); | ||
1750 | vcode_switch_base = (unsigned long) ZTWO_VADDR(board_addr + 0x003a0000); | ||
1751 | printk(KERN_INFO "CV3D detected running in Z2 mode.\n"); | ||
1752 | |||
1753 | } else { | ||
1754 | |||
1755 | /* board running in Z3 space. Separate video memory (3 apertures) | ||
1756 | and S3 register set */ | ||
1757 | |||
1758 | on_zorro2 = 0; | ||
1759 | board_size = 0x01000000; | ||
1760 | |||
1761 | if (!request_mem_region(board_addr, board_size, "S3 ViRGE")) | ||
1762 | return -ENOMEM; | ||
1763 | |||
1764 | v_ram_phys = board_addr + 0x04000000; | ||
1765 | v_ram = (unsigned long)ioremap(v_ram_phys, 0x01000000); | ||
1766 | mmio_regs_phys = board_addr + 0x05000000; | ||
1767 | vgaio_regs = (unsigned char *)ioremap(board_addr +0x0c000000, 0x00100000); /* includes PCI regs */ | ||
1768 | mmio_regs = ioremap(mmio_regs_phys, 0x00010000); | ||
1769 | vcode_switch_base = (unsigned long)ioremap(board_addr + 0x08000000, 0x1000); | ||
1770 | printk(KERN_INFO "CV3D detected running in Z3 mode\n"); | ||
1771 | } | ||
1772 | |||
1773 | #if defined (VIRGEFBDEBUG) | ||
1774 | DPRINTK("board_addr : 0x%8.8lx\n",board_addr); | ||
1775 | DPRINTK("board_size : 0x%8.8lx\n",board_size); | ||
1776 | DPRINTK("mmio_regs_phy : 0x%8.8lx\n",mmio_regs_phys); | ||
1777 | DPRINTK("v_ram_phys : 0x%8.8lx\n",v_ram_phys); | ||
1778 | DPRINTK("vgaio_regs : 0x%8.8lx\n",(unsigned long)vgaio_regs); | ||
1779 | DPRINTK("mmio_regs : 0x%8.8lx\n",(unsigned long)mmio_regs); | ||
1780 | DPRINTK("v_ram : 0x%8.8lx\n",v_ram); | ||
1781 | DPRINTK("vcode sw base : 0x%8.8lx\n",vcode_switch_base); | ||
1782 | #endif | ||
1783 | fbhw = &virgefb_hw_switch; | ||
1784 | strcpy(fb_info.modename, virgefb_name); | ||
1785 | fb_info.changevar = NULL; | ||
1786 | fb_info.fbops = &virgefb_ops; | ||
1787 | fb_info.disp = &disp; | ||
1788 | fb_info.currcon = -1; | ||
1789 | fb_info.switch_con = &virgefb_switch; | ||
1790 | fb_info.updatevar = &virgefb_updatevar; | ||
1791 | fb_info.flags = FBINFO_FLAG_DEFAULT; | ||
1792 | fbhw->init(); | ||
1793 | fbhw->decode_var(&virgefb_default, &par); | ||
1794 | fbhw->encode_var(&virgefb_default, &par); | ||
1795 | virgefb_do_fb_set_var(&virgefb_default, 1); | ||
1796 | virgefb_get_var(&fb_display[0].var, -1, &fb_info); | ||
1797 | virgefb_set_disp(-1, &fb_info); | ||
1798 | do_install_cmap(0, &fb_info); | ||
1799 | |||
1800 | if (register_framebuffer(&fb_info) < 0) { | ||
1801 | #warning release resources | ||
1802 | printk(KERN_ERR "virgefb.c: register_framebuffer failed\n"); | ||
1803 | DPRINTK("EXIT\n"); | ||
1804 | return -EINVAL; | ||
1805 | } | ||
1806 | |||
1807 | printk(KERN_INFO "fb%d: %s frame buffer device, using %ldK of video memory\n", | ||
1808 | fb_info.node, fb_info.modename, v_ram_size>>10); | ||
1809 | |||
1810 | /* TODO: This driver cannot be unloaded yet */ | ||
1811 | |||
1812 | DPRINTK("EXIT\n"); | ||
1813 | return 0; | ||
1814 | } | ||
1815 | |||
1816 | |||
1817 | static int virgefb_switch(int con, struct fb_info *info) | ||
1818 | { | ||
1819 | DPRINTK("ENTER\n"); | ||
1820 | /* Do we have to save the colormap? */ | ||
1821 | if (fb_display[info->currcon].cmap.len) | ||
1822 | fb_get_cmap(&fb_display[info->currcon].cmap, 1, | ||
1823 | fbhw->getcolreg, info); | ||
1824 | virgefb_do_fb_set_var(&fb_display[con].var, 1); | ||
1825 | info->currcon = con; | ||
1826 | /* Install new colormap */ | ||
1827 | do_install_cmap(con, info); | ||
1828 | DPRINTK("EXIT\n"); | ||
1829 | return 0; | ||
1830 | } | ||
1831 | |||
1832 | |||
1833 | /* | ||
1834 | * Update the `var' structure (called by fbcon.c) | ||
1835 | * | ||
1836 | * This call looks only at yoffset and the FB_VMODE_YWRAP flag in `var'. | ||
1837 | * Since it's called by a kernel driver, no range checking is done. | ||
1838 | */ | ||
1839 | |||
1840 | static int virgefb_updatevar(int con, struct fb_info *info) | ||
1841 | { | ||
1842 | DPRINTK("ENTER\n"); | ||
1843 | return 0; | ||
1844 | DPRINTK("EXIT\n"); | ||
1845 | } | ||
1846 | |||
1847 | /* | ||
1848 | * Blank the display. | ||
1849 | */ | ||
1850 | |||
1851 | static int virgefb_blank(int blank, struct fb_info *info) | ||
1852 | { | ||
1853 | DPRINTK("ENTER\n"); | ||
1854 | fbhw->blank(blank); | ||
1855 | DPRINTK("EXIT\n"); | ||
1856 | return 0; | ||
1857 | } | ||
1858 | |||
1859 | |||
1860 | /* | ||
1861 | * Text console acceleration | ||
1862 | */ | ||
1863 | |||
1864 | #ifdef FBCON_HAS_CFB8 | ||
1865 | static void fbcon_virge8_bmove(struct display *p, int sy, int sx, int dy, | ||
1866 | int dx, int height, int width) | ||
1867 | { | ||
1868 | sx *= 8; dx *= 8; width *= 8; | ||
1869 | virgefb_BitBLT((u_short)sx, (u_short)(sy*fontheight(p)), (u_short)dx, | ||
1870 | (u_short)(dy*fontheight(p)), (u_short)width, | ||
1871 | (u_short)(height*fontheight(p)), (u_short)p->next_line, 8); | ||
1872 | } | ||
1873 | |||
1874 | static void fbcon_virge8_clear(struct vc_data *conp, struct display *p, int sy, | ||
1875 | int sx, int height, int width) | ||
1876 | { | ||
1877 | unsigned char bg; | ||
1878 | |||
1879 | sx *= 8; width *= 8; | ||
1880 | bg = attr_bgcol_ec(p,conp); | ||
1881 | virgefb_RectFill((u_short)sx, (u_short)(sy*fontheight(p)), | ||
1882 | (u_short)width, (u_short)(height*fontheight(p)), | ||
1883 | (u_short)bg, (u_short)p->next_line, 8); | ||
1884 | } | ||
1885 | |||
1886 | static void fbcon_virge8_putc(struct vc_data *conp, struct display *p, int c, int yy, | ||
1887 | int xx) | ||
1888 | { | ||
1889 | if (blit_maybe_busy) | ||
1890 | virgefb_wait_for_idle(); | ||
1891 | fbcon_cfb8_putc(conp, p, c, yy, xx); | ||
1892 | } | ||
1893 | |||
1894 | static void fbcon_virge8_putcs(struct vc_data *conp, struct display *p, | ||
1895 | const unsigned short *s, int count, int yy, int xx) | ||
1896 | { | ||
1897 | if (blit_maybe_busy) | ||
1898 | virgefb_wait_for_idle(); | ||
1899 | fbcon_cfb8_putcs(conp, p, s, count, yy, xx); | ||
1900 | } | ||
1901 | |||
1902 | static void fbcon_virge8_revc(struct display *p, int xx, int yy) | ||
1903 | { | ||
1904 | if (blit_maybe_busy) | ||
1905 | virgefb_wait_for_idle(); | ||
1906 | fbcon_cfb8_revc(p, xx, yy); | ||
1907 | } | ||
1908 | |||
1909 | static void fbcon_virge8_clear_margins(struct vc_data *conp, struct display *p, | ||
1910 | int bottom_only) | ||
1911 | { | ||
1912 | if (blit_maybe_busy) | ||
1913 | virgefb_wait_for_idle(); | ||
1914 | fbcon_cfb8_clear_margins(conp, p, bottom_only); | ||
1915 | } | ||
1916 | |||
1917 | static struct display_switch fbcon_virge8 = { | ||
1918 | .setup = fbcon_cfb8_setup, | ||
1919 | .bmove = fbcon_virge8_bmove, | ||
1920 | .clear = fbcon_virge8_clear, | ||
1921 | .putc = fbcon_virge8_putc, | ||
1922 | .putcs = fbcon_virge8_putcs, | ||
1923 | .revc = fbcon_virge8_revc, | ||
1924 | .clear_margins = fbcon_virge8_clear_margins, | ||
1925 | .fontwidthmask = FONTWIDTH(4)|FONTWIDTH(8)|FONTWIDTH(12)|FONTWIDTH(16) | ||
1926 | }; | ||
1927 | #endif | ||
1928 | |||
1929 | #ifdef FBCON_HAS_CFB16 | ||
1930 | static void fbcon_virge16_bmove(struct display *p, int sy, int sx, int dy, | ||
1931 | int dx, int height, int width) | ||
1932 | { | ||
1933 | sx *= 8; dx *= 8; width *= 8; | ||
1934 | virgefb_BitBLT((u_short)sx, (u_short)(sy*fontheight(p)), (u_short)dx, | ||
1935 | (u_short)(dy*fontheight(p)), (u_short)width, | ||
1936 | (u_short)(height*fontheight(p)), (u_short)p->next_line, 16); | ||
1937 | } | ||
1938 | |||
1939 | static void fbcon_virge16_clear(struct vc_data *conp, struct display *p, int sy, | ||
1940 | int sx, int height, int width) | ||
1941 | { | ||
1942 | unsigned char bg; | ||
1943 | |||
1944 | sx *= 8; width *= 8; | ||
1945 | bg = attr_bgcol_ec(p,conp); | ||
1946 | virgefb_RectFill((u_short)sx, (u_short)(sy*fontheight(p)), | ||
1947 | (u_short)width, (u_short)(height*fontheight(p)), | ||
1948 | (u_short)bg, (u_short)p->next_line, 16); | ||
1949 | } | ||
1950 | |||
1951 | static void fbcon_virge16_putc(struct vc_data *conp, struct display *p, int c, int yy, | ||
1952 | int xx) | ||
1953 | { | ||
1954 | if (blit_maybe_busy) | ||
1955 | virgefb_wait_for_idle(); | ||
1956 | fbcon_cfb16_putc(conp, p, c, yy, xx); | ||
1957 | } | ||
1958 | |||
1959 | static void fbcon_virge16_putcs(struct vc_data *conp, struct display *p, | ||
1960 | const unsigned short *s, int count, int yy, int xx) | ||
1961 | { | ||
1962 | if (blit_maybe_busy) | ||
1963 | virgefb_wait_for_idle(); | ||
1964 | fbcon_cfb16_putcs(conp, p, s, count, yy, xx); | ||
1965 | } | ||
1966 | |||
1967 | static void fbcon_virge16_revc(struct display *p, int xx, int yy) | ||
1968 | { | ||
1969 | if (blit_maybe_busy) | ||
1970 | virgefb_wait_for_idle(); | ||
1971 | fbcon_cfb16_revc(p, xx, yy); | ||
1972 | } | ||
1973 | |||
1974 | static void fbcon_virge16_clear_margins(struct vc_data *conp, struct display *p, | ||
1975 | int bottom_only) | ||
1976 | { | ||
1977 | if (blit_maybe_busy) | ||
1978 | virgefb_wait_for_idle(); | ||
1979 | fbcon_cfb16_clear_margins(conp, p, bottom_only); | ||
1980 | } | ||
1981 | |||
1982 | static struct display_switch fbcon_virge16 = { | ||
1983 | .setup = fbcon_cfb16_setup, | ||
1984 | .bmove = fbcon_virge16_bmove, | ||
1985 | .clear = fbcon_virge16_clear, | ||
1986 | .putc = fbcon_virge16_putc, | ||
1987 | .putcs = fbcon_virge16_putcs, | ||
1988 | .revc = fbcon_virge16_revc, | ||
1989 | .clear_margins = fbcon_virge16_clear_margins, | ||
1990 | .fontwidthmask = FONTWIDTH(4)|FONTWIDTH(8)|FONTWIDTH(12)|FONTWIDTH(16) | ||
1991 | }; | ||
1992 | #endif | ||
1993 | |||
1994 | #ifdef FBCON_HAS_CFB32 | ||
1995 | static void fbcon_virge32_bmove(struct display *p, int sy, int sx, int dy, | ||
1996 | int dx, int height, int width) | ||
1997 | { | ||
1998 | sx *= 16; dx *= 16; width *= 16; /* doubled these values to do 32 bit blit */ | ||
1999 | virgefb_BitBLT((u_short)sx, (u_short)(sy*fontheight(p)), (u_short)dx, | ||
2000 | (u_short)(dy*fontheight(p)), (u_short)width, | ||
2001 | (u_short)(height*fontheight(p)), (u_short)p->next_line, 16); | ||
2002 | } | ||
2003 | |||
2004 | static void fbcon_virge32_clear(struct vc_data *conp, struct display *p, int sy, | ||
2005 | int sx, int height, int width) | ||
2006 | { | ||
2007 | unsigned char bg; | ||
2008 | |||
2009 | sx *= 16; width *= 16; /* doubled these values to do 32 bit blit */ | ||
2010 | bg = attr_bgcol_ec(p,conp); | ||
2011 | virgefb_RectFill((u_short)sx, (u_short)(sy*fontheight(p)), | ||
2012 | (u_short)width, (u_short)(height*fontheight(p)), | ||
2013 | (u_short)bg, (u_short)p->next_line, 16); | ||
2014 | } | ||
2015 | |||
2016 | static void fbcon_virge32_putc(struct vc_data *conp, struct display *p, int c, int yy, | ||
2017 | int xx) | ||
2018 | { | ||
2019 | if (blit_maybe_busy) | ||
2020 | virgefb_wait_for_idle(); | ||
2021 | fbcon_cfb32_putc(conp, p, c, yy, xx); | ||
2022 | } | ||
2023 | |||
2024 | static void fbcon_virge32_putcs(struct vc_data *conp, struct display *p, | ||
2025 | const unsigned short *s, int count, int yy, int xx) | ||
2026 | { | ||
2027 | if (blit_maybe_busy) | ||
2028 | virgefb_wait_for_idle(); | ||
2029 | fbcon_cfb32_putcs(conp, p, s, count, yy, xx); | ||
2030 | } | ||
2031 | |||
2032 | static void fbcon_virge32_revc(struct display *p, int xx, int yy) | ||
2033 | { | ||
2034 | if (blit_maybe_busy) | ||
2035 | virgefb_wait_for_idle(); | ||
2036 | fbcon_cfb32_revc(p, xx, yy); | ||
2037 | } | ||
2038 | |||
2039 | static void fbcon_virge32_clear_margins(struct vc_data *conp, struct display *p, | ||
2040 | int bottom_only) | ||
2041 | { | ||
2042 | if (blit_maybe_busy) | ||
2043 | virgefb_wait_for_idle(); | ||
2044 | fbcon_cfb32_clear_margins(conp, p, bottom_only); | ||
2045 | } | ||
2046 | |||
2047 | static struct display_switch fbcon_virge32 = { | ||
2048 | .setup = fbcon_cfb32_setup, | ||
2049 | .bmove = fbcon_virge32_bmove, | ||
2050 | .clear = fbcon_virge32_clear, | ||
2051 | .putc = fbcon_virge32_putc, | ||
2052 | .putcs = fbcon_virge32_putcs, | ||
2053 | .revc = fbcon_virge32_revc, | ||
2054 | .clear_margins = fbcon_virge32_clear_margins, | ||
2055 | .fontwidthmask = FONTWIDTH(4)|FONTWIDTH(8)|FONTWIDTH(12)|FONTWIDTH(16) | ||
2056 | }; | ||
2057 | #endif | ||
2058 | |||
2059 | #ifdef MODULE | ||
2060 | MODULE_LICENSE("GPL"); | ||
2061 | |||
2062 | int init_module(void) | ||
2063 | { | ||
2064 | return virgefb_init(); | ||
2065 | } | ||
2066 | #endif /* MODULE */ | ||
2067 | |||
2068 | static int cv3d_has_4mb(void) | ||
2069 | { | ||
2070 | /* cyberfb version didn't work, neither does this (not reliably) | ||
2071 | forced to return 4MB */ | ||
2072 | #if 0 | ||
2073 | volatile unsigned long *t0, *t2; | ||
2074 | #endif | ||
2075 | DPRINTK("ENTER\n"); | ||
2076 | #if 0 | ||
2077 | /* write patterns in memory and test if they can be read */ | ||
2078 | t0 = (volatile unsigned long *)v_ram; | ||
2079 | t2 = (volatile unsigned long *)(v_ram + 0x00200000); | ||
2080 | *t0 = 0x87654321; | ||
2081 | *t2 = 0x12345678; | ||
2082 | |||
2083 | if (*t0 != 0x87654321) { | ||
2084 | /* read of first location failed */ | ||
2085 | DPRINTK("EXIT - 0MB !\n"); | ||
2086 | return 0; | ||
2087 | } | ||
2088 | |||
2089 | if (*t2 == 0x87654321) { | ||
2090 | /* should read 0x12345678 if 4MB */ | ||
2091 | DPRINTK("EXIT - 2MB(a) \n"); | ||
2092 | return 0; | ||
2093 | } | ||
2094 | |||
2095 | if (*t2 != 0x12345678) { | ||
2096 | /* upper 2MB read back match failed */ | ||
2097 | DPRINTK("EXIT - 2MB(b)\n"); | ||
2098 | return 0; | ||
2099 | } | ||
2100 | |||
2101 | /* may have 4MB */ | ||
2102 | |||
2103 | *t2 = 0xAAAAAAAA; | ||
2104 | |||
2105 | if(*t2 != 0xAAAAAAAA) { | ||
2106 | /* upper 2MB read back match failed */ | ||
2107 | DPRINTK("EXIT - 2MB(c)\n"); | ||
2108 | return 0; | ||
2109 | } | ||
2110 | |||
2111 | *t2 = 0x55555555; | ||
2112 | |||
2113 | if(*t2 != 0x55555555) { | ||
2114 | /* upper 2MB read back match failed */ | ||
2115 | DPRINTK("EXIT - 2MB(d)\n"); | ||
2116 | return 0; | ||
2117 | } | ||
2118 | |||
2119 | #endif | ||
2120 | DPRINTK("EXIT - 4MB\n"); | ||
2121 | return 1; | ||
2122 | } | ||
2123 | |||
2124 | |||
2125 | /* | ||
2126 | * Computes M, N, and R pll params for freq arg. | ||
2127 | * Returns 16 bits - hi 0MMMMMM lo 0RRNNNNN | ||
2128 | */ | ||
2129 | |||
2130 | #define REFCLOCK 14318000 | ||
2131 | |||
2132 | static unsigned short virgefb_compute_clock(unsigned long freq) | ||
2133 | { | ||
2134 | |||
2135 | unsigned char m, n, r, rpwr; | ||
2136 | unsigned long diff, ftry, save = ~0UL; | ||
2137 | unsigned short mnr; | ||
2138 | |||
2139 | DPRINTK("ENTER\n"); | ||
2140 | |||
2141 | for (r = 0, rpwr = 1 ; r < 4 ; r++, rpwr *= 2) { | ||
2142 | if ((135000000 <= (rpwr * freq)) && ((rpwr * freq) <= 270000000)) { | ||
2143 | for (n = 1 ; n < 32 ; n++) { | ||
2144 | m = ((freq * (n + 2) * rpwr)/REFCLOCK) - 2; | ||
2145 | if (m == 0 || m >127) | ||
2146 | break; | ||
2147 | ftry = ((REFCLOCK / (n + 2)) * (m + 2)) / rpwr; | ||
2148 | if (ftry > freq) | ||
2149 | diff = ftry - freq; | ||
2150 | else | ||
2151 | diff = freq - ftry; | ||
2152 | if (diff < save) { | ||
2153 | save = diff; | ||
2154 | mnr = (m << 8) | (r<<5) | (n & 0x7f); | ||
2155 | } | ||
2156 | } | ||
2157 | } | ||
2158 | } | ||
2159 | if (save == ~0UL) | ||
2160 | printk("Can't compute clock PLL values for %ld Hz clock\n", freq); | ||
2161 | DPRINTK("EXIT\n"); | ||
2162 | return(mnr); | ||
2163 | } | ||
2164 | |||
2165 | static void virgefb_load_video_mode(struct fb_var_screeninfo *video_mode) | ||
2166 | { | ||
2167 | unsigned char lace, dblscan, tmp; | ||
2168 | unsigned short mnr; | ||
2169 | unsigned short HT, HDE, HBS, HBW, HSS, HSW; | ||
2170 | unsigned short VT, VDE, VBS, VBW, VSS, VSW; | ||
2171 | unsigned short SCO; | ||
2172 | int cr11; | ||
2173 | int cr67; | ||
2174 | int hmul; | ||
2175 | int xres, xres_virtual, hfront, hsync, hback; | ||
2176 | int yres, vfront, vsync, vback; | ||
2177 | int bpp; | ||
2178 | int i; | ||
2179 | long freq; | ||
2180 | |||
2181 | DPRINTK("ENTER : %dx%d-%d\n",video_mode->xres, video_mode->yres, | ||
2182 | video_mode->bits_per_pixel); | ||
2183 | |||
2184 | bpp = video_mode->bits_per_pixel; | ||
2185 | xres = video_mode->xres; | ||
2186 | xres_virtual = video_mode->xres_virtual; | ||
2187 | hfront = video_mode->right_margin; | ||
2188 | hsync = video_mode->hsync_len; | ||
2189 | hback = video_mode->left_margin; | ||
2190 | |||
2191 | lace = 0; | ||
2192 | dblscan = 0; | ||
2193 | |||
2194 | if (video_mode->vmode & FB_VMODE_DOUBLE) { | ||
2195 | yres = video_mode->yres * 2; | ||
2196 | vfront = video_mode->lower_margin * 2; | ||
2197 | vsync = video_mode->vsync_len * 2; | ||
2198 | vback = video_mode->upper_margin * 2; | ||
2199 | dblscan = 1; | ||
2200 | } else if (video_mode->vmode & FB_VMODE_INTERLACED) { | ||
2201 | yres = (video_mode->yres + 1) / 2; | ||
2202 | vfront = (video_mode->lower_margin + 1) / 2; | ||
2203 | vsync = (video_mode->vsync_len + 1) / 2; | ||
2204 | vback = (video_mode->upper_margin + 1) / 2; | ||
2205 | lace = 1; | ||
2206 | } else { | ||
2207 | yres = video_mode->yres; | ||
2208 | vfront = video_mode->lower_margin; | ||
2209 | vsync = video_mode->vsync_len; | ||
2210 | vback = video_mode->upper_margin; | ||
2211 | } | ||
2212 | |||
2213 | switch (bpp) { | ||
2214 | case 8: | ||
2215 | video_mode->red.offset = 0; | ||
2216 | video_mode->green.offset = 0; | ||
2217 | video_mode->blue.offset = 0; | ||
2218 | video_mode->transp.offset = 0; | ||
2219 | video_mode->red.length = 8; | ||
2220 | video_mode->green.length = 8; | ||
2221 | video_mode->blue.length = 8; | ||
2222 | video_mode->transp.length = 0; | ||
2223 | hmul = 1; | ||
2224 | cr67 = 0x00; | ||
2225 | SCO = xres_virtual / 8; | ||
2226 | break; | ||
2227 | case 16: | ||
2228 | video_mode->red.offset = 11; | ||
2229 | video_mode->green.offset = 5; | ||
2230 | video_mode->blue.offset = 0; | ||
2231 | video_mode->transp.offset = 0; | ||
2232 | video_mode->red.length = 5; | ||
2233 | video_mode->green.length = 6; | ||
2234 | video_mode->blue.length = 5; | ||
2235 | video_mode->transp.length = 0; | ||
2236 | hmul = 2; | ||
2237 | cr67 = 0x50; | ||
2238 | SCO = xres_virtual / 4; | ||
2239 | break; | ||
2240 | case 32: | ||
2241 | video_mode->red.offset = 16; | ||
2242 | video_mode->green.offset = 8; | ||
2243 | video_mode->blue.offset = 0; | ||
2244 | video_mode->transp.offset = 24; | ||
2245 | video_mode->red.length = 8; | ||
2246 | video_mode->green.length = 8; | ||
2247 | video_mode->blue.length = 8; | ||
2248 | video_mode->transp.length = 8; | ||
2249 | hmul = 1; | ||
2250 | cr67 = 0xd0; | ||
2251 | SCO = xres_virtual / 2; | ||
2252 | break; | ||
2253 | } | ||
2254 | |||
2255 | HT = (((xres + hfront + hsync + hback) / 8) * hmul) - 5; | ||
2256 | HDE = ((xres / 8) * hmul) - 1; | ||
2257 | HBS = (xres / 8) * hmul; | ||
2258 | HSS = ((xres + hfront) / 8) * hmul; | ||
2259 | HSW = (hsync / 8) * hmul; | ||
2260 | HBW = (((hfront + hsync + hback) / 8) * hmul) - 2; | ||
2261 | |||
2262 | VT = yres + vfront + vsync + vback - 2; | ||
2263 | VDE = yres - 1; | ||
2264 | VBS = yres - 1; | ||
2265 | VSS = yres + vfront; | ||
2266 | VSW = vsync; | ||
2267 | VBW = vfront + vsync + vback - 2; | ||
2268 | |||
2269 | #ifdef VIRGEFBDEBUG | ||
2270 | DPRINTK("HDE : 0x%4.4x, %4.4d\n", HDE, HDE); | ||
2271 | DPRINTK("HBS : 0x%4.4x, %4.4d\n", HBS, HBS); | ||
2272 | DPRINTK("HSS : 0x%4.4x, %4.4d\n", HSS, HSS); | ||
2273 | DPRINTK("HSW : 0x%4.4x, %4.4d\n", HSW, HSW); | ||
2274 | DPRINTK("HBW : 0x%4.4x, %4.4d\n", HBW, HBW); | ||
2275 | DPRINTK("HSS + HSW : 0x%4.4x, %4.4d\n", HSS+HSW, HSS+HSW); | ||
2276 | DPRINTK("HBS + HBW : 0x%4.4x, %4.4d\n", HBS+HBW, HBS+HBW); | ||
2277 | DPRINTK("HT : 0x%4.4x, %4.4d\n", HT, HT); | ||
2278 | DPRINTK("VDE : 0x%4.4x, %4.4d\n", VDE, VDE); | ||
2279 | DPRINTK("VBS : 0x%4.4x, %4.4d\n", VBS, VBS); | ||
2280 | DPRINTK("VSS : 0x%4.4x, %4.4d\n", VSS, VSS); | ||
2281 | DPRINTK("VSW : 0x%4.4x, %4.4d\n", VSW, VSW); | ||
2282 | DPRINTK("VBW : 0x%4.4x, %4.4d\n", VBW, VBW); | ||
2283 | DPRINTK("VT : 0x%4.4x, %4.4d\n", VT, VT); | ||
2284 | #endif | ||
2285 | |||
2286 | /* turn gfx off, don't mess up the display */ | ||
2287 | |||
2288 | gfx_on_off(1); | ||
2289 | |||
2290 | /* H and V sync polarity */ | ||
2291 | |||
2292 | tmp = rb_mmio(GREG_MISC_OUTPUT_R) & 0x2f; /* colour, ram enable, clk sr12/s13 sel */ | ||
2293 | if (!(video_mode->sync & FB_SYNC_HOR_HIGH_ACT)) | ||
2294 | tmp |= 0x40; /* neg H sync polarity */ | ||
2295 | if (!(video_mode->sync & FB_SYNC_VERT_HIGH_ACT)) | ||
2296 | tmp |= 0x80; /* neg V sync polarity */ | ||
2297 | tmp |= 0x0c; /* clk from sr12/sr13 */ | ||
2298 | wb_mmio(GREG_MISC_OUTPUT_W, tmp); | ||
2299 | |||
2300 | /* clocks */ | ||
2301 | |||
2302 | wseq(SEQ_ID_BUS_REQ_CNTL, 0xc0); /* 2 clk mem wr and /RAS1 */ | ||
2303 | wseq(SEQ_ID_CLKSYN_CNTL_2, 0x80); /* b7 is 2 mem clk wr */ | ||
2304 | mnr = virgefb_compute_clock(MEMCLOCK); | ||
2305 | DPRINTK("mem clock %d, m %d, n %d, r %d.\n", MEMCLOCK, ((mnr>>8)&0x7f), (mnr&0x1f), ((mnr >> 5)&0x03)); | ||
2306 | wseq(SEQ_ID_MCLK_LO, (mnr & 0x7f)); | ||
2307 | wseq(SEQ_ID_MCLK_HI, ((mnr & 0x7f00) >> 8)); | ||
2308 | freq = (1000000000 / video_mode->pixclock) * 1000; /* pixclock is in ps ... convert to Hz */ | ||
2309 | mnr = virgefb_compute_clock(freq); | ||
2310 | DPRINTK("dot clock %ld, m %d, n %d, r %d.\n", freq, ((mnr>>8)&0x7f), (mnr&0x1f), ((mnr>>5)&0x03)); | ||
2311 | wseq(SEQ_ID_DCLK_LO, (mnr & 0x7f)); | ||
2312 | wseq(SEQ_ID_DCLK_HI, ((mnr & 0x7f00) >> 8)); | ||
2313 | wseq(SEQ_ID_CLKSYN_CNTL_2, 0xa0); | ||
2314 | wseq(SEQ_ID_CLKSYN_CNTL_2, 0x80); | ||
2315 | udelay(100); | ||
2316 | |||
2317 | /* load display parameters into board */ | ||
2318 | |||
2319 | /* not sure about sync and blanking extensions bits in cr5d and cr5 */ | ||
2320 | |||
2321 | wcrt(CRT_ID_EXT_HOR_OVF, /* 0x5d */ | ||
2322 | ((HT & 0x100) ? 0x01 : 0x00) | | ||
2323 | ((HDE & 0x100) ? 0x02 : 0x00) | | ||
2324 | ((HBS & 0x100) ? 0x04 : 0x00) | | ||
2325 | /* (((HBS + HBW) & 0x40) ? 0x08 : 0x00) | */ | ||
2326 | ((HSS & 0x100) ? 0x10 : 0x00) | | ||
2327 | /* (((HSS + HSW) & 0x20) ? 0x20 : 0x00) | */ | ||
2328 | ((HSW >= 0x20) ? 0x20 : 0x00) | | ||
2329 | (((HT-5) & 0x100) ? 0x40 : 0x00)); | ||
2330 | |||
2331 | wcrt(CRT_ID_EXT_VER_OVF, /* 0x5e */ | ||
2332 | ((VT & 0x400) ? 0x01 : 0x00) | | ||
2333 | ((VDE & 0x400) ? 0x02 : 0x00) | | ||
2334 | ((VBS & 0x400) ? 0x04 : 0x00) | | ||
2335 | ((VSS & 0x400) ? 0x10 : 0x00) | | ||
2336 | 0x40); /* line compare */ | ||
2337 | |||
2338 | wcrt(CRT_ID_START_VER_RETR, VSS); | ||
2339 | cr11 = rcrt(CRT_ID_END_VER_RETR) | 0x20; /* vert interrupt flag */ | ||
2340 | wcrt(CRT_ID_END_VER_RETR, ((cr11 & 0x20) | ((VSS + VSW) & 0x0f))); /* keeps vert irq enable state, also has unlock bit cr0 to 7 */ | ||
2341 | wcrt(CRT_ID_VER_DISP_ENA_END, VDE); | ||
2342 | wcrt(CRT_ID_START_VER_BLANK, VBS); | ||
2343 | wcrt(CRT_ID_END_VER_BLANK, VBS + VBW); /* might be +/- 1 out */ | ||
2344 | wcrt(CRT_ID_HOR_TOTAL, HT); | ||
2345 | wcrt(CRT_ID_DISPLAY_FIFO, HT - 5); | ||
2346 | wcrt(CRT_ID_BACKWAD_COMP_3, 0x10); /* enable display fifo */ | ||
2347 | wcrt(CRT_ID_HOR_DISP_ENA_END, HDE); | ||
2348 | wcrt(CRT_ID_START_HOR_BLANK , HBS); | ||
2349 | wcrt(CRT_ID_END_HOR_BLANK, (HBS + HBW) & 0x1f); | ||
2350 | wcrt(CRT_ID_START_HOR_RETR, HSS); | ||
2351 | wcrt(CRT_ID_END_HOR_RETR, /* cr5 */ | ||
2352 | ((HSS + HSW) & 0x1f) | | ||
2353 | (((HBS + HBW) & 0x20) ? 0x80 : 0x00)); | ||
2354 | wcrt(CRT_ID_VER_TOTAL, VT); | ||
2355 | wcrt(CRT_ID_OVERFLOW, | ||
2356 | ((VT & 0x100) ? 0x01 : 0x00) | | ||
2357 | ((VDE & 0x100) ? 0x02 : 0x00) | | ||
2358 | ((VSS & 0x100) ? 0x04 : 0x00) | | ||
2359 | ((VBS & 0x100) ? 0x08 : 0x00) | | ||
2360 | 0x10 | | ||
2361 | ((VT & 0x200) ? 0x20 : 0x00) | | ||
2362 | ((VDE & 0x200) ? 0x40 : 0x00) | | ||
2363 | ((VSS & 0x200) ? 0x80 : 0x00)); | ||
2364 | wcrt(CRT_ID_MAX_SCAN_LINE, | ||
2365 | (dblscan ? 0x80 : 0x00) | | ||
2366 | 0x40 | | ||
2367 | ((VBS & 0x200) ? 0x20 : 0x00)); | ||
2368 | wcrt(CRT_ID_LINE_COMPARE, 0xff); | ||
2369 | wcrt(CRT_ID_LACE_RETR_START, HT / 2); /* (HT-5)/2 ? */ | ||
2370 | wcrt(CRT_ID_LACE_CONTROL, (lace ? 0x20 : 0x00)); | ||
2371 | |||
2372 | wcrt(CRT_ID_SCREEN_OFFSET, SCO); | ||
2373 | wcrt(CRT_ID_EXT_SYS_CNTL_2, (SCO >> 4) & 0x30 ); | ||
2374 | |||
2375 | /* wait for vert sync before cr67 update */ | ||
2376 | |||
2377 | for (i=0; i < 10000; i++) { | ||
2378 | udelay(10); | ||
2379 | mb(); | ||
2380 | if (rb_mmio(GREG_INPUT_STATUS1_R) & 0x08) | ||
2381 | break; | ||
2382 | } | ||
2383 | |||
2384 | wl_mmio(0x8200, 0x0000c000); /* fifo control (0x00110400 ?) */ | ||
2385 | wcrt(CRT_ID_EXT_MISC_CNTL_2, cr67); | ||
2386 | |||
2387 | /* enable video */ | ||
2388 | |||
2389 | tmp = rb_mmio(ACT_ADDRESS_RESET); | ||
2390 | wb_mmio(ACT_ADDRESS_W, ((bpp == 8) ? 0x20 : 0x00)); /* set b5, ENB PLT in attr idx reg) */ | ||
2391 | tmp = rb_mmio(ACT_ADDRESS_RESET); | ||
2392 | |||
2393 | /* turn gfx on again */ | ||
2394 | |||
2395 | gfx_on_off(0); | ||
2396 | |||
2397 | /* pass-through */ | ||
2398 | |||
2399 | SetVSwitch(1); /* cv3d */ | ||
2400 | |||
2401 | DUMP; | ||
2402 | DPRINTK("EXIT\n"); | ||
2403 | } | ||
2404 | |||
2405 | static inline void gfx_on_off(int toggle) | ||
2406 | { | ||
2407 | unsigned char tmp; | ||
2408 | |||
2409 | DPRINTK("ENTER gfx %s\n", (toggle ? "off" : "on")); | ||
2410 | |||
2411 | toggle = (toggle & 0x01) << 5; | ||
2412 | tmp = rseq(SEQ_ID_CLOCKING_MODE) & (~(0x01 << 5)); | ||
2413 | wseq(SEQ_ID_CLOCKING_MODE, tmp | toggle); | ||
2414 | |||
2415 | DPRINTK("EXIT\n"); | ||
2416 | } | ||
2417 | |||
2418 | #if defined (VIRGEFBDUMP) | ||
2419 | |||
2420 | /* | ||
2421 | * Dump board registers | ||
2422 | */ | ||
2423 | |||
2424 | static void cv64_dump(void) | ||
2425 | { | ||
2426 | int i; | ||
2427 | u8 c, b; | ||
2428 | u16 w; | ||
2429 | u32 l; | ||
2430 | |||
2431 | /* crt, seq, gfx and atr regs */ | ||
2432 | |||
2433 | SelectMMIO; | ||
2434 | |||
2435 | printk("\n"); | ||
2436 | for (i = 0; i <= 0x6f; i++) { | ||
2437 | wb_mmio(CRT_ADDRESS, i); | ||
2438 | printk("crt idx : 0x%2.2x : 0x%2.2x\n", i, rb_mmio(CRT_ADDRESS_R)); | ||
2439 | } | ||
2440 | for (i = 0; i <= 0x1c; i++) { | ||
2441 | wb_mmio(SEQ_ADDRESS, i); | ||
2442 | printk("seq idx : 0x%2.2x : 0x%2.2x\n", i, rb_mmio(SEQ_ADDRESS_R)); | ||
2443 | } | ||
2444 | for (i = 0; i <= 8; i++) { | ||
2445 | wb_mmio(GCT_ADDRESS, i); | ||
2446 | printk("gfx idx : 0x%2.2x : 0x%2.2x\n", i, rb_mmio(GCT_ADDRESS_R)); | ||
2447 | } | ||
2448 | for (i = 0; i <= 0x14; i++) { | ||
2449 | c = rb_mmio(ACT_ADDRESS_RESET); | ||
2450 | wb_mmio(ACT_ADDRESS_W, i); | ||
2451 | printk("atr idx : 0x%2.2x : 0x%2.2x\n", i, rb_mmio(ACT_ADDRESS_R)); | ||
2452 | } | ||
2453 | |||
2454 | /* re-enable video access to palette */ | ||
2455 | |||
2456 | c = rb_mmio(ACT_ADDRESS_RESET); | ||
2457 | udelay(10); | ||
2458 | wb_mmio(ACT_ADDRESS_W, 0x20); | ||
2459 | c = rb_mmio(ACT_ADDRESS_RESET); | ||
2460 | udelay(10); | ||
2461 | |||
2462 | /* general regs */ | ||
2463 | |||
2464 | printk("0x3cc(w 0x3c2) : 0x%2.2x\n", rb_mmio(0x3cc)); /* GREG_MISC_OUTPUT READ */ | ||
2465 | printk("0x3c2(-------) : 0x%2.2x\n", rb_mmio(0x3c2)); /* GREG_INPUT_STATUS 0 READ */ | ||
2466 | printk("0x3c3(w 0x3c3) : 0x%2.2x\n", rb_vgaio(0x3c3)); /* GREG_VIDEO_SUBS_ENABLE */ | ||
2467 | printk("0x3ca(w 0x3da) : 0x%2.2x\n", rb_vgaio(0x3ca)); /* GREG_FEATURE_CONTROL read */ | ||
2468 | printk("0x3da(-------) : 0x%2.2x\n", rb_mmio(0x3da)); /* GREG_INPUT_STATUS 1 READ */ | ||
2469 | |||
2470 | /* engine regs */ | ||
2471 | |||
2472 | for (i = 0x8180; i <= 0x8200; i = i + 4) | ||
2473 | printk("0x%8.8x : 0x%8.8x\n", i, rl_mmio(i)); | ||
2474 | |||
2475 | i = 0x8504; | ||
2476 | printk("0x%8.8x : 0x%8.8x\n", i, rl_mmio(i)); | ||
2477 | i = 0x850c; | ||
2478 | printk("0x%8.8x : 0x%8.8x\n", i, rl_mmio(i)); | ||
2479 | for (i = 0xa4d4; i <= 0xa50c; i = i + 4) | ||
2480 | printk("0x%8.8x : 0x%8.8x\n", i, rl_mmio(i)); | ||
2481 | |||
2482 | /* PCI regs */ | ||
2483 | |||
2484 | SelectCFG; | ||
2485 | |||
2486 | for (c = 0; c < 0x08; c = c + 2) { | ||
2487 | w = (*((u16 *)((u32)(vgaio_regs + c + (on_zorro2 ? 0 : 0x000e0000)) ^ 2))); | ||
2488 | printk("pci 0x%2.2x : 0x%4.4x\n", c, w); | ||
2489 | } | ||
2490 | c = 8; | ||
2491 | l = (*((u32 *)((u32)(vgaio_regs + c + (on_zorro2 ? 0 : 0x000e0000))))); | ||
2492 | printk("pci 0x%2.2x : 0x%8.8x\n", c, l); | ||
2493 | c = 0x0d; | ||
2494 | b = (*((u8 *)((u32)(vgaio_regs + c + (on_zorro2 ? 0 : 0x000e0000)) ^ 3))); | ||
2495 | printk("pci 0x%2.2x : 0x%2.2x\n", c, b); | ||
2496 | c = 0x10; | ||
2497 | l = (*((u32 *)((u32)(vgaio_regs + c + (on_zorro2 ? 0 : 0x000e0000))))); | ||
2498 | printk("pci 0x%2.2x : 0x%8.8x\n", c, l); | ||
2499 | c = 0x30; | ||
2500 | l = (*((u32 *)((u32)(vgaio_regs + c + (on_zorro2 ? 0 : 0x000e0000))))); | ||
2501 | printk("pci 0x%2.2x : 0x%8.8x\n", c, l); | ||
2502 | c = 0x3c; | ||
2503 | b = (*((u8 *)((u32)(vgaio_regs + c + (on_zorro2 ? 0 : 0x000e0000)) ^ 3))); | ||
2504 | printk("pci 0x%2.2x : 0x%2.2x\n", c, b); | ||
2505 | c = 0x3d; | ||
2506 | b = (*((u8 *)((u32)(vgaio_regs + c + (on_zorro2 ? 0 : 0x000e0000)) ^ 3))); | ||
2507 | printk("pci 0x%2.2x : 0x%2.2x\n", c, b); | ||
2508 | c = 0x3e; | ||
2509 | w = (*((u16 *)((u32)(vgaio_regs + c + (on_zorro2 ? 0 : 0x000e0000)) ^ 2))); | ||
2510 | printk("pci 0x%2.2x : 0x%4.4x\n", c, w); | ||
2511 | SelectMMIO; | ||
2512 | } | ||
2513 | #endif | ||