1/* $Id: creatorfb.c,v 1.1.1.1 2008/10/15 03:27:04 james26_jang Exp $ 2 * creatorfb.c: Creator/Creator3D frame buffer driver 3 * 4 * Copyright (C) 1997,1998,1999 Jakub Jelinek (jj@ultra.linux.cz) 5 */ 6 7#include <linux/module.h> 8#include <linux/sched.h> 9#include <linux/kernel.h> 10#include <linux/errno.h> 11#include <linux/string.h> 12#include <linux/mm.h> 13#include <linux/tty.h> 14#include <linux/slab.h> 15#include <linux/vmalloc.h> 16#include <linux/delay.h> 17#include <linux/interrupt.h> 18#include <linux/fb.h> 19#include <linux/init.h> 20#include <linux/selection.h> 21 22#include <video/sbusfb.h> 23 24#include <asm/upa.h> 25 26#define FFB_SFB8R_VOFF 0x00000000 27#define FFB_SFB8G_VOFF 0x00400000 28#define FFB_SFB8B_VOFF 0x00800000 29#define FFB_SFB8X_VOFF 0x00c00000 30#define FFB_SFB32_VOFF 0x01000000 31#define FFB_SFB64_VOFF 0x02000000 32#define FFB_FBC_REGS_VOFF 0x04000000 33#define FFB_BM_FBC_REGS_VOFF 0x04002000 34#define FFB_DFB8R_VOFF 0x04004000 35#define FFB_DFB8G_VOFF 0x04404000 36#define FFB_DFB8B_VOFF 0x04804000 37#define FFB_DFB8X_VOFF 0x04c04000 38#define FFB_DFB24_VOFF 0x05004000 39#define FFB_DFB32_VOFF 0x06004000 40#define FFB_DFB422A_VOFF 0x07004000 /* DFB 422 mode write to A */ 41#define FFB_DFB422AD_VOFF 0x07804000 /* DFB 422 mode with line doubling */ 42#define FFB_DFB24B_VOFF 0x08004000 /* DFB 24bit mode write to B */ 43#define FFB_DFB422B_VOFF 0x09004000 /* DFB 422 mode write to B */ 44#define FFB_DFB422BD_VOFF 0x09804000 /* DFB 422 mode with line doubling */ 45#define FFB_SFB16Z_VOFF 0x0a004000 /* 16bit mode Z planes */ 46#define FFB_SFB8Z_VOFF 0x0a404000 /* 8bit mode Z planes */ 47#define FFB_SFB422_VOFF 0x0ac04000 /* SFB 422 mode write to A/B */ 48#define FFB_SFB422D_VOFF 0x0b404000 /* SFB 422 mode with line doubling */ 49#define FFB_FBC_KREGS_VOFF 0x0bc04000 50#define FFB_DAC_VOFF 0x0bc06000 51#define FFB_PROM_VOFF 0x0bc08000 52#define FFB_EXP_VOFF 0x0bc18000 53 54#define FFB_SFB8R_POFF 0x04000000UL 55#define FFB_SFB8G_POFF 0x04400000UL 56#define FFB_SFB8B_POFF 0x04800000UL 57#define FFB_SFB8X_POFF 0x04c00000UL 58#define FFB_SFB32_POFF 0x05000000UL 59#define FFB_SFB64_POFF 0x06000000UL 60#define FFB_FBC_REGS_POFF 0x00600000UL 61#define FFB_BM_FBC_REGS_POFF 0x00600000UL 62#define FFB_DFB8R_POFF 0x01000000UL 63#define FFB_DFB8G_POFF 0x01400000UL 64#define FFB_DFB8B_POFF 0x01800000UL 65#define FFB_DFB8X_POFF 0x01c00000UL 66#define FFB_DFB24_POFF 0x02000000UL 67#define FFB_DFB32_POFF 0x03000000UL 68#define FFB_FBC_KREGS_POFF 0x00610000UL 69#define FFB_DAC_POFF 0x00400000UL 70#define FFB_PROM_POFF 0x00000000UL 71#define FFB_EXP_POFF 0x00200000UL 72#define FFB_DFB422A_POFF 0x09000000UL 73#define FFB_DFB422AD_POFF 0x09800000UL 74#define FFB_DFB24B_POFF 0x0a000000UL 75#define FFB_DFB422B_POFF 0x0b000000UL 76#define FFB_DFB422BD_POFF 0x0b800000UL 77#define FFB_SFB16Z_POFF 0x0c800000UL 78#define FFB_SFB8Z_POFF 0x0c000000UL 79#define FFB_SFB422_POFF 0x0d000000UL 80#define FFB_SFB422D_POFF 0x0d800000UL 81 82/* Draw operations */ 83#define FFB_DRAWOP_DOT 0x00 84#define FFB_DRAWOP_AADOT 0x01 85#define FFB_DRAWOP_BRLINECAP 0x02 86#define FFB_DRAWOP_BRLINEOPEN 0x03 87#define FFB_DRAWOP_DDLINE 0x04 88#define FFB_DRAWOP_AALINE 0x05 89#define FFB_DRAWOP_TRIANGLE 0x06 90#define FFB_DRAWOP_POLYGON 0x07 91#define FFB_DRAWOP_RECTANGLE 0x08 92#define FFB_DRAWOP_FASTFILL 0x09 93#define FFB_DRAWOP_BCOPY 0x0a 94#define FFB_DRAWOP_VSCROLL 0x0b 95 96/* Pixel processor control */ 97/* Force WID */ 98#define FFB_PPC_FW_DISABLE 0x800000 99#define FFB_PPC_FW_ENABLE 0xc00000 100/* Auxiliary clip */ 101#define FFB_PPC_ACE_DISABLE 0x040000 102#define FFB_PPC_ACE_AUX_SUB 0x080000 103#define FFB_PPC_ACE_AUX_ADD 0x0c0000 104/* Depth cue */ 105#define FFB_PPC_DCE_DISABLE 0x020000 106#define FFB_PPC_DCE_ENABLE 0x030000 107/* Alpha blend */ 108#define FFB_PPC_ABE_DISABLE 0x008000 109#define FFB_PPC_ABE_ENABLE 0x00c000 110/* View clip */ 111#define FFB_PPC_VCE_DISABLE 0x001000 112#define FFB_PPC_VCE_2D 0x002000 113#define FFB_PPC_VCE_3D 0x003000 114/* Area pattern */ 115#define FFB_PPC_APE_DISABLE 0x000800 116#define FFB_PPC_APE_ENABLE 0x000c00 117/* Transparent background */ 118#define FFB_PPC_TBE_OPAQUE 0x000200 119#define FFB_PPC_TBE_TRANSPARENT 0x000300 120/* Z source */ 121#define FFB_PPC_ZS_VAR 0x000080 122#define FFB_PPC_ZS_CONST 0x0000c0 123/* Y source */ 124#define FFB_PPC_YS_VAR 0x000020 125#define FFB_PPC_YS_CONST 0x000030 126/* X source */ 127#define FFB_PPC_XS_WID 0x000004 128#define FFB_PPC_XS_VAR 0x000008 129#define FFB_PPC_XS_CONST 0x00000c 130/* Color (BGR) source */ 131#define FFB_PPC_CS_VAR 0x000002 132#define FFB_PPC_CS_CONST 0x000003 133 134#define FFB_ROP_NEW 0x83 135 136#define FFB_UCSR_FIFO_MASK 0x00000fff 137#define FFB_UCSR_FB_BUSY 0x01000000 138#define FFB_UCSR_RP_BUSY 0x02000000 139#define FFB_UCSR_ALL_BUSY (FFB_UCSR_RP_BUSY|FFB_UCSR_FB_BUSY) 140#define FFB_UCSR_READ_ERR 0x40000000 141#define FFB_UCSR_FIFO_OVFL 0x80000000 142#define FFB_UCSR_ALL_ERRORS (FFB_UCSR_READ_ERR|FFB_UCSR_FIFO_OVFL) 143 144struct ffb_fbc { 145 /* Next vertex registers */ 146 u32 xxx1[3]; 147 volatile u32 alpha; 148 volatile u32 red; 149 volatile u32 green; 150 volatile u32 blue; 151 volatile u32 depth; 152 volatile u32 y; 153 volatile u32 x; 154 u32 xxx2[2]; 155 volatile u32 ryf; 156 volatile u32 rxf; 157 u32 xxx3[2]; 158 159 volatile u32 dmyf; 160 volatile u32 dmxf; 161 u32 xxx4[2]; 162 volatile u32 ebyi; 163 volatile u32 ebxi; 164 u32 xxx5[2]; 165 volatile u32 by; 166 volatile u32 bx; 167 u32 dy; 168 u32 dx; 169 volatile u32 bh; 170 volatile u32 bw; 171 u32 xxx6[2]; 172 173 u32 xxx7[32]; 174 175 /* Setup unit vertex state register */ 176 volatile u32 suvtx; 177 u32 xxx8[63]; 178 179 /* Control registers */ 180 volatile u32 ppc; 181 volatile u32 wid; 182 volatile u32 fg; 183 volatile u32 bg; 184 volatile u32 consty; 185 volatile u32 constz; 186 volatile u32 xclip; 187 volatile u32 dcss; 188 volatile u32 vclipmin; 189 volatile u32 vclipmax; 190 volatile u32 vclipzmin; 191 volatile u32 vclipzmax; 192 volatile u32 dcsf; 193 volatile u32 dcsb; 194 volatile u32 dczf; 195 volatile u32 dczb; 196 197 u32 xxx9; 198 volatile u32 blendc; 199 volatile u32 blendc1; 200 volatile u32 blendc2; 201 volatile u32 fbramitc; 202 volatile u32 fbc; 203 volatile u32 rop; 204 volatile u32 cmp; 205 volatile u32 matchab; 206 volatile u32 matchc; 207 volatile u32 magnab; 208 volatile u32 magnc; 209 volatile u32 fbcfg0; 210 volatile u32 fbcfg1; 211 volatile u32 fbcfg2; 212 volatile u32 fbcfg3; 213 214 u32 ppcfg; 215 volatile u32 pick; 216 volatile u32 fillmode; 217 volatile u32 fbramwac; 218 volatile u32 pmask; 219 volatile u32 xpmask; 220 volatile u32 ypmask; 221 volatile u32 zpmask; 222 volatile u32 clip0min; 223 volatile u32 clip0max; 224 volatile u32 clip1min; 225 volatile u32 clip1max; 226 volatile u32 clip2min; 227 volatile u32 clip2max; 228 volatile u32 clip3min; 229 volatile u32 clip3max; 230 231 /* New 3dRAM III support regs */ 232 volatile u32 rawblend2; 233 volatile u32 rawpreblend; 234 volatile u32 rawstencil; 235 volatile u32 rawstencilctl; 236 volatile u32 threedram1; 237 volatile u32 threedram2; 238 volatile u32 passin; 239 volatile u32 rawclrdepth; 240 volatile u32 rawpmask; 241 volatile u32 rawcsrc; 242 volatile u32 rawmatch; 243 volatile u32 rawmagn; 244 volatile u32 rawropblend; 245 volatile u32 rawcmp; 246 volatile u32 rawwac; 247 volatile u32 fbramid; 248 249 volatile u32 drawop; 250 u32 xxx10[2]; 251 volatile u32 fontlpat; 252 u32 xxx11; 253 volatile u32 fontxy; 254 volatile u32 fontw; 255 volatile u32 fontinc; 256 volatile u32 font; 257 u32 xxx12[3]; 258 volatile u32 blend2; 259 volatile u32 preblend; 260 volatile u32 stencil; 261 volatile u32 stencilctl; 262 263 u32 xxx13[4]; 264 volatile u32 dcss1; 265 volatile u32 dcss2; 266 volatile u32 dcss3; 267 volatile u32 widpmask; 268 volatile u32 dcs2; 269 volatile u32 dcs3; 270 volatile u32 dcs4; 271 u32 xxx14; 272 volatile u32 dcd2; 273 volatile u32 dcd3; 274 volatile u32 dcd4; 275 u32 xxx15; 276 277 volatile u32 pattern[32]; 278 279 u32 xxx16[256]; 280 281 volatile u32 devid; 282 u32 xxx17[63]; 283 284 volatile u32 ucsr; 285 u32 xxx18[31]; 286 287 volatile u32 mer; 288}; 289 290static __inline__ void FFBFifo(struct fb_info_sbusfb *fb, int n) 291{ 292 struct ffb_fbc *fbc; 293 int cache = fb->s.ffb.fifo_cache; 294 295 if (cache - n < 0) { 296 fbc = fb->s.ffb.fbc; 297 do { cache = (upa_readl(&fbc->ucsr) & FFB_UCSR_FIFO_MASK) - 8; 298 } while (cache - n < 0); 299 } 300 fb->s.ffb.fifo_cache = cache - n; 301} 302 303static __inline__ void FFBWait(struct ffb_fbc *ffb) 304{ 305 int limit = 10000; 306 307 do { 308 if ((upa_readl(&ffb->ucsr) & FFB_UCSR_ALL_BUSY) == 0) 309 break; 310 if ((upa_readl(&ffb->ucsr) & FFB_UCSR_ALL_ERRORS) != 0) { 311 upa_writel(FFB_UCSR_ALL_ERRORS, &ffb->ucsr); 312 } 313 } while(--limit > 0); 314} 315 316struct ffb_dac { 317 volatile u32 type; 318 volatile u32 value; 319 volatile u32 type2; 320 volatile u32 value2; 321}; 322 323static struct sbus_mmap_map ffb_mmap_map[] = { 324 { FFB_SFB8R_VOFF, FFB_SFB8R_POFF, 0x0400000 }, 325 { FFB_SFB8G_VOFF, FFB_SFB8G_POFF, 0x0400000 }, 326 { FFB_SFB8B_VOFF, FFB_SFB8B_POFF, 0x0400000 }, 327 { FFB_SFB8X_VOFF, FFB_SFB8X_POFF, 0x0400000 }, 328 { FFB_SFB32_VOFF, FFB_SFB32_POFF, 0x1000000 }, 329 { FFB_SFB64_VOFF, FFB_SFB64_POFF, 0x2000000 }, 330 { FFB_FBC_REGS_VOFF, FFB_FBC_REGS_POFF, 0x0002000 }, 331 { FFB_BM_FBC_REGS_VOFF, FFB_BM_FBC_REGS_POFF, 0x0002000 }, 332 { FFB_DFB8R_VOFF, FFB_DFB8R_POFF, 0x0400000 }, 333 { FFB_DFB8G_VOFF, FFB_DFB8G_POFF, 0x0400000 }, 334 { FFB_DFB8B_VOFF, FFB_DFB8B_POFF, 0x0400000 }, 335 { FFB_DFB8X_VOFF, FFB_DFB8X_POFF, 0x0400000 }, 336 { FFB_DFB24_VOFF, FFB_DFB24_POFF, 0x1000000 }, 337 { FFB_DFB32_VOFF, FFB_DFB32_POFF, 0x1000000 }, 338 { FFB_FBC_KREGS_VOFF, FFB_FBC_KREGS_POFF, 0x0002000 }, 339 { FFB_DAC_VOFF, FFB_DAC_POFF, 0x0002000 }, 340 { FFB_PROM_VOFF, FFB_PROM_POFF, 0x0010000 }, 341 { FFB_EXP_VOFF, FFB_EXP_POFF, 0x0002000 }, 342 { FFB_DFB422A_VOFF, FFB_DFB422A_POFF, 0x0800000 }, 343 { FFB_DFB422AD_VOFF, FFB_DFB422AD_POFF, 0x0800000 }, 344 { FFB_DFB24B_VOFF, FFB_DFB24B_POFF, 0x1000000 }, 345 { FFB_DFB422B_VOFF, FFB_DFB422B_POFF, 0x0800000 }, 346 { FFB_DFB422BD_VOFF, FFB_DFB422BD_POFF, 0x0800000 }, 347 { FFB_SFB16Z_VOFF, FFB_SFB16Z_POFF, 0x0800000 }, 348 { FFB_SFB8Z_VOFF, FFB_SFB8Z_POFF, 0x0800000 }, 349 { FFB_SFB422_VOFF, FFB_SFB422_POFF, 0x0800000 }, 350 { FFB_SFB422D_VOFF, FFB_SFB422D_POFF, 0x0800000 }, 351 { 0, 0, 0 } 352}; 353 354static void ffb_setup(struct display *p) 355{ 356 p->next_line = 8192; 357 p->next_plane = 0; 358} 359 360static void ffb_clear(struct vc_data *conp, struct display *p, int sy, int sx, 361 int height, int width) 362{ 363 struct fb_info_sbusfb *fb = (struct fb_info_sbusfb *)p->fb_info; 364 register struct ffb_fbc *fbc = fb->s.ffb.fbc; 365 unsigned long flags; 366 u64 yx, hw; 367 int fg; 368 369 spin_lock_irqsave(&fb->lock, flags); 370 fg = ((u32 *)p->dispsw_data)[attr_bgcol_ec(p,conp)]; 371 if (fg != fb->s.ffb.fg_cache) { 372 FFBFifo(fb, 5); 373 upa_writel(fg, &fbc->fg); 374 fb->s.ffb.fg_cache = fg; 375 } else 376 FFBFifo(fb, 4); 377 378 if (fontheightlog(p)) { 379 yx = (u64)sy << (fontheightlog(p) + 32); hw = (u64)height << (fontheightlog(p) + 32); 380 } else { 381 yx = (u64)(sy * fontheight(p)) << 32; hw = (u64)(height * fontheight(p)) << 32; 382 } 383 if (fontwidthlog(p)) { 384 yx += sx << fontwidthlog(p); hw += width << fontwidthlog(p); 385 } else { 386 yx += sx * fontwidth(p); hw += width * fontwidth(p); 387 } 388 upa_writeq(yx + fb->s.ffb.yx_margin, &fbc->by); 389 upa_writeq(hw, &fbc->bh); 390 spin_unlock_irqrestore(&fb->lock, flags); 391} 392 393static void ffb_fill(struct fb_info_sbusfb *fb, struct display *p, int s, 394 int count, unsigned short *boxes) 395{ 396 register struct ffb_fbc *fbc = fb->s.ffb.fbc; 397 unsigned long flags; 398 int fg; 399 400 spin_lock_irqsave(&fb->lock, flags); 401 fg = ((u32 *)p->dispsw_data)[attr_bgcol(p,s)]; 402 if (fg != fb->s.ffb.fg_cache) { 403 FFBFifo(fb, 1); 404 upa_writel(fg, &fbc->fg); 405 fb->s.ffb.fg_cache = fg; 406 } 407 while (count-- > 0) { 408 FFBFifo(fb, 4); 409 upa_writel(boxes[1], &fbc->by); 410 upa_writel(boxes[0], &fbc->bx); 411 upa_writel(boxes[3] - boxes[1], &fbc->bh); 412 upa_writel(boxes[2] - boxes[0], &fbc->bw); 413 boxes += 4; 414 } 415 spin_unlock_irqrestore(&fb->lock, flags); 416} 417 418static void ffb_putc(struct vc_data *conp, struct display *p, int c, int yy, int xx) 419{ 420 struct fb_info_sbusfb *fb = (struct fb_info_sbusfb *)p->fb_info; 421 register struct ffb_fbc *fbc = fb->s.ffb.fbc; 422 unsigned long flags; 423 int i, xy; 424 u8 *fd; 425 u64 fgbg; 426 427 spin_lock_irqsave(&fb->lock, flags); 428 if (fontheightlog(p)) { 429 xy = (yy << (16 + fontheightlog(p))); 430 i = ((c & p->charmask) << fontheightlog(p)); 431 } else { 432 xy = ((yy * fontheight(p)) << 16); 433 i = (c & p->charmask) * fontheight(p); 434 } 435 if (fontwidth(p) <= 8) 436 fd = p->fontdata + i; 437 else 438 fd = p->fontdata + (i << 1); 439 if (fontwidthlog(p)) 440 xy += (xx << fontwidthlog(p)) + fb->s.ffb.xy_margin; 441 else 442 xy += (xx * fontwidth(p)) + fb->s.ffb.xy_margin; 443 fgbg = (((u64)(((u32 *)p->dispsw_data)[attr_fgcol(p,c)])) << 32) | 444 ((u32 *)p->dispsw_data)[attr_bgcol(p,c)]; 445 if (fgbg != *(u64 *)&fb->s.ffb.fg_cache) { 446 FFBFifo(fb, 2); 447 upa_writeq(fgbg, &fbc->fg); 448 *(u64 *)&fb->s.ffb.fg_cache = fgbg; 449 } 450 FFBFifo(fb, 2 + fontheight(p)); 451 upa_writel(xy, &fbc->fontxy); 452 upa_writel(fontwidth(p), &fbc->fontw); 453 if (fontwidth(p) <= 8) { 454 for (i = 0; i < fontheight(p); i++) { 455 u32 val = *fd++ << 24; 456 457 upa_writel(val, &fbc->font); 458 } 459 } else { 460 for (i = 0; i < fontheight(p); i++) { 461 u32 val = *(u16 *)fd << 16; 462 463 upa_writel(val, &fbc->font); 464 fd += 2; 465 } 466 } 467 spin_unlock_irqrestore(&fb->lock, flags); 468} 469 470static void ffb_putcs(struct vc_data *conp, struct display *p, const unsigned short *s, 471 int count, int yy, int xx) 472{ 473 struct fb_info_sbusfb *fb = (struct fb_info_sbusfb *)p->fb_info; 474 register struct ffb_fbc *fbc = fb->s.ffb.fbc; 475 unsigned long flags; 476 int i, xy; 477 u8 *fd1, *fd2, *fd3, *fd4; 478 u16 c; 479 u64 fgbg; 480 481 spin_lock_irqsave(&fb->lock, flags); 482 c = scr_readw(s); 483 fgbg = (((u64)(((u32 *)p->dispsw_data)[attr_fgcol(p, c)])) << 32) | 484 ((u32 *)p->dispsw_data)[attr_bgcol(p, c)]; 485 if (fgbg != *(u64 *)&fb->s.ffb.fg_cache) { 486 FFBFifo(fb, 2); 487 upa_writeq(fgbg, &fbc->fg); 488 *(u64 *)&fb->s.ffb.fg_cache = fgbg; 489 } 490 xy = fb->s.ffb.xy_margin; 491 if (fontwidthlog(p)) 492 xy += (xx << fontwidthlog(p)); 493 else 494 xy += xx * fontwidth(p); 495 if (fontheightlog(p)) 496 xy += (yy << (16 + fontheightlog(p))); 497 else 498 xy += ((yy * fontheight(p)) << 16); 499 if (fontwidth(p) <= 8) { 500 while (count >= 4) { 501 count -= 4; 502 FFBFifo(fb, 2 + fontheight(p)); 503 upa_writel(4 * fontwidth(p), &fbc->fontw); 504 upa_writel(xy, &fbc->fontxy); 505 if (fontheightlog(p)) { 506 fd1 = p->fontdata + ((scr_readw(s++) & p->charmask) << fontheightlog(p)); 507 fd2 = p->fontdata + ((scr_readw(s++) & p->charmask) << fontheightlog(p)); 508 fd3 = p->fontdata + ((scr_readw(s++) & p->charmask) << fontheightlog(p)); 509 fd4 = p->fontdata + ((scr_readw(s++) & p->charmask) << fontheightlog(p)); 510 } else { 511 fd1 = p->fontdata + ((scr_readw(s++) & p->charmask) * fontheight(p)); 512 fd2 = p->fontdata + ((scr_readw(s++) & p->charmask) * fontheight(p)); 513 fd3 = p->fontdata + ((scr_readw(s++) & p->charmask) * fontheight(p)); 514 fd4 = p->fontdata + ((scr_readw(s++) & p->charmask) * fontheight(p)); 515 } 516 if (fontwidth(p) == 8) { 517 for (i = 0; i < fontheight(p); i++) { 518 u32 val; 519 520 val = ((u32)*fd4++) | ((((u32)*fd3++) | ((((u32)*fd2++) | (((u32)*fd1++) 521 << 8)) << 8)) << 8); 522 upa_writel(val, &fbc->font); 523 } 524 xy += 32; 525 } else { 526 for (i = 0; i < fontheight(p); i++) { 527 u32 val = (((u32)*fd4++) | ((((u32)*fd3++) | ((((u32)*fd2++) | (((u32)*fd1++) 528 << fontwidth(p))) << fontwidth(p))) << fontwidth(p))) << (24 - 3 * fontwidth(p)); 529 upa_writel(val, &fbc->font); 530 } 531 xy += 4 * fontwidth(p); 532 } 533 } 534 } else { 535 while (count >= 2) { 536 count -= 2; 537 FFBFifo(fb, 2 + fontheight(p)); 538 upa_writel(2 * fontwidth(p), &fbc->fontw); 539 upa_writel(xy, &fbc->fontxy); 540 if (fontheightlog(p)) { 541 fd1 = p->fontdata + ((scr_readw(s++) & p->charmask) << (fontheightlog(p) + 1)); 542 fd2 = p->fontdata + ((scr_readw(s++) & p->charmask) << (fontheightlog(p) + 1)); 543 } else { 544 fd1 = p->fontdata + (((scr_readw(s++) & p->charmask) * fontheight(p)) << 1); 545 fd2 = p->fontdata + (((scr_readw(s++) & p->charmask) * fontheight(p)) << 1); 546 } 547 for (i = 0; i < fontheight(p); i++) { 548 u32 val = ((((u32)*(u16 *)fd1) << fontwidth(p)) | ((u32)*(u16 *)fd2)) << (16 - fontwidth(p)); 549 550 upa_writel(val, &fbc->font); 551 fd1 += 2; fd2 += 2; 552 } 553 xy += 2 * fontwidth(p); 554 } 555 } 556 while (count) { 557 count--; 558 FFBFifo(fb, 2 + fontheight(p)); 559 upa_writel(fontwidth(p), &fbc->fontw); 560 upa_writel(xy, &fbc->fontxy); 561 if (fontheightlog(p)) 562 i = ((scr_readw(s++) & p->charmask) << fontheightlog(p)); 563 else 564 i = ((scr_readw(s++) & p->charmask) * fontheight(p)); 565 if (fontwidth(p) <= 8) { 566 fd1 = p->fontdata + i; 567 for (i = 0; i < fontheight(p); i++) { 568 u32 val = *fd1++ << 24; 569 570 upa_writel(val, &fbc->font); 571 } 572 } else { 573 fd1 = p->fontdata + (i << 1); 574 for (i = 0; i < fontheight(p); i++) { 575 u32 val = *(u16 *)fd1 << 16; 576 577 upa_writel(val, &fbc->font); 578 fd1 += 2; 579 } 580 } 581 xy += fontwidth(p); 582 } 583 spin_unlock_irqrestore(&fb->lock, flags); 584} 585 586static void ffb_revc(struct display *p, int xx, int yy) 587{ 588 /* Not used if hw cursor */ 589} 590 591 592static void ffb_unblank(struct fb_info_sbusfb *fb) 593{ 594 struct ffb_dac *dac = fb->s.ffb.dac; 595 unsigned long flags; 596 u32 tmp; 597 598 spin_lock_irqsave(&fb->lock, flags); 599 upa_writel(0x6000, &dac->type); 600 tmp = (upa_readl(&dac->value) | 0x1); 601 upa_writel(0x6000, &dac->type); 602 upa_writel(tmp, &dac->value); 603 spin_unlock_irqrestore(&fb->lock, flags); 604} 605 606static void ffb_loadcmap (struct fb_info_sbusfb *fb, struct display *p, int index, int count) 607{ 608 struct ffb_dac *dac = fb->s.ffb.dac; 609 unsigned long flags; 610 int i, j = count; 611 612 spin_lock_irqsave(&fb->lock, flags); 613 upa_writel(0x2000 | index, &dac->type); 614 for (i = index; j--; i++) { 615 u32 val; 616 617 /* Feed the colors in :)) */ 618 val = ((fb->color_map CM(i,0))) | 619 ((fb->color_map CM(i,1)) << 8) | 620 ((fb->color_map CM(i,2)) << 16); 621 upa_writel(val, &dac->value); 622 } 623 if (!p) 624 goto out; 625 for (i = index, j = count; i < 16 && j--; i++) 626 ((u32 *)p->dispsw_data)[i] = ((fb->color_map CM(i,0))) | 627 ((fb->color_map CM(i,1)) << 8) | 628 ((fb->color_map CM(i,2)) << 16); 629out: 630 spin_unlock_irqrestore(&fb->lock, flags); 631} 632 633static struct display_switch ffb_dispsw __initdata = { 634 setup: ffb_setup, 635 bmove: fbcon_redraw_bmove, 636 clear: ffb_clear, 637 putc: ffb_putc, 638 putcs: ffb_putcs, 639 revc: ffb_revc, 640 fontwidthmask: FONTWIDTHRANGE(1,16) /* Allow fontwidths up to 16 */ 641}; 642 643static void ffb_margins (struct fb_info_sbusfb *fb, struct display *p, int x_margin, int y_margin) 644{ 645 register struct ffb_fbc *fbc = fb->s.ffb.fbc; 646 unsigned long flags; 647 648 spin_lock_irqsave(&fb->lock, flags); 649 fb->s.ffb.xy_margin = (y_margin << 16) + x_margin; 650 fb->s.ffb.yx_margin = (((u64)y_margin) << 32) + x_margin; 651 p->screen_base += 8192 * (y_margin - fb->y_margin) + 4 * (x_margin - fb->x_margin); 652 FFBWait(fbc); 653 spin_unlock_irqrestore(&fb->lock, flags); 654} 655 656static __inline__ void __ffb_curs_enable (struct fb_info_sbusfb *fb, int enable) 657{ 658 struct ffb_dac *dac = fb->s.ffb.dac; 659 u32 val; 660 661 upa_writel(0x100, &dac->type2); 662 if (fb->s.ffb.dac_rev <= 2) { 663 val = enable ? 3 : 0; 664 } else { 665 val = enable ? 0 : 3; 666 } 667 upa_writel(val, &dac->value2); 668} 669 670static void ffb_setcursormap (struct fb_info_sbusfb *fb, u8 *red, u8 *green, u8 *blue) 671{ 672 struct ffb_dac *dac = fb->s.ffb.dac; 673 unsigned long flags; 674 675 spin_lock_irqsave(&fb->lock, flags); 676 __ffb_curs_enable (fb, 0); 677 upa_writel(0x102, &dac->type2); 678 upa_writel((red[0] | (green[0]<<8) | (blue[0]<<16)), &dac->value2); 679 upa_writel((red[1] | (green[1]<<8) | (blue[1]<<16)), &dac->value2); 680 spin_unlock_irqrestore(&fb->lock, flags); 681} 682 683/* Set cursor shape */ 684static void ffb_setcurshape (struct fb_info_sbusfb *fb) 685{ 686 struct ffb_dac *dac = fb->s.ffb.dac; 687 unsigned long flags; 688 int i, j; 689 690 spin_lock_irqsave(&fb->lock, flags); 691 __ffb_curs_enable (fb, 0); 692 for (j = 0; j < 2; j++) { 693 u32 val = j ? 0 : 0x80; 694 695 upa_writel(val, &dac->type2); 696 for (i = 0; i < 0x40; i++) { 697 if (fb->cursor.size.fbx <= 32) { 698 upa_writel(fb->cursor.bits [j][i], &dac->value2); 699 upa_writel(0, &dac->value2); 700 } else { 701 upa_writel(fb->cursor.bits [j][2*i], &dac->value2); 702 upa_writel(fb->cursor.bits [j][2*i+1], &dac->value2); 703 } 704 } 705 } 706 spin_unlock_irqrestore(&fb->lock, flags); 707} 708 709/* Load cursor information */ 710static void ffb_setcursor (struct fb_info_sbusfb *fb) 711{ 712 struct ffb_dac *dac = fb->s.ffb.dac; 713 struct cg_cursor *c = &fb->cursor; 714 unsigned long flags; 715 u32 val; 716 717 spin_lock_irqsave(&fb->lock, flags); 718 upa_writel(0x104, &dac->type2); 719 /* Should this be just 0x7ff?? 720 Should I do some margin handling and setcurshape in that case? */ 721 val = (((c->cpos.fby - c->chot.fby) & 0xffff) << 16) 722 |((c->cpos.fbx - c->chot.fbx) & 0xffff); 723 upa_writel(val, &dac->value2); 724 __ffb_curs_enable (fb, fb->cursor.enable); 725 spin_unlock_irqrestore(&fb->lock, flags); 726} 727 728static void ffb_switch_from_graph (struct fb_info_sbusfb *fb) 729{ 730 register struct ffb_fbc *fbc = fb->s.ffb.fbc; 731 unsigned long flags; 732 733 spin_lock_irqsave(&fb->lock, flags); 734 FFBWait(fbc); 735 fb->s.ffb.fifo_cache = 0; 736 FFBFifo(fb, 8); 737 upa_writel(FFB_PPC_VCE_DISABLE|FFB_PPC_TBE_OPAQUE| 738 FFB_PPC_APE_DISABLE|FFB_PPC_CS_CONST, 739 &fbc->ppc); 740 upa_writel(0x2000707f, &fbc->fbc); 741 upa_writel(FFB_ROP_NEW, &fbc->rop); 742 upa_writel(FFB_DRAWOP_RECTANGLE, &fbc->drawop); 743 upa_writel(0xffffffff, &fbc->pmask); 744 upa_writel(0x10000, &fbc->fontinc); 745 upa_writel(fb->s.ffb.fg_cache, &fbc->fg); 746 upa_writel(fb->s.ffb.bg_cache, &fbc->bg); 747 FFBWait(fbc); 748 spin_unlock_irqrestore(&fb->lock, flags); 749} 750 751static int __init ffb_rasterimg (struct fb_info *info, int start) 752{ 753 ffb_switch_from_graph (sbusfbinfo(info)); 754 return 0; 755} 756 757static char idstring[60] __initdata = { 0 }; 758 759static int __init creator_apply_upa_parent_ranges(int parent, struct linux_prom64_registers *regs) 760{ 761 struct linux_prom64_ranges ranges[PROMREG_MAX]; 762 char name[128]; 763 int len, i; 764 765 prom_getproperty(parent, "name", name, sizeof(name)); 766 if (strcmp(name, "upa") != 0) 767 return 0; 768 769 len = prom_getproperty(parent, "ranges", (void *) ranges, sizeof(ranges)); 770 if (len <= 0) 771 return 1; 772 773 len /= sizeof(struct linux_prom64_ranges); 774 for (i = 0; i < len; i++) { 775 struct linux_prom64_ranges *rng = &ranges[i]; 776 u64 phys_addr = regs->phys_addr; 777 778 if (phys_addr >= rng->ot_child_base && 779 phys_addr < (rng->ot_child_base + rng->or_size)) { 780 regs->phys_addr -= rng->ot_child_base; 781 regs->phys_addr += rng->ot_parent_base; 782 return 0; 783 } 784 } 785 786 return 1; 787} 788 789char __init *creatorfb_init(struct fb_info_sbusfb *fb) 790{ 791 struct fb_fix_screeninfo *fix = &fb->fix; 792 struct fb_var_screeninfo *var = &fb->var; 793 struct display *disp = &fb->disp; 794 struct fbtype *type = &fb->type; 795 struct linux_prom64_registers regs[2*PROMREG_MAX]; 796 int i, afb = 0; 797 unsigned int btype; 798 char name[64]; 799 struct fb_ops *fbops; 800 801 if (prom_getproperty(fb->prom_node, "reg", (void *) regs, sizeof(regs)) <= 0) 802 return NULL; 803 804 if (creator_apply_upa_parent_ranges(fb->prom_parent, ®s[0])) 805 return NULL; 806 807 disp->dispsw_data = (void *)kmalloc(16 * sizeof(u32), GFP_KERNEL); 808 if (disp->dispsw_data == NULL) 809 return NULL; 810 memset(disp->dispsw_data, 0, 16 * sizeof(u32)); 811 812 fbops = kmalloc(sizeof(*fbops), GFP_KERNEL); 813 if (fbops == NULL) { 814 kfree(disp->dispsw_data); 815 return NULL; 816 } 817 818 *fbops = *fb->info.fbops; 819 fbops->fb_rasterimg = ffb_rasterimg; 820 fb->info.fbops = fbops; 821 822 prom_getstring(fb->prom_node, "name", name, sizeof(name)); 823 if (!strcmp(name, "SUNW,afb")) 824 afb = 1; 825 826 btype = prom_getintdefault(fb->prom_node, "board_type", 0); 827 828 strcpy(fb->info.modename, "Creator"); 829 if (!afb) { 830 if ((btype & 7) == 3) 831 strcpy(fix->id, "Creator 3D"); 832 else 833 strcpy(fix->id, "Creator"); 834 } else 835 strcpy(fix->id, "Elite 3D"); 836 837 fix->visual = FB_VISUAL_TRUECOLOR; 838 fix->line_length = 8192; 839 fix->accel = FB_ACCEL_SUN_CREATOR; 840 841 var->bits_per_pixel = 32; 842 var->green.offset = 8; 843 var->blue.offset = 16; 844 var->accel_flags = FB_ACCELF_TEXT; 845 846 disp->scrollmode = SCROLL_YREDRAW; 847 disp->screen_base = (char *)__va(regs[0].phys_addr) + FFB_DFB24_POFF + 8192 * fb->y_margin + 4 * fb->x_margin; 848 fb->s.ffb.xy_margin = (fb->y_margin << 16) + fb->x_margin; 849 fb->s.ffb.yx_margin = (((u64)fb->y_margin) << 32) + fb->x_margin; 850 fb->s.ffb.fbc = (struct ffb_fbc *)(regs[0].phys_addr + FFB_FBC_REGS_POFF); 851 fb->s.ffb.dac = (struct ffb_dac *)(regs[0].phys_addr + FFB_DAC_POFF); 852 fb->dispsw = ffb_dispsw; 853 854 fb->margins = ffb_margins; 855 fb->loadcmap = ffb_loadcmap; 856 fb->setcursor = ffb_setcursor; 857 fb->setcursormap = ffb_setcursormap; 858 fb->setcurshape = ffb_setcurshape; 859 fb->switch_from_graph = ffb_switch_from_graph; 860 fb->fill = ffb_fill; 861 862 /* If there are any read errors or fifo overflow conditions, 863 * clear them now. 864 */ 865 if((upa_readl(&fb->s.ffb.fbc->ucsr) & FFB_UCSR_ALL_ERRORS) != 0) 866 upa_writel(FFB_UCSR_ALL_ERRORS, &fb->s.ffb.fbc->ucsr); 867 868 ffb_switch_from_graph(fb); 869 870 fb->physbase = regs[0].phys_addr; 871 fb->mmap_map = ffb_mmap_map; 872 873 fb->cursor.hwsize.fbx = 64; 874 fb->cursor.hwsize.fby = 64; 875 876 type->fb_depth = 24; 877 878 upa_writel(0x8000, &fb->s.ffb.dac->type); 879 fb->s.ffb.dac_rev = (upa_readl(&fb->s.ffb.dac->value) >> 0x1c); 880 881 i = prom_getintdefault (fb->prom_node, "board_type", 8); 882 883 sprintf(idstring, "%s at %016lx type %d DAC %d", 884 fix->id, regs[0].phys_addr, i, fb->s.ffb.dac_rev); 885 886 /* Elite3D has different DAC revision numbering, and no DAC revisions 887 have the reversed meaning of cursor enable */ 888 if (afb) 889 fb->s.ffb.dac_rev = 10; 890 891 /* Unblank it just to be sure. When there are multiple 892 * FFB/AFB cards in the system, or it is not the OBP 893 * chosen console, it will have video outputs off in 894 * the DAC. 895 */ 896 ffb_unblank(fb); 897 898 return idstring; 899} 900 901MODULE_LICENSE("GPL"); 902