1/* 2 * Permedia2 framebuffer driver. 3 * Copyright (c) 1998-1999 Ilario Nardinocchi (nardinoc@CS.UniBO.IT) 4 * Copyright (c) 1999 Jakub Jelinek (jakub@redhat.com) 5 * Based on linux/drivers/video/skeletonfb.c by Geert Uytterhoeven. 6 * -------------------------------------------------------------------------- 7 * $Id: pm2fb.c,v 1.1.1.1 2008/10/15 03:27:04 james26_jang Exp $ 8 * -------------------------------------------------------------------------- 9 * TODO multiple boards support 10 * -------------------------------------------------------------------------- 11 * This file is subject to the terms and conditions of the GNU General Public 12 * License. See the file COPYING in the main directory of this archive 13 * for more details. 14 */ 15 16#include <linux/config.h> 17#include <linux/module.h> 18#include <linux/kernel.h> 19#include <linux/errno.h> 20#include <linux/string.h> 21#include <linux/mm.h> 22#include <linux/tty.h> 23#include <linux/slab.h> 24#include <linux/vmalloc.h> 25#include <linux/delay.h> 26#include <linux/interrupt.h> 27#include <linux/fb.h> 28#include <linux/selection.h> 29#include <linux/console.h> 30#include <linux/init.h> 31#include <linux/pci.h> 32#include <asm/system.h> 33#include <asm/io.h> 34#include <asm/uaccess.h> 35#include <video/fbcon.h> 36#include <video/fbcon-cfb8.h> 37#include <video/fbcon-cfb16.h> 38#include <video/fbcon-cfb24.h> 39#include <video/fbcon-cfb32.h> 40#include "pm2fb.h" 41#include "cvisionppc.h" 42#ifdef __sparc__ 43#include <asm/pbm.h> 44#include <asm/fbio.h> 45#endif 46 47#if !defined(__LITTLE_ENDIAN) && !defined(__BIG_ENDIAN) 48#error "The endianness of the target host has not been defined." 49#endif 50 51#if defined(__BIG_ENDIAN) && !defined(__sparc__) 52#define PM2FB_BE_APERTURE 53#endif 54 55/* Need to debug this some more */ 56#undef PM2FB_HW_CURSOR 57 58#if defined(CONFIG_FB_PM2_PCI) && !defined(CONFIG_PCI) 59#undef CONFIG_FB_PM2_PCI 60#warning "support for Permedia2 PCI boards with no generic PCI support!" 61#endif 62 63#undef PM2FB_MASTER_DEBUG 64#ifdef PM2FB_MASTER_DEBUG 65#define DPRINTK(a,b...) printk(KERN_DEBUG "pm2fb: %s: " a, __FUNCTION__ , ## b) 66#else 67#define DPRINTK(a,b...) 68#endif 69 70#define PICOS2KHZ(a) (1000000000UL/(a)) 71#define KHZ2PICOS(a) (1000000000UL/(a)) 72 73/* 74 * The _DEFINITIVE_ memory mapping/unmapping functions. 75 * This is due to the fact that they're changing soooo often... 76 */ 77#define MMAP(a,b) ioremap((unsigned long )(a), b) 78#define UNMAP(a,b) iounmap(a) 79 80/* 81 * The _DEFINITIVE_ memory i/o barrier functions. 82 * This is due to the fact that they're changing soooo often... 83 */ 84#define DEFW() wmb() 85#define DEFR() rmb() 86#define DEFRW() mb() 87 88#ifndef MIN 89#define MIN(a,b) ((a)<(b)?(a):(b)) 90#endif 91 92#ifndef MAX 93#define MAX(a,b) ((a)>(b)?(a):(b)) 94#endif 95 96struct pm2fb_par { 97 u32 pixclock; /* pixclock in KHz */ 98 u32 width; /* width of virtual screen */ 99 u32 height; /* height of virtual screen */ 100 u32 hsstart; /* horiz. sync start */ 101 u32 hsend; /* horiz. sync end */ 102 u32 hbend; /* horiz. blank end (also gate end) */ 103 u32 htotal; /* total width (w/ sync & blank) */ 104 u32 vsstart; /* vert. sync start */ 105 u32 vsend; /* vert. sync end */ 106 u32 vbend; /* vert. blank end */ 107 u32 vtotal; /* total height (w/ sync & blank) */ 108 u32 stride; /* screen stride */ 109 u32 base; /* screen base (xoffset+yoffset) */ 110 u32 depth; /* screen depth (8, 16, 24 or 32) */ 111 u32 video; /* video control (hsync,vsync) */ 112}; 113 114#define OPTF_OLD_MEM (1L<<0) 115#define OPTF_YPAN (1L<<1) 116#define OPTF_VIRTUAL (1L<<2) 117#define OPTF_USER (1L<<3) 118static struct { 119 char font[40]; 120 u32 flags; 121 struct pm2fb_par user_mode; 122} pm2fb_options = 123#ifdef __sparc__ 124 /* For some reason Raptor is not happy with the low-end mode */ 125 {"\0", 0L, {31499,640,480,4,20,50,209,0,3,20,499,80,0,8,121}}; 126#else 127 {"\0", 0L, {25174,640,480,4,28,40,199,9,11,45,524,80,0,8,121}}; 128#endif 129 130static char curblink __initdata = 1; 131 132static struct { 133 char name[16]; 134 struct pm2fb_par par; 135} user_mode[] __initdata = { 136 {"640x480-60", 137 {25174,640,480,4,28,40,199,9,11,45,524,80,0,8,121}}, 138 {"640x480-72", 139 {31199,640,480,6,16,48,207,8,10,39,518,80,0,8,121}}, 140 {"640x480-75", 141 {31499,640,480,4,20,50,209,0,3,20,499,80,0,8,121}}, 142 {"640x480-90", 143 {39909,640,480,8,18,48,207,24,38,53,532,80,0,8,121}}, 144 {"640x480-100", 145 {44899,640,480,8,40,52,211,21,33,51,530,80,0,8,121}}, 146 {"800x600-56", 147 {35999,800,600,6,24,56,255,0,2,25,624,100,0,8,41}}, 148 {"800x600-60", 149 {40000,800,600,10,42,64,263,0,4,28,627,100,0,8,41}}, 150 {"800x600-70", 151 {44899,800,600,6,42,52,251,8,20,36,635,100,0,8,105}}, 152 {"800x600-72", 153 {50000,800,600,14,44,60,259,36,42,66,665,100,0,8,41}}, 154 {"800x600-75", 155 {49497,800,600,4,24,64,263,0,3,25,624,100,0,8,41}}, 156 {"800x600-90", 157 {56637,800,600,2,18,48,247,7,18,35,634,100,0,8,41}}, 158 {"800x600-100", 159 {67499,800,600,0,16,70,269,6,10,25,624,100,0,8,41}}, 160 {"1024x768-60", 161 {64998,1024,768,6,40,80,335,2,8,38,805,128,0,8,121}}, 162 {"1024x768-70", 163 {74996,1024,768,6,40,76,331,2,8,38,805,128,0,8,121}}, 164 {"1024x768-72", 165 {74996,1024,768,6,40,66,321,2,8,38,805,128,0,8,121}}, 166 {"1024x768-75", 167 {78932,1024,768,4,28,72,327,0,3,32,799,128,0,8,41}}, 168 {"1024x768-90", 169 {100000,1024,768,0,24,72,327,20,35,77,844,128,0,8,121}}, 170 {"1024x768-100", 171 {109998,1024,768,0,22,92,347,0,7,24,791,128,0,8,121}}, 172 {"1024x768-illo", 173 {120322,1024,768,12,48,120,375,3,7,32,799,128,0,8,41}}, 174 {"1152x864-60", 175 {80000,1152,864,16,44,76,363,5,10,52,915,144,0,8,41}}, 176 {"1152x864-70", 177 {100000,1152,864,10,48,90,377,12,23,81,944,144,0,8,41}}, 178 {"1152x864-75", 179 {109998,1152,864,6,42,78,365,44,52,138,1001,144,0,8,41}}, 180 {"1152x864-80", 181 {109998,1152,864,4,32,72,359,29,36,94,957,144,0,8,41}}, 182 {"1280x1024-60", 183 {107991,1280,1024,12,40,102,421,0,3,42,1065,160,0,8,41}}, 184 {"1280x1024-70", 185 {125992,1280,1024,20,48,102,421,0,5,42,1065,160,0,8,41}}, 186 {"1280x1024-74", 187 {134989,1280,1024,8,44,108,427,0,29,40,1063,160,0,8,41}}, 188 {"1280x1024-75", 189 {134989,1280,1024,4,40,102,421,0,3,42,1065,160,0,8,41}}, 190 {"1600x1200-60", 191 {155981,1600,1200,8,48,112,511,9,17,70,1269,200,0,8,121}}, 192 {"1600x1200-66", 193 {171998,1600,1200,10,44,120,519,2,5,53,1252,200,0,8,121}}, 194 {"1600x1200-76", 195 {197980,1600,1200,10,44,120,519,2,7,50,1249,200,0,8,121}}, 196 {"\0", }, 197}; 198 199#ifdef CONFIG_FB_PM2_PCI 200struct pm2pci_par { 201 u32 mem_config; 202 u32 mem_control; 203 u32 boot_address; 204 struct pci_dev* dev; 205}; 206#endif 207 208#define DEFAULT_CURSOR_BLINK_RATE (20) 209#define CURSOR_DRAW_DELAY (2) 210 211struct pm2_cursor { 212 int enable; 213 int on; 214 int vbl_cnt; 215 int blink_rate; 216 struct { 217 u16 x, y; 218 } pos, hot, size; 219 u8 color[6]; 220 u8 bits[8][64]; 221 u8 mask[8][64]; 222 struct timer_list *timer; 223}; 224 225static const char permedia2_name[16]="Permedia2"; 226 227static struct pm2fb_info { 228 struct fb_info_gen gen; 229 int board; /* Permedia2 board index (see 230 board_table[] below) */ 231 pm2type_t type; 232 struct { 233 unsigned long fb_base; /* physical framebuffer memory base */ 234 u32 fb_size; /* framebuffer memory size */ 235 unsigned long rg_base; /* physical register memory base */ 236 unsigned long p_fb; /* physical address of frame buffer */ 237 unsigned char* v_fb; /* virtual address of frame buffer */ 238 unsigned long p_regs; /* physical address of registers 239 region, must be rg_base or 240 rg_base+PM2_REGS_SIZE depending on 241 the host endianness */ 242 unsigned char* v_regs; /* virtual address of p_regs */ 243 } regions; 244 union { /* here, the per-board par structs */ 245#ifdef CONFIG_FB_PM2_CVPPC 246 struct cvppc_par cvppc; /* CVisionPPC data */ 247#endif 248#ifdef CONFIG_FB_PM2_PCI 249 struct pm2pci_par pci; /* Permedia2 PCI boards data */ 250#endif 251 } board_par; 252 struct pm2fb_par current_par; /* displayed screen */ 253 int current_par_valid; 254 u32 memclock; /* memclock (set by the per-board 255 init routine) */ 256 struct display disp; 257 struct { 258 u8 transp; 259 u8 red; 260 u8 green; 261 u8 blue; 262 } palette[256]; 263 union { 264#ifdef FBCON_HAS_CFB16 265 u16 cmap16[16]; 266#endif 267#ifdef FBCON_HAS_CFB24 268 u32 cmap24[16]; 269#endif 270#ifdef FBCON_HAS_CFB32 271 u32 cmap32[16]; 272#endif 273 } cmap; 274 struct pm2_cursor *cursor; 275} fb_info; 276 277#ifdef CONFIG_FB_PM2_CVPPC 278static int cvppc_detect(struct pm2fb_info*); 279static void cvppc_init(struct pm2fb_info*); 280#endif 281 282#ifdef CONFIG_FB_PM2_PCI 283static int pm2pci_detect(struct pm2fb_info*); 284static void pm2pci_init(struct pm2fb_info*); 285#endif 286 287#ifdef PM2FB_HW_CURSOR 288static void pm2fb_cursor(struct display *p, int mode, int x, int y); 289static int pm2fb_set_font(struct display *d, int width, int height); 290static struct pm2_cursor *pm2_init_cursor(struct pm2fb_info *fb); 291static void pm2v_set_cursor_color(struct pm2fb_info *fb, u8 *red, u8 *green, u8 *blue); 292static void pm2v_set_cursor_shape(struct pm2fb_info *fb); 293static u8 cursor_color_map[2] = { 0, 0xff }; 294#else 295#define pm2fb_cursor NULL 296#define pm2fb_set_font NULL 297#endif 298 299/* 300 * Table of the supported Permedia2 based boards. 301 * Three hooks are defined for each board: 302 * detect(): should return 1 if the related board has been detected, 0 303 * otherwise. It should also fill the fields 'regions.fb_base', 304 * 'regions.fb_size', 'regions.rg_base' and 'memclock' in the 305 * passed pm2fb_info structure. 306 * init(): called immediately after the reset of the Permedia2 chip. 307 * It should reset the memory controller if needed (the MClk 308 * is set shortly afterwards by the caller). 309 * cleanup(): called after the driver has been unregistered. 310 * 311 * the init and cleanup pointers can be NULL. 312 */ 313static const struct { 314 int (*detect)(struct pm2fb_info*); 315 void (*init)(struct pm2fb_info*); 316 void (*cleanup)(struct pm2fb_info*); 317 char name[32]; 318} board_table[] = { 319#ifdef CONFIG_FB_PM2_PCI 320 { pm2pci_detect, pm2pci_init, NULL, "Permedia2 PCI board" }, 321#endif 322#ifdef CONFIG_FB_PM2_CVPPC 323 { cvppc_detect, cvppc_init, NULL, "CVisionPPC/BVisionPPC" }, 324#endif 325 { NULL, } 326}; 327 328/* 329 * partial products for the supported horizontal resolutions. 330 */ 331#define PACKPP(p0,p1,p2) (((p2)<<6)|((p1)<<3)|(p0)) 332static const struct { 333 u16 width; 334 u16 pp; 335} pp_table[] = { 336 { 32, PACKPP(1, 0, 0) }, { 64, PACKPP(1, 1, 0) }, 337 { 96, PACKPP(1, 1, 1) }, { 128, PACKPP(2, 1, 1) }, 338 { 160, PACKPP(2, 2, 1) }, { 192, PACKPP(2, 2, 2) }, 339 { 224, PACKPP(3, 2, 1) }, { 256, PACKPP(3, 2, 2) }, 340 { 288, PACKPP(3, 3, 1) }, { 320, PACKPP(3, 3, 2) }, 341 { 384, PACKPP(3, 3, 3) }, { 416, PACKPP(4, 3, 1) }, 342 { 448, PACKPP(4, 3, 2) }, { 512, PACKPP(4, 3, 3) }, 343 { 544, PACKPP(4, 4, 1) }, { 576, PACKPP(4, 4, 2) }, 344 { 640, PACKPP(4, 4, 3) }, { 768, PACKPP(4, 4, 4) }, 345 { 800, PACKPP(5, 4, 1) }, { 832, PACKPP(5, 4, 2) }, 346 { 896, PACKPP(5, 4, 3) }, { 1024, PACKPP(5, 4, 4) }, 347 { 1056, PACKPP(5, 5, 1) }, { 1088, PACKPP(5, 5, 2) }, 348 { 1152, PACKPP(5, 5, 3) }, { 1280, PACKPP(5, 5, 4) }, 349 { 1536, PACKPP(5, 5, 5) }, { 1568, PACKPP(6, 5, 1) }, 350 { 1600, PACKPP(6, 5, 2) }, { 1664, PACKPP(6, 5, 3) }, 351 { 1792, PACKPP(6, 5, 4) }, { 2048, PACKPP(6, 5, 5) }, 352 { 0, 0 } }; 353 354static void pm2fb_detect(void); 355static int pm2fb_encode_fix(struct fb_fix_screeninfo* fix, 356 const void* par, struct fb_info_gen* info); 357static int pm2fb_decode_var(const struct fb_var_screeninfo* var, 358 void* par, struct fb_info_gen* info); 359static int pm2fb_encode_var(struct fb_var_screeninfo* var, 360 const void* par, struct fb_info_gen* info); 361static void pm2fb_get_par(void* par, struct fb_info_gen* info); 362static void pm2fb_set_par(const void* par, struct fb_info_gen* info); 363static int pm2fb_getcolreg(unsigned regno, 364 unsigned* red, unsigned* green, unsigned* blue, 365 unsigned* transp, struct fb_info* info); 366static int pm2fb_setcolreg(unsigned regno, 367 unsigned red, unsigned green, unsigned blue, 368 unsigned transp, struct fb_info* info); 369static int pm2fb_blank(int blank_mode, struct fb_info_gen* info); 370static int pm2fb_pan_display(const struct fb_var_screeninfo* var, 371 struct fb_info_gen* info); 372static void pm2fb_set_disp(const void* par, struct display* disp, 373 struct fb_info_gen* info); 374 375static struct fbgen_hwswitch pm2fb_hwswitch={ 376 pm2fb_detect, pm2fb_encode_fix, pm2fb_decode_var, 377 pm2fb_encode_var, pm2fb_get_par, pm2fb_set_par, 378 pm2fb_getcolreg, pm2fb_setcolreg, pm2fb_pan_display, 379 pm2fb_blank, pm2fb_set_disp 380}; 381 382static struct fb_ops pm2fb_ops={ 383 owner: THIS_MODULE, 384 fb_get_fix: fbgen_get_fix, 385 fb_get_var: fbgen_get_var, 386 fb_set_var: fbgen_set_var, 387 fb_get_cmap: fbgen_get_cmap, 388 fb_set_cmap: fbgen_set_cmap, 389 fb_pan_display: fbgen_pan_display, 390}; 391 392/*************************************************************************** 393 * Begin of Permedia2 specific functions 394 ***************************************************************************/ 395 396inline static u32 RD32(unsigned char* base, s32 off) { 397 398 return readl(base+off); 399} 400 401inline static void WR32(unsigned char* base, s32 off, u32 v) { 402 403 writel(v, base+off); 404} 405 406inline static u32 pm2_RD(struct pm2fb_info* p, s32 off) { 407 408 return RD32(p->regions.v_regs, off); 409} 410 411inline static void pm2_WR(struct pm2fb_info* p, s32 off, u32 v) { 412 413 WR32(p->regions.v_regs, off, v); 414} 415 416inline static u32 pm2_RDAC_RD(struct pm2fb_info* p, s32 idx) { 417 418 int index = PM2R_RD_INDEXED_DATA; 419 switch (p->type) { 420 case PM2_TYPE_PERMEDIA2: 421 pm2_WR(p, PM2R_RD_PALETTE_WRITE_ADDRESS, idx); 422 break; 423 case PM2_TYPE_PERMEDIA2V: 424 pm2_WR(p, PM2VR_RD_INDEX_LOW, idx & 0xff); 425 index = PM2VR_RD_INDEXED_DATA; 426 break; 427 } 428 DEFRW(); 429 return pm2_RD(p, index); 430} 431 432inline static void pm2_RDAC_WR(struct pm2fb_info* p, s32 idx, 433 u32 v) { 434 435 int index = PM2R_RD_INDEXED_DATA; 436 switch (p->type) { 437 case PM2_TYPE_PERMEDIA2: 438 pm2_WR(p, PM2R_RD_PALETTE_WRITE_ADDRESS, idx); 439 break; 440 case PM2_TYPE_PERMEDIA2V: 441 pm2_WR(p, PM2VR_RD_INDEX_LOW, idx & 0xff); 442 index = PM2VR_RD_INDEXED_DATA; 443 break; 444 } 445 DEFRW(); 446 pm2_WR(p, index, v); 447} 448 449inline static u32 pm2v_RDAC_RD(struct pm2fb_info* p, s32 idx) { 450 451 pm2_WR(p, PM2VR_RD_INDEX_LOW, idx & 0xff); 452 DEFRW(); 453 return pm2_RD(p, PM2VR_RD_INDEXED_DATA); 454} 455 456inline static void pm2v_RDAC_WR(struct pm2fb_info* p, s32 idx, 457 u32 v) { 458 459 pm2_WR(p, PM2VR_RD_INDEX_LOW, idx & 0xff); 460 DEFRW(); 461 pm2_WR(p, PM2VR_RD_INDEXED_DATA, v); 462} 463 464#ifdef CONFIG_FB_PM2_FIFO_DISCONNECT 465#define WAIT_FIFO(p,a) 466#else 467inline static void WAIT_FIFO(struct pm2fb_info* p, u32 a) { 468 469 while(pm2_RD(p, PM2R_IN_FIFO_SPACE)<a); 470 DEFRW(); 471} 472#endif 473 474static u32 partprod(u32 xres) { 475 int i; 476 477 for (i=0; pp_table[i].width && pp_table[i].width!=xres; i++); 478 if (!pp_table[i].width) 479 DPRINTK("invalid width %u\n", xres); 480 return pp_table[i].pp; 481} 482 483static u32 to3264(u32 timing, int bpp, int is64) { 484 485 switch (bpp) { 486 case 8: 487 timing=timing>>(2+is64); 488 break; 489 case 16: 490 timing=timing>>(1+is64); 491 break; 492 case 24: 493 timing=(timing*3)>>(2+is64); 494 break; 495 case 32: 496 if (is64) 497 timing=timing>>1; 498 break; 499 } 500 return timing; 501} 502 503static u32 from3264(u32 timing, int bpp, int is64) { 504 505 switch (bpp) { 506 case 8: 507 timing=timing<<(2+is64); 508 break; 509 case 16: 510 timing=timing<<(1+is64); 511 break; 512 case 24: 513 timing=(timing<<(2+is64))/3; 514 break; 515 case 32: 516 if (is64) 517 timing=timing<<1; 518 break; 519 } 520 return timing; 521} 522 523static void pm2_mnp(u32 clk, unsigned char* mm, unsigned char* nn, 524 unsigned char* pp) { 525 unsigned char m; 526 unsigned char n; 527 unsigned char p; 528 u32 f; 529 s32 curr; 530 s32 delta=100000; 531 532 *mm=*nn=*pp=0; 533 for (n=2; n<15; n++) { 534 for (m=2; m; m++) { 535 f=PM2_REFERENCE_CLOCK*m/n; 536 if (f>=150000 && f<=300000) { 537 for (p=0; p<5; p++, f>>=1) { 538 curr=clk>f?clk-f:f-clk; 539 if (curr<delta) { 540 delta=curr; 541 *mm=m; 542 *nn=n; 543 *pp=p; 544 } 545 } 546 } 547 } 548 } 549} 550 551static void pm2v_mnp(u32 clk, unsigned char* mm, unsigned char* nn, 552 unsigned char* pp) { 553 unsigned char m; 554 unsigned char n; 555 unsigned char p; 556 u32 f; 557 s32 delta=1000; 558 559 *mm=*nn=*pp=0; 560 for (n=1; n; n++) { 561 for (m=1; m; m++) { 562 for (p=0; p<2; p++) { 563 f=PM2_REFERENCE_CLOCK*n/(m * (1<<(p+1))); 564 if (clk>f-delta && clk<f+delta) { 565 delta=clk>f?clk-f:f-clk; 566 *mm=m; 567 *nn=n; 568 *pp=p; 569 } 570 } 571 } 572 } 573} 574 575static void wait_pm2(struct pm2fb_info* i) { 576 577 WAIT_FIFO(i, 1); 578 pm2_WR(i, PM2R_SYNC, 0); 579 DEFRW(); 580 do { 581 while (pm2_RD(i, PM2R_OUT_FIFO_WORDS)==0); 582 DEFR(); 583 } while (pm2_RD(i, PM2R_OUT_FIFO)!=PM2TAG(PM2R_SYNC)); 584} 585 586static void pm2_set_memclock(struct pm2fb_info* info, u32 clk) { 587 int i; 588 unsigned char m, n, p; 589 590 pm2_mnp(clk, &m, &n, &p); 591 WAIT_FIFO(info, 10); 592 pm2_RDAC_WR(info, PM2I_RD_MEMORY_CLOCK_3, 6); 593 DEFW(); 594 pm2_RDAC_WR(info, PM2I_RD_MEMORY_CLOCK_1, m); 595 pm2_RDAC_WR(info, PM2I_RD_MEMORY_CLOCK_2, n); 596 DEFW(); 597 pm2_RDAC_WR(info, PM2I_RD_MEMORY_CLOCK_3, 8|p); 598 DEFW(); 599 pm2_RDAC_RD(info, PM2I_RD_MEMORY_CLOCK_STATUS); 600 DEFR(); 601 for (i=256; i && 602 !(pm2_RD(info, PM2R_RD_INDEXED_DATA)&PM2F_PLL_LOCKED); i--); 603} 604 605static void pm2_set_pixclock(struct pm2fb_info* info, u32 clk) { 606 int i; 607 unsigned char m, n, p; 608 609 switch (info->type) { 610 case PM2_TYPE_PERMEDIA2: 611 pm2_mnp(clk, &m, &n, &p); 612 WAIT_FIFO(info, 10); 613 pm2_RDAC_WR(info, PM2I_RD_PIXEL_CLOCK_A3, 0); 614 DEFW(); 615 pm2_RDAC_WR(info, PM2I_RD_PIXEL_CLOCK_A1, m); 616 pm2_RDAC_WR(info, PM2I_RD_PIXEL_CLOCK_A2, n); 617 DEFW(); 618 pm2_RDAC_WR(info, PM2I_RD_PIXEL_CLOCK_A3, 8|p); 619 DEFW(); 620 pm2_RDAC_RD(info, PM2I_RD_PIXEL_CLOCK_STATUS); 621 DEFR(); 622 for (i=256; i && 623 !(pm2_RD(info, PM2R_RD_INDEXED_DATA)&PM2F_PLL_LOCKED); i--); 624 break; 625 case PM2_TYPE_PERMEDIA2V: 626 pm2v_mnp(clk/2, &m, &n, &p); 627 WAIT_FIFO(info, 8); 628 pm2_WR(info, PM2VR_RD_INDEX_HIGH, PM2VI_RD_CLK0_PRESCALE >> 8); 629 pm2v_RDAC_WR(info, PM2VI_RD_CLK0_PRESCALE, m); 630 pm2v_RDAC_WR(info, PM2VI_RD_CLK0_FEEDBACK, n); 631 pm2v_RDAC_WR(info, PM2VI_RD_CLK0_POSTSCALE, p); 632 pm2_WR(info, PM2VR_RD_INDEX_HIGH, 0); 633 break; 634 } 635} 636 637static void clear_palette(struct pm2fb_info* p) { 638 int i=256; 639 640 WAIT_FIFO(p, 1); 641 pm2_WR(p, PM2R_RD_PALETTE_WRITE_ADDRESS, 0); 642 DEFW(); 643 while (i--) { 644 WAIT_FIFO(p, 3); 645 pm2_WR(p, PM2R_RD_PALETTE_DATA, 0); 646 pm2_WR(p, PM2R_RD_PALETTE_DATA, 0); 647 pm2_WR(p, PM2R_RD_PALETTE_DATA, 0); 648 } 649} 650 651static void set_color(struct pm2fb_info* p, unsigned char regno, 652 unsigned char r, unsigned char g, unsigned char b) { 653 654 WAIT_FIFO(p, 4); 655 pm2_WR(p, PM2R_RD_PALETTE_WRITE_ADDRESS, regno); 656 DEFW(); 657 pm2_WR(p, PM2R_RD_PALETTE_DATA, r); 658 DEFW(); 659 pm2_WR(p, PM2R_RD_PALETTE_DATA, g); 660 DEFW(); 661 pm2_WR(p, PM2R_RD_PALETTE_DATA, b); 662} 663 664static void set_aperture(struct pm2fb_info* i, struct pm2fb_par* p) { 665 666 WAIT_FIFO(i, 2); 667#ifdef __LITTLE_ENDIAN 668 pm2_WR(i, PM2R_APERTURE_ONE, 0); 669 pm2_WR(i, PM2R_APERTURE_TWO, 0); 670#else 671 switch (p->depth) { 672 case 8: 673 case 24: 674 pm2_WR(i, PM2R_APERTURE_ONE, 0); 675 pm2_WR(i, PM2R_APERTURE_TWO, 1); 676 break; 677 case 16: 678 pm2_WR(i, PM2R_APERTURE_ONE, 2); 679 pm2_WR(i, PM2R_APERTURE_TWO, 1); 680 break; 681 case 32: 682 pm2_WR(i, PM2R_APERTURE_ONE, 1); 683 pm2_WR(i, PM2R_APERTURE_TWO, 1); 684 break; 685 } 686#endif 687} 688 689static void set_screen(struct pm2fb_info* i, struct pm2fb_par* p) { 690 u32 clrmode=0; 691 u32 txtmap=0; 692 u32 pixsize=0; 693 u32 clrformat=0; 694 u32 xres; 695 u32 video, tmp; 696 697 if (i->type == PM2_TYPE_PERMEDIA2V) { 698 WAIT_FIFO(i, 1); 699 pm2_WR(i, PM2VR_RD_INDEX_HIGH, 0); 700 } 701 xres=(p->width+31)&~31; 702 set_aperture(i, p); 703 DEFRW(); 704 WAIT_FIFO(i, 27); 705 pm2_RDAC_WR(i, PM2I_RD_COLOR_KEY_CONTROL, p->depth==8?0: 706 PM2F_COLOR_KEY_TEST_OFF); 707 switch (p->depth) { 708 case 8: 709 pm2_WR(i, PM2R_FB_READ_PIXEL, 0); 710 clrformat=0x0e; 711 break; 712 case 16: 713 pm2_WR(i, PM2R_FB_READ_PIXEL, 1); 714 clrmode=PM2F_RD_TRUECOLOR|0x06; 715 txtmap=PM2F_TEXTEL_SIZE_16; 716 pixsize=1; 717 clrformat=0x70; 718 break; 719 case 32: 720 pm2_WR(i, PM2R_FB_READ_PIXEL, 2); 721 clrmode=PM2F_RD_TRUECOLOR|0x08; 722 txtmap=PM2F_TEXTEL_SIZE_32; 723 pixsize=2; 724 clrformat=0x20; 725 break; 726 case 24: 727 pm2_WR(i, PM2R_FB_READ_PIXEL, 4); 728 clrmode=PM2F_RD_TRUECOLOR|0x09; 729 txtmap=PM2F_TEXTEL_SIZE_24; 730 pixsize=4; 731 clrformat=0x20; 732 break; 733 } 734 pm2_WR(i, PM2R_SCREEN_SIZE, (p->height<<16)|p->width); 735 pm2_WR(i, PM2R_SCISSOR_MODE, PM2F_SCREEN_SCISSOR_ENABLE); 736 pm2_WR(i, PM2R_FB_WRITE_MODE, PM2F_FB_WRITE_ENABLE); 737 pm2_WR(i, PM2R_FB_READ_MODE, partprod(xres)); 738 pm2_WR(i, PM2R_LB_READ_MODE, partprod(xres)); 739 pm2_WR(i, PM2R_TEXTURE_MAP_FORMAT, txtmap|partprod(xres)); 740 pm2_WR(i, PM2R_H_TOTAL, p->htotal); 741 pm2_WR(i, PM2R_HS_START, p->hsstart); 742 pm2_WR(i, PM2R_HS_END, p->hsend); 743 pm2_WR(i, PM2R_HG_END, p->hbend); 744 pm2_WR(i, PM2R_HB_END, p->hbend); 745 pm2_WR(i, PM2R_V_TOTAL, p->vtotal); 746 pm2_WR(i, PM2R_VS_START, p->vsstart); 747 pm2_WR(i, PM2R_VS_END, p->vsend); 748 pm2_WR(i, PM2R_VB_END, p->vbend); 749 pm2_WR(i, PM2R_SCREEN_STRIDE, p->stride); 750 DEFW(); 751 pm2_WR(i, PM2R_SCREEN_BASE, p->base); 752 /* HW cursor needs /VSYNC for recognizing vert retrace */ 753 video=p->video & ~(PM2F_HSYNC_ACT_LOW|PM2F_VSYNC_ACT_LOW); 754 video|=PM2F_HSYNC_ACT_HIGH|PM2F_VSYNC_ACT_HIGH; 755 switch (i->type) { 756 case PM2_TYPE_PERMEDIA2: 757 tmp = PM2F_RD_PALETTE_WIDTH_8; 758 pm2_RDAC_WR(i, PM2I_RD_COLOR_MODE, PM2F_RD_COLOR_MODE_RGB| 759 PM2F_RD_GUI_ACTIVE|clrmode); 760 if ((p->video & PM2F_HSYNC_ACT_LOW) == PM2F_HSYNC_ACT_LOW) 761 tmp |= 4; /* invert hsync */ 762 if ((p->video & PM2F_HSYNC_ACT_LOW) == PM2F_HSYNC_ACT_LOW) 763 tmp |= 8; /* invert vsync */ 764 pm2_RDAC_WR(i, PM2I_RD_MISC_CONTROL, tmp); 765 break; 766 case PM2_TYPE_PERMEDIA2V: 767 tmp = 0; 768 pm2v_RDAC_WR(i, PM2VI_RD_PIXEL_SIZE, pixsize); 769 pm2v_RDAC_WR(i, PM2VI_RD_COLOR_FORMAT, clrformat); 770 if ((p->video & PM2F_HSYNC_ACT_LOW) == PM2F_HSYNC_ACT_LOW) 771 tmp |= 1; /* invert hsync */ 772 if ((p->video & PM2F_HSYNC_ACT_LOW) == PM2F_HSYNC_ACT_LOW) 773 tmp |= 4; /* invert vsync */ 774 pm2v_RDAC_WR(i, PM2VI_RD_SYNC_CONTROL, tmp); 775 pm2v_RDAC_WR(i, PM2VI_RD_MISC_CONTROL, 1); 776 break; 777 } 778 pm2_WR(i, PM2R_VIDEO_CONTROL, video); 779 pm2_set_pixclock(i, p->pixclock); 780}; 781 782/* 783 * copy with packed pixels (8/16bpp only). 784 */ 785static void pm2fb_pp_copy(struct pm2fb_info* i, s32 xsrc, s32 ysrc, 786 s32 x, s32 y, s32 w, s32 h) { 787 s32 scale=i->current_par.depth==8?2:1; 788 s32 offset; 789 790 if (!w || !h) 791 return; 792 WAIT_FIFO(i, 7); 793 pm2_WR(i, PM2R_CONFIG, PM2F_CONFIG_FB_WRITE_ENABLE| 794 PM2F_CONFIG_FB_PACKED_DATA| 795 PM2F_CONFIG_FB_READ_SOURCE_ENABLE); 796 pm2_WR(i, PM2R_FB_PIXEL_OFFSET, 0); 797 pm2_WR(i, PM2R_FB_SOURCE_DELTA, ((ysrc-y)&0xfff)<<16| 798 ((xsrc-x)&0xfff)); 799 offset=(x&0x3)-(xsrc&0x3); 800 pm2_WR(i, PM2R_RECTANGLE_ORIGIN, (y<<16)|(x>>scale)); 801 pm2_WR(i, PM2R_RECTANGLE_SIZE, (h<<16)|((w+7)>>scale)); 802 pm2_WR(i, PM2R_PACKED_DATA_LIMITS, (offset<<29)|(x<<16)|(x+w)); 803 DEFW(); 804 pm2_WR(i, PM2R_RENDER, PM2F_RENDER_RECTANGLE| 805 (x<xsrc?PM2F_INCREASE_X:0)| 806 (y<ysrc?PM2F_INCREASE_Y:0)); 807 wait_pm2(i); 808} 809 810/* 811 * block operation. copy=0: rectangle fill, copy=1: rectangle copy. 812 */ 813static void pm2fb_block_op(struct pm2fb_info* i, int copy, 814 s32 xsrc, s32 ysrc, 815 s32 x, s32 y, s32 w, s32 h, 816 u32 color) { 817 818 if (!w || !h) 819 return; 820 WAIT_FIFO(i, 6); 821 pm2_WR(i, PM2R_CONFIG, PM2F_CONFIG_FB_WRITE_ENABLE| 822 PM2F_CONFIG_FB_READ_SOURCE_ENABLE); 823 pm2_WR(i, PM2R_FB_PIXEL_OFFSET, 0); 824 if (copy) 825 pm2_WR(i, PM2R_FB_SOURCE_DELTA, ((ysrc-y)&0xfff)<<16| 826 ((xsrc-x)&0xfff)); 827 else 828 pm2_WR(i, PM2R_FB_BLOCK_COLOR, color); 829 pm2_WR(i, PM2R_RECTANGLE_ORIGIN, (y<<16)|x); 830 pm2_WR(i, PM2R_RECTANGLE_SIZE, (h<<16)|w); 831 DEFW(); 832 pm2_WR(i, PM2R_RENDER, PM2F_RENDER_RECTANGLE| 833 (x<xsrc?PM2F_INCREASE_X:0)| 834 (y<ysrc?PM2F_INCREASE_Y:0)| 835 (copy?0:PM2F_RENDER_FASTFILL)); 836 wait_pm2(i); 837} 838 839/*************************************************************************** 840 * Begin of generic initialization functions 841 ***************************************************************************/ 842 843static void pm2fb_reset(struct pm2fb_info* p) { 844 845 if (p->type == PM2_TYPE_PERMEDIA2V) 846 pm2_WR(p, PM2VR_RD_INDEX_HIGH, 0); 847 pm2_WR(p, PM2R_RESET_STATUS, 0); 848 DEFRW(); 849 while (pm2_RD(p, PM2R_RESET_STATUS)&PM2F_BEING_RESET); 850 DEFRW(); 851#ifdef CONFIG_FB_PM2_FIFO_DISCONNECT 852 DPRINTK("FIFO disconnect enabled\n"); 853 pm2_WR(p, PM2R_FIFO_DISCON, 1); 854 DEFRW(); 855#endif 856 if (board_table[p->board].init) 857 board_table[p->board].init(p); 858 WAIT_FIFO(p, 48); 859 pm2_WR(p, PM2R_CHIP_CONFIG, pm2_RD(p, PM2R_CHIP_CONFIG)& 860 ~(PM2F_VGA_ENABLE|PM2F_VGA_FIXED)); 861 pm2_WR(p, PM2R_BYPASS_WRITE_MASK, ~(0L)); 862 pm2_WR(p, PM2R_FRAMEBUFFER_WRITE_MASK, ~(0L)); 863 pm2_WR(p, PM2R_FIFO_CONTROL, 0); 864 pm2_WR(p, PM2R_FILTER_MODE, PM2F_SYNCHRONIZATION); 865 pm2_WR(p, PM2R_APERTURE_ONE, 0); 866 pm2_WR(p, PM2R_APERTURE_TWO, 0); 867 pm2_WR(p, PM2R_LB_READ_FORMAT, 0); 868 pm2_WR(p, PM2R_LB_WRITE_FORMAT, 0); 869 pm2_WR(p, PM2R_LB_READ_MODE, 0); 870 pm2_WR(p, PM2R_LB_SOURCE_OFFSET, 0); 871 pm2_WR(p, PM2R_FB_SOURCE_OFFSET, 0); 872 pm2_WR(p, PM2R_FB_PIXEL_OFFSET, 0); 873 pm2_WR(p, PM2R_WINDOW_ORIGIN, 0); 874 pm2_WR(p, PM2R_FB_WINDOW_BASE, 0); 875 pm2_WR(p, PM2R_LB_WINDOW_BASE, 0); 876 pm2_WR(p, PM2R_FB_SOFT_WRITE_MASK, ~(0L)); 877 pm2_WR(p, PM2R_FB_HARD_WRITE_MASK, ~(0L)); 878 pm2_WR(p, PM2R_FB_READ_PIXEL, 0); 879 pm2_WR(p, PM2R_DITHER_MODE, 0); 880 pm2_WR(p, PM2R_AREA_STIPPLE_MODE, 0); 881 pm2_WR(p, PM2R_DEPTH_MODE, 0); 882 pm2_WR(p, PM2R_STENCIL_MODE, 0); 883 pm2_WR(p, PM2R_TEXTURE_ADDRESS_MODE, 0); 884 pm2_WR(p, PM2R_TEXTURE_READ_MODE, 0); 885 pm2_WR(p, PM2R_TEXEL_LUT_MODE, 0); 886 pm2_WR(p, PM2R_YUV_MODE, 0); 887 pm2_WR(p, PM2R_COLOR_DDA_MODE, 0); 888 pm2_WR(p, PM2R_TEXTURE_COLOR_MODE, 0); 889 pm2_WR(p, PM2R_FOG_MODE, 0); 890 pm2_WR(p, PM2R_ALPHA_BLEND_MODE, 0); 891 pm2_WR(p, PM2R_LOGICAL_OP_MODE, 0); 892 pm2_WR(p, PM2R_STATISTICS_MODE, 0); 893 pm2_WR(p, PM2R_SCISSOR_MODE, 0); 894 switch (p->type) { 895 case PM2_TYPE_PERMEDIA2: 896 pm2_RDAC_WR(p, PM2I_RD_MODE_CONTROL, 0); /* no overlay */ 897 pm2_RDAC_WR(p, PM2I_RD_CURSOR_CONTROL, 0); 898 pm2_RDAC_WR(p, PM2I_RD_MISC_CONTROL, PM2F_RD_PALETTE_WIDTH_8); 899 break; 900 case PM2_TYPE_PERMEDIA2V: 901 pm2v_RDAC_WR(p, PM2VI_RD_MISC_CONTROL, 1); /* 8bit */ 902 break; 903 } 904 pm2_RDAC_WR(p, PM2I_RD_COLOR_KEY_CONTROL, 0); 905 pm2_RDAC_WR(p, PM2I_RD_OVERLAY_KEY, 0); 906 pm2_RDAC_WR(p, PM2I_RD_RED_KEY, 0); 907 pm2_RDAC_WR(p, PM2I_RD_GREEN_KEY, 0); 908 pm2_RDAC_WR(p, PM2I_RD_BLUE_KEY, 0); 909 clear_palette(p); 910 if (p->memclock) 911 pm2_set_memclock(p, p->memclock); 912} 913 914static int __init pm2fb_conf(struct pm2fb_info* p){ 915 916 for (p->board=0; board_table[p->board].detect && 917 !(board_table[p->board].detect(p)); p->board++); 918 if (!board_table[p->board].detect) { 919 DPRINTK("no board found.\n"); 920 return 0; 921 } 922 DPRINTK("found board: %s\n", board_table[p->board].name); 923 924 p->regions.p_fb=p->regions.fb_base; 925 if (!request_mem_region(p->regions.p_fb, p->regions.fb_size, 926 "pm2fb")) { 927 printk (KERN_ERR "pm2fb: cannot reserve fb memory, abort\n"); 928 return 0; 929 } 930 p->regions.v_fb=MMAP(p->regions.p_fb, p->regions.fb_size); 931 932#ifndef PM2FB_BE_APERTURE 933 p->regions.p_regs=p->regions.rg_base; 934#else 935 p->regions.p_regs=p->regions.rg_base+PM2_REGS_SIZE; 936#endif 937 if (!request_mem_region(p->regions.p_regs, PM2_REGS_SIZE, "pm2fb")) { 938 printk (KERN_ERR "pm2fb: cannot reserve mmio memory, abort\n"); 939 UNMAP(p->regions.v_fb, p->regions.fb_size); 940 return 0; 941 } 942 p->regions.v_regs=MMAP(p->regions.p_regs, PM2_REGS_SIZE); 943 944#ifdef PM2FB_HW_CURSOR 945 p->cursor = pm2_init_cursor(p); 946#endif 947 return 1; 948} 949 950/*************************************************************************** 951 * Begin of per-board initialization functions 952 ***************************************************************************/ 953 954/* 955 * Phase5 CvisionPPC/BVisionPPC 956 */ 957#ifdef CONFIG_FB_PM2_CVPPC 958static int cvppc_PCI_init(struct cvppc_par* p) { 959 extern u32 powerup_PCI_present; 960 961 if (!powerup_PCI_present) { 962 DPRINTK("no PCI bridge detected\n"); 963 return 0; 964 } 965 if (!(p->pci_config=MMAP(CVPPC_PCI_CONFIG, 256))) { 966 DPRINTK("unable to map PCI config region\n"); 967 return 0; 968 } 969 if (RD32(p->pci_config, PCI_VENDOR_ID)!= 970 ((PCI_DEVICE_ID_TI_TVP4020<<16)|PCI_VENDOR_ID_TI)) { 971 DPRINTK("bad vendorID/deviceID\n"); 972 return 0; 973 } 974 if (!(p->pci_bridge=MMAP(CSPPC_PCI_BRIDGE, 256))) { 975 DPRINTK("unable to map PCI bridge\n"); 976 return 0; 977 } 978 WR32(p->pci_bridge, CSPPC_BRIDGE_ENDIAN, CSPPCF_BRIDGE_BIG_ENDIAN); 979 DEFW(); 980 if (pm2fb_options.flags & OPTF_OLD_MEM) 981 WR32(p->pci_config, PCI_CACHE_LINE_SIZE, 0xff00); 982 WR32(p->pci_config, PCI_BASE_ADDRESS_0, CVPPC_REGS_REGION); 983 WR32(p->pci_config, PCI_BASE_ADDRESS_1, CVPPC_FB_APERTURE_ONE); 984 WR32(p->pci_config, PCI_BASE_ADDRESS_2, CVPPC_FB_APERTURE_TWO); 985 WR32(p->pci_config, PCI_ROM_ADDRESS, CVPPC_ROM_ADDRESS); 986 DEFW(); 987 WR32(p->pci_config, PCI_COMMAND, 0xef000000 | 988 PCI_COMMAND_IO | 989 PCI_COMMAND_MEMORY | 990 PCI_COMMAND_MASTER); 991 return 1; 992} 993 994static int __init cvppc_detect(struct pm2fb_info* p) { 995 996 if (!cvppc_PCI_init(&p->board_par.cvppc)) 997 return 0; 998 p->type = PM2_TYPE_PERMEDIA2; 999 p->regions.fb_base=CVPPC_FB_APERTURE_ONE; 1000 p->regions.fb_size=CVPPC_FB_SIZE; 1001 p->regions.rg_base=CVPPC_REGS_REGION; 1002 p->memclock=CVPPC_MEMCLOCK; 1003 return 1; 1004} 1005 1006static void cvppc_init(struct pm2fb_info* p) { 1007 1008 WAIT_FIFO(p, 3); 1009 pm2_WR(p, PM2R_MEM_CONTROL, 0); 1010 pm2_WR(p, PM2R_BOOT_ADDRESS, 0x30); 1011 DEFW(); 1012 if (pm2fb_options.flags & OPTF_OLD_MEM) 1013 pm2_WR(p, PM2R_MEM_CONFIG, CVPPC_MEM_CONFIG_OLD); 1014 else 1015 pm2_WR(p, PM2R_MEM_CONFIG, CVPPC_MEM_CONFIG_NEW); 1016} 1017#endif /* CONFIG_FB_PM2_CVPPC */ 1018 1019/* 1020 * Generic PCI detection routines 1021 */ 1022#ifdef CONFIG_FB_PM2_PCI 1023struct { 1024 unsigned short vendor, device; 1025 char *name; 1026 pm2type_t type; 1027} pm2pci_cards[] __initdata = { 1028{ PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_TVP4020, "Texas Instruments TVP4020", PM2_TYPE_PERMEDIA2 }, 1029{ PCI_VENDOR_ID_3DLABS, PCI_DEVICE_ID_3DLABS_PERMEDIA2, "3dLabs Permedia 2", PM2_TYPE_PERMEDIA2 }, 1030{ PCI_VENDOR_ID_3DLABS, PCI_DEVICE_ID_3DLABS_PERMEDIA2V, "3dLabs Permedia 2v", PM2_TYPE_PERMEDIA2V }, 1031{ 0, 0 } 1032}; 1033 1034static int __init pm2pci_detect(struct pm2fb_info* p) { 1035 struct pm2pci_par* pci=&p->board_par.pci; 1036 struct pci_dev* dev; 1037 int i; 1038 unsigned char* m; 1039#ifdef __sparc__ 1040 struct pcidev_cookie *pcp; 1041#endif 1042 1043 memset(pci, 0, sizeof(struct pm2pci_par)); 1044 if (!pci_present()) { 1045 DPRINTK("no PCI bus found.\n"); 1046 return 0; 1047 } 1048 DPRINTK("scanning PCI bus for known chipsets...\n"); 1049 1050 pci_for_each_dev(dev) { 1051 for (i = 0; pm2pci_cards[i].vendor; i++) 1052 if (pm2pci_cards[i].vendor == dev->vendor && 1053 pm2pci_cards[i].device == dev->device) { 1054 pci->dev = dev; 1055 p->type = pm2pci_cards[i].type; 1056 DPRINTK("... found %s\n", pm2pci_cards[i].name); 1057 break; 1058 } 1059 if (pci->dev) 1060 break; 1061 } 1062 if (!pci->dev) { 1063 DPRINTK("no PCI board found.\n"); 1064 return 0; 1065 } 1066 DPRINTK("PCI board @%08lx %08lx %08lx rom %08lx\n", 1067 pci->dev->resource[0].start, 1068 pci->dev->resource[1].start, 1069 pci->dev->resource[2].start, 1070 pci->dev->resource[PCI_ROM_RESOURCE].start); 1071#ifdef __sparc__ 1072 p->regions.rg_base= pci->dev->resource[0].start; 1073 p->regions.fb_base= pci->dev->resource[1].start; 1074 pcp = pci->dev->sysdata; 1075 /* If the user has not asked for a particular mode, lets guess */ 1076 if (pcp->prom_node && !(pm2fb_options.flags & OPTF_USER)) { 1077 char timing[256], *q, *r; 1078 unsigned long w, h; 1079 int i; 1080 prom_getstring(pcp->prom_node, "timing-numbers", timing, 256); 1081 if (timing[0]) { 1082 w = simple_strtoul(timing, &q, 0); 1083 h = 0; 1084 if (q == timing) w = 0; 1085 if (w) { 1086 for (i = 0; i < 3; i++) { 1087 for (r = q; *r && (*r < '0' || *r > '9'); r++); 1088 simple_strtoul(r, &q, 0); 1089 if (r == q) break; 1090 } 1091 if (i < 3) w = 0; 1092 } 1093 if (w) { 1094 for (r = q; *r && (*r < '0' || *r > '9'); r++); 1095 h = simple_strtoul(r, &q, 0); 1096 if (r == q) w = 0; 1097 } 1098 if (w == 640 && h == 480) w = 0; 1099 if (w) { 1100 for (i=0; user_mode[i].name[0] && 1101 (w != user_mode[i].par.width || 1102 h != user_mode[i].par.height); i++); 1103 if (user_mode[i].name[0]) 1104 memcpy(&p->current_par, &user_mode[i].par, sizeof(user_mode[i].par)); 1105 } 1106 } 1107 } 1108#else 1109 if (pm2fb_options.flags & OPTF_VIRTUAL) { 1110 p->regions.rg_base = __pa(pci_resource_start(pci->dev, 0)); 1111 p->regions.fb_base = __pa(pci_resource_start(pci->dev, 1)); 1112 } 1113 else { 1114 p->regions.rg_base = pci_resource_start(pci->dev, 0); 1115 p->regions.fb_base = pci_resource_start(pci->dev, 1); 1116 } 1117#endif 1118#ifdef PM2FB_BE_APERTURE 1119 p->regions.rg_base += PM2_REGS_SIZE; 1120#endif 1121 if ((m=MMAP(p->regions.rg_base, PM2_REGS_SIZE))) { 1122 pci->mem_control=RD32(m, PM2R_MEM_CONTROL); 1123 pci->boot_address=RD32(m, PM2R_BOOT_ADDRESS); 1124 pci->mem_config=RD32(m, PM2R_MEM_CONFIG); 1125 switch (pci->mem_config & PM2F_MEM_CONFIG_RAM_MASK) { 1126 case PM2F_MEM_BANKS_1: 1127 p->regions.fb_size=0x200000; 1128 break; 1129 case PM2F_MEM_BANKS_2: 1130 p->regions.fb_size=0x400000; 1131 break; 1132 case PM2F_MEM_BANKS_3: 1133 p->regions.fb_size=0x600000; 1134 break; 1135 case PM2F_MEM_BANKS_4: 1136 p->regions.fb_size=0x800000; 1137 break; 1138 } 1139 p->memclock=CVPPC_MEMCLOCK; 1140 UNMAP(m, PM2_REGS_SIZE); 1141 return 1; 1142 } 1143 DPRINTK("MMAP() failed.\n"); 1144 return 0; 1145} 1146 1147static void pm2pci_init(struct pm2fb_info* p) { 1148 struct pm2pci_par* pci=&p->board_par.pci; 1149 1150 WAIT_FIFO(p, 3); 1151 pm2_WR(p, PM2R_MEM_CONTROL, pci->mem_control); 1152 pm2_WR(p, PM2R_BOOT_ADDRESS, pci->boot_address); 1153 DEFW(); 1154 pm2_WR(p, PM2R_MEM_CONFIG, pci->mem_config); 1155} 1156#endif /* CONFIG_FB_PM2_PCI */ 1157 1158/*************************************************************************** 1159 * Console hw acceleration 1160 ***************************************************************************/ 1161 1162 1163static int pm2fb_blank(int blank_mode, struct fb_info_gen* info) { 1164 struct pm2fb_info* i=(struct pm2fb_info* )info; 1165 u32 video; 1166 1167 if (!i->current_par_valid) 1168 return 1; 1169 video=i->current_par.video; 1170 if (blank_mode>0) { 1171 switch (blank_mode-1) { 1172 case VESA_NO_BLANKING: 1173 video=video&~(PM2F_VIDEO_ENABLE); 1174 break; 1175 case VESA_HSYNC_SUSPEND: 1176 video=video&~(PM2F_HSYNC_MASK| 1177 PM2F_BLANK_LOW); 1178 break; 1179 case VESA_VSYNC_SUSPEND: 1180 video=video&~(PM2F_VSYNC_MASK| 1181 PM2F_BLANK_LOW); 1182 break; 1183 case VESA_POWERDOWN: 1184 video=video&~(PM2F_VSYNC_MASK| 1185 PM2F_HSYNC_MASK| 1186 PM2F_BLANK_LOW); 1187 break; 1188 } 1189 } 1190 WAIT_FIFO(i, 1); 1191 pm2_WR(i, PM2R_VIDEO_CONTROL, video); 1192 return 0; 1193} 1194 1195static int pm2fb_pan_display(const struct fb_var_screeninfo* var, 1196 struct fb_info_gen* info) { 1197 struct pm2fb_info* i=(struct pm2fb_info* )info; 1198 1199 if (!i->current_par_valid) 1200 return -EINVAL; 1201 i->current_par.base=to3264(var->yoffset*i->current_par.width+ 1202 var->xoffset, i->current_par.depth, 1); 1203 WAIT_FIFO(i, 1); 1204 pm2_WR(i, PM2R_SCREEN_BASE, i->current_par.base); 1205 return 0; 1206} 1207 1208static void pm2fb_pp_bmove(struct display* p, int sy, int sx, 1209 int dy, int dx, int height, int width) { 1210 1211 if (fontwidthlog(p)) { 1212 sx=sx<<fontwidthlog(p); 1213 dx=dx<<fontwidthlog(p); 1214 width=width<<fontwidthlog(p); 1215 } 1216 else { 1217 sx=sx*fontwidth(p); 1218 dx=dx*fontwidth(p); 1219 width=width*fontwidth(p); 1220 } 1221 sy=sy*fontheight(p); 1222 dy=dy*fontheight(p); 1223 height=height*fontheight(p); 1224 pm2fb_pp_copy((struct pm2fb_info* )p->fb_info, sx, sy, dx, 1225 dy, width, height); 1226} 1227 1228static void pm2fb_bmove(struct display* p, int sy, int sx, 1229 int dy, int dx, int height, int width) { 1230 1231 if (fontwidthlog(p)) { 1232 sx=sx<<fontwidthlog(p); 1233 dx=dx<<fontwidthlog(p); 1234 width=width<<fontwidthlog(p); 1235 } 1236 else { 1237 sx=sx*fontwidth(p); 1238 dx=dx*fontwidth(p); 1239 width=width*fontwidth(p); 1240 } 1241 sy=sy*fontheight(p); 1242 dy=dy*fontheight(p); 1243 height=height*fontheight(p); 1244 pm2fb_block_op((struct pm2fb_info* )p->fb_info, 1, sx, sy, dx, dy, 1245 width, height, 0); 1246} 1247 1248#ifdef FBCON_HAS_CFB8 1249static void pm2fb_clear8(struct vc_data* conp, struct display* p, 1250 int sy, int sx, int height, int width) { 1251 u32 c; 1252 1253 sx=sx*fontwidth(p); 1254 width=width*fontwidth(p); 1255 sy=sy*fontheight(p); 1256 height=height*fontheight(p); 1257 c=attr_bgcol_ec(p, conp); 1258 c|=c<<8; 1259 c|=c<<16; 1260 pm2fb_block_op((struct pm2fb_info* )p->fb_info, 0, 0, 0, sx, sy, 1261 width, height, c); 1262} 1263 1264static void pm2fb_clear_margins8(struct vc_data* conp, struct display* p, 1265 int bottom_only) { 1266 u32 c; 1267 u32 sx; 1268 u32 sy; 1269 1270 c=attr_bgcol_ec(p, conp); 1271 c|=c<<8; 1272 c|=c<<16; 1273 sx=conp->vc_cols*fontwidth(p); 1274 sy=conp->vc_rows*fontheight(p); 1275 if (!bottom_only) 1276 pm2fb_block_op((struct pm2fb_info* )p->fb_info, 0, 0, 0, 1277 sx, 0, (p->var.xres-sx), p->var.yres_virtual, c); 1278 pm2fb_block_op((struct pm2fb_info* )p->fb_info, 0, 0, 0, 1279 0, p->var.yoffset+sy, sx, p->var.yres-sy, c); 1280} 1281 1282static struct display_switch pm2_cfb8 = { 1283 setup: fbcon_cfb8_setup, 1284 bmove: pm2fb_pp_bmove, 1285#ifdef __alpha__ 1286 /* Not sure why, but this works and the other does not. */ 1287 /* Also, perhaps we need a separate routine to wait for the 1288 blitter to stop before doing this? */ 1289 /* In addition, maybe we need to do this for 16 and 32 bit depths? */ 1290 clear: fbcon_cfb8_clear, 1291#else 1292 clear: pm2fb_clear8, 1293#endif 1294 putc: fbcon_cfb8_putc, 1295 putcs: fbcon_cfb8_putcs, 1296 revc: fbcon_cfb8_revc, 1297 cursor: pm2fb_cursor, 1298 set_font: pm2fb_set_font, 1299 clear_margins: pm2fb_clear_margins8, 1300 fontwidthmask: FONTWIDTH(4)|FONTWIDTH(8)|FONTWIDTH(12)|FONTWIDTH(16) }; 1301#endif /* FBCON_HAS_CFB8 */ 1302 1303#ifdef FBCON_HAS_CFB16 1304static void pm2fb_clear16(struct vc_data* conp, struct display* p, 1305 int sy, int sx, int height, int width) { 1306 u32 c; 1307 1308 sx=sx*fontwidth(p); 1309 width=width*fontwidth(p); 1310 sy=sy*fontheight(p); 1311 height=height*fontheight(p); 1312 c=((u16 *)p->dispsw_data)[attr_bgcol_ec(p, conp)]; 1313 c|=c<<16; 1314 pm2fb_block_op((struct pm2fb_info* )p->fb_info, 0, 0, 0, sx, sy, 1315 width, height, c); 1316} 1317 1318static void pm2fb_clear_margins16(struct vc_data* conp, struct display* p, 1319 int bottom_only) { 1320 u32 c; 1321 u32 sx; 1322 u32 sy; 1323 1324 c = ((u16 *)p->dispsw_data)[attr_bgcol_ec(p, conp)]; 1325 c|=c<<16; 1326 sx=conp->vc_cols*fontwidth(p); 1327 sy=conp->vc_rows*fontheight(p); 1328 if (!bottom_only) 1329 pm2fb_block_op((struct pm2fb_info* )p->fb_info, 0, 0, 0, 1330 sx, 0, (p->var.xres-sx), p->var.yres_virtual, c); 1331 pm2fb_block_op((struct pm2fb_info* )p->fb_info, 0, 0, 0, 1332 0, p->var.yoffset+sy, sx, p->var.yres-sy, c); 1333} 1334 1335static struct display_switch pm2_cfb16 = { 1336 setup: fbcon_cfb16_setup, 1337 bmove: pm2fb_pp_bmove, 1338 clear: pm2fb_clear16, 1339 putc: fbcon_cfb16_putc, 1340 putcs: fbcon_cfb16_putcs, 1341 revc: fbcon_cfb16_revc, 1342 cursor: pm2fb_cursor, 1343 set_font: pm2fb_set_font, 1344 clear_margins: pm2fb_clear_margins16, 1345 fontwidthmask: FONTWIDTH(4)|FONTWIDTH(8)|FONTWIDTH(12)|FONTWIDTH(16) 1346}; 1347#endif /* FBCON_HAS_CFB16 */ 1348 1349#ifdef FBCON_HAS_CFB24 1350/* 1351 * fast fill for 24bpp works only when red==green==blue 1352 */ 1353static void pm2fb_clear24(struct vc_data* conp, struct display* p, 1354 int sy, int sx, int height, int width) { 1355 struct pm2fb_info* i=(struct pm2fb_info* )p->fb_info; 1356 u32 c; 1357 1358 c=attr_bgcol_ec(p, conp); 1359 if ( i->palette[c].red==i->palette[c].green && 1360 i->palette[c].green==i->palette[c].blue) { 1361 c=((u32 *)p->dispsw_data)[c]; 1362 c|=(c&0xff0000)<<8; 1363 sx=sx*fontwidth(p); 1364 width=width*fontwidth(p); 1365 sy=sy*fontheight(p); 1366 height=height*fontheight(p); 1367 pm2fb_block_op(i, 0, 0, 0, sx, sy, width, height, c); 1368 } 1369 else 1370 fbcon_cfb24_clear(conp, p, sy, sx, height, width); 1371 1372} 1373 1374static void pm2fb_clear_margins24(struct vc_data* conp, struct display* p, 1375 int bottom_only) { 1376 struct pm2fb_info* i=(struct pm2fb_info* )p->fb_info; 1377 u32 c; 1378 u32 sx; 1379 u32 sy; 1380 1381 c=attr_bgcol_ec(p, conp); 1382 if ( i->palette[c].red==i->palette[c].green && 1383 i->palette[c].green==i->palette[c].blue) { 1384 c=((u32 *)p->dispsw_data)[c]; 1385 c|=(c&0xff0000)<<8; 1386 sx=conp->vc_cols*fontwidth(p); 1387 sy=conp->vc_rows*fontheight(p); 1388 if (!bottom_only) 1389 pm2fb_block_op(i, 0, 0, 0, sx, 0, (p->var.xres-sx), 1390 p->var.yres_virtual, c); 1391 pm2fb_block_op(i, 0, 0, 0, 0, p->var.yoffset+sy, 1392 sx, p->var.yres-sy, c); 1393 } 1394 else 1395 fbcon_cfb24_clear_margins(conp, p, bottom_only); 1396 1397} 1398 1399static struct display_switch pm2_cfb24 = { 1400 setup: fbcon_cfb24_setup, 1401 bmove: pm2fb_bmove, 1402 clear: pm2fb_clear24, 1403 putc: fbcon_cfb24_putc, 1404 putcs: fbcon_cfb24_putcs, 1405 revc: fbcon_cfb24_revc, 1406 cursor: pm2fb_cursor, 1407 set_font: pm2fb_set_font, 1408 clear_margins: pm2fb_clear_margins24, 1409 fontwidthmask: FONTWIDTH(4)|FONTWIDTH(8)|FONTWIDTH(12)|FONTWIDTH(16) 1410}; 1411#endif /* FBCON_HAS_CFB24 */ 1412 1413#ifdef FBCON_HAS_CFB32 1414static void pm2fb_clear32(struct vc_data* conp, struct display* p, 1415 int sy, int sx, int height, int width) { 1416 u32 c; 1417 1418 sx=sx*fontwidth(p); 1419 width=width*fontwidth(p); 1420 sy=sy*fontheight(p); 1421 height=height*fontheight(p); 1422 c=((u32 *)p->dispsw_data)[attr_bgcol_ec(p, conp)]; 1423 pm2fb_block_op((struct pm2fb_info* )p->fb_info, 0, 0, 0, sx, sy, 1424 width, height, c); 1425} 1426 1427static void pm2fb_clear_margins32(struct vc_data* conp, struct display* p, 1428 int bottom_only) { 1429 u32 c; 1430 u32 sx; 1431 u32 sy; 1432 1433 c = ((u32 *)p->dispsw_data)[attr_bgcol_ec(p, conp)]; 1434 sx=conp->vc_cols*fontwidth(p); 1435 sy=conp->vc_rows*fontheight(p); 1436 if (!bottom_only) 1437 pm2fb_block_op((struct pm2fb_info* )p->fb_info, 0, 0, 0, 1438 sx, 0, (p->var.xres-sx), p->var.yres_virtual, c); 1439 pm2fb_block_op((struct pm2fb_info* )p->fb_info, 0, 0, 0, 1440 0, p->var.yoffset+sy, sx, p->var.yres-sy, c); 1441} 1442 1443static struct display_switch pm2_cfb32 = { 1444 setup: fbcon_cfb32_setup, 1445 bmove: pm2fb_bmove, 1446 clear: pm2fb_clear32, 1447 putc: fbcon_cfb32_putc, 1448 putcs: fbcon_cfb32_putcs, 1449 revc: fbcon_cfb32_revc, 1450 cursor: pm2fb_cursor, 1451 set_font: pm2fb_set_font, 1452 clear_margins: pm2fb_clear_margins32, 1453 fontwidthmask: FONTWIDTH(4)|FONTWIDTH(8)|FONTWIDTH(12)|FONTWIDTH(16) 1454}; 1455#endif /* FBCON_HAS_CFB32 */ 1456 1457/*************************************************************************** 1458 * Framebuffer functions 1459 ***************************************************************************/ 1460 1461static void pm2fb_detect(void) {} 1462 1463static int pm2fb_encode_fix(struct fb_fix_screeninfo* fix, 1464 const void* par, struct fb_info_gen* info) { 1465 struct pm2fb_info* i=(struct pm2fb_info* )info; 1466 struct pm2fb_par* p=(struct pm2fb_par* )par; 1467 1468 strcpy(fix->id, permedia2_name); 1469 fix->smem_start=i->regions.p_fb; 1470 fix->smem_len=i->regions.fb_size; 1471 fix->mmio_start=i->regions.p_regs; 1472 fix->mmio_len=PM2_REGS_SIZE; 1473 fix->accel=FB_ACCEL_3DLABS_PERMEDIA2; 1474 fix->type=FB_TYPE_PACKED_PIXELS; 1475 fix->visual=p->depth==8?FB_VISUAL_PSEUDOCOLOR:FB_VISUAL_TRUECOLOR; 1476 if (i->current_par_valid) 1477 fix->line_length=i->current_par.width*(i->current_par.depth/8); 1478 else 1479 fix->line_length=0; 1480 fix->xpanstep=p->depth==24?8:64/p->depth; 1481 fix->ypanstep=1; 1482 fix->ywrapstep=0; 1483 return 0; 1484} 1485 1486#ifdef PM2FB_MASTER_DEBUG 1487static void pm2fb_display_var(const struct fb_var_screeninfo* var) { 1488 1489 printk( KERN_DEBUG 1490"- struct fb_var_screeninfo ---------------------------------------------------\n"); 1491 printk( KERN_DEBUG 1492 "resolution: %ux%ux%u (virtual %ux%u+%u+%u)\n", 1493 var->xres, var->yres, var->bits_per_pixel, 1494 var->xres_virtual, var->yres_virtual, 1495 var->xoffset, var->yoffset); 1496 printk( KERN_DEBUG 1497 "color: %c%c " 1498 "R(%u,%u,%u), G(%u,%u,%u), B(%u,%u,%u), T(%u,%u,%u)\n", 1499 var->grayscale?'G':'C', var->nonstd?'N':'S', 1500 var->red.offset, var->red.length, var->red.msb_right, 1501 var->green.offset, var->green.length, var->green.msb_right, 1502 var->blue.offset, var->blue.length, var->blue.msb_right, 1503 var->transp.offset, var->transp.length, 1504 var->transp.msb_right); 1505 printk( KERN_DEBUG 1506 "timings: %ups (%u,%u)-(%u,%u)+%u+%u\n", 1507 var->pixclock, 1508 var->left_margin, var->upper_margin, var->right_margin, 1509 var->lower_margin, var->hsync_len, var->vsync_len); 1510 printk( KERN_DEBUG 1511 "activate %08x accel_flags %08x sync %08x vmode %08x\n", 1512 var->activate, var->accel_flags, var->sync, var->vmode); 1513 printk( KERN_DEBUG 1514"------------------------------------------------------------------------------\n"); 1515} 1516 1517#define pm2fb_decode_var pm2fb_wrapped_decode_var 1518#endif 1519 1520static int pm2fb_decode_var(const struct fb_var_screeninfo* var, 1521 void* par, struct fb_info_gen* info) { 1522 struct pm2fb_info* i=(struct pm2fb_info* )info; 1523 struct pm2fb_par p; 1524 u32 xres; 1525 int data64; 1526 1527 memset(&p, 0, sizeof(struct pm2fb_par)); 1528 p.width=(var->xres_virtual+7)&~7; 1529 p.height=var->yres_virtual; 1530 p.depth=(var->bits_per_pixel+7)&~7; 1531 p.depth=p.depth>32?32:p.depth; 1532 data64=p.depth>8 || i->type == PM2_TYPE_PERMEDIA2V; 1533 xres=(var->xres+31)&~31; 1534 if (p.width<xres+var->xoffset) 1535 p.width=xres+var->xoffset; 1536 if (p.height<var->yres+var->yoffset) 1537 p.height=var->yres+var->yoffset; 1538 if (!partprod(xres)) { 1539 DPRINTK("width not supported: %u\n", xres); 1540 return -EINVAL; 1541 } 1542 if (p.width>2047) { 1543 DPRINTK("virtual width not supported: %u\n", p.width); 1544 return -EINVAL; 1545 } 1546 if (var->yres<200) { 1547 DPRINTK("height not supported: %u\n", 1548 (u32 )var->yres); 1549 return -EINVAL; 1550 } 1551 if (p.height<200 || p.height>2047) { 1552 DPRINTK("virtual height not supported: %u\n", p.height); 1553 return -EINVAL; 1554 } 1555 if (p.depth>32) { 1556 DPRINTK("depth not supported: %u\n", p.depth); 1557 return -EINVAL; 1558 } 1559 if (p.width*p.height*p.depth/8>i->regions.fb_size) { 1560 DPRINTK("no memory for screen (%ux%ux%u)\n", 1561 p.width, p.height, p.depth); 1562 return -EINVAL; 1563 } 1564 p.pixclock=PICOS2KHZ(var->pixclock); 1565 if (p.pixclock>PM2_MAX_PIXCLOCK) { 1566 DPRINTK("pixclock too high (%uKHz)\n", p.pixclock); 1567 return -EINVAL; 1568 } 1569 p.hsstart=to3264(var->right_margin, p.depth, data64); 1570 p.hsend=p.hsstart+to3264(var->hsync_len, p.depth, data64); 1571 p.hbend=p.hsend+to3264(var->left_margin, p.depth, data64); 1572 p.htotal=to3264(xres, p.depth, data64)+p.hbend-1; 1573 p.vsstart=var->lower_margin?var->lower_margin-1:0; 1574 p.vsend=var->lower_margin+var->vsync_len-1; 1575 p.vbend=var->lower_margin+var->vsync_len+var->upper_margin; 1576 p.vtotal=var->yres+p.vbend-1; 1577 p.stride=to3264(p.width, p.depth, 1); 1578 p.base=to3264(var->yoffset*xres+var->xoffset, p.depth, 1); 1579 if (data64) 1580 p.video|=PM2F_DATA_64_ENABLE; 1581 if (var->sync & FB_SYNC_HOR_HIGH_ACT) 1582 p.video|=PM2F_HSYNC_ACT_HIGH; 1583 else 1584 p.video|=PM2F_HSYNC_ACT_LOW; 1585 if (var->sync & FB_SYNC_VERT_HIGH_ACT) 1586 p.video|=PM2F_VSYNC_ACT_HIGH; 1587 else 1588 p.video|=PM2F_VSYNC_ACT_LOW; 1589 if ((var->vmode & FB_VMODE_MASK)==FB_VMODE_INTERLACED) { 1590 DPRINTK("interlaced not supported\n"); 1591 return -EINVAL; 1592 } 1593 if ((var->vmode & FB_VMODE_MASK)==FB_VMODE_DOUBLE) 1594 p.video|=PM2F_LINE_DOUBLE; 1595 if (var->activate==FB_ACTIVATE_NOW) 1596 p.video|=PM2F_VIDEO_ENABLE; 1597 *((struct pm2fb_par* )par)=p; 1598 return 0; 1599} 1600 1601#ifdef PM2FB_MASTER_DEBUG 1602#undef pm2fb_decode_var 1603 1604static int pm2fb_decode_var(const struct fb_var_screeninfo* var, 1605 void* par, struct fb_info_gen* info) { 1606 int result; 1607 1608 result=pm2fb_wrapped_decode_var(var, par, info); 1609 pm2fb_display_var(var); 1610 return result; 1611} 1612#endif 1613 1614static int pm2fb_encode_var(struct fb_var_screeninfo* var, 1615 const void* par, struct fb_info_gen* info) { 1616 struct pm2fb_par* p=(struct pm2fb_par* )par; 1617 struct fb_var_screeninfo v; 1618 u32 base; 1619 1620 memset(&v, 0, sizeof(struct fb_var_screeninfo)); 1621 v.xres_virtual=p->width; 1622 v.yres_virtual=p->height; 1623 v.xres=(p->htotal+1)-p->hbend; 1624 v.yres=(p->vtotal+1)-p->vbend; 1625 v.right_margin=p->hsstart; 1626 v.hsync_len=p->hsend-p->hsstart; 1627 v.left_margin=p->hbend-p->hsend; 1628 v.lower_margin=p->vsstart+1; 1629 v.vsync_len=p->vsend-v.lower_margin+1; 1630 v.upper_margin=p->vbend-v.lower_margin-v.vsync_len; 1631 v.bits_per_pixel=p->depth; 1632 if (p->video & PM2F_DATA_64_ENABLE) { 1633 v.xres=v.xres<<1; 1634 v.right_margin=v.right_margin<<1; 1635 v.hsync_len=v.hsync_len<<1; 1636 v.left_margin=v.left_margin<<1; 1637 } 1638 switch (p->depth) { 1639 case 8: 1640 v.red.length=v.green.length=v.blue.length=8; 1641 v.xres=v.xres<<2; 1642 v.right_margin=v.right_margin<<2; 1643 v.hsync_len=v.hsync_len<<2; 1644 v.left_margin=v.left_margin<<2; 1645 break; 1646 case 16: 1647 v.red.offset=11; 1648 v.red.length=5; 1649 v.green.offset=5; 1650 v.green.length=6; 1651 v.blue.length=5; 1652 v.xres=v.xres<<1; 1653 v.right_margin=v.right_margin<<1; 1654 v.hsync_len=v.hsync_len<<1; 1655 v.left_margin=v.left_margin<<1; 1656 break; 1657 case 32: 1658 v.transp.offset=24; 1659 v.red.offset=16; 1660 v.green.offset=8; 1661 v.red.length=v.green.length=v.blue.length= 1662 v.transp.length=8; 1663 break; 1664 case 24: 1665 v.blue.offset=16; 1666 v.green.offset=8; 1667 v.red.length=v.green.length=v.blue.length=8; 1668 v.xres=(v.xres<<2)/3; 1669 v.right_margin=(v.right_margin<<2)/3; 1670 v.hsync_len=(v.hsync_len<<2)/3; 1671 v.left_margin=(v.left_margin<<2)/3; 1672 break; 1673 } 1674 base=from3264(p->base, p->depth, 1); 1675 v.xoffset=base%v.xres; 1676 v.yoffset=base/v.xres; 1677 v.height=v.width=-1; 1678 v.pixclock=KHZ2PICOS(p->pixclock); 1679 if ((p->video & PM2F_HSYNC_MASK)==PM2F_HSYNC_ACT_HIGH) 1680 v.sync|=FB_SYNC_HOR_HIGH_ACT; 1681 if ((p->video & PM2F_VSYNC_MASK)==PM2F_VSYNC_ACT_HIGH) 1682 v.sync|=FB_SYNC_VERT_HIGH_ACT; 1683 if (p->video & PM2F_LINE_DOUBLE) 1684 v.vmode=FB_VMODE_DOUBLE; 1685 *var=v; 1686 return 0; 1687} 1688 1689static void set_user_mode(struct pm2fb_info* i) { 1690 1691 if (pm2fb_options.flags & OPTF_YPAN) { 1692 int h = i->current_par.height; 1693 i->current_par.height=i->regions.fb_size/ 1694 (i->current_par.width*i->current_par.depth/8); 1695 i->current_par.height=MIN(i->current_par.height,2047); 1696 i->current_par.height=MAX(i->current_par.height,h); 1697 } 1698} 1699 1700static void pm2fb_get_par(void* par, struct fb_info_gen* info) { 1701 struct pm2fb_info* i=(struct pm2fb_info* )info; 1702 1703 if (!i->current_par_valid) { 1704 set_user_mode(i); 1705 pm2fb_reset(i); 1706 set_screen(i, &i->current_par); 1707 i->current_par_valid=1; 1708 } 1709 *((struct pm2fb_par* )par)=i->current_par; 1710} 1711 1712static void pm2fb_set_par(const void* par, struct fb_info_gen* info) { 1713 struct pm2fb_info* i=(struct pm2fb_info* )info; 1714 struct pm2fb_par* p; 1715 1716 p=(struct pm2fb_par* )par; 1717 if (i->current_par_valid) { 1718 i->current_par.base=p->base; 1719 if (!memcmp(p, &i->current_par, sizeof(struct pm2fb_par))) { 1720 WAIT_FIFO(i, 1); 1721 pm2_WR(i, PM2R_SCREEN_BASE, p->base); 1722 return; 1723 } 1724 } 1725 set_screen(i, p); 1726 i->current_par=*p; 1727 i->current_par_valid=1; 1728#ifdef PM2FB_HW_CURSOR 1729 if (i->cursor) { 1730 pm2v_set_cursor_color(i, cursor_color_map, cursor_color_map, cursor_color_map); 1731 pm2v_set_cursor_shape(i); 1732 } 1733#endif 1734} 1735 1736static int pm2fb_getcolreg(unsigned regno, 1737 unsigned* red, unsigned* green, unsigned* blue, 1738 unsigned* transp, struct fb_info* info) { 1739 struct pm2fb_info* i=(struct pm2fb_info* )info; 1740 1741 if (regno<256) { 1742 *red=i->palette[regno].red<<8|i->palette[regno].red; 1743 *green=i->palette[regno].green<<8|i->palette[regno].green; 1744 *blue=i->palette[regno].blue<<8|i->palette[regno].blue; 1745 *transp=i->palette[regno].transp<<8|i->palette[regno].transp; 1746 } 1747 return regno>255; 1748} 1749 1750static int pm2fb_setcolreg(unsigned regno, 1751 unsigned red, unsigned green, unsigned blue, 1752 unsigned transp, struct fb_info* info) { 1753 struct pm2fb_info* i=(struct pm2fb_info* )info; 1754 1755 if (regno<16) { 1756 switch (i->current_par.depth) { 1757#ifdef FBCON_HAS_CFB8 1758 case 8: 1759 break; 1760#endif 1761#ifdef FBCON_HAS_CFB16 1762 case 16: 1763 i->cmap.cmap16[regno]= 1764 ((u32 )red & 0xf800) | 1765 (((u32 )green & 0xfc00)>>5) | 1766 (((u32 )blue & 0xf800)>>11); 1767 break; 1768#endif 1769#ifdef FBCON_HAS_CFB24 1770 case 24: 1771 i->cmap.cmap24[regno]= 1772 (((u32 )blue & 0xff00) << 8) | 1773 ((u32 )green & 0xff00) | 1774 (((u32 )red & 0xff00) >> 8); 1775 break; 1776#endif 1777#ifdef FBCON_HAS_CFB32 1778 case 32: 1779 i->cmap.cmap32[regno]= 1780 (((u32 )transp & 0xff00) << 16) | 1781 (((u32 )red & 0xff00) << 8) | 1782 (((u32 )green & 0xff00)) | 1783 (((u32 )blue & 0xff00) >> 8); 1784 break; 1785#endif 1786 default: 1787 DPRINTK("bad depth %u\n", 1788 i->current_par.depth); 1789 break; 1790 } 1791 } 1792 if (regno<256) { 1793 i->palette[regno].red=red >> 8; 1794 i->palette[regno].green=green >> 8; 1795 i->palette[regno].blue=blue >> 8; 1796 i->palette[regno].transp=transp >> 8; 1797 if (i->current_par.depth==8) 1798 set_color(i, regno, red>>8, green>>8, blue>>8); 1799 } 1800 return regno>255; 1801} 1802 1803static void pm2fb_set_disp(const void* par, struct display* disp, 1804 struct fb_info_gen* info) { 1805 struct pm2fb_info* i=(struct pm2fb_info* )info; 1806 unsigned long flags; 1807 unsigned long depth; 1808 1809 save_flags(flags); 1810 cli(); 1811 disp->screen_base = i->regions.v_fb; 1812 switch (depth=((struct pm2fb_par* )par)->depth) { 1813#ifdef FBCON_HAS_CFB8 1814 case 8: 1815 disp->dispsw=&pm2_cfb8; 1816 break; 1817#endif 1818#ifdef FBCON_HAS_CFB16 1819 case 16: 1820 disp->dispsw=&pm2_cfb16; 1821 disp->dispsw_data=i->cmap.cmap16; 1822 break; 1823#endif 1824#ifdef FBCON_HAS_CFB24 1825 case 24: 1826 disp->dispsw=&pm2_cfb24; 1827 disp->dispsw_data=i->cmap.cmap24; 1828 break; 1829#endif 1830#ifdef FBCON_HAS_CFB32 1831 case 32: 1832 disp->dispsw=&pm2_cfb32; 1833 disp->dispsw_data=i->cmap.cmap32; 1834 break; 1835#endif 1836 default: 1837 disp->dispsw=&fbcon_dummy; 1838 break; 1839 } 1840 restore_flags(flags); 1841} 1842 1843#ifdef PM2FB_HW_CURSOR 1844/*************************************************************************** 1845 * Hardware cursor support 1846 ***************************************************************************/ 1847 1848static u8 cursor_bits_lookup[16] = { 1849 0x00, 0x40, 0x10, 0x50, 0x04, 0x44, 0x14, 0x54, 1850 0x01, 0x41, 0x11, 0x51, 0x05, 0x45, 0x15, 0x55 1851}; 1852 1853static u8 cursor_mask_lookup[16] = { 1854 0x00, 0x80, 0x20, 0xa0, 0x08, 0x88, 0x28, 0xa8, 1855 0x02, 0x82, 0x22, 0xa2, 0x0a, 0x8a, 0x2a, 0xaa 1856}; 1857 1858static void pm2v_set_cursor_color(struct pm2fb_info *fb, u8 *red, u8 *green, u8 *blue) 1859{ 1860 struct pm2_cursor *c = fb->cursor; 1861 int i; 1862 1863 for (i = 0; i < 2; i++) { 1864 c->color[3*i] = red[i]; 1865 c->color[3*i+1] = green[i]; 1866 c->color[3*i+2] = blue[i]; 1867 } 1868 1869 WAIT_FIFO(fb, 14); 1870 pm2_WR(fb, PM2VR_RD_INDEX_HIGH, PM2VI_RD_CURSOR_PALETTE >> 8); 1871 for (i = 0; i < 6; i++) 1872 pm2v_RDAC_WR(fb, PM2VI_RD_CURSOR_PALETTE+i, c->color[i]); 1873 pm2_WR(fb, PM2VR_RD_INDEX_HIGH, 0); 1874} 1875 1876static void pm2v_set_cursor_shape(struct pm2fb_info *fb) 1877{ 1878 struct pm2_cursor *c = fb->cursor; 1879 u8 m, b; 1880 int i, x, y; 1881 1882 WAIT_FIFO(fb, 1); 1883 pm2_WR(fb, PM2VR_RD_INDEX_HIGH, PM2VI_RD_CURSOR_PATTERN >> 8); 1884 for (y = 0, i = 0; y < c->size.y; y++) { 1885 WAIT_FIFO(fb, 32); 1886 for (x = 0; x < c->size.x >> 3; x++) { 1887 m = c->mask[x][y]; 1888 b = c->bits[x][y]; 1889 pm2v_RDAC_WR(fb, PM2VI_RD_CURSOR_PATTERN + i, 1890 cursor_mask_lookup[m >> 4] | 1891 cursor_bits_lookup[(b & m) >> 4]); 1892 pm2v_RDAC_WR(fb, PM2VI_RD_CURSOR_PATTERN + i + 1, 1893 cursor_mask_lookup[m & 0x0f] | 1894 cursor_bits_lookup[(b & m) & 0x0f]); 1895 i+=2; 1896 } 1897 for ( ; x < 8; x++) { 1898 pm2v_RDAC_WR(fb, PM2VI_RD_CURSOR_PATTERN + i, 0); 1899 pm2v_RDAC_WR(fb, PM2VI_RD_CURSOR_PATTERN + i + 1, 0); 1900 i+=2; 1901 } 1902 } 1903 for (; y < 64; y++) { 1904 WAIT_FIFO(fb, 32); 1905 for (x = 0; x < 8; x++) { 1906 pm2v_RDAC_WR(fb, PM2VI_RD_CURSOR_PATTERN + i, 0); 1907 pm2v_RDAC_WR(fb, PM2VI_RD_CURSOR_PATTERN + i + 1, 0); 1908 i+=2; 1909 } 1910 } 1911 WAIT_FIFO(fb, 1); 1912 pm2_WR(fb, PM2VR_RD_INDEX_HIGH, 0); 1913} 1914 1915static void pm2v_set_cursor(struct pm2fb_info *fb, int on) 1916{ 1917 struct pm2_cursor *c = fb->cursor; 1918 int x = c->pos.x; 1919 1920 if (!on) x = 4000; 1921 WAIT_FIFO(fb, 14); 1922 pm2v_RDAC_WR(fb, PM2VI_RD_CURSOR_X_LOW, x & 0xff); 1923 pm2v_RDAC_WR(fb, PM2VI_RD_CURSOR_X_HIGH, (x >> 8) & 0x0f); 1924 pm2v_RDAC_WR(fb, PM2VI_RD_CURSOR_Y_LOW, c->pos.y & 0xff); 1925 pm2v_RDAC_WR(fb, PM2VI_RD_CURSOR_Y_HIGH, (c->pos.y >> 8) & 0x0f); 1926 pm2v_RDAC_WR(fb, PM2VI_RD_CURSOR_X_HOT, c->hot.x & 0x3f); 1927 pm2v_RDAC_WR(fb, PM2VI_RD_CURSOR_Y_HOT, c->hot.y & 0x3f); 1928 pm2v_RDAC_WR(fb, PM2VI_RD_CURSOR_MODE, 0x11); 1929} 1930 1931static void pm2_cursor_timer_handler(unsigned long dev_addr) 1932{ 1933 struct pm2fb_info *fb = (struct pm2fb_info *)dev_addr; 1934 1935 if (!fb->cursor->enable) 1936 goto out; 1937 1938 if (fb->cursor->vbl_cnt && --fb->cursor->vbl_cnt == 0) { 1939 fb->cursor->on ^= 1; 1940 pm2v_set_cursor(fb, fb->cursor->on); 1941 fb->cursor->vbl_cnt = fb->cursor->blink_rate; 1942 } 1943 1944out: 1945 fb->cursor->timer->expires = jiffies + (HZ / 50); 1946 add_timer(fb->cursor->timer); 1947} 1948 1949static void pm2fb_cursor(struct display *p, int mode, int x, int y) 1950{ 1951 struct pm2fb_info *fb = (struct pm2fb_info *)p->fb_info; 1952 struct pm2_cursor *c = fb->cursor; 1953 1954 if (!c) return; 1955 1956 x *= fontwidth(p); 1957 y *= fontheight(p); 1958 if (c->pos.x == x && c->pos.y == y && (mode == CM_ERASE) == !c->enable) 1959 return; 1960 1961 c->enable = 0; 1962 if (c->on) 1963 pm2v_set_cursor(fb, 0); 1964 c->pos.x = x; 1965 c->pos.y = y; 1966 1967 switch (mode) { 1968 case CM_ERASE: 1969 c->on = 0; 1970 break; 1971 1972 case CM_DRAW: 1973 case CM_MOVE: 1974 if (c->on) 1975 pm2v_set_cursor(fb, 1); 1976 else 1977 c->vbl_cnt = CURSOR_DRAW_DELAY; 1978 c->enable = 1; 1979 break; 1980 } 1981} 1982 1983static struct pm2_cursor * __init pm2_init_cursor(struct pm2fb_info *fb) 1984{ 1985 struct pm2_cursor *cursor; 1986 1987 if (fb->type != PM2_TYPE_PERMEDIA2V) 1988 return 0; 1989 1990 cursor = kmalloc(sizeof(struct pm2_cursor), GFP_ATOMIC); 1991 if (!cursor) 1992 return 0; 1993 memset(cursor, 0, sizeof(*cursor)); 1994 1995 cursor->timer = kmalloc(sizeof(*cursor->timer), GFP_KERNEL); 1996 if (!cursor->timer) { 1997 kfree(cursor); 1998 return 0; 1999 } 2000 memset(cursor->timer, 0, sizeof(*cursor->timer)); 2001 2002 cursor->blink_rate = DEFAULT_CURSOR_BLINK_RATE; 2003 2004 if (curblink) { 2005 init_timer(cursor->timer); 2006 cursor->timer->expires = jiffies + (HZ / 50); 2007 cursor->timer->data = (unsigned long)fb; 2008 cursor->timer->function = pm2_cursor_timer_handler; 2009 add_timer(cursor->timer); 2010 } 2011 2012 return cursor; 2013} 2014 2015static int pm2fb_set_font(struct display *d, int width, int height) 2016{ 2017 struct pm2fb_info *fb = (struct pm2fb_info *)d->fb_info; 2018 struct pm2_cursor *c = fb->cursor; 2019 int i, j; 2020 2021 if (c) { 2022 if (!width || !height) { 2023 width = 8; 2024 height = 16; 2025 } 2026 2027 c->hot.x = 0; 2028 c->hot.y = 0; 2029 c->size.x = width; 2030 c->size.y = height; 2031 2032 memset(c->bits, 0xff, sizeof(c->bits)); 2033 memset(c->mask, 0, sizeof(c->mask)); 2034 2035 for (i = 0, j = width; j >= 0; j -= 8, i++) { 2036 c->mask[i][height-2] = (j >= 8) ? 0xff : (0xff << (8 - j)); 2037 c->mask[i][height-1] = (j >= 8) ? 0xff : (0xff << (8 - j)); 2038 } 2039 2040 pm2v_set_cursor_color(fb, cursor_color_map, cursor_color_map, cursor_color_map); 2041 pm2v_set_cursor_shape(fb); 2042 } 2043 return 1; 2044} 2045#endif /* PM2FB_HW_CURSOR */ 2046 2047/*************************************************************************** 2048 * Begin of public functions 2049 ***************************************************************************/ 2050 2051#ifdef MODULE 2052static void pm2fb_cleanup(void) { 2053 struct pm2fb_info* i = &fb_info; 2054 2055 unregister_framebuffer((struct fb_info *)i); 2056 pm2fb_reset(i); 2057 2058 UNMAP(i->regions.v_fb, i->regions.fb_size); 2059 release_mem_region(i->regions.p_fb, i->regions.fb_size); 2060 2061 UNMAP(i->regions.v_regs, PM2_REGS_SIZE); 2062 release_mem_region(i->regions.p_regs, PM2_REGS_SIZE); 2063 2064 if (board_table[i->board].cleanup) 2065 board_table[i->board].cleanup(i); 2066} 2067#endif /* MODULE */ 2068 2069int __init pm2fb_init(void){ 2070 2071 MOD_INC_USE_COUNT; 2072 memset(&fb_info, 0, sizeof(fb_info)); 2073 memcpy(&fb_info.current_par, &pm2fb_options.user_mode, sizeof(fb_info.current_par)); 2074 if (!pm2fb_conf(&fb_info)) { 2075 MOD_DEC_USE_COUNT; 2076 return -ENXIO; 2077 } 2078 pm2fb_reset(&fb_info); 2079 fb_info.disp.scrollmode=SCROLL_YNOMOVE; 2080 fb_info.gen.parsize=sizeof(struct pm2fb_par); 2081 fb_info.gen.fbhw=&pm2fb_hwswitch; 2082 strcpy(fb_info.gen.info.modename, permedia2_name); 2083 fb_info.gen.info.flags=FBINFO_FLAG_DEFAULT; 2084 fb_info.gen.info.fbops=&pm2fb_ops; 2085 fb_info.gen.info.disp=&fb_info.disp; 2086 strcpy(fb_info.gen.info.fontname, pm2fb_options.font); 2087 fb_info.gen.info.switch_con=&fbgen_switch; 2088 fb_info.gen.info.updatevar=&fbgen_update_var; 2089 fb_info.gen.info.blank=&fbgen_blank; 2090 fbgen_get_var(&fb_info.disp.var, -1, &fb_info.gen.info); 2091 fbgen_do_set_var(&fb_info.disp.var, 1, &fb_info.gen); 2092 fbgen_set_disp(-1, &fb_info.gen); 2093 fbgen_install_cmap(0, &fb_info.gen); 2094 if (register_framebuffer(&fb_info.gen.info)<0) { 2095 printk(KERN_ERR "pm2fb: unable to register.\n"); 2096 MOD_DEC_USE_COUNT; 2097 return -EINVAL; 2098 } 2099 printk(KERN_INFO "fb%d: %s (%s), using %uK of video memory.\n", 2100 GET_FB_IDX(fb_info.gen.info.node), 2101 board_table[fb_info.board].name, 2102 permedia2_name, 2103 (u32 )(fb_info.regions.fb_size>>10)); 2104 return 0; 2105} 2106 2107static void __init pm2fb_mode_setup(char* options){ 2108 int i; 2109 2110 for (i=0; user_mode[i].name[0] && 2111 strcmp(options, user_mode[i].name); i++); 2112 if (user_mode[i].name[0]) { 2113 memcpy(&pm2fb_options.user_mode, &user_mode[i].par, 2114 sizeof(pm2fb_options.user_mode)); 2115 pm2fb_options.flags |= OPTF_USER; 2116 } 2117} 2118 2119static void __init pm2fb_font_setup(char* options){ 2120 2121 strncpy(pm2fb_options.font, options, sizeof(pm2fb_options.font)); 2122 pm2fb_options.font[sizeof(pm2fb_options.font)-1]='\0'; 2123} 2124 2125int __init pm2fb_setup(char* options){ 2126 char* next; 2127 2128 while (options) { 2129 if ((next=strchr(options, ','))) 2130 *(next++)='\0'; 2131 if (!strncmp(options, "font:", 5)) 2132 pm2fb_font_setup(options+5); 2133 else if (!strncmp(options, "mode:", 5)) 2134 pm2fb_mode_setup(options+5); 2135 else if (!strcmp(options, "ypan")) 2136 pm2fb_options.flags |= OPTF_YPAN; 2137 else if (!strcmp(options, "oldmem")) 2138 pm2fb_options.flags |= OPTF_OLD_MEM; 2139 else if (!strcmp(options, "virtual")) 2140 pm2fb_options.flags |= OPTF_VIRTUAL; 2141 else if (!strcmp(options, "noblink")) 2142 curblink = 0; 2143 options=next; 2144 } 2145 return 0; 2146} 2147 2148/*************************************************************************** 2149 * Begin of module functions 2150 ***************************************************************************/ 2151 2152#ifdef MODULE 2153 2154MODULE_LICENSE("GPL"); 2155 2156static char *mode = NULL; 2157 2158MODULE_PARM(mode, "s"); 2159 2160int __init init_module(void) { 2161 2162 if (mode) pm2fb_mode_setup(mode); 2163 return pm2fb_init(); 2164} 2165 2166void cleanup_module(void) { 2167 2168 pm2fb_cleanup(); 2169} 2170#endif /* MODULE */ 2171 2172/*************************************************************************** 2173 * That's all folks! 2174 ***************************************************************************/ 2175