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