Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

at v2.6.18-rc4 3641 lines 112 kB view raw
1/* 2 * linux/drivers/video/pm3fb.c -- 3DLabs Permedia3 frame buffer device 3 * 4 * Copyright (C) 2001 Romain Dolbeau <dolbeau@irisa.fr> 5 * Based on code written by: 6 * Sven Luther, <luther@dpt-info.u-strasbg.fr> 7 * Alan Hourihane, <alanh@fairlite.demon.co.uk> 8 * Russell King, <rmk@arm.linux.org.uk> 9 * Based on linux/drivers/video/skeletonfb.c: 10 * Copyright (C) 1997 Geert Uytterhoeven 11 * Based on linux/driver/video/pm2fb.c: 12 * Copyright (C) 1998-1999 Ilario Nardinocchi (nardinoc@CS.UniBO.IT) 13 * Copyright (C) 1999 Jakub Jelinek (jakub@redhat.com) 14 * 15 * This file is subject to the terms and conditions of the GNU General Public 16 * License. See the file COPYING in the main directory of this archive for 17 * more details. 18 * 19 * $Header: /cvsroot/linux/drivers/video/pm3fb.c,v 1.1 2002/02/25 19:11:06 marcelo Exp $ 20 * 21 * CHANGELOG: 22 * Mon Feb 11 10:35:48 MET 2002, v 1.4.11B: Cosmetic update. 23 * Wed Jan 23 14:16:59 MET 2002, v 1.4.11: Preliminary 2.5.x support, patch for 2.5.2. 24 * Wed Nov 28 11:08:29 MET 2001, v 1.4.10: potential bug fix for SDRAM-based board, patch for 2.4.16. 25 * Thu Sep 20 10:24:42 MET DST 2001, v 1.4.9: sync bug fix, preliminary flatpanel support, better timings. 26 * Tue Aug 28 10:13:01 MET DST 2001, v 1.4.8: memory timings check, minor bug fixes. 27 * Wed Jul 18 19:06:14 CEST 2001, v 1.4.7: Mode fix (800x600-100, 1024x768-100 changed), using HW panning + accel bug fix. 28 * Mon Jun 25 10:33:56 MET DST 2001, v 1.4.6: Depth 12 fix, chip reset ioctl, moved memory erase ioctl to DEBUG. 29 * Wed Jun 20 11:13:08 MET DST 2001, v 1.4.5: Fixed missing blinking cursor in 8bpp, code cleaning, memory erase IOCTL. 30 * Mon Jun 18 16:00:27 CEST 2001, v 1.4.4: Depth 12 (RGBA 4444) support, code cleaning. 31 * Fri Jun 15 13:53:01 CEST 2001, v 1.4.3: Removed warnings, depth 15 support, add 'depth' option. 32 * Thu Jun 14 10:13:52 MET DST 2001, v 1.4.2: Fixed depth switching bug, preliminary 15bpp (RGB5551) support. 33 * Thu Apr 12 11:16:45 MET DST 2001, v 1.4.1B: Doc updates. 34 * Fri Apr 6 11:12:53 MET DST 2001, v 1.4.1: Configure.help, minor cleanup 35 * Thu Mar 29 10:56:50 MET DST 2001, v 1.4.0: Module & module options support (note: linux patch changed, 2.2.19 added). 36 * Thu Mar 15 15:30:31 MET 2001, v 1.3.2: Fixed mirroring bug on little-endian. 37 * Wed Mar 14 21:25:54 CET 2001, v 1.3.1: Fixed bug in BlockMove (_bmov). 38 * Tue Mar 13 10:53:19 MET 2001, v 1.3.0: Character drawing hardware support (in all width between 1 and 16), fixes. 39 * Thu Mar 8 10:20:16 MET 2001, v 1.2.2: Better J2000 support, "font:" option. 40 * Tue Mar 6 21:25:04 CET 2001, v 1.2.1: Better acceleration support. 41 * Mon Mar 5 21:54:17 CET 2001, v 1.2.0: Partial acceleration support (clear & bmove) 42 * Mon Mar 5 12:52:15 CET 2001, v 1.1.3: Big pan_display fix. 43 * Sun Mar 4 22:21:50 CET 2001, v 1.1.2: (numerous) bug fixes. 44 * Fri Mar 2 15:54:07 CET 2001, v 1.1.1: Might have Appian J2000 support, resource mangement in 2.4 45 * Wed Feb 28 18:21:35 CET 2001, v 1.1.0: Might have multiple boards support (added, but not yest tested) 46 * Tue Feb 27 17:31:12 CET 2001, v 1.0.6: fixes boot-time mode select, add more default mode 47 * Tue Feb 27 14:01:36 CET 2001, v 1.0.5: fixes (1.0.4 was broken for 2.2), cleaning up 48 * Mon Feb 26 23:17:36 CET 2001, v 1.0.4: preliminary 2.4.x support, dropped (useless on pm3) partial product, more OF fix 49 * Mon Feb 26 20:59:05 CET 2001, v 1.0.3: No more shadow register (and wasted memory), endianess fix, use OF-preset resolution by default 50 * Wed Feb 21 22:09:30 CET 2001, v 1.0.2: Code cleaning for future multiboard support, better OF support, bugs fix 51 * Wed Feb 21 19:58:56 CET 2001, v 1.0.1: OpenFirmware support, fixed memory detection, better debug support, code cleaning 52 * Wed Feb 21 14:47:06 CET 2001, v 1.0.0: First working version 53 */ 54 55#include <linux/module.h> 56#include <linux/kernel.h> 57#include <linux/errno.h> 58#include <linux/string.h> 59#include <linux/mm.h> 60#include <linux/slab.h> 61#include <linux/vmalloc.h> 62#include <linux/delay.h> 63#include <linux/interrupt.h> 64#include <linux/fb.h> 65#include <linux/init.h> 66#include <linux/pci.h> 67#include <linux/ioport.h> 68#include <linux/ctype.h> 69 70#include <video/fbcon.h> 71#include <video/fbcon-mfb.h> 72#include <video/fbcon-cfb2.h> 73#include <video/fbcon-cfb4.h> 74#include <video/fbcon-cfb8.h> 75#include <video/fbcon-cfb16.h> 76#include <video/fbcon-cfb24.h> 77#include <video/fbcon-cfb32.h> 78#include <video/pm3fb.h> 79 80#include <asm/io.h> 81#include <asm/uaccess.h> 82 83#ifdef CONFIG_FB_OF 84#include <asm/prom.h> 85#endif 86 87/* ************************************* */ 88/* ***** The various "global" data ***** */ 89/* ************************************* */ 90 91/* those will need a rework for multiple board support */ 92/* Driver name */ 93static const char permedia3_name[16] = "Permedia3"; 94 95/* the fb_par struct, mandatory */ 96struct pm3fb_par { 97 u32 pixclock; /* pixclock in KHz */ 98 99 u32 width; /* width of virtual screen */ 100 u32 height; /* height of virtual screen */ 101 102 u32 hsstart; /* horiz. sync start */ 103 u32 hsend; /* horiz. sync end */ 104 u32 hbend; /* horiz. blank end (also gate end) */ 105 u32 htotal; /* total width (w/ sync & blank) */ 106 107 u32 vsstart; /* vert. sync start */ 108 u32 vsend; /* vert. sync end */ 109 u32 vbend; /* vert. blank end */ 110 u32 vtotal; /* total height (w/ sync & blank) */ 111 112 u32 stride; /* screen stride */ 113 u32 base; /* screen base (xoffset+yoffset) in 128 bits unit */ 114 /* NOTE : unlike other pm3 stuff above, stored *after* shiftbpp. don't ask */ 115 u32 depth; /* screen depth (8, 12, 15, 16 or 32) */ 116 u32 video; /* video control (hsync,vsync) */ 117}; 118 119/* memory timings */ 120struct pm3fb_timings 121{ 122 unsigned long caps; 123 unsigned long timings; 124 unsigned long control; 125 unsigned long refresh; 126 unsigned long powerdown; 127}; 128typedef enum pm3fb_timing_result { pm3fb_timing_ok, pm3fb_timing_problem, pm3fb_timing_retry } pm3fb_timing_result; 129#define PM3FB_UNKNOWN_TIMING_VALUE ((unsigned long)-1) 130#define PM3FB_UNKNOWN_TIMINGS { PM3FB_UNKNOWN_TIMING_VALUE, PM3FB_UNKNOWN_TIMING_VALUE, PM3FB_UNKNOWN_TIMING_VALUE, PM3FB_UNKNOWN_TIMING_VALUE, PM3FB_UNKNOWN_TIMING_VALUE } 131 132/* the fb_info struct, mandatory */ 133struct pm3fb_info { 134 struct fb_info_gen gen; 135 unsigned long board_num; /* internal board number */ 136 unsigned long use_current; 137 struct pm3fb_par *current_par; 138 struct pci_dev *dev; /* PCI device */ 139 unsigned long board_type; /* index in the cardbase */ 140 unsigned char *fb_base; /* framebuffer memory base */ 141 u32 fb_size; /* framebuffer memory size */ 142 unsigned char *p_fb; /* physical address of frame buffer */ 143 unsigned char *v_fb; /* virtual address of frame buffer */ 144 unsigned char *pIOBase; /* physical address of registers region, must be rg_base or rg_base+PM2_REGS_SIZE depending on the host endianness */ 145 unsigned char *vIOBase; /* address of registers after ioremap() */ 146 struct { 147 u8 transp; 148 u8 red; 149 u8 green; 150 u8 blue; 151 } palette[256]; 152 union { 153#ifdef FBCON_HAS_CFB16 154 u16 cmap12[16]; /* RGBA 4444 */ 155 u16 cmap15[16]; /* RGBA 5551 */ 156 u16 cmap16[16]; /* RGBA 5650 */ 157#endif 158#ifdef FBCON_HAS_CFB32 159 u32 cmap32[16]; 160#endif 161 } cmap; 162 struct pm3fb_timings memt; 163}; 164 165/* regular resolution database*/ 166static struct { 167 char name[16]; 168 struct pm3fb_par user_mode; 169} mode_base[] __initdata = { 170 { 171 "default-800x600", { 172 49500, 800, 600, 16, 96, 256, 1056, 1, 4, 25, 625, 173 800, 0, 8, 174 PM3VideoControl_ENABLE | 175 PM3VideoControl_HSYNC_ACTIVE_HIGH 176 | 177 PM3VideoControl_VSYNC_ACTIVE_HIGH 178 | PM3VideoControl_PIXELSIZE_8BIT}}, { 179 "1024x768-74", { 180 78752, 1024, 768, 32, 128, 304, 1328, 1, 4, 38, 181 806, 1024, 0, 8, 182 PM3VideoControl_ENABLE | 183 PM3VideoControl_HSYNC_ACTIVE_HIGH 184 | 185 PM3VideoControl_VSYNC_ACTIVE_HIGH 186 | PM3VideoControl_PIXELSIZE_8BIT}}, { 187 "1024x768-74-32", { 188 78752, 1024, 768, 32, 128, 304, 1328, 1, 4, 38, 189 806, 1024, 0, 32, 190 PM3VideoControl_ENABLE | 191 PM3VideoControl_HSYNC_ACTIVE_HIGH 192 | 193 PM3VideoControl_VSYNC_ACTIVE_HIGH 194 | PM3VideoControl_PIXELSIZE_32BIT}}, 195/* Generated mode : "1600x1024", for the SGI 1600SW flat panel*/ 196 { 197 "SGI1600SW", { 198 108000, 1600, 1024, 16, 56, 104, 1704, 3, 6, 32, 199 1056, 1600, 0, 8, 200 PM3VideoControl_ENABLE| 201 PM3VideoControl_HSYNC_ACTIVE_LOW|PM3VideoControl_VSYNC_ACTIVE_LOW| 202 PM3VideoControl_PIXELSIZE_32BIT}}, 203/* ##### auto-generated mode, by fbtimings2pm3 */ 204/* Generated mode : "640x480-60" */ 205 { 206 "640x480-60", { 207 25174, 640, 480, 16, 112, 160, 800, 10, 12, 45, 208 525, 640, 0, 8, 209 PM3VideoControl_ENABLE | 210 PM3VideoControl_HSYNC_ACTIVE_LOW 211 | 212 PM3VideoControl_VSYNC_ACTIVE_LOW 213 | PM3VideoControl_PIXELSIZE_8BIT}}, 214/* Generated mode : "640x480-72" */ 215 { 216 "640x480-72", { 217 31199, 640, 480, 24, 64, 192, 832, 9, 12, 40, 520, 218 640, 0, 8, 219 PM3VideoControl_ENABLE | 220 PM3VideoControl_HSYNC_ACTIVE_LOW 221 | 222 PM3VideoControl_VSYNC_ACTIVE_LOW 223 | PM3VideoControl_PIXELSIZE_8BIT}}, 224/* Generated mode : "640x480-75" */ 225 { 226 "640x480-75", { 227 31499, 640, 480, 16, 80, 200, 840, 1, 4, 20, 500, 228 640, 0, 8, 229 PM3VideoControl_ENABLE | 230 PM3VideoControl_HSYNC_ACTIVE_LOW 231 | 232 PM3VideoControl_VSYNC_ACTIVE_LOW 233 | PM3VideoControl_PIXELSIZE_8BIT}}, 234/* Generated mode : "640x480-90" */ 235 { 236 "640x480-90", { 237 39909, 640, 480, 32, 72, 192, 832, 25, 39, 53, 533, 238 640, 0, 8, 239 PM3VideoControl_ENABLE | 240 PM3VideoControl_HSYNC_ACTIVE_LOW 241 | 242 PM3VideoControl_VSYNC_ACTIVE_LOW 243 | PM3VideoControl_PIXELSIZE_8BIT}}, 244/* Generated mode : "640x480-100" */ 245 { 246 "640x480-100", { 247 44899, 640, 480, 32, 160, 208, 848, 22, 34, 51, 248 531, 640, 0, 8, 249 PM3VideoControl_ENABLE | 250 PM3VideoControl_HSYNC_ACTIVE_LOW 251 | 252 PM3VideoControl_VSYNC_ACTIVE_LOW 253 | PM3VideoControl_PIXELSIZE_8BIT}}, 254/* Generated mode : "800x600-48-lace" */ 255/* INTERLACED NOT SUPPORTED 256 {"800x600-48-lace", {35999, 800, 600, 80, 208, 264, 1064, 11, 23, 102, 702, 800, 0, 8, PM3VideoControl_ENABLE|PM3VideoControl_HSYNC_ACTIVE_HIGH|PM3VideoControl_VSYNC_ACTIVE_HIGH|PM3VideoControl_PIXELSIZE_8BIT}}, 257 INTERLACED NOT SUPPORTED */ 258/* Generated mode : "800x600-56" */ 259 { 260 "800x600-56", { 261 35999, 800, 600, 24, 96, 224, 1024, 1, 3, 25, 625, 262 800, 0, 8, 263 PM3VideoControl_ENABLE | 264 PM3VideoControl_HSYNC_ACTIVE_HIGH 265 | 266 PM3VideoControl_VSYNC_ACTIVE_HIGH 267 | PM3VideoControl_PIXELSIZE_8BIT}}, 268/* Generated mode : "800x600-60" */ 269 { 270 "800x600-60", { 271 40000, 800, 600, 40, 168, 256, 1056, 1, 5, 28, 628, 272 800, 0, 8, 273 PM3VideoControl_ENABLE | 274 PM3VideoControl_HSYNC_ACTIVE_HIGH 275 | 276 PM3VideoControl_VSYNC_ACTIVE_HIGH 277 | PM3VideoControl_PIXELSIZE_8BIT}}, 278/* Generated mode : "800x600-70" */ 279 { 280 "800x600-70", { 281 44899, 800, 600, 24, 168, 208, 1008, 9, 21, 36, 282 636, 800, 0, 8, 283 PM3VideoControl_ENABLE | 284 PM3VideoControl_HSYNC_ACTIVE_HIGH 285 | 286 PM3VideoControl_VSYNC_ACTIVE_LOW 287 | PM3VideoControl_PIXELSIZE_8BIT}}, 288/* Generated mode : "800x600-72" */ 289 { 290 "800x600-72", { 291 50000, 800, 600, 56, 176, 240, 1040, 37, 43, 66, 292 666, 800, 0, 8, 293 PM3VideoControl_ENABLE | 294 PM3VideoControl_HSYNC_ACTIVE_HIGH 295 | 296 PM3VideoControl_VSYNC_ACTIVE_HIGH 297 | PM3VideoControl_PIXELSIZE_8BIT}}, 298/* Generated mode : "800x600-75" */ 299 { 300 "800x600-75", { 301 49497, 800, 600, 16, 96, 256, 1056, 1, 4, 25, 625, 302 800, 0, 8, 303 PM3VideoControl_ENABLE | 304 PM3VideoControl_HSYNC_ACTIVE_HIGH 305 | 306 PM3VideoControl_VSYNC_ACTIVE_HIGH 307 | PM3VideoControl_PIXELSIZE_8BIT}}, 308/* Generated mode : "800x600-90" */ 309 { 310 "800x600-90", { 311 56637, 800, 600, 8, 72, 192, 992, 8, 19, 35, 635, 312 800, 0, 8, 313 PM3VideoControl_ENABLE | 314 PM3VideoControl_HSYNC_ACTIVE_HIGH 315 | 316 PM3VideoControl_VSYNC_ACTIVE_HIGH 317 | PM3VideoControl_PIXELSIZE_8BIT}}, 318/* Generated mode : "800x600-100", from /etc/fb.modes */ 319/* DISABLED, hsstart == 0 320 { 321 "800x600-100", { 322 67499, 800, 600, 0, 64, 280, 1080, 7, 11, 25, 625, 323 800, 0, 8, 324 PM3VideoControl_ENABLE | 325 PM3VideoControl_HSYNC_ACTIVE_HIGH 326 | 327 PM3VideoControl_VSYNC_ACTIVE_HIGH 328 | PM3VideoControl_PIXELSIZE_8BIT}}, 329*/ 330/* Generated mode : "800x600-100", from ??? */ 331 { 332 "800x600-100", { 333 69650, 800, 600, 64, 128, 288, 1088, 4, 10, 40, 640, 800, 0, 8, 334 PM3VideoControl_ENABLE|PM3VideoControl_HSYNC_ACTIVE_LOW| 335 PM3VideoControl_VSYNC_ACTIVE_LOW|PM3VideoControl_PIXELSIZE_8BIT}}, 336/* Generated mode : "1024x768-43-lace" */ 337/* INTERLACED NOT SUPPORTED 338 {"1024x768-43-lace", {44899, 1024, 768, 8, 184, 240, 1264, 1, 9, 49, 817, 1024, 0, 8, PM3VideoControl_ENABLE|PM3VideoControl_HSYNC_ACTIVE_HIGH|PM3VideoControl_VSYNC_ACTIVE_HIGH|PM3VideoControl_PIXELSIZE_8BIT}}, 339 INTERLACED NOT SUPPORTED */ 340/* Generated mode : "1024x768-60" */ 341 { 342 "1024x768-60", { 343 64998, 1024, 768, 24, 160, 320, 1344, 3, 9, 38, 344 806, 1024, 0, 8, 345 PM3VideoControl_ENABLE | 346 PM3VideoControl_HSYNC_ACTIVE_LOW 347 | 348 PM3VideoControl_VSYNC_ACTIVE_LOW 349 | PM3VideoControl_PIXELSIZE_8BIT}}, 350/* Generated mode : "1024x768-70" */ 351 { 352 "1024x768-70", { 353 74996, 1024, 768, 24, 160, 304, 1328, 3, 9, 38, 354 806, 1024, 0, 8, 355 PM3VideoControl_ENABLE | 356 PM3VideoControl_HSYNC_ACTIVE_LOW 357 | 358 PM3VideoControl_VSYNC_ACTIVE_LOW 359 | PM3VideoControl_PIXELSIZE_8BIT}}, 360/* Generated mode : "1024x768-72" */ 361 { 362 "1024x768-72", { 363 74996, 10224, 768, 24, 160, 264, 10488, 3, 9, 38, 364 806, 10224, 0, 8, 365 PM3VideoControl_ENABLE | 366 PM3VideoControl_HSYNC_ACTIVE_LOW 367 | 368 PM3VideoControl_VSYNC_ACTIVE_LOW 369 | PM3VideoControl_PIXELSIZE_8BIT}}, 370/* Generated mode : "1024x768-75" */ 371 { 372 "1024x768-75", { 373 78746, 1024, 768, 16, 112, 288, 1312, 1, 4, 32, 374 800, 1024, 0, 8, 375 PM3VideoControl_ENABLE | 376 PM3VideoControl_HSYNC_ACTIVE_HIGH 377 | 378 PM3VideoControl_VSYNC_ACTIVE_HIGH 379 | PM3VideoControl_PIXELSIZE_8BIT}}, 380/* Generated mode : "1024x768-90" */ 381 { 382 "1024x768-90", { 383 100000, 1024, 768, 0, 96, 288, 1312, 21, 36, 77, 384 845, 1024, 0, 8, 385 PM3VideoControl_ENABLE | 386 PM3VideoControl_HSYNC_ACTIVE_LOW 387 | 388 PM3VideoControl_VSYNC_ACTIVE_LOW 389 | PM3VideoControl_PIXELSIZE_8BIT}}, 390/* Generated mode : "1024x768-100", from /etc/fb.modes */ 391/* DISABLED, vsstart == 0 392 { 393 "1024x768-100", { 394 109998, 1024, 768, 0, 88, 368, 1392, 0, 8, 24, 792, 395 1024, 0, 8, 396 PM3VideoControl_ENABLE | 397 PM3VideoControl_HSYNC_ACTIVE_LOW 398 | 399 PM3VideoControl_VSYNC_ACTIVE_LOW 400 | PM3VideoControl_PIXELSIZE_8BIT}}, 401*/ 402/* Generated mode : "1024x768-100", from ??? */ 403 { 404 "1024x768-100", { 405 115500, 1024, 768, 32, 224, 416, 1440, 3, 13, 34, 802, 1024, 0, 8, 406 PM3VideoControl_ENABLE|PM3VideoControl_HSYNC_ACTIVE_LOW| 407 PM3VideoControl_VSYNC_ACTIVE_LOW|PM3VideoControl_PIXELSIZE_8BIT}}, 408/* Generated mode : "1152x864-43-lace" */ 409/* INTERLACED NOT SUPPORTED 410 {"1152x864-43-lace", {64998, 1152, 864, 72, 200, 264, 1416, 78, 87, 191, 1055, 1152, 0, 8, PM3VideoControl_ENABLE|PM3VideoControl_HSYNC_ACTIVE_HIGH|PM3VideoControl_VSYNC_ACTIVE_HIGH|PM3VideoControl_PIXELSIZE_8BIT}}, 411 INTERLACED NOT SUPPORTED */ 412/* Generated mode : "1152x864-47-lace" */ 413/* INTERLACED NOT SUPPORTED 414 {"1152x864-47-lace", {64998, 1152, 864, 88, 216, 296, 1448, 30, 39, 83, 947, 1152, 0, 8, PM3VideoControl_ENABLE|PM3VideoControl_HSYNC_ACTIVE_HIGH|PM3VideoControl_VSYNC_ACTIVE_HIGH|PM3VideoControl_PIXELSIZE_8BIT}}, 415 INTERLACED NOT SUPPORTED */ 416/* Generated mode : "1152x864-60" */ 417 { 418 "1152x864-60", { 419 80000, 1152, 864, 64, 176, 304, 1456, 6, 11, 52, 420 916, 1152, 0, 8, 421 PM3VideoControl_ENABLE | 422 PM3VideoControl_HSYNC_ACTIVE_HIGH 423 | 424 PM3VideoControl_VSYNC_ACTIVE_HIGH 425 | PM3VideoControl_PIXELSIZE_8BIT}}, 426/* Generated mode : "1152x864-70" */ 427 { 428 "1152x864-70", { 429 100000, 1152, 864, 40, 192, 360, 1512, 13, 24, 81, 430 945, 1152, 0, 8, 431 PM3VideoControl_ENABLE | 432 PM3VideoControl_HSYNC_ACTIVE_HIGH 433 | 434 PM3VideoControl_VSYNC_ACTIVE_HIGH 435 | PM3VideoControl_PIXELSIZE_8BIT}}, 436/* Generated mode : "1152x864-75" */ 437 { 438 "1152x864-75", { 439 109998, 1152, 864, 24, 168, 312, 1464, 45, 53, 138, 440 1002, 1152, 0, 8, 441 PM3VideoControl_ENABLE | 442 PM3VideoControl_HSYNC_ACTIVE_HIGH 443 | 444 PM3VideoControl_VSYNC_ACTIVE_HIGH 445 | PM3VideoControl_PIXELSIZE_8BIT}}, 446/* Generated mode : "1152x864-80" */ 447 { 448 "1152x864-80", { 449 109998, 1152, 864, 16, 128, 288, 1440, 30, 37, 94, 450 958, 1152, 0, 8, 451 PM3VideoControl_ENABLE | 452 PM3VideoControl_HSYNC_ACTIVE_HIGH 453 | 454 PM3VideoControl_VSYNC_ACTIVE_HIGH 455 | PM3VideoControl_PIXELSIZE_8BIT}}, 456/* Generated mode : "1280x1024-43-lace" */ 457/* INTERLACED NOT SUPPORTED 458 {"1280x1024-43-lace", {80000, 1024, 1024, 80, 160, 320, 1344, 50, 60, 125, 1149, 1024, 0, 8, PM3VideoControl_ENABLE|PM3VideoControl_HSYNC_ACTIVE_HIGH|PM3VideoControl_VSYNC_ACTIVE_HIGH|PM3VideoControl_PIXELSIZE_8BIT}}, 459 INTERLACED NOT SUPPORTED */ 460/* Generated mode : "1280x1024-47-lace" */ 461/* INTERLACED NOT SUPPORTED 462 {"1280x1024-47-lace", {80000, 1280, 1024, 80, 160, 320, 1600, 1, 11, 29, 1053, 1280, 0, 8, PM3VideoControl_ENABLE|PM3VideoControl_HSYNC_ACTIVE_HIGH|PM3VideoControl_VSYNC_ACTIVE_HIGH|PM3VideoControl_PIXELSIZE_8BIT}}, 463 INTERLACED NOT SUPPORTED */ 464/* Generated mode : "1280x1024-60" */ 465 { 466 "1280x1024-60", { 467 107991, 1280, 1024, 48, 160, 408, 1688, 1, 4, 42, 468 1066, 1280, 0, 8, 469 PM3VideoControl_ENABLE | 470 PM3VideoControl_HSYNC_ACTIVE_HIGH 471 | 472 PM3VideoControl_VSYNC_ACTIVE_HIGH 473 | PM3VideoControl_PIXELSIZE_8BIT}}, 474/* Generated mode : "1280x1024-70" */ 475 { 476 "1280x1024-70", { 477 125992, 1280, 1024, 80, 192, 408, 1688, 1, 6, 42, 478 1066, 1280, 0, 8, 479 PM3VideoControl_ENABLE | 480 PM3VideoControl_HSYNC_ACTIVE_HIGH 481 | 482 PM3VideoControl_VSYNC_ACTIVE_HIGH 483 | PM3VideoControl_PIXELSIZE_8BIT}}, 484/* Generated mode : "1280x1024-74" */ 485 { 486 "1280x1024-74", { 487 134989, 1280, 1024, 32, 176, 432, 1712, 0, 30, 40, 488 1064, 1280, 0, 8, 489 PM3VideoControl_ENABLE | 490 PM3VideoControl_HSYNC_ACTIVE_HIGH 491 | 492 PM3VideoControl_VSYNC_ACTIVE_HIGH 493 | PM3VideoControl_PIXELSIZE_8BIT}}, 494/* Generated mode : "1280x1024-75" */ 495 { 496 "1280x1024-75", { 497 134989, 1280, 1024, 16, 160, 408, 1688, 1, 4, 42, 498 1066, 1280, 0, 8, 499 PM3VideoControl_ENABLE | 500 PM3VideoControl_HSYNC_ACTIVE_HIGH 501 | 502 PM3VideoControl_VSYNC_ACTIVE_HIGH 503 | PM3VideoControl_PIXELSIZE_8BIT}}, 504/* Generated mode : "1600x1200-60" */ 505 { 506 "1600x1200-60", { 507 155981, 1600, 1200, 32, 192, 448, 2048, 10, 18, 70, 508 1270, 1600, 0, 8, 509 PM3VideoControl_ENABLE | 510 PM3VideoControl_HSYNC_ACTIVE_LOW 511 | 512 PM3VideoControl_VSYNC_ACTIVE_LOW 513 | PM3VideoControl_PIXELSIZE_8BIT}}, 514/* Generated mode : "1600x1200-66" */ 515 { 516 "1600x1200-66", { 517 171998, 1600, 1200, 40, 176, 480, 2080, 3, 6, 53, 518 1253, 1600, 0, 8, 519 PM3VideoControl_ENABLE | 520 PM3VideoControl_HSYNC_ACTIVE_LOW 521 | 522 PM3VideoControl_VSYNC_ACTIVE_LOW 523 | PM3VideoControl_PIXELSIZE_8BIT}}, 524/* Generated mode : "1600x1200-76" */ 525 { 526 "1600x1200-76", { 527 197980, 1600, 1200, 40, 176, 480, 2080, 3, 8, 50, 528 1250, 1600, 0, 8, 529 PM3VideoControl_ENABLE | 530 PM3VideoControl_HSYNC_ACTIVE_LOW 531 | 532 PM3VideoControl_VSYNC_ACTIVE_LOW 533 | PM3VideoControl_PIXELSIZE_8BIT}}, 534/* ##### end of auto-generated mode */ 535 { 536 "\0",} 537}; 538 539/* more mandatory stuff (see skeletonfb.c + framebuffer driver HOWTO */ 540static struct pm3fb_info fb_info[PM3_MAX_BOARD]; 541static struct pm3fb_par current_par[PM3_MAX_BOARD]; 542static int current_par_valid[PM3_MAX_BOARD]; 543/* to allow explicit filtering of board */ 544short bus[PM3_MAX_BOARD]; 545short slot[PM3_MAX_BOARD]; 546short func[PM3_MAX_BOARD]; 547short disable[PM3_MAX_BOARD]; 548short noaccel[PM3_MAX_BOARD]; 549char fontn[PM3_MAX_BOARD][PM3_FONTNAME_SIZE]; 550short depth[PM3_MAX_BOARD]; 551short flatpanel[PM3_MAX_BOARD]; 552static struct display disp[PM3_MAX_BOARD]; 553static char g_options[PM3_OPTIONS_SIZE] __initdata = "pm3fb,dummy"; 554short printtimings = 0; 555short forcesize[PM3_MAX_BOARD]; 556 557/* ********************* */ 558/* ***** prototype ***** */ 559/* ********************* */ 560/* card-specific */ 561static void pm3fb_j2000_setup(struct pm3fb_info *l_fb_info); 562/* permedia3-specific */ 563static pm3fb_timing_result pm3fb_preserve_memory_timings(struct pm3fb_info *l_fb_info); 564static pm3fb_timing_result pm3fb_try_memory_timings(struct pm3fb_info *l_fb_info); 565static void pm3fb_write_memory_timings(struct pm3fb_info *l_fb_info); 566static unsigned long pm3fb_read_dac_reg(struct pm3fb_info *l_fb_info, 567 unsigned long r); 568static unsigned long pm3fb_CalculateClock(struct pm3fb_info *l_fb_info, unsigned long reqclock, /* In kHz units */ 569 unsigned long refclock, /* In kHz units */ 570 unsigned char *prescale, /* ClkPreScale */ 571 unsigned char *feedback, /* ClkFeedBackScale */ 572 unsigned char *postscale 573 /* ClkPostScale */ ); 574static void pm3fb_clear_memory(struct pm3fb_info *l_fb_info, u32 cc); 575static void pm3fb_clear_colormap(struct pm3fb_info *l_fb_info, unsigned char r, unsigned char g, unsigned char b); 576static void pm3fb_common_init(struct pm3fb_info *l_fb_info); 577static int pm3fb_Shiftbpp(struct pm3fb_info *l_fb_info, 578 unsigned long depth, int v); 579static int pm3fb_Unshiftbpp(struct pm3fb_info *l_fb_info, 580 unsigned long depth, int v); 581static void pm3fb_mapIO(struct pm3fb_info *l_fb_info); 582static void pm3fb_unmapIO(struct pm3fb_info *l_fb_info); 583#if defined(PM3FB_MASTER_DEBUG) && (PM3FB_MASTER_DEBUG >= 2) 584static void pm3fb_show_cur_mode(struct pm3fb_info *l_fb_info); 585#endif 586static void pm3fb_show_cur_timing(struct pm3fb_info *l_fb_info); 587static void pm3fb_write_mode(struct pm3fb_info *l_fb_info); 588static void pm3fb_read_mode(struct pm3fb_info *l_fb_info, 589 struct pm3fb_par *curpar); 590static unsigned long pm3fb_size_memory(struct pm3fb_info *l_fb_info); 591/* accelerated permedia3-specific */ 592#ifdef PM3FB_USE_ACCEL 593static void pm3fb_wait_pm3(struct pm3fb_info *l_fb_info); 594static void pm3fb_init_engine(struct pm3fb_info *l_fb_info); 595#ifdef FBCON_HAS_CFB32 596static void pm3fb_cfb32_clear(struct vc_data *conp, 597 struct display *p, 598 int sy, int sx, int height, int width); 599static void pm3fb_cfb32_clear_margins(struct vc_data *conp, 600 struct display *p, int bottom_only); 601#endif /* FBCON_HAS_CFB32 */ 602#ifdef FBCON_HAS_CFB16 603static void pm3fb_cfb16_clear(struct vc_data *conp, 604 struct display *p, 605 int sy, int sx, int height, int width); 606static void pm3fb_cfb16_clear_margins(struct vc_data *conp, 607 struct display *p, int bottom_only); 608#endif /* FBCON_HAS_CFB16 */ 609#ifdef FBCON_HAS_CFB8 610static void pm3fb_cfb8_clear(struct vc_data *conp, 611 struct display *p, 612 int sy, int sx, int height, int width); 613static void pm3fb_cfb8_clear_margins(struct vc_data *conp, 614 struct display *p, int bottom_only); 615#endif /* FBCON_HAS_CFB8 */ 616#if defined(FBCON_HAS_CFB8) || defined(FBCON_HAS_CFB16) || defined(FBCON_HAS_CFB32) 617static void pm3fb_cfbX_bmove(struct display *p, 618 int sy, int sx, 619 int dy, int dx, int height, int width); 620static void pm3fb_cfbX_putc(struct vc_data *conp, struct display *p, 621 int c, int yy, int xx); 622static void pm3fb_cfbX_putcs(struct vc_data *conp, struct display *p, 623 const unsigned short *s, int count, int yy, 624 int xx); 625static void pm3fb_cfbX_revc(struct display *p, int xx, int yy); 626#endif /* FBCON_HAS_CFB8 || FBCON_HAS_CFB16 || FBCON_HAS_CFB32 */ 627#endif /* PM3FB_USE_ACCEL */ 628/* pre-init */ 629static void pm3fb_mode_setup(char *mode, unsigned long board_num); 630static void pm3fb_pciid_setup(char *pciid, unsigned long board_num); 631static char *pm3fb_boardnum_setup(char *options, unsigned long *bn); 632static void pm3fb_real_setup(char *options); 633/* fbdev */ 634static int pm3fb_encode_fix(struct fb_fix_screeninfo *fix, 635 const void *par, struct fb_info_gen *info); 636static int pm3fb_decode_var(const struct fb_var_screeninfo *var, 637 void *par, struct fb_info_gen *info); 638static void pm3fb_encode_depth(struct fb_var_screeninfo *var, long d); 639static int pm3fb_encode_var(struct fb_var_screeninfo *var, 640 const void *par, struct fb_info_gen *info); 641static void pm3fb_get_par(void *par, struct fb_info_gen *info); 642static void pm3fb_set_par(const void *par, struct fb_info_gen *info); 643static void pm3fb_set_color(struct pm3fb_info *l_fb_info, 644 unsigned char regno, unsigned char r, 645 unsigned char g, unsigned char b); 646static int pm3fb_getcolreg(unsigned regno, unsigned *red, unsigned *green, 647 unsigned *blue, unsigned *transp, 648 struct fb_info *info); 649static int pm3fb_setcolreg(unsigned regno, unsigned red, unsigned green, 650 unsigned blue, unsigned transp, 651 struct fb_info *info); 652static int pm3fb_blank(int blank_mode, struct fb_info_gen *info); 653static void pm3fb_set_disp(const void *par, struct display *disp, 654 struct fb_info_gen *info); 655static void pm3fb_detect(void); 656static int pm3fb_pan_display(const struct fb_var_screeninfo *var, 657 struct fb_info_gen *info); 658static int pm3fb_ioctl(struct fb_info *info, u_int cmd, u_long arg); 659 660 661/* the struct that hold them together */ 662struct fbgen_hwswitch pm3fb_switch = { 663 pm3fb_detect, pm3fb_encode_fix, pm3fb_decode_var, pm3fb_encode_var, 664 pm3fb_get_par, pm3fb_set_par, pm3fb_getcolreg, 665 pm3fb_pan_display, pm3fb_blank, pm3fb_set_disp 666}; 667 668static struct fb_ops pm3fb_ops = { 669 .owner = THIS_MODULE, 670 .fb_get_fix = fbgen_get_fix, 671 .fb_get_var = fbgen_get_var, 672 .fb_set_var = fbgen_set_var, 673 .fb_get_cmap = fbgen_get_cmap, 674 .fb_set_cmap = fbgen_set_cmap, 675 .fb_setcolreg = pm3fb_setcolreg, 676 .fb_pan_display =fbgen_pan_display, 677 .fb_blank = fbgen_blank, 678 .fb_ioctl = pm3fb_ioctl, 679}; 680 681#ifdef PM3FB_USE_ACCEL 682#ifdef FBCON_HAS_CFB32 683static struct display_switch pm3fb_cfb32 = { 684 fbcon_cfb32_setup, pm3fb_cfbX_bmove, pm3fb_cfb32_clear, 685 pm3fb_cfbX_putc, pm3fb_cfbX_putcs, pm3fb_cfbX_revc, 686 NULL /* cursor() */ , NULL /* set_font() */ , 687 pm3fb_cfb32_clear_margins, 688 FONTWIDTHRANGE(1, 16) /* true only if accelerated... */ 689}; 690#endif /* FBCON_HAS_CFB32 */ 691#ifdef FBCON_HAS_CFB16 692static struct display_switch pm3fb_cfb16 = { 693 fbcon_cfb16_setup, pm3fb_cfbX_bmove, pm3fb_cfb16_clear, 694 pm3fb_cfbX_putc, pm3fb_cfbX_putcs, pm3fb_cfbX_revc, 695 NULL /* cursor() */ , NULL /* set_font() */ , 696 pm3fb_cfb16_clear_margins, 697 FONTWIDTHRANGE(1, 16) /* true only if accelerated... */ 698}; 699#endif /* FBCON_HAS_CFB16 */ 700#ifdef FBCON_HAS_CFB8 701static struct display_switch pm3fb_cfb8 = { 702 fbcon_cfb8_setup, pm3fb_cfbX_bmove, pm3fb_cfb8_clear, 703 pm3fb_cfbX_putc, pm3fb_cfbX_putcs, pm3fb_cfbX_revc, 704 NULL /* cursor() */ , NULL /* set_font() */ , 705 pm3fb_cfb8_clear_margins, 706 FONTWIDTHRANGE(1, 16) /* true only if accelerated... */ 707}; 708#endif /* FBCON_HAS_CFB8 */ 709#endif /* PM3FB_USE_ACCEL */ 710 711/* ****************************** */ 712/* ***** card-specific data ***** */ 713/* ****************************** */ 714struct pm3fb_card_timings { 715 unsigned long memsize; /* 0 for last value (i.e. default) */ 716 struct pm3fb_timings memt; 717}; 718 719static struct pm3fb_card_timings t_FormacProFormance3[] = { 720 { 16, { 0x02e311b8, 0x06100205, 0x08000002, 0x00000079, 0x00000000} }, 721 { 0, { 0x02e311b8, 0x06100205, 0x08000002, 0x00000079, 0x00000000} } /* from 16 MB PF3 */ 722}; 723 724static struct pm3fb_card_timings t_AppianJeronimo2000[] = { 725 { 32, { 0x02e311B8, 0x07424905, 0x0c000003, 0x00000061, 0x00000000} }, 726 { 0, { 0x02e311B8, 0x07424905, 0x0c000003, 0x00000061, 0x00000000} } /* from 32MB J2000 */ 727}; 728 729static struct pm3fb_card_timings t_3DLabsOxygenVX1[] = { 730 { 32, { 0x30e311b8, 0x08501204, 0x08000002, 0x0000006b, 0x00000000} }, 731 { 0, { 0x30e311b8, 0x08501204, 0x08000002, 0x0000006b, 0x00000000} } /* from 32MB VX1 */ 732}; 733 734static struct { 735 char cardname[32]; /* recognized card name */ 736 u16 subvendor; /* subvendor of the card */ 737 u16 subdevice; /* subdevice of the card */ 738 u8 func; /* function of the card to which the extra init apply */ 739 void (*specific_setup)(struct pm3fb_info *l_fb_info); /* card/func specific setup, done before _any_ FB access */ 740 struct pm3fb_card_timings *c_memt; /* defauls timings for the boards */ 741} cardbase[] = { 742 { "Unknown Permedia3 board", 0xFFFF, 0xFFFF, 0xFF, NULL, NULL }, 743 { "Appian Jeronimo 2000 head 1", 0x1097, 0x3d32, 1, NULL, 744 t_AppianJeronimo2000 745 }, 746 { "Appian Jeronimo 2000 head 2", 0x1097, 0x3d32, 2, pm3fb_j2000_setup, 747 t_AppianJeronimo2000 748 }, 749 { "Formac ProFormance 3", PCI_VENDOR_ID_3DLABS, 0x000a, 0, NULL, /* Formac use 3DLabs ID ?!? */ 750 t_FormacProFormance3 751 }, 752 { "3DLabs Permedia3 Create!", PCI_VENDOR_ID_3DLABS, 0x0127, 0, NULL, NULL }, 753 { "3DLabs Oxygen VX1 PCI", PCI_VENDOR_ID_3DLABS, 0x0121, 0, NULL, 754 t_3DLabsOxygenVX1 755 }, 756 { "3DLabs Oxygen VX1 AGP", PCI_VENDOR_ID_3DLABS, 0x0125, 0, NULL, NULL }, 757 { "3DLabs Oxygen VX1-16 AGP", PCI_VENDOR_ID_3DLABS, 0x0140, 0, NULL, NULL }, 758 { "3DLabs Oxygen VX1-1600SW PCI", PCI_VENDOR_ID_3DLABS, 0x0800, 0, NULL, NULL }, 759 { "\0", 0x0, 0x0, 0, NULL, NULL } 760}; 761 762/* ********************************** */ 763/* ***** card-specific function ***** */ 764/* ********************************** */ 765static void pm3fb_j2000_setup(struct pm3fb_info *l_fb_info) 766{ /* the appian j2000 require more initialization of the second head */ 767 /* l_fb_info must point to the _second_ head of the J2000 */ 768 769 DTRACE; 770 771 l_fb_info->memt = t_AppianJeronimo2000[0].memt; /* 32 MB, first and only j2000 ? */ 772 773 pm3fb_write_memory_timings(l_fb_info); 774} 775 776/* *************************************** */ 777/* ***** permedia3-specific function ***** */ 778/* *************************************** */ 779static pm3fb_timing_result pm3fb_preserve_memory_timings(struct pm3fb_info *l_fb_info) 780{ 781 l_fb_info->memt.caps = PM3_READ_REG(PM3LocalMemCaps); 782 l_fb_info->memt.timings = PM3_READ_REG(PM3LocalMemTimings); 783 l_fb_info->memt.control = PM3_READ_REG(PM3LocalMemControl); 784 l_fb_info->memt.refresh = PM3_READ_REG(PM3LocalMemRefresh); 785 l_fb_info->memt.powerdown = PM3_READ_REG(PM3LocalMemPowerDown); 786 787 if ((l_fb_info->memt.caps == PM3FB_UNKNOWN_TIMING_VALUE) || 788 (l_fb_info->memt.timings == PM3FB_UNKNOWN_TIMING_VALUE) || 789 (l_fb_info->memt.control == PM3FB_UNKNOWN_TIMING_VALUE) || 790 (l_fb_info->memt.refresh == PM3FB_UNKNOWN_TIMING_VALUE) || 791 (l_fb_info->memt.powerdown == PM3FB_UNKNOWN_TIMING_VALUE)) 792 { 793 printk(KERN_ERR "pm3fb: invalid memory timings in permedia3 board #%ld\n", l_fb_info->board_num); 794 return(pm3fb_try_memory_timings(l_fb_info)); 795 } 796 return(pm3fb_timing_ok); 797} 798 799static pm3fb_timing_result pm3fb_try_memory_timings(struct pm3fb_info *l_fb_info) 800{ 801 if (cardbase[l_fb_info->board_type].c_memt) 802 { 803 int i = 0, done = 0; 804 while (!done) 805 { 806 if ((cardbase[l_fb_info->board_type].c_memt[i].memsize == l_fb_info->fb_size) 807 || !(cardbase[l_fb_info->board_type].c_memt[i].memsize)) 808 { /* will use the 0-sized timings by default */ 809 done = 1; 810 l_fb_info->memt = cardbase[l_fb_info->board_type].c_memt[i].memt; 811 printk(KERN_WARNING "pm3fb: trying to use predefined memory timings for permedia3 board #%ld (%s, %ld MB)\n", 812 l_fb_info->board_num, 813 cardbase[l_fb_info->board_type].cardname, 814 cardbase[l_fb_info->board_type].c_memt[i].memsize); 815 pm3fb_write_memory_timings(l_fb_info); 816 return(pm3fb_timing_retry); 817 } 818 i++; 819 } 820 } else 821 return(pm3fb_timing_problem); 822 return(pm3fb_timing_ok); 823} 824 825static void pm3fb_write_memory_timings(struct pm3fb_info *l_fb_info) 826{ 827 unsigned char m, n, p; 828 unsigned long clockused; 829 830 PM3_SLOW_WRITE_REG(PM3LocalMemCaps, l_fb_info->memt.caps); 831 PM3_SLOW_WRITE_REG(PM3LocalMemTimings, l_fb_info->memt.timings); 832 PM3_SLOW_WRITE_REG(PM3LocalMemControl, l_fb_info->memt.control); 833 PM3_SLOW_WRITE_REG(PM3LocalMemRefresh, l_fb_info->memt.refresh); 834 PM3_SLOW_WRITE_REG(PM3LocalMemPowerDown, l_fb_info->memt.powerdown); 835 836 clockused = 837 pm3fb_CalculateClock(l_fb_info, 2 * 105000, PM3_REF_CLOCK, &m, 838 &n, &p); 839 840 PM3_WRITE_DAC_REG(PM3RD_KClkPreScale, m); 841 PM3_WRITE_DAC_REG(PM3RD_KClkFeedbackScale, n); 842 PM3_WRITE_DAC_REG(PM3RD_KClkPostScale, p); 843 PM3_WRITE_DAC_REG(PM3RD_KClkControl, 844 PM3RD_KClkControl_STATE_RUN | 845 PM3RD_KClkControl_SOURCE_PLL | 846 PM3RD_KClkControl_ENABLE); 847 PM3_WRITE_DAC_REG(PM3RD_MClkControl, 848 PM3RD_MClkControl_STATE_RUN | 849 PM3RD_MClkControl_SOURCE_KCLK | 850 PM3RD_MClkControl_ENABLE); 851 PM3_WRITE_DAC_REG(PM3RD_SClkControl, 852 PM3RD_SClkControl_STATE_RUN | 853 PM3RD_SClkControl_SOURCE_PCLK | 854 PM3RD_SClkControl_ENABLE); 855} 856 857static unsigned long pm3fb_read_dac_reg(struct pm3fb_info *l_fb_info, 858 unsigned long r) 859{ 860 DASSERT((l_fb_info->vIOBase != (unsigned char *) (-1)), 861 "l_fb_info->vIOBase mapped in read dac reg\n"); 862 PM3_SET_INDEX(r); 863 mb(); 864 return (PM3_READ_REG(PM3RD_IndexedData)); 865} 866 867/* Calculating various clock parameter */ 868static unsigned long pm3fb_CalculateClock(struct pm3fb_info *l_fb_info, unsigned long reqclock, /* In kHz units */ 869 unsigned long refclock, /* In kHz units */ 870 unsigned char *prescale, /* ClkPreScale */ 871 unsigned char *feedback, /* ClkFeedBackScale */ 872 unsigned char *postscale 873 /* ClkPostScale */ ) 874{ 875 int f, pre, post; 876 unsigned long freq; 877 long freqerr = 1000; 878 unsigned long actualclock = 0; 879 880 DTRACE; 881 882 for (f = 1; f < 256; f++) { 883 for (pre = 1; pre < 256; pre++) { 884 for (post = 0; post < 5; post++) { 885 freq = 886 ((2 * refclock * f) / 887 (pre * (1 << post))); 888 if ((reqclock > freq - freqerr) 889 && (reqclock < freq + freqerr)) { 890 freqerr = 891 (reqclock > 892 freq) ? reqclock - 893 freq : freq - reqclock; 894 *feedback = f; 895 *prescale = pre; 896 *postscale = post; 897 actualclock = freq; 898 } 899 } 900 } 901 } 902 903 return (actualclock); 904} 905 906static int pm3fb_Shiftbpp(struct pm3fb_info *l_fb_info, 907 unsigned long depth, int v) 908{ 909 DTRACE; 910 911 switch (depth) { 912 case 8: 913 return (v >> 4); 914 case 12: 915 case 15: 916 case 16: 917 return (v >> 3); 918 case 32: 919 return (v >> 2); 920 } 921 DPRINTK(1, "Unsupported depth %ld\n", depth); 922 return (0); 923} 924 925static int pm3fb_Unshiftbpp(struct pm3fb_info *l_fb_info, 926 unsigned long depth, int v) 927{ 928 DTRACE; 929 930 switch (depth) { 931 case 8: 932 return (v << 4); 933 case 12: 934 case 15: 935 case 16: 936 return (v << 3); 937 case 32: 938 return (v << 2); 939 } 940 DPRINTK(1, "Unsupported depth %ld\n", depth); 941 return (0); 942} 943 944static void pm3fb_mapIO(struct pm3fb_info *l_fb_info) 945{ 946 DTRACE; 947 948 l_fb_info->vIOBase = 949 ioremap((unsigned long) l_fb_info->pIOBase, PM3_REGS_SIZE); 950 l_fb_info->v_fb = 951 ioremap((unsigned long) l_fb_info->p_fb, l_fb_info->fb_size); 952 DPRINTK(2, "IO mapping : IOBase %lx / %lx, fb %lx / %lx\n", 953 (unsigned long) l_fb_info->pIOBase, 954 (unsigned long) l_fb_info->vIOBase, 955 (unsigned long) l_fb_info->p_fb, 956 (unsigned long) l_fb_info->v_fb); 957} 958 959static void pm3fb_unmapIO(struct pm3fb_info *l_fb_info) 960{ 961 DTRACE; 962 963 iounmap(l_fb_info->vIOBase); 964 iounmap(l_fb_info->v_fb); 965 l_fb_info->vIOBase = (unsigned char *) -1; 966 l_fb_info->v_fb = (unsigned char *) -1; 967} 968 969#if defined(PM3FB_MASTER_DEBUG) && (PM3FB_MASTER_DEBUG >= 2) 970static void pm3fb_show_cur_mode(struct pm3fb_info *l_fb_info) 971{ 972 DPRINTK(2, "PM3Aperture0: 0x%08x\n", PM3_READ_REG(PM3Aperture0)); 973 DPRINTK(2, "PM3Aperture1: 0x%08x\n", PM3_READ_REG(PM3Aperture1)); 974 DPRINTK(2, "PM3ByAperture1Mode: 0x%08x\n", 975 PM3_READ_REG(PM3ByAperture1Mode)); 976 DPRINTK(2, "PM3ByAperture2Mode: 0x%08x\n", 977 PM3_READ_REG(PM3ByAperture2Mode)); 978 DPRINTK(2, "PM3ChipConfig: 0x%08x\n", PM3_READ_REG(PM3ChipConfig)); 979 DPRINTK(2, "PM3FIFODis: 0x%08x\n", PM3_READ_REG(PM3FIFODis)); 980 DPRINTK(2, "PM3HTotal: 0x%08x\n", PM3_READ_REG(PM3HTotal)); 981 DPRINTK(2, "PM3HbEnd: 0x%08x\n", PM3_READ_REG(PM3HbEnd)); 982 DPRINTK(2, "PM3HgEnd: 0x%08x\n", PM3_READ_REG(PM3HgEnd)); 983 DPRINTK(2, "PM3HsEnd: 0x%08x\n", PM3_READ_REG(PM3HsEnd)); 984 DPRINTK(2, "PM3HsStart: 0x%08x\n", PM3_READ_REG(PM3HsStart)); 985 DPRINTK(2, "PM3MemBypassWriteMask: 0x%08x\n", 986 PM3_READ_REG(PM3MemBypassWriteMask)); 987 DPRINTK(2, "PM3RD_IndexControl: 0x%08x\n", 988 PM3_READ_REG(PM3RD_IndexControl)); 989 DPRINTK(2, "PM3ScreenBase: 0x%08x\n", PM3_READ_REG(PM3ScreenBase)); 990 DPRINTK(2, "PM3ScreenStride: 0x%08x\n", 991 PM3_READ_REG(PM3ScreenStride)); 992 DPRINTK(2, "PM3VClkCtl: 0x%08x\n", PM3_READ_REG(PM3VClkCtl)); 993 DPRINTK(2, "PM3VTotal: 0x%08x\n", PM3_READ_REG(PM3VTotal)); 994 DPRINTK(2, "PM3VbEnd: 0x%08x\n", PM3_READ_REG(PM3VbEnd)); 995 DPRINTK(2, "PM3VideoControl: 0x%08x\n", 996 PM3_READ_REG(PM3VideoControl)); 997 DPRINTK(2, "PM3VsEnd: 0x%08x\n", PM3_READ_REG(PM3VsEnd)); 998 DPRINTK(2, "PM3VsStart: 0x%08x\n", PM3_READ_REG(PM3VsStart)); 999 1000 DPRINTK(2, "PM3RD_ColorFormat: %ld\n", 1001 PM3_READ_DAC_REG(PM3RD_ColorFormat)); 1002 DPRINTK(2, "PM3RD_DACControl: %ld\n", 1003 PM3_READ_DAC_REG(PM3RD_DACControl)); 1004 DPRINTK(2, "PM3RD_DClk0FeedbackScale: %ld\n", 1005 PM3_READ_DAC_REG(PM3RD_DClk0FeedbackScale)); 1006 DPRINTK(2, "PM3RD_DClk0PostScale: %ld\n", 1007 PM3_READ_DAC_REG(PM3RD_DClk0PostScale)); 1008 DPRINTK(2, "PM3RD_DClk0PreScale: %ld\n", 1009 PM3_READ_DAC_REG(PM3RD_DClk0PreScale)); 1010 DPRINTK(2, "[not set] PM3RD_IndexControl: %ld\n", 1011 PM3_READ_DAC_REG(PM3RD_IndexControl)); 1012 DPRINTK(2, "PM3RD_MiscControl: %ld\n", 1013 PM3_READ_DAC_REG(PM3RD_MiscControl)); 1014 DPRINTK(2, "PM3RD_PixelSize: %ld\n", 1015 PM3_READ_DAC_REG(PM3RD_PixelSize)); 1016 DPRINTK(2, "PM3RD_SyncControl: %ld\n", 1017 PM3_READ_DAC_REG(PM3RD_SyncControl)); 1018} 1019 1020#endif /* defined(PM3FB_MASTER_DEBUG) && (PM3FB_MASTER_DEBUG >= 2) */ 1021static void pm3fb_show_cur_timing(struct pm3fb_info *l_fb_info) 1022{ 1023 u16 subvendor, subdevice; 1024 1025 if ((!pci_read_config_word 1026 (l_fb_info->dev, PCI_SUBSYSTEM_VENDOR_ID, &subvendor)) 1027 && 1028 (!pci_read_config_word 1029 (l_fb_info->dev, PCI_SUBSYSTEM_ID, &subdevice))) { 1030 /* well, nothing... */ 1031 } else { 1032 subvendor = subdevice = (u16)-1; 1033 } 1034 1035 printk(KERN_INFO "pm3fb: memory timings for board #%ld (subvendor: 0x%hx, subdevice: 0x%hx)\n", l_fb_info->board_num, subvendor, subdevice); 1036 printk(KERN_INFO " PM3LocalMemCaps: 0x%08x\n", 1037 PM3_READ_REG(PM3LocalMemCaps)); 1038 printk(KERN_INFO " PM3LocalMemTimings: 0x%08x\n", 1039 PM3_READ_REG(PM3LocalMemTimings)); 1040 printk(KERN_INFO " PM3LocalMemControl: 0x%08x\n", 1041 PM3_READ_REG(PM3LocalMemControl)); 1042 printk(KERN_INFO " PM3LocalMemRefresh: 0x%08x\n", 1043 PM3_READ_REG(PM3LocalMemRefresh)); 1044 printk(KERN_INFO " PM3LocalMemPowerDown: 0x%08x\n", 1045 PM3_READ_REG(PM3LocalMemPowerDown)); 1046} 1047 1048/* write the mode to registers */ 1049static void pm3fb_write_mode(struct pm3fb_info *l_fb_info) 1050{ 1051 char tempsync = 0x00, tempmisc = 0x00; 1052 DTRACE; 1053 1054 PM3_SLOW_WRITE_REG(PM3MemBypassWriteMask, 0xffffffff); 1055 PM3_SLOW_WRITE_REG(PM3Aperture0, 0x00000000); 1056 PM3_SLOW_WRITE_REG(PM3Aperture1, 0x00000000); 1057 PM3_SLOW_WRITE_REG(PM3FIFODis, 0x00000007); 1058 1059 PM3_SLOW_WRITE_REG(PM3HTotal, 1060 pm3fb_Shiftbpp(l_fb_info, 1061 l_fb_info->current_par->depth, 1062 l_fb_info->current_par->htotal - 1063 1)); 1064 PM3_SLOW_WRITE_REG(PM3HsEnd, 1065 pm3fb_Shiftbpp(l_fb_info, 1066 l_fb_info->current_par->depth, 1067 l_fb_info->current_par->hsend)); 1068 PM3_SLOW_WRITE_REG(PM3HsStart, 1069 pm3fb_Shiftbpp(l_fb_info, 1070 l_fb_info->current_par->depth, 1071 l_fb_info->current_par-> 1072 hsstart)); 1073 PM3_SLOW_WRITE_REG(PM3HbEnd, 1074 pm3fb_Shiftbpp(l_fb_info, 1075 l_fb_info->current_par->depth, 1076 l_fb_info->current_par->hbend)); 1077 PM3_SLOW_WRITE_REG(PM3HgEnd, 1078 pm3fb_Shiftbpp(l_fb_info, 1079 l_fb_info->current_par->depth, 1080 l_fb_info->current_par->hbend)); 1081 PM3_SLOW_WRITE_REG(PM3ScreenStride, 1082 pm3fb_Shiftbpp(l_fb_info, 1083 l_fb_info->current_par->depth, 1084 l_fb_info->current_par->stride)); 1085 PM3_SLOW_WRITE_REG(PM3VTotal, l_fb_info->current_par->vtotal - 1); 1086 PM3_SLOW_WRITE_REG(PM3VsEnd, l_fb_info->current_par->vsend - 1); 1087 PM3_SLOW_WRITE_REG(PM3VsStart, 1088 l_fb_info->current_par->vsstart - 1); 1089 PM3_SLOW_WRITE_REG(PM3VbEnd, l_fb_info->current_par->vbend); 1090 1091 switch (l_fb_info->current_par->depth) { 1092 case 8: 1093 PM3_SLOW_WRITE_REG(PM3ByAperture1Mode, 1094 PM3ByApertureMode_PIXELSIZE_8BIT); 1095 PM3_SLOW_WRITE_REG(PM3ByAperture2Mode, 1096 PM3ByApertureMode_PIXELSIZE_8BIT); 1097 break; 1098 1099 case 12: 1100 case 15: 1101 case 16: 1102#ifndef __BIG_ENDIAN 1103 PM3_SLOW_WRITE_REG(PM3ByAperture1Mode, 1104 PM3ByApertureMode_PIXELSIZE_16BIT); 1105 PM3_SLOW_WRITE_REG(PM3ByAperture2Mode, 1106 PM3ByApertureMode_PIXELSIZE_16BIT); 1107#else 1108 PM3_SLOW_WRITE_REG(PM3ByAperture1Mode, 1109 PM3ByApertureMode_PIXELSIZE_16BIT | 1110 PM3ByApertureMode_BYTESWAP_BADC); 1111 PM3_SLOW_WRITE_REG(PM3ByAperture2Mode, 1112 PM3ByApertureMode_PIXELSIZE_16BIT | 1113 PM3ByApertureMode_BYTESWAP_BADC); 1114#endif /* ! __BIG_ENDIAN */ 1115 break; 1116 1117 case 32: 1118#ifndef __BIG_ENDIAN 1119 PM3_SLOW_WRITE_REG(PM3ByAperture1Mode, 1120 PM3ByApertureMode_PIXELSIZE_32BIT); 1121 PM3_SLOW_WRITE_REG(PM3ByAperture2Mode, 1122 PM3ByApertureMode_PIXELSIZE_32BIT); 1123#else 1124 PM3_SLOW_WRITE_REG(PM3ByAperture1Mode, 1125 PM3ByApertureMode_PIXELSIZE_32BIT | 1126 PM3ByApertureMode_BYTESWAP_DCBA); 1127 PM3_SLOW_WRITE_REG(PM3ByAperture2Mode, 1128 PM3ByApertureMode_PIXELSIZE_32BIT | 1129 PM3ByApertureMode_BYTESWAP_DCBA); 1130#endif /* ! __BIG_ENDIAN */ 1131 break; 1132 1133 default: 1134 DPRINTK(1, "Unsupported depth %d\n", 1135 l_fb_info->current_par->depth); 1136 break; 1137 } 1138 1139 /* 1140 * Oxygen VX1 - it appears that setting PM3VideoControl and 1141 * then PM3RD_SyncControl to the same SYNC settings undoes 1142 * any net change - they seem to xor together. Only set the 1143 * sync options in PM3RD_SyncControl. --rmk 1144 */ 1145 { 1146 unsigned int video = l_fb_info->current_par->video; 1147 1148 video &= ~(PM3VideoControl_HSYNC_MASK | 1149 PM3VideoControl_VSYNC_MASK); 1150 video |= PM3VideoControl_HSYNC_ACTIVE_HIGH | 1151 PM3VideoControl_VSYNC_ACTIVE_HIGH; 1152 PM3_SLOW_WRITE_REG(PM3VideoControl, video); 1153 } 1154 PM3_SLOW_WRITE_REG(PM3VClkCtl, 1155 (PM3_READ_REG(PM3VClkCtl) & 0xFFFFFFFC)); 1156 PM3_SLOW_WRITE_REG(PM3ScreenBase, l_fb_info->current_par->base); 1157 PM3_SLOW_WRITE_REG(PM3ChipConfig, 1158 (PM3_READ_REG(PM3ChipConfig) & 0xFFFFFFFD)); 1159 1160 { 1161 unsigned char m; /* ClkPreScale */ 1162 unsigned char n; /* ClkFeedBackScale */ 1163 unsigned char p; /* ClkPostScale */ 1164 (void)pm3fb_CalculateClock(l_fb_info, l_fb_info->current_par->pixclock, PM3_REF_CLOCK, &m, &n, &p); 1165 1166 DPRINTK(2, 1167 "Pixclock: %d, Pre: %d, Feedback: %d, Post: %d\n", 1168 l_fb_info->current_par->pixclock, (int) m, (int) n, 1169 (int) p); 1170 1171 PM3_WRITE_DAC_REG(PM3RD_DClk0PreScale, m); 1172 PM3_WRITE_DAC_REG(PM3RD_DClk0FeedbackScale, n); 1173 PM3_WRITE_DAC_REG(PM3RD_DClk0PostScale, p); 1174 } 1175 /* 1176 PM3_WRITE_DAC_REG(PM3RD_IndexControl, 0x00); 1177 */ 1178 /* 1179 PM3_SLOW_WRITE_REG(PM3RD_IndexControl, 0x00); 1180 */ 1181 if ((l_fb_info->current_par->video & PM3VideoControl_HSYNC_MASK) == 1182 PM3VideoControl_HSYNC_ACTIVE_HIGH) 1183 tempsync |= PM3RD_SyncControl_HSYNC_ACTIVE_HIGH; 1184 if ((l_fb_info->current_par->video & PM3VideoControl_VSYNC_MASK) == 1185 PM3VideoControl_VSYNC_ACTIVE_HIGH) 1186 tempsync |= PM3RD_SyncControl_VSYNC_ACTIVE_HIGH; 1187 1188 PM3_WRITE_DAC_REG(PM3RD_SyncControl, tempsync); 1189 DPRINTK(2, "PM3RD_SyncControl: %d\n", tempsync); 1190 1191 if (flatpanel[l_fb_info->board_num]) 1192 { 1193 PM3_WRITE_DAC_REG(PM3RD_DACControl, PM3RD_DACControl_BLANK_PEDESTAL_ENABLE); 1194 PM3_WAIT(2); 1195 PM3_WRITE_REG(PM3VSConfiguration, 0x06); 1196 PM3_WRITE_REG(0x5a00, 1 << 14); /* black magic... */ 1197 tempmisc = PM3RD_MiscControl_VSB_OUTPUT_ENABLE; 1198 } 1199 else 1200 PM3_WRITE_DAC_REG(PM3RD_DACControl, 0x00); 1201 1202 switch (l_fb_info->current_par->depth) { 1203 case 8: 1204 PM3_WRITE_DAC_REG(PM3RD_PixelSize, 1205 PM3RD_PixelSize_8_BIT_PIXELS); 1206 PM3_WRITE_DAC_REG(PM3RD_ColorFormat, 1207 PM3RD_ColorFormat_CI8_COLOR | 1208 PM3RD_ColorFormat_COLOR_ORDER_BLUE_LOW); 1209 tempmisc |= PM3RD_MiscControl_HIGHCOLOR_RES_ENABLE; 1210 break; 1211 case 12: 1212 PM3_WRITE_DAC_REG(PM3RD_PixelSize, 1213 PM3RD_PixelSize_16_BIT_PIXELS); 1214 PM3_WRITE_DAC_REG(PM3RD_ColorFormat, 1215 PM3RD_ColorFormat_4444_COLOR | 1216 PM3RD_ColorFormat_COLOR_ORDER_BLUE_LOW | 1217 PM3RD_ColorFormat_LINEAR_COLOR_EXT_ENABLE); 1218 tempmisc |= PM3RD_MiscControl_DIRECTCOLOR_ENABLE | 1219 PM3RD_MiscControl_HIGHCOLOR_RES_ENABLE; 1220 break; 1221 case 15: 1222 PM3_WRITE_DAC_REG(PM3RD_PixelSize, 1223 PM3RD_PixelSize_16_BIT_PIXELS); 1224 PM3_WRITE_DAC_REG(PM3RD_ColorFormat, 1225 PM3RD_ColorFormat_5551_FRONT_COLOR | 1226 PM3RD_ColorFormat_COLOR_ORDER_BLUE_LOW | 1227 PM3RD_ColorFormat_LINEAR_COLOR_EXT_ENABLE); 1228 tempmisc |= PM3RD_MiscControl_DIRECTCOLOR_ENABLE | 1229 PM3RD_MiscControl_HIGHCOLOR_RES_ENABLE; 1230 break; 1231 case 16: 1232 PM3_WRITE_DAC_REG(PM3RD_PixelSize, 1233 PM3RD_PixelSize_16_BIT_PIXELS); 1234 PM3_WRITE_DAC_REG(PM3RD_ColorFormat, 1235 PM3RD_ColorFormat_565_FRONT_COLOR | 1236 PM3RD_ColorFormat_COLOR_ORDER_BLUE_LOW | 1237 PM3RD_ColorFormat_LINEAR_COLOR_EXT_ENABLE); 1238 tempmisc |= PM3RD_MiscControl_DIRECTCOLOR_ENABLE | 1239 PM3RD_MiscControl_HIGHCOLOR_RES_ENABLE; 1240 break; 1241 case 32: 1242 PM3_WRITE_DAC_REG(PM3RD_PixelSize, 1243 PM3RD_PixelSize_32_BIT_PIXELS); 1244 PM3_WRITE_DAC_REG(PM3RD_ColorFormat, 1245 PM3RD_ColorFormat_8888_COLOR | 1246 PM3RD_ColorFormat_COLOR_ORDER_BLUE_LOW); 1247 tempmisc |= PM3RD_MiscControl_DIRECTCOLOR_ENABLE | 1248 PM3RD_MiscControl_HIGHCOLOR_RES_ENABLE; 1249 break; 1250 } 1251 PM3_WRITE_DAC_REG(PM3RD_MiscControl, tempmisc); 1252 1253 PM3_SHOW_CUR_MODE; 1254} 1255 1256static void pm3fb_read_mode(struct pm3fb_info *l_fb_info, 1257 struct pm3fb_par *curpar) 1258{ 1259 unsigned long pixsize1, pixsize2, clockused; 1260 unsigned long pre, feedback, post; 1261 1262 DTRACE; 1263 1264 clockused = PM3_READ_REG(PM3VClkCtl); 1265 1266 switch (clockused) { 1267 case 3: 1268 pre = PM3_READ_DAC_REG(PM3RD_DClk3PreScale); 1269 feedback = PM3_READ_DAC_REG(PM3RD_DClk3FeedbackScale); 1270 post = PM3_READ_DAC_REG(PM3RD_DClk3PostScale); 1271 1272 DPRINTK(2, 1273 "DClk3 parameter: Pre: %ld, Feedback: %ld, Post: %ld ; giving pixclock: %ld\n", 1274 pre, feedback, post, PM3_SCALE_TO_CLOCK(pre, 1275 feedback, 1276 post)); 1277 break; 1278 case 2: 1279 pre = PM3_READ_DAC_REG(PM3RD_DClk2PreScale); 1280 feedback = PM3_READ_DAC_REG(PM3RD_DClk2FeedbackScale); 1281 post = PM3_READ_DAC_REG(PM3RD_DClk2PostScale); 1282 1283 DPRINTK(2, 1284 "DClk2 parameter: Pre: %ld, Feedback: %ld, Post: %ld ; giving pixclock: %ld\n", 1285 pre, feedback, post, PM3_SCALE_TO_CLOCK(pre, 1286 feedback, 1287 post)); 1288 break; 1289 case 1: 1290 pre = PM3_READ_DAC_REG(PM3RD_DClk1PreScale); 1291 feedback = PM3_READ_DAC_REG(PM3RD_DClk1FeedbackScale); 1292 post = PM3_READ_DAC_REG(PM3RD_DClk1PostScale); 1293 1294 DPRINTK(2, 1295 "DClk1 parameter: Pre: %ld, Feedback: %ld, Post: %ld ; giving pixclock: %ld\n", 1296 pre, feedback, post, PM3_SCALE_TO_CLOCK(pre, 1297 feedback, 1298 post)); 1299 break; 1300 case 0: 1301 pre = PM3_READ_DAC_REG(PM3RD_DClk0PreScale); 1302 feedback = PM3_READ_DAC_REG(PM3RD_DClk0FeedbackScale); 1303 post = PM3_READ_DAC_REG(PM3RD_DClk0PostScale); 1304 1305 DPRINTK(2, 1306 "DClk0 parameter: Pre: %ld, Feedback: %ld, Post: %ld ; giving pixclock: %ld\n", 1307 pre, feedback, post, PM3_SCALE_TO_CLOCK(pre, 1308 feedback, 1309 post)); 1310 break; 1311 default: 1312 pre = feedback = post = 0; 1313 DPRINTK(1, "Unknowk D clock used : %ld\n", clockused); 1314 break; 1315 } 1316 1317 curpar->pixclock = PM3_SCALE_TO_CLOCK(pre, feedback, post); 1318 1319 pixsize1 = 1320 PM3ByApertureMode_PIXELSIZE_MASK & 1321 (PM3_READ_REG(PM3ByAperture1Mode)); 1322 pixsize2 = 1323 PM3ByApertureMode_PIXELSIZE_MASK & 1324 (PM3_READ_REG(PM3ByAperture2Mode)); 1325 1326 DASSERT((pixsize1 == pixsize2), 1327 "pixsize the same in both aperture\n"); 1328 1329 if (pixsize1 & PM3ByApertureMode_PIXELSIZE_32BIT) 1330 curpar->depth = 32; 1331 else if (pixsize1 & PM3ByApertureMode_PIXELSIZE_16BIT) 1332 { 1333 curpar->depth = 16; 1334 } 1335 else 1336 curpar->depth = 8; 1337 1338 /* not sure if I need to add one on the next ; it give better result with */ 1339 curpar->htotal = 1340 pm3fb_Unshiftbpp(l_fb_info, curpar->depth, 1341 1 + PM3_READ_REG(PM3HTotal)); 1342 curpar->hsend = 1343 pm3fb_Unshiftbpp(l_fb_info, curpar->depth, 1344 PM3_READ_REG(PM3HsEnd)); 1345 curpar->hsstart = 1346 pm3fb_Unshiftbpp(l_fb_info, curpar->depth, 1347 PM3_READ_REG(PM3HsStart)); 1348 curpar->hbend = 1349 pm3fb_Unshiftbpp(l_fb_info, curpar->depth, 1350 PM3_READ_REG(PM3HbEnd)); 1351 1352 curpar->stride = 1353 pm3fb_Unshiftbpp(l_fb_info, curpar->depth, 1354 PM3_READ_REG(PM3ScreenStride)); 1355 1356 curpar->vtotal = 1 + PM3_READ_REG(PM3VTotal); 1357 curpar->vsend = 1 + PM3_READ_REG(PM3VsEnd); 1358 curpar->vsstart = 1 + PM3_READ_REG(PM3VsStart); 1359 curpar->vbend = PM3_READ_REG(PM3VbEnd); 1360 1361 curpar->video = PM3_READ_REG(PM3VideoControl); 1362 1363 curpar->base = PM3_READ_REG(PM3ScreenBase); 1364 curpar->width = curpar->htotal - curpar->hbend; /* make virtual == displayed resolution */ 1365 curpar->height = curpar->vtotal - curpar->vbend; 1366 1367 DPRINTK(2, "Found : %d * %d, %d Khz, stride is %08x\n", 1368 curpar->width, curpar->height, curpar->pixclock, 1369 curpar->stride); 1370} 1371 1372static unsigned long pm3fb_size_memory(struct pm3fb_info *l_fb_info) 1373{ 1374 unsigned long memsize = 0, tempBypass, i, temp1, temp2; 1375 u16 subvendor, subdevice; 1376 pm3fb_timing_result ptr; 1377 1378 DTRACE; 1379 1380 l_fb_info->fb_size = 64 * 1024 * 1024; /* pm3 aperture always 64 MB */ 1381 pm3fb_mapIO(l_fb_info); /* temporary map IO */ 1382 1383 DASSERT((l_fb_info->vIOBase != NULL), 1384 "IO successfully mapped before mem detect\n"); 1385 DASSERT((l_fb_info->v_fb != NULL), 1386 "FB successfully mapped before mem detect\n"); 1387 1388 /* card-specific stuff, *before* accessing *any* FB memory */ 1389 if ((!pci_read_config_word 1390 (l_fb_info->dev, PCI_SUBSYSTEM_VENDOR_ID, &subvendor)) 1391 && 1392 (!pci_read_config_word 1393 (l_fb_info->dev, PCI_SUBSYSTEM_ID, &subdevice))) { 1394 i = 0; l_fb_info->board_type = 0; 1395 while ((cardbase[i].cardname[0]) && !(l_fb_info->board_type)) { 1396 if ((cardbase[i].subvendor == subvendor) && 1397 (cardbase[i].subdevice == subdevice) && 1398 (cardbase[i].func == PCI_FUNC(l_fb_info->dev->devfn))) { 1399 DPRINTK(2, "Card #%ld is an %s\n", 1400 l_fb_info->board_num, 1401 cardbase[i].cardname); 1402 if (cardbase[i].specific_setup) 1403 cardbase[i].specific_setup(l_fb_info); 1404 l_fb_info->board_type = i; 1405 } 1406 i++; 1407 } 1408 if (!l_fb_info->board_type) { 1409 DPRINTK(1, "Card #%ld is an unknown 0x%04x / 0x%04x\n", 1410 l_fb_info->board_num, subvendor, subdevice); 1411 } 1412 } else { 1413 printk(KERN_ERR "pm3fb: Error: pci_read_config_word failed, board #%ld\n", 1414 l_fb_info->board_num); 1415 } 1416 1417 if (printtimings) 1418 pm3fb_show_cur_timing(l_fb_info); 1419 1420 /* card-specific setup is done, we preserve the final 1421 memory timing for future reference */ 1422 if ((ptr = pm3fb_preserve_memory_timings(l_fb_info)) == pm3fb_timing_problem) { /* memory timings were wrong ! oops.... */ 1423 return(0); 1424 } 1425 1426 tempBypass = PM3_READ_REG(PM3MemBypassWriteMask); 1427 1428 DPRINTK(2, "PM3MemBypassWriteMask was: 0x%08lx\n", tempBypass); 1429 1430 PM3_SLOW_WRITE_REG(PM3MemBypassWriteMask, 0xFFFFFFFF); 1431 1432 /* pm3 split up memory, replicates, and do a lot of nasty stuff IMHO ;-) */ 1433 for (i = 0; i < 32; i++) { 1434 fb_writel(i * 0x00345678, 1435 (l_fb_info->v_fb + (i * 1048576))); 1436 mb(); 1437 temp1 = fb_readl((l_fb_info->v_fb + (i * 1048576))); 1438 1439 /* Let's check for wrapover, write will fail at 16MB boundary */ 1440 if (temp1 == (i * 0x00345678)) 1441 memsize = i; 1442 else 1443 break; 1444 } 1445 1446 DPRINTK(2, "First detect pass already got %ld MB\n", memsize + 1); 1447 1448 if (memsize == i) { 1449 for (i = 0; i < 32; i++) { 1450 /* Clear first 32MB ; 0 is 0, no need to byteswap */ 1451 writel(0x0000000, 1452 (l_fb_info->v_fb + (i * 1048576))); 1453 mb(); 1454 } 1455 1456 for (i = 32; i < 64; i++) { 1457 fb_writel(i * 0x00345678, 1458 (l_fb_info->v_fb + (i * 1048576))); 1459 mb(); 1460 temp1 = 1461 fb_readl((l_fb_info->v_fb + (i * 1048576))); 1462 temp2 = 1463 fb_readl((l_fb_info->v_fb + 1464 ((i - 32) * 1048576))); 1465 if ((temp1 == (i * 0x00345678)) && (temp2 == 0)) /* different value, different RAM... */ 1466 memsize = i; 1467 else 1468 break; 1469 } 1470 } 1471 1472 DPRINTK(2, "Second detect pass got %ld MB\n", memsize + 1); 1473 1474 PM3_SLOW_WRITE_REG(PM3MemBypassWriteMask, tempBypass); 1475 1476 pm3fb_unmapIO(l_fb_info); 1477 memsize = 1048576 * (memsize + 1); 1478 1479 DPRINTK(2, "Returning 0x%08lx bytes\n", memsize); 1480 1481 if (forcesize[l_fb_info->board_num] && ((forcesize[l_fb_info->board_num] * 1048576) != memsize)) 1482 { 1483 printk(KERN_WARNING "pm3fb: mismatch between probed (%ld MB) and specified (%hd MB) memory size, using SPECIFIED !\n", memsize, forcesize[l_fb_info->board_num]); 1484 memsize = 1048576 * forcesize[l_fb_info->board_num]; 1485 } 1486 1487 l_fb_info->fb_size = memsize; 1488 1489 if (ptr == pm3fb_timing_retry) 1490 { 1491 printk(KERN_WARNING "pm3fb: retrying memory timings check"); 1492 if (pm3fb_try_memory_timings(l_fb_info) == pm3fb_timing_problem) 1493 return(0); 1494 } 1495 1496 return (memsize); 1497} 1498 1499static void pm3fb_clear_memory(struct pm3fb_info *l_fb_info, u32 cc) 1500{ 1501 int i; 1502 1503 DTRACE; 1504 1505 for (i = 0; i < (l_fb_info->fb_size / sizeof(u32)) ; i++) /* clear entire FB memory to black */ 1506 { 1507 fb_writel(cc, (l_fb_info->v_fb + (i * sizeof(u32)))); 1508 } 1509} 1510 1511static void pm3fb_clear_colormap(struct pm3fb_info *l_fb_info, unsigned char r, unsigned char g, unsigned char b) 1512{ 1513 int i; 1514 1515 DTRACE; 1516 1517 for (i = 0; i < 256 ; i++) /* fill color map with white */ 1518 pm3fb_set_color(l_fb_info, i, r, g, b); 1519 1520} 1521 1522/* common initialisation */ 1523static void pm3fb_common_init(struct pm3fb_info *l_fb_info) 1524{ 1525 DTRACE; 1526 1527 DPRINTK(2, "Initializing board #%ld @ %lx\n", l_fb_info->board_num, 1528 (unsigned long) l_fb_info); 1529 1530 strcpy(l_fb_info->gen.info.modename, permedia3_name); 1531 disp[l_fb_info->board_num].scrollmode = 0; /* SCROLL_YNOMOVE; *//* 0 means "let fbcon choose" */ 1532 l_fb_info->gen.parsize = sizeof(struct pm3fb_par); 1533 l_fb_info->gen.info.changevar = NULL; 1534 l_fb_info->gen.info.fbops = &pm3fb_ops; 1535 l_fb_info->gen.info.disp = &(disp[l_fb_info->board_num]); 1536 if (fontn[l_fb_info->board_num][0]) 1537 strcpy(l_fb_info->gen.info.fontname, 1538 fontn[l_fb_info->board_num]); 1539 l_fb_info->gen.info.switch_con = &fbgen_switch; 1540 l_fb_info->gen.info.updatevar = &fbgen_update_var; /* */ 1541 l_fb_info->gen.info.flags = FBINFO_FLAG_DEFAULT; 1542 1543 pm3fb_mapIO(l_fb_info); 1544 1545 pm3fb_clear_memory(l_fb_info, 0); 1546 pm3fb_clear_colormap(l_fb_info, 0, 0, 0); 1547 1548 (void) fbgen_get_var(&(disp[l_fb_info->board_num]).var, -1, 1549 &l_fb_info->gen.info); 1550 1551 if (depth[l_fb_info->board_num]) /* override mode-defined depth */ 1552 { 1553 pm3fb_encode_depth(&(disp[l_fb_info->board_num]).var, depth[l_fb_info->board_num]); 1554 (disp[l_fb_info->board_num]).var.bits_per_pixel = depth2bpp(depth[l_fb_info->board_num]); 1555 } 1556 1557 (void) fbgen_do_set_var(&(disp[l_fb_info->board_num]).var, 1, 1558 &l_fb_info->gen); 1559 1560 fbgen_set_disp(-1, &l_fb_info->gen); 1561 1562 do_install_cmap(0, &l_fb_info->gen.info); 1563 1564 if (register_framebuffer(&l_fb_info->gen.info) < 0) { 1565 DPRINTK(1, "Couldn't register framebuffer\n"); 1566 return; 1567 } 1568 1569 PM3_WRITE_DAC_REG(PM3RD_CursorMode, 1570 PM3RD_CursorMode_CURSOR_DISABLE); 1571 1572 PM3_SHOW_CUR_MODE; 1573 1574 pm3fb_write_mode(l_fb_info); 1575 1576 printk("fb%d: %s, using %uK of video memory (%s)\n", 1577 l_fb_info->gen.info.node, 1578 permedia3_name, (u32) (l_fb_info->fb_size >> 10), 1579 cardbase[l_fb_info->board_type].cardname); 1580} 1581 1582/* **************************************************** */ 1583/* ***** accelerated permedia3-specific functions ***** */ 1584/* **************************************************** */ 1585#ifdef PM3FB_USE_ACCEL 1586static void pm3fb_wait_pm3(struct pm3fb_info *l_fb_info) 1587{ 1588 DTRACE; 1589 1590 PM3_SLOW_WRITE_REG(PM3FilterMode, PM3FilterModeSync); 1591 PM3_SLOW_WRITE_REG(PM3Sync, 0); 1592 mb(); 1593 do { 1594 while ((PM3_READ_REG(PM3OutFIFOWords)) == 0); 1595 rmb(); 1596 } while ((PM3_READ_REG(PM3OutputFifo)) != PM3Sync_Tag); 1597} 1598 1599static void pm3fb_init_engine(struct pm3fb_info *l_fb_info) 1600{ 1601 PM3_SLOW_WRITE_REG(PM3FilterMode, PM3FilterModeSync); 1602 PM3_SLOW_WRITE_REG(PM3StatisticMode, 0x0); 1603 PM3_SLOW_WRITE_REG(PM3DeltaMode, 0x0); 1604 PM3_SLOW_WRITE_REG(PM3RasterizerMode, 0x0); 1605 PM3_SLOW_WRITE_REG(PM3ScissorMode, 0x0); 1606 PM3_SLOW_WRITE_REG(PM3LineStippleMode, 0x0); 1607 PM3_SLOW_WRITE_REG(PM3AreaStippleMode, 0x0); 1608 PM3_SLOW_WRITE_REG(PM3GIDMode, 0x0); 1609 PM3_SLOW_WRITE_REG(PM3DepthMode, 0x0); 1610 PM3_SLOW_WRITE_REG(PM3StencilMode, 0x0); 1611 PM3_SLOW_WRITE_REG(PM3StencilData, 0x0); 1612 PM3_SLOW_WRITE_REG(PM3ColorDDAMode, 0x0); 1613 PM3_SLOW_WRITE_REG(PM3TextureCoordMode, 0x0); 1614 PM3_SLOW_WRITE_REG(PM3TextureIndexMode0, 0x0); 1615 PM3_SLOW_WRITE_REG(PM3TextureIndexMode1, 0x0); 1616 PM3_SLOW_WRITE_REG(PM3TextureReadMode, 0x0); 1617 PM3_SLOW_WRITE_REG(PM3LUTMode, 0x0); 1618 PM3_SLOW_WRITE_REG(PM3TextureFilterMode, 0x0); 1619 PM3_SLOW_WRITE_REG(PM3TextureCompositeMode, 0x0); 1620 PM3_SLOW_WRITE_REG(PM3TextureApplicationMode, 0x0); 1621 PM3_SLOW_WRITE_REG(PM3TextureCompositeColorMode1, 0x0); 1622 PM3_SLOW_WRITE_REG(PM3TextureCompositeAlphaMode1, 0x0); 1623 PM3_SLOW_WRITE_REG(PM3TextureCompositeColorMode0, 0x0); 1624 PM3_SLOW_WRITE_REG(PM3TextureCompositeAlphaMode0, 0x0); 1625 PM3_SLOW_WRITE_REG(PM3FogMode, 0x0); 1626 PM3_SLOW_WRITE_REG(PM3ChromaTestMode, 0x0); 1627 PM3_SLOW_WRITE_REG(PM3AlphaTestMode, 0x0); 1628 PM3_SLOW_WRITE_REG(PM3AntialiasMode, 0x0); 1629 PM3_SLOW_WRITE_REG(PM3YUVMode, 0x0); 1630 PM3_SLOW_WRITE_REG(PM3AlphaBlendColorMode, 0x0); 1631 PM3_SLOW_WRITE_REG(PM3AlphaBlendAlphaMode, 0x0); 1632 PM3_SLOW_WRITE_REG(PM3DitherMode, 0x0); 1633 PM3_SLOW_WRITE_REG(PM3LogicalOpMode, 0x0); 1634 PM3_SLOW_WRITE_REG(PM3RouterMode, 0x0); 1635 PM3_SLOW_WRITE_REG(PM3Window, 0x0); 1636 1637 PM3_SLOW_WRITE_REG(PM3Config2D, 0x0); 1638 1639 PM3_SLOW_WRITE_REG(PM3SpanColorMask, 0xffffffff); 1640 1641 PM3_SLOW_WRITE_REG(PM3XBias, 0x0); 1642 PM3_SLOW_WRITE_REG(PM3YBias, 0x0); 1643 PM3_SLOW_WRITE_REG(PM3DeltaControl, 0x0); 1644 1645 PM3_SLOW_WRITE_REG(PM3BitMaskPattern, 0xffffffff); 1646 1647 PM3_SLOW_WRITE_REG(PM3FBDestReadEnables, 1648 PM3FBDestReadEnables_E(0xff) | 1649 PM3FBDestReadEnables_R(0xff) | 1650 PM3FBDestReadEnables_ReferenceAlpha(0xff)); 1651 PM3_SLOW_WRITE_REG(PM3FBDestReadBufferAddr0, 0x0); 1652 PM3_SLOW_WRITE_REG(PM3FBDestReadBufferOffset0, 0x0); 1653 PM3_SLOW_WRITE_REG(PM3FBDestReadBufferWidth0, 1654 PM3FBDestReadBufferWidth_Width(l_fb_info-> 1655 current_par-> 1656 width)); 1657 1658 PM3_SLOW_WRITE_REG(PM3FBDestReadMode, 1659 PM3FBDestReadMode_ReadEnable | 1660 PM3FBDestReadMode_Enable0); 1661 PM3_SLOW_WRITE_REG(PM3FBSourceReadBufferAddr, 0x0); 1662 PM3_SLOW_WRITE_REG(PM3FBSourceReadBufferOffset, 0x0); 1663 PM3_SLOW_WRITE_REG(PM3FBSourceReadBufferWidth, 1664 PM3FBSourceReadBufferWidth_Width(l_fb_info-> 1665 current_par-> 1666 width)); 1667 PM3_SLOW_WRITE_REG(PM3FBSourceReadMode, 1668 PM3FBSourceReadMode_Blocking | 1669 PM3FBSourceReadMode_ReadEnable); 1670 1671 { 1672 unsigned long rm = 1; 1673 switch (l_fb_info->current_par->depth) { 1674 case 8: 1675 PM3_SLOW_WRITE_REG(PM3PixelSize, 1676 PM3PixelSize_GLOBAL_8BIT); 1677 break; 1678 case 12: 1679 case 15: 1680 case 16: 1681 PM3_SLOW_WRITE_REG(PM3PixelSize, 1682 PM3PixelSize_GLOBAL_16BIT); 1683 break; 1684 case 32: 1685 PM3_SLOW_WRITE_REG(PM3PixelSize, 1686 PM3PixelSize_GLOBAL_32BIT); 1687 break; 1688 default: 1689 DPRINTK(1, "Unsupported depth %d\n", 1690 l_fb_info->current_par->depth); 1691 break; 1692 } 1693 PM3_SLOW_WRITE_REG(PM3RasterizerMode, rm); 1694 } 1695 1696 PM3_SLOW_WRITE_REG(PM3FBSoftwareWriteMask, 0xffffffff); 1697 PM3_SLOW_WRITE_REG(PM3FBHardwareWriteMask, 0xffffffff); 1698 PM3_SLOW_WRITE_REG(PM3FBWriteMode, 1699 PM3FBWriteMode_WriteEnable | 1700 PM3FBWriteMode_OpaqueSpan | 1701 PM3FBWriteMode_Enable0); 1702 PM3_SLOW_WRITE_REG(PM3FBWriteBufferAddr0, 0x0); 1703 PM3_SLOW_WRITE_REG(PM3FBWriteBufferOffset0, 0x0); 1704 PM3_SLOW_WRITE_REG(PM3FBWriteBufferWidth0, 1705 PM3FBWriteBufferWidth_Width(l_fb_info-> 1706 current_par-> 1707 width)); 1708 1709 PM3_SLOW_WRITE_REG(PM3SizeOfFramebuffer, 0x0); 1710 { 1711 unsigned long sofb = (8UL * l_fb_info->fb_size) / 1712 ((depth2bpp(l_fb_info->current_par->depth)) 1713 * l_fb_info->current_par->width); /* size in lines of FB */ 1714 if (sofb > 4095) 1715 PM3_SLOW_WRITE_REG(PM3SizeOfFramebuffer, 4095); 1716 else 1717 PM3_SLOW_WRITE_REG(PM3SizeOfFramebuffer, sofb); 1718 1719 switch (l_fb_info->current_par->depth) { 1720 case 8: 1721 PM3_SLOW_WRITE_REG(PM3DitherMode, 1722 (1 << 10) | (2 << 3)); 1723 break; 1724 case 12: 1725 case 15: 1726 case 16: 1727 PM3_SLOW_WRITE_REG(PM3DitherMode, 1728 (1 << 10) | (1 << 3)); 1729 break; 1730 case 32: 1731 PM3_SLOW_WRITE_REG(PM3DitherMode, 1732 (1 << 10) | (0 << 3)); 1733 break; 1734 default: 1735 DPRINTK(1, "Unsupported depth %d\n", 1736 l_fb_info->current_par->depth); 1737 break; 1738 } 1739 } 1740 1741 PM3_SLOW_WRITE_REG(PM3dXDom, 0x0); 1742 PM3_SLOW_WRITE_REG(PM3dXSub, 0x0); 1743 PM3_SLOW_WRITE_REG(PM3dY, (1 << 16)); 1744 PM3_SLOW_WRITE_REG(PM3StartXDom, 0x0); 1745 PM3_SLOW_WRITE_REG(PM3StartXSub, 0x0); 1746 PM3_SLOW_WRITE_REG(PM3StartY, 0x0); 1747 PM3_SLOW_WRITE_REG(PM3Count, 0x0); 1748 1749/* Disable LocalBuffer. better safe than sorry */ 1750 PM3_SLOW_WRITE_REG(PM3LBDestReadMode, 0x0); 1751 PM3_SLOW_WRITE_REG(PM3LBDestReadEnables, 0x0); 1752 PM3_SLOW_WRITE_REG(PM3LBSourceReadMode, 0x0); 1753 PM3_SLOW_WRITE_REG(PM3LBWriteMode, 0x0); 1754 1755 pm3fb_wait_pm3(l_fb_info); 1756} 1757 1758#ifdef FBCON_HAS_CFB32 1759static void pm3fb_cfb32_clear(struct vc_data *conp, 1760 struct display *p, 1761 int sy, int sx, int height, int width) 1762{ 1763 struct pm3fb_info *l_fb_info = (struct pm3fb_info *) p->fb_info; 1764 u32 c; 1765 1766 DTRACE; 1767 1768 sx = sx * fontwidth(p); 1769 width = width * fontwidth(p); 1770 sy = sy * fontheight(p); 1771 height = height * fontheight(p); 1772 c = ((u32 *) p->dispsw_data)[attr_bgcol_ec(p, conp)]; 1773 1774 /* block fills in 32bpp are hard, but in low res (width <= 1600 :-) 1775 we can use 16bpp operations, but not if NoWriteMask is on (SDRAM) */ 1776 if ((l_fb_info->current_par->width > 1600) || 1777 (l_fb_info->memt.caps & PM3LocalMemCaps_NoWriteMask)) { 1778 PM3_WAIT(4); 1779 1780 PM3_WRITE_REG(PM3Config2D, 1781 PM3Config2D_UseConstantSource | 1782 PM3Config2D_ForegroundROPEnable | 1783 (PM3Config2D_ForegroundROP(0x3)) | /* Ox3 is GXcopy */ 1784 PM3Config2D_FBWriteEnable); 1785 1786 PM3_WRITE_REG(PM3ForegroundColor, c); 1787 1788 PM3_WRITE_REG(PM3RectanglePosition, 1789 (PM3RectanglePosition_XOffset(sx)) | 1790 (PM3RectanglePosition_YOffset(sy))); 1791 1792 PM3_WRITE_REG(PM3Render2D, 1793 PM3Render2D_XPositive | 1794 PM3Render2D_YPositive | 1795 PM3Render2D_Operation_Normal | 1796 PM3Render2D_SpanOperation | 1797 (PM3Render2D_Width(width)) | 1798 (PM3Render2D_Height(height))); 1799 } else { 1800 PM3_WAIT(8); 1801 1802 PM3_WRITE_REG(PM3FBBlockColor, c); 1803 1804 PM3_WRITE_REG(PM3PixelSize, PM3PixelSize_GLOBAL_16BIT); 1805 1806 PM3_WRITE_REG(PM3FBWriteBufferWidth0, 1807 PM3FBWriteBufferWidth_Width(l_fb_info-> 1808 current_par-> 1809 width << 1)); 1810 1811 PM3_WRITE_REG(PM3Config2D, 1812 PM3Config2D_UseConstantSource | 1813 PM3Config2D_ForegroundROPEnable | 1814 (PM3Config2D_ForegroundROP(0x3)) | /* Ox3 is GXcopy */ 1815 PM3Config2D_FBWriteEnable); 1816 1817 PM3_WRITE_REG(PM3RectanglePosition, 1818 (PM3RectanglePosition_XOffset(sx << 1)) | 1819 (PM3RectanglePosition_YOffset(sy))); 1820 1821 PM3_WRITE_REG(PM3Render2D, 1822 PM3Render2D_XPositive | 1823 PM3Render2D_YPositive | 1824 PM3Render2D_Operation_Normal | 1825 (PM3Render2D_Width(width << 1)) | 1826 (PM3Render2D_Height(height))); 1827 1828 PM3_WRITE_REG(PM3FBWriteBufferWidth0, 1829 PM3FBWriteBufferWidth_Width(l_fb_info-> 1830 current_par-> 1831 width)); 1832 1833 PM3_WRITE_REG(PM3PixelSize, PM3PixelSize_GLOBAL_32BIT); 1834 } 1835 1836 pm3fb_wait_pm3(l_fb_info); 1837} 1838 1839static void pm3fb_cfb32_clear_margins(struct vc_data *conp, 1840 struct display *p, int bottom_only) 1841{ 1842 struct pm3fb_info *l_fb_info = (struct pm3fb_info *) p->fb_info; 1843 int sx, sy; 1844 u32 c; 1845 1846 DTRACE; 1847 1848 sx = conp->vc_cols * fontwidth(p); /* right margin */ 1849 sy = conp->vc_rows * fontheight(p); /* bottom margin */ 1850 c = ((u32 *) p->dispsw_data)[attr_bgcol_ec(p, conp)]; 1851 1852 if (!bottom_only) { /* right margin top->bottom */ 1853 PM3_WAIT(4); 1854 1855 PM3_WRITE_REG(PM3Config2D, 1856 PM3Config2D_UseConstantSource | 1857 PM3Config2D_ForegroundROPEnable | 1858 (PM3Config2D_ForegroundROP(0x3)) | /* Ox3 is GXcopy */ 1859 PM3Config2D_FBWriteEnable); 1860 1861 PM3_WRITE_REG(PM3ForegroundColor, c); 1862 1863 PM3_WRITE_REG(PM3RectanglePosition, 1864 (PM3RectanglePosition_XOffset 1865 (p->var.xoffset + 1866 sx)) | (PM3RectanglePosition_YOffset(p-> 1867 var. 1868 yoffset))); 1869 1870 PM3_WRITE_REG(PM3Render2D, 1871 PM3Render2D_XPositive | 1872 PM3Render2D_YPositive | 1873 PM3Render2D_Operation_Normal | 1874 PM3Render2D_SpanOperation | 1875 (PM3Render2D_Width(p->var.xres - sx)) | 1876 (PM3Render2D_Height(p->var.yres))); 1877 } 1878 1879 /* bottom margin left -> right */ 1880 PM3_WAIT(4); 1881 1882 PM3_WRITE_REG(PM3Config2D, 1883 PM3Config2D_UseConstantSource | 1884 PM3Config2D_ForegroundROPEnable | 1885 (PM3Config2D_ForegroundROP(0x3)) | /* Ox3 is GXcopy */ 1886 PM3Config2D_FBWriteEnable); 1887 1888 PM3_WRITE_REG(PM3ForegroundColor, c); 1889 1890 PM3_WRITE_REG(PM3RectanglePosition, 1891 (PM3RectanglePosition_XOffset(p->var.xoffset)) | 1892 (PM3RectanglePosition_YOffset(p->var.yoffset + sy))); 1893 1894 PM3_WRITE_REG(PM3Render2D, 1895 PM3Render2D_XPositive | 1896 PM3Render2D_YPositive | 1897 PM3Render2D_Operation_Normal | 1898 PM3Render2D_SpanOperation | 1899 (PM3Render2D_Width(p->var.xres)) | 1900 (PM3Render2D_Height(p->var.yres - sy))); 1901 1902 pm3fb_wait_pm3(l_fb_info); 1903} 1904#endif /* FBCON_HAS_CFB32 */ 1905#ifdef FBCON_HAS_CFB16 1906static void pm3fb_cfb16_clear(struct vc_data *conp, 1907 struct display *p, 1908 int sy, int sx, int height, int width) 1909{ 1910 struct pm3fb_info *l_fb_info = (struct pm3fb_info *) p->fb_info; 1911 u32 c; 1912 1913 DTRACE; 1914 1915 sx = sx * fontwidth(p); 1916 width = width * fontwidth(p); 1917 sy = sy * fontheight(p); 1918 height = height * fontheight(p); 1919 c = ((u16 *) p->dispsw_data)[attr_bgcol_ec(p, conp)]; 1920 c = c | (c << 16); 1921 1922 PM3_WAIT(4); 1923 1924 if (l_fb_info->memt.caps & PM3LocalMemCaps_NoWriteMask) 1925 PM3_WRITE_REG(PM3ForegroundColor, c); 1926 else 1927 PM3_WRITE_REG(PM3FBBlockColor, c); 1928 1929 PM3_WRITE_REG(PM3Config2D, 1930 PM3Config2D_UseConstantSource | 1931 PM3Config2D_ForegroundROPEnable | 1932 (PM3Config2D_ForegroundROP(0x3)) | /* Ox3 is GXcopy */ 1933 PM3Config2D_FBWriteEnable); 1934 1935 PM3_WRITE_REG(PM3RectanglePosition, 1936 (PM3RectanglePosition_XOffset(sx)) | 1937 (PM3RectanglePosition_YOffset(sy))); 1938 1939 if (l_fb_info->memt.caps & PM3LocalMemCaps_NoWriteMask) 1940 PM3_WRITE_REG(PM3Render2D, 1941 PM3Render2D_XPositive | 1942 PM3Render2D_YPositive | 1943 PM3Render2D_Operation_Normal | 1944 PM3Render2D_SpanOperation | 1945 (PM3Render2D_Width(width)) | 1946 (PM3Render2D_Height(height))); 1947 else 1948 PM3_WRITE_REG(PM3Render2D, 1949 PM3Render2D_XPositive | 1950 PM3Render2D_YPositive | 1951 PM3Render2D_Operation_Normal | 1952 (PM3Render2D_Width(width)) | 1953 (PM3Render2D_Height(height))); 1954 1955 pm3fb_wait_pm3(l_fb_info); 1956} 1957 1958static void pm3fb_cfb16_clear_margins(struct vc_data *conp, 1959 struct display *p, int bottom_only) 1960{ 1961 struct pm3fb_info *l_fb_info = (struct pm3fb_info *) p->fb_info; 1962 int sx, sy; 1963 u32 c; 1964 1965 DTRACE; 1966 1967 sx = conp->vc_cols * fontwidth(p); /* right margin */ 1968 sy = conp->vc_rows * fontheight(p); /* bottom margin */ 1969 c = ((u16 *) p->dispsw_data)[attr_bgcol_ec(p, conp)]; 1970 c = c | (c << 16); 1971 1972 if (!bottom_only) { /* right margin top->bottom */ 1973 PM3_WAIT(4); 1974 1975 PM3_WRITE_REG(PM3Config2D, 1976 PM3Config2D_UseConstantSource | 1977 PM3Config2D_ForegroundROPEnable | 1978 (PM3Config2D_ForegroundROP(0x3)) | /* Ox3 is GXcopy */ 1979 PM3Config2D_FBWriteEnable); 1980 1981 if (l_fb_info->memt.caps & PM3LocalMemCaps_NoWriteMask) 1982 PM3_WRITE_REG(PM3ForegroundColor, c); 1983 else 1984 PM3_WRITE_REG(PM3FBBlockColor, c); 1985 1986 PM3_WRITE_REG(PM3RectanglePosition, 1987 (PM3RectanglePosition_XOffset 1988 (p->var.xoffset + 1989 sx)) | (PM3RectanglePosition_YOffset(p-> 1990 var. 1991 yoffset))); 1992 if (l_fb_info->memt.caps & PM3LocalMemCaps_NoWriteMask) 1993 PM3_WRITE_REG(PM3Render2D, 1994 PM3Render2D_XPositive | 1995 PM3Render2D_YPositive | 1996 PM3Render2D_Operation_Normal | 1997 PM3Render2D_SpanOperation | 1998 (PM3Render2D_Width(p->var.xres - sx)) | 1999 (PM3Render2D_Height(p->var.yres))); 2000 else 2001 PM3_WRITE_REG(PM3Render2D, 2002 PM3Render2D_XPositive | 2003 PM3Render2D_YPositive | 2004 PM3Render2D_Operation_Normal | 2005 (PM3Render2D_Width(p->var.xres - sx)) | 2006 (PM3Render2D_Height(p->var.yres))); 2007 } 2008 2009 /* bottom margin left -> right */ 2010 PM3_WAIT(4); 2011 2012 PM3_WRITE_REG(PM3Config2D, 2013 PM3Config2D_UseConstantSource | 2014 PM3Config2D_ForegroundROPEnable | 2015 (PM3Config2D_ForegroundROP(0x3)) | /* Ox3 is GXcopy */ 2016 PM3Config2D_FBWriteEnable); 2017 2018 if (l_fb_info->memt.caps & PM3LocalMemCaps_NoWriteMask) 2019 PM3_WRITE_REG(PM3ForegroundColor, c); 2020 else 2021 PM3_WRITE_REG(PM3FBBlockColor, c); 2022 2023 2024 PM3_WRITE_REG(PM3RectanglePosition, 2025 (PM3RectanglePosition_XOffset(p->var.xoffset)) | 2026 (PM3RectanglePosition_YOffset(p->var.yoffset + sy))); 2027 2028 if (l_fb_info->memt.caps & PM3LocalMemCaps_NoWriteMask) 2029 PM3_WRITE_REG(PM3Render2D, 2030 PM3Render2D_XPositive | 2031 PM3Render2D_YPositive | 2032 PM3Render2D_Operation_Normal | 2033 PM3Render2D_SpanOperation | 2034 (PM3Render2D_Width(p->var.xres)) | 2035 (PM3Render2D_Height(p->var.yres - sy))); 2036 else 2037 PM3_WRITE_REG(PM3Render2D, 2038 PM3Render2D_XPositive | 2039 PM3Render2D_YPositive | 2040 PM3Render2D_Operation_Normal | 2041 (PM3Render2D_Width(p->var.xres)) | 2042 (PM3Render2D_Height(p->var.yres - sy))); 2043 2044 pm3fb_wait_pm3(l_fb_info); 2045} 2046#endif /* FBCON_HAS_CFB16 */ 2047#ifdef FBCON_HAS_CFB8 2048static void pm3fb_cfb8_clear(struct vc_data *conp, 2049 struct display *p, 2050 int sy, int sx, int height, int width) 2051{ 2052 struct pm3fb_info *l_fb_info = (struct pm3fb_info *) p->fb_info; 2053 u32 c; 2054 2055 DTRACE; 2056 2057 sx = sx * fontwidth(p); 2058 width = width * fontwidth(p); 2059 sy = sy * fontheight(p); 2060 height = height * fontheight(p); 2061 2062 c = attr_bgcol_ec(p, conp); 2063 c |= c << 8; 2064 c |= c << 16; 2065 2066 PM3_WAIT(4); 2067 2068 PM3_WRITE_REG(PM3Config2D, 2069 PM3Config2D_UseConstantSource | 2070 PM3Config2D_ForegroundROPEnable | 2071 (PM3Config2D_ForegroundROP(0x3)) | /* Ox3 is GXcopy */ 2072 PM3Config2D_FBWriteEnable); 2073 2074 PM3_WRITE_REG(PM3ForegroundColor, c); 2075 2076 PM3_WRITE_REG(PM3RectanglePosition, 2077 (PM3RectanglePosition_XOffset(sx)) | 2078 (PM3RectanglePosition_YOffset(sy))); 2079 2080 PM3_WRITE_REG(PM3Render2D, 2081 PM3Render2D_XPositive | 2082 PM3Render2D_YPositive | 2083 PM3Render2D_Operation_Normal | 2084 PM3Render2D_SpanOperation | 2085 (PM3Render2D_Width(width)) | 2086 (PM3Render2D_Height(height))); 2087 2088 pm3fb_wait_pm3(l_fb_info); 2089} 2090 2091static void pm3fb_cfb8_clear_margins(struct vc_data *conp, 2092 struct display *p, int bottom_only) 2093{ 2094 struct pm3fb_info *l_fb_info = (struct pm3fb_info *) p->fb_info; 2095 int sx, sy; 2096 u32 c; 2097 2098 DTRACE; 2099 2100 sx = conp->vc_cols * fontwidth(p); /* right margin */ 2101 sy = conp->vc_rows * fontheight(p); /* bottom margin */ 2102 c = attr_bgcol_ec(p, conp); 2103 c |= c << 8; 2104 c |= c << 16; 2105 2106 if (!bottom_only) { /* right margin top->bottom */ 2107 PM3_WAIT(4); 2108 2109 PM3_WRITE_REG(PM3Config2D, 2110 PM3Config2D_UseConstantSource | 2111 PM3Config2D_ForegroundROPEnable | 2112 (PM3Config2D_ForegroundROP(0x3)) | /* Ox3 is GXcopy */ 2113 PM3Config2D_FBWriteEnable); 2114 2115 PM3_WRITE_REG(PM3ForegroundColor, c); 2116 2117 PM3_WRITE_REG(PM3RectanglePosition, 2118 (PM3RectanglePosition_XOffset 2119 (p->var.xoffset + 2120 sx)) | (PM3RectanglePosition_YOffset(p-> 2121 var. 2122 yoffset))); 2123 2124 PM3_WRITE_REG(PM3Render2D, 2125 PM3Render2D_XPositive | 2126 PM3Render2D_YPositive | 2127 PM3Render2D_Operation_Normal | 2128 PM3Render2D_SpanOperation | 2129 (PM3Render2D_Width(p->var.xres - sx)) | 2130 (PM3Render2D_Height(p->var.yres))); 2131 } 2132 2133 /* bottom margin left -> right */ 2134 PM3_WAIT(4); 2135 2136 PM3_WRITE_REG(PM3Config2D, 2137 PM3Config2D_UseConstantSource | 2138 PM3Config2D_ForegroundROPEnable | 2139 (PM3Config2D_ForegroundROP(0x3)) | /* Ox3 is GXcopy */ 2140 PM3Config2D_FBWriteEnable); 2141 2142 PM3_WRITE_REG(PM3ForegroundColor, c); 2143 2144 PM3_WRITE_REG(PM3RectanglePosition, 2145 (PM3RectanglePosition_XOffset(p->var.xoffset)) | 2146 (PM3RectanglePosition_YOffset(p->var.yoffset + sy))); 2147 2148 PM3_WRITE_REG(PM3Render2D, 2149 PM3Render2D_XPositive | 2150 PM3Render2D_YPositive | 2151 PM3Render2D_Operation_Normal | 2152 PM3Render2D_SpanOperation | 2153 (PM3Render2D_Width(p->var.xres)) | 2154 (PM3Render2D_Height(p->var.yres - sy))); 2155 2156 pm3fb_wait_pm3(l_fb_info); 2157} 2158#endif /* FBCON_HAS_CFB8 */ 2159#if defined(FBCON_HAS_CFB8) || defined(FBCON_HAS_CFB16) || defined(FBCON_HAS_CFB32) 2160static void pm3fb_cfbX_bmove(struct display *p, 2161 int sy, int sx, 2162 int dy, int dx, int height, int width) 2163{ 2164 struct pm3fb_info *l_fb_info = (struct pm3fb_info *) p->fb_info; 2165 int x_align, o_x, o_y; 2166 2167 DTRACE; 2168 2169 sx = sx * fontwidth(p); 2170 dx = dx * fontwidth(p); 2171 width = width * fontwidth(p); 2172 sy = sy * fontheight(p); 2173 dy = dy * fontheight(p); 2174 height = height * fontheight(p); 2175 2176 o_x = sx - dx; /*(sx > dx ) ? (sx - dx) : (dx - sx); */ 2177 o_y = sy - dy; /*(sy > dy ) ? (sy - dy) : (dy - sy); */ 2178 2179 x_align = (sx & 0x1f); 2180 2181 PM3_WAIT(6); 2182 2183 PM3_WRITE_REG(PM3Config2D, 2184 PM3Config2D_UserScissorEnable | 2185 PM3Config2D_ForegroundROPEnable | 2186 PM3Config2D_Blocking | 2187 (PM3Config2D_ForegroundROP(0x3)) | /* Ox3 is GXcopy */ 2188 PM3Config2D_FBWriteEnable); 2189 2190 PM3_WRITE_REG(PM3ScissorMinXY, 2191 ((dy & 0x0fff) << 16) | (dx & 0x0fff)); 2192 PM3_WRITE_REG(PM3ScissorMaxXY, 2193 (((dy + height) & 0x0fff) << 16) | 2194 ((dx + width) & 0x0fff)); 2195 2196 PM3_WRITE_REG(PM3FBSourceReadBufferOffset, 2197 PM3FBSourceReadBufferOffset_XOffset(o_x) | 2198 PM3FBSourceReadBufferOffset_YOffset(o_y)); 2199 2200 PM3_WRITE_REG(PM3RectanglePosition, 2201 (PM3RectanglePosition_XOffset(dx - x_align)) | 2202 (PM3RectanglePosition_YOffset(dy))); 2203 2204 PM3_WRITE_REG(PM3Render2D, 2205 ((sx > dx) ? PM3Render2D_XPositive : 0) | 2206 ((sy > dy) ? PM3Render2D_YPositive : 0) | 2207 PM3Render2D_Operation_Normal | 2208 PM3Render2D_SpanOperation | 2209 PM3Render2D_FBSourceReadEnable | 2210 (PM3Render2D_Width(width + x_align)) | 2211 (PM3Render2D_Height(height))); 2212 2213 pm3fb_wait_pm3(l_fb_info); 2214} 2215 2216static void pm3fb_cfbX_putc(struct vc_data *conp, struct display *p, 2217 int c, int yy, int xx) 2218{ 2219 struct pm3fb_info *l_fb_info = (struct pm3fb_info *) p->fb_info; 2220 u8 *cdat, asx = 0, asy = 0, o_x = 0, o_y = 0; 2221 u32 fgx, bgx, ldat; 2222 int sx, sy, i; 2223 2224 DTRACE; 2225 2226 if (l_fb_info->current_par->depth == 8) 2227 fgx = attr_fgcol(p, c); 2228 else if (depth2bpp(l_fb_info->current_par->depth) == 16) 2229 fgx = ((u16 *) p->dispsw_data)[attr_fgcol(p, c)]; 2230 else 2231 fgx = ((u32 *) p->dispsw_data)[attr_fgcol(p, c)]; 2232 2233 PM3_COLOR(fgx); 2234 2235 if (l_fb_info->current_par->depth == 8) 2236 bgx = attr_bgcol(p, c); 2237 else if (depth2bpp(l_fb_info->current_par->depth) == 16) 2238 bgx = ((u16 *) p->dispsw_data)[attr_bgcol(p, c)]; 2239 else 2240 bgx = ((u32 *) p->dispsw_data)[attr_bgcol(p, c)]; 2241 2242 PM3_COLOR(bgx); 2243 2244 PM3_WAIT(4); 2245 2246 PM3_WRITE_REG(PM3Config2D, 2247 PM3Config2D_UseConstantSource | 2248 PM3Config2D_ForegroundROPEnable | 2249 (PM3Config2D_ForegroundROP(0x3)) | /* Ox3 is GXcopy */ 2250 PM3Config2D_FBWriteEnable | PM3Config2D_OpaqueSpan); 2251 2252 PM3_WRITE_REG(PM3ForegroundColor, fgx); 2253 PM3_WRITE_REG(PM3FillBackgroundColor, bgx); 2254 2255 /* WARNING : address select X need to specify 8 bits for fontwidth <= 8 */ 2256 /* and 16 bits for fontwidth <= 16 */ 2257 /* same in _putcs, same for Y and fontheight */ 2258 if (fontwidth(p) <= 8) 2259 asx = 2; 2260 else if (fontwidth(p) <= 16) 2261 asx = 3; /* look OK */ 2262 if (fontheight(p) <= 8) 2263 asy = 2; 2264 else if (fontheight(p) <= 16) 2265 asy = 3; /* look OK */ 2266 else if (fontheight(p) <= 32) 2267 asy = 4; /* look OK */ 2268 2269 sx = xx * fontwidth(p); 2270 sy = yy * fontheight(p); 2271 2272 if (fontwidth(p) <= 8) 2273 o_x = (8 - (sx & 0x7)) & 0x7; 2274 else if (fontwidth(p) <= 16) 2275 o_x = (16 - (sx & 0xF)) & 0xF; 2276 if (fontheight(p) <= 8) 2277 o_y = (8 - (sy & 0x7)) & 0x7; 2278 else if (fontheight(p) <= 16) 2279 o_y = (16 - (sy & 0xF)) & 0xF; 2280 else if (fontheight(p) <= 32) 2281 o_y = (32 - (sy & 0x1F)) & 0x1F; 2282 2283 PM3_WRITE_REG(PM3AreaStippleMode, (o_x << 7) | (o_y << 12) | /* x_offset, y_offset in pattern */ 2284 (1 << 18) | /* BE */ 2285 1 | (asx << 1) | (asy << 4) | /* address select x/y */ 2286 (1 << 20)); /* OpaqueSpan */ 2287 2288 if (fontwidth(p) <= 8) { 2289 cdat = p->fontdata + (c & p->charmask) * fontheight(p); 2290 } else { 2291 cdat = 2292 p->fontdata + 2293 ((c & p->charmask) * (fontheight(p) << 1)); 2294 } 2295 2296 PM3_WAIT(2 + fontheight(p)); 2297 2298 for (i = 0; i < fontheight(p); i++) { /* assume fontheight <= 32 */ 2299 if (fontwidth(p) <= 8) { 2300 ldat = *cdat++; 2301 } else { /* assume fontwidth <= 16 ATM */ 2302 2303 ldat = ((*cdat++) << 8); 2304 ldat |= *cdat++; 2305 } 2306 PM3_WRITE_REG(AreaStipplePattern_indexed(i), ldat); 2307 } 2308 2309 PM3_WRITE_REG(PM3RectanglePosition, 2310 (PM3RectanglePosition_XOffset(sx)) | 2311 (PM3RectanglePosition_YOffset(sy))); 2312 2313 PM3_WRITE_REG(PM3Render2D, 2314 PM3Render2D_AreaStippleEnable | 2315 PM3Render2D_XPositive | 2316 PM3Render2D_YPositive | 2317 PM3Render2D_Operation_Normal | 2318 PM3Render2D_SpanOperation | 2319 (PM3Render2D_Width(fontwidth(p))) | 2320 (PM3Render2D_Height(fontheight(p)))); 2321 2322 pm3fb_wait_pm3(l_fb_info); 2323} 2324 2325static void pm3fb_cfbX_putcs(struct vc_data *conp, struct display *p, 2326 const unsigned short *s, int count, int yy, 2327 int xx) 2328{ 2329 struct pm3fb_info *l_fb_info = (struct pm3fb_info *) p->fb_info; 2330 u8 *cdat, asx = 0, asy = 0, o_x = 0, o_y = 0; 2331 u32 fgx, bgx, ldat; 2332 int sx, sy, i, j; 2333 u16 sc; 2334 2335 DTRACE; 2336 2337 sc = scr_readw(s); 2338 if (l_fb_info->current_par->depth == 8) 2339 fgx = attr_fgcol(p, sc); 2340 else if (depth2bpp(l_fb_info->current_par->depth) == 16) 2341 fgx = ((u16 *) p->dispsw_data)[attr_fgcol(p, sc)]; 2342 else 2343 fgx = ((u32 *) p->dispsw_data)[attr_fgcol(p, sc)]; 2344 2345 PM3_COLOR(fgx); 2346 2347 if (l_fb_info->current_par->depth == 8) 2348 bgx = attr_bgcol(p, sc); 2349 else if (depth2bpp(l_fb_info->current_par->depth) == 16) 2350 bgx = ((u16 *) p->dispsw_data)[attr_bgcol(p, sc)]; 2351 else 2352 bgx = ((u32 *) p->dispsw_data)[attr_bgcol(p, sc)]; 2353 2354 PM3_COLOR(bgx); 2355 2356 PM3_WAIT(4); 2357 2358 PM3_WRITE_REG(PM3Config2D, 2359 PM3Config2D_UseConstantSource | 2360 PM3Config2D_ForegroundROPEnable | 2361 (PM3Config2D_ForegroundROP(0x3)) | /* Ox3 is GXcopy */ 2362 PM3Config2D_FBWriteEnable | 2363 PM3Config2D_OpaqueSpan); 2364 2365 PM3_WRITE_REG(PM3ForegroundColor, fgx); 2366 PM3_WRITE_REG(PM3FillBackgroundColor, bgx); 2367 2368 /* WARNING : address select X need to specify 8 bits for fontwidth <= 8 */ 2369 /* and 16 bits for fontwidth <= 16 */ 2370 /* same in _putc, same for Y and fontheight */ 2371 if (fontwidth(p) <= 8) 2372 asx = 2; 2373 else if (fontwidth(p) <= 16) 2374 asx = 3; /* look OK */ 2375 if (fontheight(p) <= 8) 2376 asy = 2; 2377 else if (fontheight(p) <= 16) 2378 asy = 3; /* look OK */ 2379 else if (fontheight(p) <= 32) 2380 asy = 4; /* look OK */ 2381 2382 sy = yy * fontheight(p); 2383 2384 if (fontheight(p) <= 8) 2385 o_y = (8 - (sy & 0x7)) & 0x7; 2386 else if (fontheight(p) <= 16) 2387 o_y = (16 - (sy & 0xF)) & 0xF; 2388 else if (fontheight(p) <= 32) 2389 o_y = (32 - (sy & 0x1F)) & 0x1F; 2390 2391 for (j = 0; j < count; j++) { 2392 sc = scr_readw(s + j); 2393 if (fontwidth(p) <= 8) 2394 cdat = p->fontdata + 2395 (sc & p->charmask) * fontheight(p); 2396 else 2397 cdat = p->fontdata + 2398 ((sc & p->charmask) * fontheight(p) << 1); 2399 2400 sx = (xx + j) * fontwidth(p); 2401 2402 if (fontwidth(p) <= 8) 2403 o_x = (8 - (sx & 0x7)) & 0x7; 2404 else if (fontwidth(p) <= 16) 2405 o_x = (16 - (sx & 0xF)) & 0xF; 2406 2407 PM3_WAIT(3 + fontheight(p)); 2408 2409 PM3_WRITE_REG(PM3AreaStippleMode, (o_x << 7) | (o_y << 12) | /* x_offset, y_offset in pattern */ 2410 (1 << 18) | /* BE */ 2411 1 | (asx << 1) | (asy << 4) | /* address select x/y */ 2412 (1 << 20)); /* OpaqueSpan */ 2413 2414 for (i = 0; i < fontheight(p); i++) { /* assume fontheight <= 32 */ 2415 if (fontwidth(p) <= 8) { 2416 ldat = *cdat++; 2417 } else { /* assume fontwidth <= 16 ATM */ 2418 ldat = ((*cdat++) << 8); 2419 ldat |= *cdat++; 2420 } 2421 PM3_WRITE_REG(AreaStipplePattern_indexed(i), ldat); 2422 } 2423 2424 PM3_WRITE_REG(PM3RectanglePosition, 2425 (PM3RectanglePosition_XOffset(sx)) | 2426 (PM3RectanglePosition_YOffset(sy))); 2427 2428 PM3_WRITE_REG(PM3Render2D, 2429 PM3Render2D_AreaStippleEnable | 2430 PM3Render2D_XPositive | 2431 PM3Render2D_YPositive | 2432 PM3Render2D_Operation_Normal | 2433 PM3Render2D_SpanOperation | 2434 (PM3Render2D_Width(fontwidth(p))) | 2435 (PM3Render2D_Height(fontheight(p)))); 2436 } 2437 pm3fb_wait_pm3(l_fb_info); 2438} 2439 2440static void pm3fb_cfbX_revc(struct display *p, int xx, int yy) 2441{ 2442 struct pm3fb_info *l_fb_info = (struct pm3fb_info *) p->fb_info; 2443 2444 xx = xx * fontwidth(p); 2445 yy = yy * fontheight(p); 2446 2447 if (l_fb_info->current_par->depth == 8) 2448 { 2449 if (l_fb_info->memt.caps & PM3LocalMemCaps_NoWriteMask) 2450 PM3_SLOW_WRITE_REG(PM3FBSoftwareWriteMask, 0x0F0F0F0F); 2451 else 2452 PM3_SLOW_WRITE_REG(PM3FBHardwareWriteMask, 0x0F0F0F0F); 2453 } 2454 2455 PM3_WAIT(3); 2456 2457 PM3_WRITE_REG(PM3Config2D, 2458 PM3Config2D_UseConstantSource | 2459 PM3Config2D_ForegroundROPEnable | 2460 (PM3Config2D_ForegroundROP(0xa)) | /* Oxa is GXinvert */ 2461 PM3Config2D_FBDestReadEnable | 2462 PM3Config2D_FBWriteEnable); 2463 2464 PM3_WRITE_REG(PM3RectanglePosition, 2465 (PM3RectanglePosition_XOffset(xx)) | 2466 (PM3RectanglePosition_YOffset(yy))); 2467 2468 PM3_WRITE_REG(PM3Render2D, 2469 PM3Render2D_XPositive | 2470 PM3Render2D_YPositive | 2471 PM3Render2D_Operation_Normal | 2472 PM3Render2D_SpanOperation | 2473 (PM3Render2D_Width(fontwidth(p))) | 2474 (PM3Render2D_Height(fontheight(p)))); 2475 2476 pm3fb_wait_pm3(l_fb_info); 2477 2478 if (l_fb_info->current_par->depth == 8) 2479 { 2480 if (l_fb_info->memt.caps & PM3LocalMemCaps_NoWriteMask) 2481 PM3_SLOW_WRITE_REG(PM3FBSoftwareWriteMask, 0xFFFFFFFF); 2482 else 2483 PM3_SLOW_WRITE_REG(PM3FBHardwareWriteMask, 0xFFFFFFFF); 2484 } 2485} 2486 2487#endif /* FBCON_HAS_CFB8 || FBCON_HAS_CFB16 || FBCON_HAS_CFB32 */ 2488#endif /* PM3FB_USE_ACCEL */ 2489/* *********************************** */ 2490/* ***** pre-init board(s) setup ***** */ 2491/* *********************************** */ 2492 2493static void pm3fb_mode_setup(char *mode, unsigned long board_num) 2494{ 2495 struct pm3fb_info *l_fb_info = &(fb_info[board_num]); 2496 struct pm3fb_par *l_fb_par = &(current_par[board_num]); 2497 unsigned long i = 0; 2498 2499 current_par_valid[board_num] = 0; 2500 2501 if (!strncmp(mode, "current", 7)) { 2502 l_fb_info->use_current = 1; /* default w/ OpenFirmware */ 2503 } else { 2504 while ((mode_base[i].name[0]) 2505 && (!current_par_valid[board_num])) { 2506 if (! 2507 (strncmp 2508 (mode, mode_base[i].name, 2509 strlen(mode_base[i].name)))) { 2510 memcpy(l_fb_par, &(mode_base[i].user_mode), 2511 sizeof(struct pm3fb_par)); 2512 current_par_valid[board_num] = 1; 2513 DPRINTK(2, "Mode set to %s\n", 2514 mode_base[i].name); 2515 } 2516 i++; 2517 } 2518 DASSERT(current_par_valid[board_num], 2519 "Valid mode on command line\n"); 2520 } 2521} 2522 2523static void pm3fb_pciid_setup(char *pciid, unsigned long board_num) 2524{ 2525 short l_bus = -1, l_slot = -1, l_func = -1; 2526 char *next; 2527 2528 if (pciid) { 2529 l_bus = simple_strtoul(pciid, &next, 10); 2530 if (next && (next[0] == ':')) { 2531 pciid = next + 1; 2532 l_slot = simple_strtoul(pciid, &next, 10); 2533 if (next && (next[0] == ':')) { 2534 pciid = next + 1; 2535 l_func = 2536 simple_strtoul(pciid, (char **) NULL, 2537 10); 2538 } 2539 } 2540 } else 2541 return; 2542 2543 if ((l_bus >= 0) && (l_slot >= 0) && (l_func >= 0)) { 2544 bus[board_num] = l_bus; 2545 slot[board_num] = l_slot; 2546 func[board_num] = l_func; 2547 DPRINTK(2, "Board #%ld will be PciId: %hd:%hd:%hd\n", 2548 board_num, l_bus, l_slot, l_func); 2549 } else { 2550 DPRINTK(1, "Invalid PciId: %hd:%hd:%hd for board #%ld\n", 2551 l_bus, l_slot, l_func, board_num); 2552 } 2553} 2554 2555static void pm3fb_font_setup(char *lf, unsigned long board_num) 2556{ 2557 unsigned long lfs = strlen(lf); 2558 2559 if (lfs > (PM3_FONTNAME_SIZE - 1)) { 2560 DPRINTK(1, "Fontname %s too long\n", lf); 2561 return; 2562 } 2563 strlcpy(fontn[board_num], lf, lfs + 1); 2564} 2565 2566static void pm3fb_bootdepth_setup(char *bds, unsigned long board_num) 2567{ 2568 unsigned long bd = simple_strtoul(bds, (char **) NULL, 10); 2569 2570 if (!(depth_supported(bd))) { 2571 printk(KERN_WARNING "pm3fb: ignoring invalid depth %s for board #%ld\n", 2572 bds, board_num); 2573 return; 2574 } 2575 depth[board_num] = bd; 2576} 2577 2578static void pm3fb_forcesize_setup(char *bds, unsigned long board_num) 2579{ 2580 unsigned long bd = simple_strtoul(bds, (char **) NULL, 10); 2581 2582 if (bd > 64) { 2583 printk(KERN_WARNING "pm3fb: ignoring invalid memory size %s for board #%ld\n", 2584 bds, board_num); 2585 return; 2586 } 2587 forcesize[board_num] = bd; 2588} 2589 2590static char *pm3fb_boardnum_setup(char *options, unsigned long *bn) 2591{ 2592 char *next; 2593 2594 if (!(isdigit(options[0]))) { 2595 (*bn) = 0; 2596 return (options); 2597 } 2598 2599 (*bn) = simple_strtoul(options, &next, 10); 2600 2601 if (next && (next[0] == ':') && ((*bn) >= 0) 2602 && ((*bn) <= PM3_MAX_BOARD)) { 2603 DPRINTK(2, "Board_num seen as %ld\n", (*bn)); 2604 return (next + 1); 2605 } else { 2606 (*bn) = 0; 2607 DPRINTK(2, "Board_num default to %ld\n", (*bn)); 2608 return (options); 2609 } 2610} 2611 2612static void pm3fb_real_setup(char *options) 2613{ 2614 char *next; 2615 unsigned long i, bn; 2616 struct pm3fb_info *l_fb_info; 2617 2618 DTRACE; 2619 2620 DPRINTK(2, "Options : %s\n", options); 2621 2622 for (i = 0; i < PM3_MAX_BOARD; i++) { 2623 l_fb_info = &(fb_info[i]); 2624 memset(l_fb_info, 0, sizeof(struct pm3fb_info)); 2625 l_fb_info->gen.fbhw = &pm3fb_switch; 2626 l_fb_info->board_num = i; 2627 current_par_valid[i] = 0; 2628 slot[i] = -1; 2629 func[i] = -1; 2630 bus[i] = -1; 2631 disable[i] = 0; 2632 noaccel[i] = 0; 2633 fontn[i][0] = '\0'; 2634 depth[i] = 0; 2635 l_fb_info->current_par = &(current_par[i]); 2636 } 2637 2638 /* eat up prefix pm3fb and whatever is used as separator i.e. :,= */ 2639 if (!strncmp(options, "pm3fb", 5)) { 2640 options += 5; 2641 while (((*options) == ',') || ((*options) == ':') 2642 || ((*options) == '=')) 2643 options++; 2644 } 2645 2646 while (options) { 2647 bn = 0; 2648 if ((next = strchr(options, ','))) { 2649 (*next) = '\0'; 2650 next++; 2651 } 2652 2653 if (!strncmp(options, "mode:", 5)) { 2654 options = pm3fb_boardnum_setup(options + 5, &bn); 2655 DPRINTK(2, "Setting mode for board #%ld\n", bn); 2656 pm3fb_mode_setup(options, bn); 2657 } else if (!strncmp(options, "off:", 4)) { 2658 options = pm3fb_boardnum_setup(options + 4, &bn); 2659 DPRINTK(2, "Disabling board #%ld\n", bn); 2660 disable[bn] = 1; 2661 } else if (!strncmp(options, "off", 3)) { /* disable everything */ 2662 for (i = 0; i < PM3_MAX_BOARD; i++) 2663 disable[i] = 1; 2664 } else if (!strncmp(options, "disable:", 8)) { 2665 options = pm3fb_boardnum_setup(options + 8, &bn); 2666 DPRINTK(2, "Disabling board #%ld\n", bn); 2667 disable[bn] = 1; 2668 } else if (!strncmp(options, "pciid:", 6)) { 2669 options = pm3fb_boardnum_setup(options + 6, &bn); 2670 DPRINTK(2, "Setting PciID for board #%ld\n", bn); 2671 pm3fb_pciid_setup(options, bn); 2672 } else if (!strncmp(options, "noaccel:", 8)) { 2673 options = pm3fb_boardnum_setup(options + 8, &bn); 2674 noaccel[bn] = 1; 2675 } else if (!strncmp(options, "font:", 5)) { 2676 options = pm3fb_boardnum_setup(options + 5, &bn); 2677 pm3fb_font_setup(options, bn); 2678 } else if (!strncmp(options, "depth:", 6)) { 2679 options = pm3fb_boardnum_setup(options + 6, &bn); 2680 pm3fb_bootdepth_setup(options, bn); 2681 } else if (!strncmp(options, "printtimings", 12)) { 2682 printtimings = 1; 2683 } else if (!strncmp(options, "flatpanel:", 10)) { 2684 options = pm3fb_boardnum_setup(options + 10, &bn); 2685 flatpanel[bn] = 1; 2686 } else if (!strncmp(options, "forcesize:", 10)) { 2687 options = pm3fb_boardnum_setup(options + 10, &bn); 2688 pm3fb_forcesize_setup(options, bn); 2689 } 2690 options = next; 2691 } 2692} 2693 2694/* ********************************************** */ 2695/* ***** framebuffer API standard functions ***** */ 2696/* ********************************************** */ 2697 2698static int pm3fb_encode_fix(struct fb_fix_screeninfo *fix, 2699 const void *par, struct fb_info_gen *info) 2700{ 2701 struct pm3fb_info *l_fb_info = (struct pm3fb_info *) info; 2702 struct pm3fb_par *p = (struct pm3fb_par *) par; 2703 2704 DTRACE; 2705 2706 strcpy(fix->id, permedia3_name); 2707 fix->smem_start = (unsigned long)l_fb_info->p_fb; 2708 fix->smem_len = l_fb_info->fb_size; 2709 fix->mmio_start = (unsigned long)l_fb_info->pIOBase; 2710 fix->mmio_len = PM3_REGS_SIZE; 2711#ifdef PM3FB_USE_ACCEL 2712 if (!(noaccel[l_fb_info->board_num])) 2713 fix->accel = FB_ACCEL_3DLABS_PERMEDIA3; 2714 else 2715#endif /* PM3FB_USE_ACCEL */ 2716 fix->accel = FB_ACCEL_NONE; 2717 fix->type = FB_TYPE_PACKED_PIXELS; 2718 fix->visual = 2719 (p->depth == 8) ? FB_VISUAL_PSEUDOCOLOR : FB_VISUAL_TRUECOLOR; 2720 if (current_par_valid[l_fb_info->board_num]) 2721 fix->line_length = 2722 l_fb_info->current_par->width * 2723 depth2ByPP(l_fb_info->current_par->depth); 2724 else 2725 fix->line_length = 0; 2726 fix->xpanstep = 64 / depth2bpp(p->depth); 2727 fix->ypanstep = 1; 2728 fix->ywrapstep = 0; 2729 return (0); 2730} 2731 2732static int pm3fb_decode_var(const struct fb_var_screeninfo *var, 2733 void *par, struct fb_info_gen *info) 2734{ 2735 struct pm3fb_info *l_fb_info = (struct pm3fb_info *) info; 2736 struct pm3fb_par *p = (struct pm3fb_par *) par; 2737 struct pm3fb_par temp_p; 2738 u32 xres; 2739 2740 DTRACE; 2741 2742 DASSERT((var != NULL), "fb_var_screeninfo* not NULL"); 2743 DASSERT((p != NULL), "pm3fb_par* not NULL"); 2744 DASSERT((l_fb_info != NULL), "pm3fb_info* not NULL"); 2745 2746 memset(&temp_p, 0, sizeof(struct pm3fb_par)); 2747 temp_p.width = (var->xres_virtual + 7) & ~7; 2748 temp_p.height = var->yres_virtual; 2749 2750 if (!(depth_supported(var->bits_per_pixel))) /* round unsupported up to a multiple of 8 */ 2751 temp_p.depth = depth2bpp(var->bits_per_pixel); 2752 else 2753 temp_p.depth = var->bits_per_pixel; 2754 2755 temp_p.depth = (temp_p.depth > 32) ? 32 : temp_p.depth; /* max 32 */ 2756 temp_p.depth = (temp_p.depth == 24) ? 32 : temp_p.depth; /* 24 unsupported, round-up to 32 */ 2757 2758 if ((temp_p.depth == 16) && (var->red.length == 5) && (var->green.length == 5) && (var->blue.length == 5)) 2759 temp_p.depth = 15; /* RGBA 5551 is stored as depth 15 */ 2760 2761 if ((temp_p.depth == 16) && (var->red.length == 4) && (var->green.length == 4) && (var->blue.length == 4)) 2762 temp_p.depth = 12; /* RGBA 4444 is stored as depth 12 */ 2763 2764 2765 DPRINTK(2, 2766 "xres: %d, yres: %d, vxres: %d, vyres: %d ; xoffset:%d, yoffset: %d\n", 2767 var->xres, var->yres, var->xres_virtual, var->yres_virtual, 2768 var->xoffset, var->yoffset); 2769 2770 xres = (var->xres + 31) & ~31; 2771 if (temp_p.width < xres + var->xoffset) 2772 temp_p.width = xres + var->xoffset; 2773 if (temp_p.height < var->yres + var->yoffset) 2774 temp_p.height = var->yres + var->yoffset; 2775 2776 if (temp_p.width > 2048) { 2777 DPRINTK(1, "virtual width not supported: %u\n", 2778 temp_p.width); 2779 return (-EINVAL); 2780 } 2781 if (var->yres < 200) { 2782 DPRINTK(1, "height not supported: %u\n", (u32) var->yres); 2783 return (-EINVAL); 2784 } 2785 if (temp_p.height < 200 || temp_p.height > 4095) { 2786 DPRINTK(1, "virtual height not supported: %u\n", 2787 temp_p.height); 2788 return (-EINVAL); 2789 } 2790 if (!(depth_supported(temp_p.depth))) { 2791 DPRINTK(1, "depth not supported: %u\n", temp_p.depth); 2792 return (-EINVAL); 2793 } 2794 if ((temp_p.width * temp_p.height * depth2ByPP(temp_p.depth)) > 2795 l_fb_info->fb_size) { 2796 DPRINTK(1, "no memory for screen (%ux%ux%u)\n", 2797 temp_p.width, temp_p.height, temp_p.depth); 2798 return (-EINVAL); 2799 } 2800 2801 if ((!var->pixclock) || 2802 (!var->right_margin) || 2803 (!var->hsync_len) || 2804 (!var->left_margin) || 2805 (!var->lower_margin) || 2806 (!var->vsync_len) || (!var->upper_margin) 2807 ) { 2808 unsigned long i = 0, done = 0; 2809 printk(KERN_WARNING "pm3fb: refusing to use a likely wrong timing\n"); 2810 2811 while ((mode_base[i].user_mode.width) && !done) { 2812 if ((mode_base[i].user_mode.width == temp_p.width) 2813 && (mode_base[i].user_mode.height == 2814 temp_p.height)) { 2815 printk(KERN_NOTICE "pm3fb: using close match %s\n", 2816 mode_base[i].name); 2817 temp_p = mode_base[i].user_mode; 2818 done = 1; 2819 } 2820 i++; 2821 } 2822 if (!done) 2823 return (-EINVAL); 2824 } else { 2825 temp_p.pixclock = PICOS2KHZ(var->pixclock); 2826 if (temp_p.pixclock > PM3_MAX_PIXCLOCK) { 2827 DPRINTK(1, "pixclock too high (%uKHz)\n", 2828 temp_p.pixclock); 2829 return (-EINVAL); 2830 } 2831 2832 temp_p.hsstart = var->right_margin; 2833 temp_p.hsend = var->right_margin + var->hsync_len; 2834 temp_p.hbend = 2835 var->right_margin + var->hsync_len + var->left_margin; 2836 temp_p.htotal = xres + temp_p.hbend; 2837 2838 temp_p.vsstart = var->lower_margin; 2839 temp_p.vsend = var->lower_margin + var->vsync_len; 2840 temp_p.vbend = 2841 var->lower_margin + var->vsync_len + var->upper_margin; 2842 temp_p.vtotal = var->yres + temp_p.vbend; 2843 2844 temp_p.stride = temp_p.width; 2845 2846 DPRINTK(2, "Using %d * %d, %d Khz, stride is %08x\n", 2847 temp_p.width, temp_p.height, temp_p.pixclock, 2848 temp_p.stride); 2849 2850 temp_p.base = 2851 pm3fb_Shiftbpp(l_fb_info, temp_p.depth, 2852 (var->yoffset * xres) + var->xoffset); 2853 2854 temp_p.video = 0; 2855 2856 if (var->sync & FB_SYNC_HOR_HIGH_ACT) 2857 temp_p.video |= PM3VideoControl_HSYNC_ACTIVE_HIGH; 2858 else 2859 temp_p.video |= PM3VideoControl_HSYNC_ACTIVE_LOW; 2860 2861 if (var->sync & FB_SYNC_VERT_HIGH_ACT) 2862 temp_p.video |= PM3VideoControl_VSYNC_ACTIVE_HIGH; 2863 else 2864 temp_p.video |= PM3VideoControl_VSYNC_ACTIVE_LOW; 2865 2866 if ((var->vmode & FB_VMODE_MASK) == FB_VMODE_INTERLACED) { 2867 DPRINTK(1, "Interlaced mode not supported\n\n"); 2868 return (-EINVAL); 2869 } 2870 2871 if ((var->vmode & FB_VMODE_MASK) == FB_VMODE_DOUBLE) 2872 temp_p.video |= PM3VideoControl_LINE_DOUBLE_ON; 2873 else 2874 temp_p.video |= PM3VideoControl_LINE_DOUBLE_OFF; 2875 2876 if (var->activate == FB_ACTIVATE_NOW) 2877 temp_p.video |= PM3VideoControl_ENABLE; 2878 else { 2879 temp_p.video |= PM3VideoControl_DISABLE; 2880 DPRINTK(2, "PM3Video disabled\n"); 2881 } 2882 2883 switch (temp_p.depth) { 2884 case 8: 2885 temp_p.video |= PM3VideoControl_PIXELSIZE_8BIT; 2886 break; 2887 case 12: 2888 case 15: 2889 case 16: 2890 temp_p.video |= PM3VideoControl_PIXELSIZE_16BIT; 2891 break; 2892 case 32: 2893 temp_p.video |= PM3VideoControl_PIXELSIZE_32BIT; 2894 break; 2895 default: 2896 DPRINTK(1, "Unsupported depth\n"); 2897 break; 2898 } 2899 } 2900 (*p) = temp_p; 2901 2902#ifdef PM3FB_USE_ACCEL 2903 if (var->accel_flags & FB_ACCELF_TEXT) 2904 noaccel[l_fb_info->board_num] = 0; 2905 else 2906 noaccel[l_fb_info->board_num] = 1; 2907#endif /* PM3FB_USE_ACCEL */ 2908 2909 return (0); 2910} 2911 2912static void pm3fb_encode_depth(struct fb_var_screeninfo *var, long d) 2913{ 2914 switch (d) { 2915 case 8: 2916 var->red.length = var->green.length = var->blue.length = 8; 2917 var->red.offset = var->green.offset = var->blue.offset = 0; 2918 var->transp.offset = var->transp.length = 0; 2919 break; 2920 2921 case 12: 2922 var->red.offset = 8; 2923 var->red.length = 4; 2924 var->green.offset = 4; 2925 var->green.length = 4; 2926 var->blue.offset = 0; 2927 var->blue.length = 4; 2928 var->transp.offset = 12; 2929 var->transp.length = 4; 2930 break; 2931 2932 case 15: 2933 var->red.offset = 10; 2934 var->red.length = 5; 2935 var->green.offset = 5; 2936 var->green.length = 5; 2937 var->blue.offset = 0; 2938 var->blue.length = 5; 2939 var->transp.offset = 15; 2940 var->transp.length = 1; 2941 break; 2942 2943 case 16: 2944 var->red.offset = 11; 2945 var->red.length = 5; 2946 var->green.offset = 5; 2947 var->green.length = 6; 2948 var->blue.offset = 0; 2949 var->blue.length = 5; 2950 var->transp.offset = var->transp.length = 0; 2951 break; 2952 2953 case 32: 2954 var->transp.offset = 24; 2955 var->red.offset = 16; 2956 var->green.offset = 8; 2957 var->blue.offset = 0; 2958 var->red.length = var->green.length = 2959 var->blue.length = var->transp.length = 8; 2960 break; 2961 2962 default: 2963 DPRINTK(1, "Unsupported depth %ld\n", d); 2964 break; 2965 } 2966} 2967 2968static int pm3fb_encode_var(struct fb_var_screeninfo *var, 2969 const void *par, struct fb_info_gen *info) 2970{ 2971 struct pm3fb_par *p = (struct pm3fb_par *) par; 2972 struct pm3fb_info *l_fb_info = (struct pm3fb_info *) info; 2973 2974 u32 base; 2975 2976 DTRACE; 2977 2978 DASSERT((var != NULL), "fb_var_screeninfo* not NULL"); 2979 DASSERT((p != NULL), "pm3fb_par* not NULL"); 2980 DASSERT((info != NULL), "fb_info_gen* not NULL"); 2981 2982 memset(var, 0, sizeof(struct fb_var_screeninfo)); 2983 2984#ifdef PM3FB_USE_ACCEL 2985 if (!(noaccel[l_fb_info->board_num])) 2986 var->accel_flags |= FB_ACCELF_TEXT; 2987#endif /* PM3FB_USE_ACCEL */ 2988 2989 var->xres_virtual = p->width; 2990 var->yres_virtual = p->height; 2991 var->xres = p->htotal - p->hbend; 2992 var->yres = p->vtotal - p->vbend; 2993 2994 DPRINTK(2, "xres = %d, yres : %d\n", var->xres, var->yres); 2995 2996 var->right_margin = p->hsstart; 2997 var->hsync_len = p->hsend - p->hsstart; 2998 var->left_margin = p->hbend - p->hsend; 2999 var->lower_margin = p->vsstart; 3000 var->vsync_len = p->vsend - p->vsstart; 3001 var->upper_margin = p->vbend - p->vsend; 3002 var->bits_per_pixel = depth2bpp(p->depth); 3003 3004 pm3fb_encode_depth(var, p->depth); 3005 3006 base = pm3fb_Unshiftbpp(l_fb_info, p->depth, p->base); 3007 3008 var->xoffset = base % var->xres; 3009 var->yoffset = base / var->xres; 3010 3011 var->height = var->width = -1; 3012 3013 var->pixclock = KHZ2PICOS(p->pixclock); 3014 3015 if ((p->video & PM3VideoControl_HSYNC_MASK) == 3016 PM3VideoControl_HSYNC_ACTIVE_HIGH) 3017 var->sync |= FB_SYNC_HOR_HIGH_ACT; 3018 if ((p->video & PM3VideoControl_VSYNC_MASK) == 3019 PM3VideoControl_VSYNC_ACTIVE_HIGH) 3020 var->sync |= FB_SYNC_VERT_HIGH_ACT; 3021 if (p->video & PM3VideoControl_LINE_DOUBLE_ON) 3022 var->vmode = FB_VMODE_DOUBLE; 3023 3024 return (0); 3025} 3026 3027static void pm3fb_get_par(void *par, struct fb_info_gen *info) 3028{ 3029 struct pm3fb_info *l_fb_info = (struct pm3fb_info *) info; 3030 3031 DTRACE; 3032 3033 if (!current_par_valid[l_fb_info->board_num]) { 3034 if (l_fb_info->use_current) 3035 pm3fb_read_mode(l_fb_info, l_fb_info->current_par); 3036 else 3037 memcpy(l_fb_info->current_par, 3038 &(mode_base[0].user_mode), 3039 sizeof(struct pm3fb_par)); 3040 current_par_valid[l_fb_info->board_num] = 1; 3041 } 3042 *((struct pm3fb_par *) par) = *(l_fb_info->current_par); 3043} 3044 3045static void pm3fb_set_par(const void *par, struct fb_info_gen *info) 3046{ 3047 struct pm3fb_info *l_fb_info = (struct pm3fb_info *) info; 3048 3049 DTRACE; 3050 3051 *(l_fb_info->current_par) = *((struct pm3fb_par *) par); 3052 current_par_valid[l_fb_info->board_num] = 1; 3053 3054 pm3fb_write_mode(l_fb_info); 3055 3056#ifdef PM3FB_USE_ACCEL 3057 pm3fb_init_engine(l_fb_info); 3058#endif /* PM3FB_USE_ACCEL */ 3059} 3060 3061static void pm3fb_set_color(struct pm3fb_info *l_fb_info, 3062 unsigned char regno, unsigned char r, 3063 unsigned char g, unsigned char b) 3064{ 3065 DTRACE; 3066 3067 PM3_SLOW_WRITE_REG(PM3RD_PaletteWriteAddress, regno); 3068 PM3_SLOW_WRITE_REG(PM3RD_PaletteData, r); 3069 PM3_SLOW_WRITE_REG(PM3RD_PaletteData, g); 3070 PM3_SLOW_WRITE_REG(PM3RD_PaletteData, b); 3071} 3072 3073static int pm3fb_getcolreg(unsigned regno, unsigned *red, unsigned *green, 3074 unsigned *blue, unsigned *transp, 3075 struct fb_info *info) 3076{ 3077 struct pm3fb_info *l_fb_info = (struct pm3fb_info *) info; 3078 3079 DTRACE; 3080 3081 if (regno < 256) { 3082 *red = 3083 l_fb_info->palette[regno].red << 8 | l_fb_info-> 3084 palette[regno].red; 3085 *green = 3086 l_fb_info->palette[regno].green << 8 | l_fb_info-> 3087 palette[regno].green; 3088 *blue = 3089 l_fb_info->palette[regno].blue << 8 | l_fb_info-> 3090 palette[regno].blue; 3091 *transp = 3092 l_fb_info->palette[regno].transp << 8 | l_fb_info-> 3093 palette[regno].transp; 3094 } 3095 return (regno > 255); 3096} 3097 3098static int pm3fb_setcolreg(unsigned regno, unsigned red, unsigned green, 3099 unsigned blue, unsigned transp, 3100 struct fb_info *info) 3101{ 3102 struct pm3fb_info *l_fb_info = (struct pm3fb_info *) info; 3103 3104 DTRACE; 3105 3106 if (regno < 16) { 3107 switch (l_fb_info->current_par->depth) { 3108#ifdef FBCON_HAS_CFB8 3109 case 8: 3110 break; 3111#endif 3112#ifdef FBCON_HAS_CFB16 3113 case 12: 3114 l_fb_info->cmap.cmap12[regno] = 3115 (((u32) red & 0xf000) >> 4) | 3116 (((u32) green & 0xf000) >> 8) | 3117 (((u32) blue & 0xf000) >> 12); 3118 break; 3119 3120 case 15: 3121 l_fb_info->cmap.cmap15[regno] = 3122 (((u32) red & 0xf800) >> 1) | 3123 (((u32) green & 0xf800) >> 6) | 3124 (((u32) blue & 0xf800) >> 11); 3125 break; 3126 3127 case 16: 3128 l_fb_info->cmap.cmap16[regno] = 3129 ((u32) red & 0xf800) | 3130 (((u32) green & 0xfc00) >> 5) | 3131 (((u32) blue & 0xf800) >> 11); 3132 break; 3133#endif 3134#ifdef FBCON_HAS_CFB32 3135 case 32: 3136 l_fb_info->cmap.cmap32[regno] = 3137 (((u32) transp & 0xff00) << 16) | 3138 (((u32) red & 0xff00) << 8) | 3139 (((u32) green & 0xff00)) | 3140 (((u32) blue & 0xff00) >> 8); 3141 break; 3142#endif 3143 default: 3144 DPRINTK(1, "bad depth %u\n", 3145 l_fb_info->current_par->depth); 3146 break; 3147 } 3148 } 3149 if (regno < 256) { 3150 l_fb_info->palette[regno].red = red >> 8; 3151 l_fb_info->palette[regno].green = green >> 8; 3152 l_fb_info->palette[regno].blue = blue >> 8; 3153 l_fb_info->palette[regno].transp = transp >> 8; 3154 if (l_fb_info->current_par->depth == 8) 3155 pm3fb_set_color(l_fb_info, regno, red >> 8, 3156 green >> 8, blue >> 8); 3157 } 3158 return (regno > 255); 3159} 3160 3161static int pm3fb_blank(int blank_mode, struct fb_info_gen *info) 3162{ 3163 struct pm3fb_info *l_fb_info = (struct pm3fb_info *) info; 3164 u32 video; 3165 3166 DTRACE; 3167 3168 if (!current_par_valid[l_fb_info->board_num]) 3169 return (1); 3170 3171 video = l_fb_info->current_par->video; 3172 3173 /* 3174 * Oxygen VX1 - it appears that setting PM3VideoControl and 3175 * then PM3RD_SyncControl to the same SYNC settings undoes 3176 * any net change - they seem to xor together. Only set the 3177 * sync options in PM3RD_SyncControl. --rmk 3178 */ 3179 video &= ~(PM3VideoControl_HSYNC_MASK | 3180 PM3VideoControl_VSYNC_MASK); 3181 video |= PM3VideoControl_HSYNC_ACTIVE_HIGH | 3182 PM3VideoControl_VSYNC_ACTIVE_HIGH; 3183 3184 if (blank_mode > 0) { 3185 switch (blank_mode - 1) { 3186 3187 case VESA_NO_BLANKING: /* FIXME */ 3188 video = video & ~(PM3VideoControl_ENABLE); 3189 break; 3190 3191 case VESA_HSYNC_SUSPEND: 3192 video = video & ~(PM3VideoControl_HSYNC_MASK | 3193 PM3VideoControl_BLANK_ACTIVE_LOW); 3194 break; 3195 case VESA_VSYNC_SUSPEND: 3196 video = video & ~(PM3VideoControl_VSYNC_MASK | 3197 PM3VideoControl_BLANK_ACTIVE_LOW); 3198 break; 3199 case VESA_POWERDOWN: 3200 video = video & ~(PM3VideoControl_HSYNC_MASK | 3201 PM3VideoControl_VSYNC_MASK | 3202 PM3VideoControl_BLANK_ACTIVE_LOW); 3203 break; 3204 default: 3205 DPRINTK(1, "Unsupported blanking %d\n", 3206 blank_mode); 3207 return (1); 3208 break; 3209 } 3210 } 3211 3212 PM3_SLOW_WRITE_REG(PM3VideoControl, video); 3213 3214 return (0); 3215} 3216 3217static void pm3fb_set_disp(const void *par, struct display *disp, 3218 struct fb_info_gen *info) 3219{ 3220 struct pm3fb_info *l_fb_info = (struct pm3fb_info *) info; 3221 struct pm3fb_par *p = (struct pm3fb_par *) par; 3222 u32 flags; 3223 3224 DTRACE; 3225 3226 local_irq_save(flags); 3227 info->info.screen_base = l_fb_info->v_fb; 3228 switch (p->depth) { 3229#ifdef FBCON_HAS_CFB8 3230 case 8: 3231#ifdef PM3FB_USE_ACCEL 3232 if (!(noaccel[l_fb_info->board_num])) 3233 disp->dispsw = &pm3fb_cfb8; 3234 else 3235#endif /* PM3FB_USE_ACCEL */ 3236 disp->dispsw = &fbcon_cfb8; 3237 break; 3238#endif 3239#ifdef FBCON_HAS_CFB16 3240 case 12: 3241#ifdef PM3FB_USE_ACCEL 3242 if (!(noaccel[l_fb_info->board_num])) 3243 disp->dispsw = &pm3fb_cfb16; 3244 else 3245#endif /* PM3FB_USE_ACCEL */ 3246 disp->dispsw = &fbcon_cfb16; 3247 disp->dispsw_data = l_fb_info->cmap.cmap12; 3248 break; 3249 case 15: 3250#ifdef PM3FB_USE_ACCEL 3251 if (!(noaccel[l_fb_info->board_num])) 3252 disp->dispsw = &pm3fb_cfb16; 3253 else 3254#endif /* PM3FB_USE_ACCEL */ 3255 disp->dispsw = &fbcon_cfb16; 3256 disp->dispsw_data = l_fb_info->cmap.cmap15; 3257 break; 3258 case 16: 3259#ifdef PM3FB_USE_ACCEL 3260 if (!(noaccel[l_fb_info->board_num])) 3261 disp->dispsw = &pm3fb_cfb16; 3262 else 3263#endif /* PM3FB_USE_ACCEL */ 3264 disp->dispsw = &fbcon_cfb16; 3265 disp->dispsw_data = l_fb_info->cmap.cmap16; 3266 break; 3267#endif 3268#ifdef FBCON_HAS_CFB32 3269 case 32: 3270#ifdef PM3FB_USE_ACCEL 3271 if (!(noaccel[l_fb_info->board_num])) 3272 disp->dispsw = &pm3fb_cfb32; 3273 else 3274#endif /* PM3FB_USE_ACCEL */ 3275 disp->dispsw = &fbcon_cfb32; 3276 disp->dispsw_data = l_fb_info->cmap.cmap32; 3277 break; 3278#endif /* FBCON_HAS_CFB32 */ 3279 default: 3280 disp->dispsw = &fbcon_dummy; 3281 DPRINTK(1, "Invalid depth, using fbcon_dummy\n"); 3282 break; 3283 } 3284 local_irq_restore(flags); 3285} 3286 3287/* */ 3288static void pm3fb_detect(void) 3289{ 3290 struct pci_dev *dev_array[PM3_MAX_BOARD]; 3291 struct pci_dev *dev = NULL; 3292 struct pm3fb_info *l_fb_info = &(fb_info[0]); 3293 unsigned long i, j, done; 3294 3295 DTRACE; 3296 3297 for (i = 0; i < PM3_MAX_BOARD; i++) { 3298 dev_array[i] = NULL; 3299 fb_info[i].dev = NULL; 3300 } 3301 3302 dev = 3303 pci_find_device(PCI_VENDOR_ID_3DLABS, 3304 PCI_DEVICE_ID_3DLABS_PERMEDIA3, dev); 3305 3306 for (i = 0; ((i < PM3_MAX_BOARD) && dev); i++) { 3307 dev_array[i] = dev; 3308 dev = 3309 pci_find_device(PCI_VENDOR_ID_3DLABS, 3310 PCI_DEVICE_ID_3DLABS_PERMEDIA3, dev); 3311 } 3312 3313 if (dev) { /* more than PM3_MAX_BOARD */ 3314 printk(KERN_WARNING "pm3fb: Warning: more than %d boards found\n", 3315 PM3_MAX_BOARD); 3316 } 3317 3318 if (!dev_array[0]) { /* not a single board, abort */ 3319 return; 3320 } 3321 3322 /* allocate user-defined boards */ 3323 for (i = 0; i < PM3_MAX_BOARD; i++) { 3324 if ((bus[i] >= 0) && (slot[i] >= 0) && (func[i] >= 0)) { 3325 for (j = 0; j < PM3_MAX_BOARD; j++) { 3326 if ((dev_array[j] != NULL) && 3327 (dev_array[j]->bus->number == bus[i]) 3328 && (PCI_SLOT(dev_array[j]->devfn) == 3329 slot[i]) 3330 && (PCI_FUNC(dev_array[j]->devfn) == 3331 func[i])) { 3332 fb_info[i].dev = dev_array[j]; 3333 dev_array[j] = NULL; 3334 } 3335 } 3336 } 3337 } 3338 /* allocate remaining boards */ 3339 for (i = 0; i < PM3_MAX_BOARD; i++) { 3340 if (fb_info[i].dev == NULL) { 3341 done = 0; 3342 for (j = 0; ((j < PM3_MAX_BOARD) && (!done)); j++) { 3343 if (dev_array[j] != NULL) { 3344 fb_info[i].dev = dev_array[j]; 3345 dev_array[j] = NULL; 3346 done = 1; 3347 } 3348 } 3349 } 3350 } 3351 3352 /* at that point, all PCI Permedia3 are detected and allocated */ 3353 /* now, initialize... or not */ 3354 for (i = 0; i < PM3_MAX_BOARD; i++) { 3355 l_fb_info = &(fb_info[i]); 3356 if ((l_fb_info->dev) && (!disable[i])) { /* PCI device was found and not disabled by user */ 3357 DPRINTK(2, 3358 "found @%lx Vendor %lx Device %lx ; base @ : %lx - %lx - %lx - %lx - %lx - %lx, irq %ld\n", 3359 (unsigned long) l_fb_info->dev, 3360 (unsigned long) l_fb_info->dev->vendor, 3361 (unsigned long) l_fb_info->dev->device, 3362 (unsigned long) 3363 pci_resource_start(l_fb_info->dev, 0), 3364 (unsigned long) 3365 pci_resource_start(l_fb_info->dev, 1), 3366 (unsigned long) 3367 pci_resource_start(l_fb_info->dev, 2), 3368 (unsigned long) 3369 pci_resource_start(l_fb_info->dev, 3), 3370 (unsigned long) 3371 pci_resource_start(l_fb_info->dev, 4), 3372 (unsigned long) 3373 pci_resource_start(l_fb_info->dev, 5), 3374 (unsigned long) l_fb_info->dev->irq); 3375 3376 l_fb_info->pIOBase = 3377 (unsigned char *) 3378 pci_resource_start(l_fb_info->dev, 0); 3379#ifdef __BIG_ENDIAN 3380 l_fb_info->pIOBase += PM3_REGS_SIZE; 3381#endif 3382 l_fb_info->vIOBase = (unsigned char *) -1; 3383 l_fb_info->p_fb = 3384 (unsigned char *) 3385 pci_resource_start(l_fb_info->dev, 1); 3386 l_fb_info->v_fb = (unsigned char *) -1; 3387 3388 if (!request_mem_region 3389 ((unsigned long)l_fb_info->p_fb, 64 * 1024 * 1024, /* request full aperture size */ 3390 "pm3fb")) { 3391 printk 3392 (KERN_ERR "pm3fb: Error: couldn't request framebuffer memory, board #%ld\n", 3393 l_fb_info->board_num); 3394 continue; 3395 } 3396 if (!request_mem_region 3397 ((unsigned long)l_fb_info->pIOBase, PM3_REGS_SIZE, 3398 "pm3fb I/O regs")) { 3399 printk 3400 (KERN_ERR "pm3fb: Error: couldn't request IObase memory, board #%ld\n", 3401 l_fb_info->board_num); 3402 continue; 3403 } 3404 if (forcesize[l_fb_info->board_num]) 3405 l_fb_info->fb_size = forcesize[l_fb_info->board_num]; 3406 3407 l_fb_info->fb_size = 3408 pm3fb_size_memory(l_fb_info); 3409 if (l_fb_info->fb_size) { 3410 (void) pci_enable_device(l_fb_info->dev); 3411 pm3fb_common_init(l_fb_info); 3412 } else 3413 printk(KERN_ERR "pm3fb: memory problem, not enabling board #%ld\n", l_fb_info->board_num); 3414 } 3415 } 3416} 3417 3418static int pm3fb_pan_display(const struct fb_var_screeninfo *var, 3419 struct fb_info_gen *info) 3420{ 3421 struct pm3fb_info *l_fb_info = (struct pm3fb_info *) info; 3422 3423 DTRACE; 3424 3425 if (!current_par_valid[l_fb_info->board_num]) 3426 return -EINVAL; 3427 3428 l_fb_info->current_par->base = /* in 128 bits chunk - i.e. AFTER Shiftbpp */ 3429 pm3fb_Shiftbpp(l_fb_info, 3430 l_fb_info->current_par->depth, 3431 (var->yoffset * l_fb_info->current_par->width) + 3432 var->xoffset); 3433 PM3_SLOW_WRITE_REG(PM3ScreenBase, l_fb_info->current_par->base); 3434 return 0; 3435} 3436 3437static int pm3fb_ioctl(struct fb_info *info, u_int cmd, u_long arg) 3438{ 3439 struct pm3fb_info *l_fb_info = (struct pm3fb_info *) info; 3440 u32 cm, i; 3441#ifdef PM3FB_MASTER_DEBUG 3442 char cc[3]; 3443#endif /* PM3FB_MASTER_DEBUG */ 3444 3445 switch(cmd) 3446 { 3447#ifdef PM3FB_MASTER_DEBUG 3448 case PM3FBIO_CLEARMEMORY: 3449 if (copy_from_user(&cm, (void *)arg, sizeof(u32))) 3450 return(-EFAULT); 3451 pm3fb_clear_memory(l_fb_info, cm); 3452 return(0); 3453 break; 3454 3455 case PM3FBIO_CLEARCMAP: 3456 if (copy_from_user(cc, (void*)arg, 3 * sizeof(char))) 3457 return(-EFAULT); 3458 pm3fb_clear_colormap(l_fb_info, cc[0], cc[1], cc[2]); 3459 return(0); 3460 break; 3461#endif /* PM3FB_MASTER_DEBUG */ 3462 3463 case PM3FBIO_RESETCHIP: 3464 cm = 1; 3465 PM3_SLOW_WRITE_REG(PM3ResetStatus, 1); 3466 for (i = 0 ; (i < 10000) && cm ; i++) 3467 { 3468 PM3_DELAY(10); 3469 cm = PM3_READ_REG(PM3ResetStatus); 3470 } 3471 if (cm) 3472 { 3473 printk(KERN_ERR "pm3fb: chip reset failed with status 0x%x\n", cm); 3474 return(-EIO); 3475 } 3476 /* first thing first, reload memory timings */ 3477 pm3fb_write_memory_timings(l_fb_info); 3478#ifdef PM3FB_USE_ACCEL 3479 pm3fb_init_engine(l_fb_info); 3480#endif /* PM3FB_USE_ACCEL */ 3481 pm3fb_write_mode(l_fb_info); 3482 return(0); 3483 break; 3484 3485 default: 3486 DPRINTK(2, "unknown ioctl: %d (%x)\n", cmd, cmd); 3487 return(-EINVAL); 3488 } 3489} 3490 3491/* ****************************************** */ 3492/* ***** standard FB API init functions ***** */ 3493/* ****************************************** */ 3494 3495int __init pm3fb_setup(char *options) 3496{ 3497 long opsi = strlen(options); 3498 3499 DTRACE; 3500 3501 memcpy(g_options, options, 3502 ((opsi + 1) > 3503 PM3_OPTIONS_SIZE) ? PM3_OPTIONS_SIZE : (opsi + 1)); 3504 g_options[PM3_OPTIONS_SIZE - 1] = 0; 3505 3506 return (0); 3507} 3508 3509int __init pm3fb_init(void) 3510{ 3511 DTRACE; 3512 3513 DPRINTK(2, "This is pm3fb.c, CVS version: $Header: /cvsroot/linux/drivers/video/pm3fb.c,v 1.1 2002/02/25 19:11:06 marcelo Exp $"); 3514 3515 pm3fb_real_setup(g_options); 3516 3517 pm3fb_detect(); 3518 3519 if (!fb_info[0].dev) { /* not even one board ??? */ 3520 DPRINTK(1, "No PCI Permedia3 board detected\n"); 3521 } 3522 return (0); 3523} 3524 3525/* ************************* */ 3526/* **** Module support ***** */ 3527/* ************************* */ 3528 3529#ifdef MODULE 3530MODULE_AUTHOR("Romain Dolbeau"); 3531MODULE_DESCRIPTION("Permedia3 framebuffer device driver"); 3532static char *mode[PM3_MAX_BOARD]; 3533module_param_array(mode, charp, NULL, 0); 3534MODULE_PARM_DESC(mode,"video mode"); 3535module_param_array(disable, short, NULL, 0); 3536MODULE_PARM_DESC(disable,"disable board"); 3537static short off[PM3_MAX_BOARD]; 3538module_param_array(off, short, NULL, 0); 3539MODULE_PARM_DESC(off,"disable board"); 3540static char *pciid[PM3_MAX_BOARD]; 3541module_param_array(pciid, charp, NULL, 0); 3542MODULE_PARM_DESC(pciid,"board PCI Id"); 3543module_param_array(noaccel, short, NULL, 0); 3544MODULE_PARM_DESC(noaccel,"disable accel"); 3545static char *font[PM3_MAX_BOARD]; 3546module_param_array(font, charp, NULL, 0); 3547MODULE_PARM_DESC(font,"choose font"); 3548module_param(depth, short, NULL, 0); 3549MODULE_PARM_DESC(depth,"boot-time depth"); 3550module_param(printtimings, short, NULL, 0); 3551MODULE_PARM_DESC(printtimings, "print the memory timings of the card(s)"); 3552module_param(forcesize, short, NULL, 0); 3553MODULE_PARM_DESC(forcesize, "force specified memory size"); 3554/* 3555MODULE_SUPPORTED_DEVICE("Permedia3 PCI boards") 3556MODULE_GENERIC_TABLE(gtype,name) 3557MODULE_DEVICE_TABLE(type,name) 3558*/ 3559 3560void pm3fb_build_options(void) 3561{ 3562 int i; 3563 char ts[128]; 3564 3565 strcpy(g_options, "pm3fb"); 3566 for (i = 0; i < PM3_MAX_BOARD ; i++) 3567 { 3568 if (mode[i]) 3569 { 3570 sprintf(ts, ",mode:%d:%s", i, mode[i]); 3571 strncat(g_options, ts, PM3_OPTIONS_SIZE - strlen(g_options)); 3572 } 3573 if (disable[i] || off[i]) 3574 { 3575 sprintf(ts, ",disable:%d:", i); 3576 strncat(g_options, ts, PM3_OPTIONS_SIZE - strlen(g_options)); 3577 } 3578 if (pciid[i]) 3579 { 3580 sprintf(ts, ",pciid:%d:%s", i, pciid[i]); 3581 strncat(g_options, ts, PM3_OPTIONS_SIZE - strlen(g_options)); 3582 } 3583 if (noaccel[i]) 3584 { 3585 sprintf(ts, ",noaccel:%d:", i); 3586 strncat(g_options, ts, PM3_OPTIONS_SIZE - strlen(g_options)); 3587 } 3588 if (font[i]) 3589 { 3590 sprintf(ts, ",font:%d:%s", i, font[i]); 3591 strncat(g_options, ts, PM3_OPTIONS_SIZE - strlen(g_options)); 3592 } 3593 if (depth[i]) 3594 { 3595 sprintf(ts, ",depth:%d:%d", i, depth[i]); 3596 strncat(g_options, ts, PM3_OPTIONS_SIZE - strlen(g_options)); 3597 } 3598 } 3599 g_options[PM3_OPTIONS_SIZE - 1] = '\0'; 3600 DPRINTK(1, "pm3fb use options: %s\n", g_options); 3601} 3602 3603int init_module(void) 3604{ 3605 DTRACE; 3606 3607 pm3fb_build_options(); 3608 3609 pm3fb_init(); 3610 3611 return (0); 3612} 3613 3614void cleanup_module(void) 3615{ 3616 DTRACE; 3617 { 3618 unsigned long i; 3619 struct pm3fb_info *l_fb_info; 3620 for (i = 0; i < PM3_MAX_BOARD; i++) { 3621 l_fb_info = &(fb_info[i]); 3622 if ((l_fb_info->dev != NULL) 3623 && (!(disable[l_fb_info->board_num]))) { 3624 if (l_fb_info->vIOBase != 3625 (unsigned char *) -1) { 3626 pm3fb_unmapIO(l_fb_info); 3627 release_mem_region(l_fb_info->p_fb, 3628 l_fb_info-> 3629 fb_size); 3630 release_mem_region(l_fb_info-> 3631 pIOBase, 3632 PM3_REGS_SIZE); 3633 } 3634 unregister_framebuffer(&l_fb_info->gen. 3635 info); 3636 } 3637 } 3638 } 3639 return; 3640} 3641#endif /* MODULE */