1079 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/* ffb.c: Creator/Elite3D frame buffer driver3 *4 * Copyright (C) 2003, 2006 David S. Miller (davem@davemloft.net)5 * Copyright (C) 1997,1998,1999 Jakub Jelinek (jj@ultra.linux.cz)6 *7 * Driver layout based loosely on tgafb.c, see that file for credits.8 */9 10#include <linux/module.h>11#include <linux/kernel.h>12#include <linux/errno.h>13#include <linux/string.h>14#include <linux/delay.h>15#include <linux/init.h>16#include <linux/fb.h>17#include <linux/mm.h>18#include <linux/timer.h>19#include <linux/of.h>20#include <linux/platform_device.h>21 22#include <asm/io.h>23#include <asm/upa.h>24#include <asm/fbio.h>25 26#include "sbuslib.h"27 28/*29 * Local functions.30 */31 32static int ffb_setcolreg(unsigned, unsigned, unsigned, unsigned,33 unsigned, struct fb_info *);34static int ffb_blank(int, struct fb_info *);35 36static void ffb_imageblit(struct fb_info *, const struct fb_image *);37static void ffb_fillrect(struct fb_info *, const struct fb_fillrect *);38static void ffb_copyarea(struct fb_info *, const struct fb_copyarea *);39static int ffb_sync(struct fb_info *);40static int ffb_pan_display(struct fb_var_screeninfo *, struct fb_info *);41 42static int ffb_sbusfb_mmap(struct fb_info *info, struct vm_area_struct *vma);43static int ffb_sbusfb_ioctl(struct fb_info *info, unsigned int cmd, unsigned long arg);44 45/*46 * Frame buffer operations47 */48 49static const struct fb_ops ffb_ops = {50 .owner = THIS_MODULE,51 __FB_DEFAULT_SBUS_OPS_RDWR(ffb),52 .fb_setcolreg = ffb_setcolreg,53 .fb_blank = ffb_blank,54 .fb_pan_display = ffb_pan_display,55 .fb_fillrect = ffb_fillrect,56 .fb_copyarea = ffb_copyarea,57 .fb_imageblit = ffb_imageblit,58 .fb_sync = ffb_sync,59 __FB_DEFAULT_SBUS_OPS_IOCTL(ffb),60 __FB_DEFAULT_SBUS_OPS_MMAP(ffb),61};62 63/* Register layout and definitions */64#define FFB_SFB8R_VOFF 0x0000000065#define FFB_SFB8G_VOFF 0x0040000066#define FFB_SFB8B_VOFF 0x0080000067#define FFB_SFB8X_VOFF 0x00c0000068#define FFB_SFB32_VOFF 0x0100000069#define FFB_SFB64_VOFF 0x0200000070#define FFB_FBC_REGS_VOFF 0x0400000071#define FFB_BM_FBC_REGS_VOFF 0x0400200072#define FFB_DFB8R_VOFF 0x0400400073#define FFB_DFB8G_VOFF 0x0440400074#define FFB_DFB8B_VOFF 0x0480400075#define FFB_DFB8X_VOFF 0x04c0400076#define FFB_DFB24_VOFF 0x0500400077#define FFB_DFB32_VOFF 0x0600400078#define FFB_DFB422A_VOFF 0x07004000 /* DFB 422 mode write to A */79#define FFB_DFB422AD_VOFF 0x07804000 /* DFB 422 mode with line doubling */80#define FFB_DFB24B_VOFF 0x08004000 /* DFB 24bit mode write to B */81#define FFB_DFB422B_VOFF 0x09004000 /* DFB 422 mode write to B */82#define FFB_DFB422BD_VOFF 0x09804000 /* DFB 422 mode with line doubling */83#define FFB_SFB16Z_VOFF 0x0a004000 /* 16bit mode Z planes */84#define FFB_SFB8Z_VOFF 0x0a404000 /* 8bit mode Z planes */85#define FFB_SFB422_VOFF 0x0ac04000 /* SFB 422 mode write to A/B */86#define FFB_SFB422D_VOFF 0x0b404000 /* SFB 422 mode with line doubling */87#define FFB_FBC_KREGS_VOFF 0x0bc0400088#define FFB_DAC_VOFF 0x0bc0600089#define FFB_PROM_VOFF 0x0bc0800090#define FFB_EXP_VOFF 0x0bc1800091 92#define FFB_SFB8R_POFF 0x04000000UL93#define FFB_SFB8G_POFF 0x04400000UL94#define FFB_SFB8B_POFF 0x04800000UL95#define FFB_SFB8X_POFF 0x04c00000UL96#define FFB_SFB32_POFF 0x05000000UL97#define FFB_SFB64_POFF 0x06000000UL98#define FFB_FBC_REGS_POFF 0x00600000UL99#define FFB_BM_FBC_REGS_POFF 0x00600000UL100#define FFB_DFB8R_POFF 0x01000000UL101#define FFB_DFB8G_POFF 0x01400000UL102#define FFB_DFB8B_POFF 0x01800000UL103#define FFB_DFB8X_POFF 0x01c00000UL104#define FFB_DFB24_POFF 0x02000000UL105#define FFB_DFB32_POFF 0x03000000UL106#define FFB_FBC_KREGS_POFF 0x00610000UL107#define FFB_DAC_POFF 0x00400000UL108#define FFB_PROM_POFF 0x00000000UL109#define FFB_EXP_POFF 0x00200000UL110#define FFB_DFB422A_POFF 0x09000000UL111#define FFB_DFB422AD_POFF 0x09800000UL112#define FFB_DFB24B_POFF 0x0a000000UL113#define FFB_DFB422B_POFF 0x0b000000UL114#define FFB_DFB422BD_POFF 0x0b800000UL115#define FFB_SFB16Z_POFF 0x0c800000UL116#define FFB_SFB8Z_POFF 0x0c000000UL117#define FFB_SFB422_POFF 0x0d000000UL118#define FFB_SFB422D_POFF 0x0d800000UL119 120/* Draw operations */121#define FFB_DRAWOP_DOT 0x00122#define FFB_DRAWOP_AADOT 0x01123#define FFB_DRAWOP_BRLINECAP 0x02124#define FFB_DRAWOP_BRLINEOPEN 0x03125#define FFB_DRAWOP_DDLINE 0x04126#define FFB_DRAWOP_AALINE 0x05127#define FFB_DRAWOP_TRIANGLE 0x06128#define FFB_DRAWOP_POLYGON 0x07129#define FFB_DRAWOP_RECTANGLE 0x08130#define FFB_DRAWOP_FASTFILL 0x09131#define FFB_DRAWOP_BCOPY 0x0a132#define FFB_DRAWOP_VSCROLL 0x0b133 134/* Pixel processor control */135/* Force WID */136#define FFB_PPC_FW_DISABLE 0x800000137#define FFB_PPC_FW_ENABLE 0xc00000138/* Auxiliary clip */139#define FFB_PPC_ACE_DISABLE 0x040000140#define FFB_PPC_ACE_AUX_SUB 0x080000141#define FFB_PPC_ACE_AUX_ADD 0x0c0000142/* Depth cue */143#define FFB_PPC_DCE_DISABLE 0x020000144#define FFB_PPC_DCE_ENABLE 0x030000145/* Alpha blend */146#define FFB_PPC_ABE_DISABLE 0x008000147#define FFB_PPC_ABE_ENABLE 0x00c000148/* View clip */149#define FFB_PPC_VCE_DISABLE 0x001000150#define FFB_PPC_VCE_2D 0x002000151#define FFB_PPC_VCE_3D 0x003000152/* Area pattern */153#define FFB_PPC_APE_DISABLE 0x000800154#define FFB_PPC_APE_ENABLE 0x000c00155/* Transparent background */156#define FFB_PPC_TBE_OPAQUE 0x000200157#define FFB_PPC_TBE_TRANSPARENT 0x000300158/* Z source */159#define FFB_PPC_ZS_VAR 0x000080160#define FFB_PPC_ZS_CONST 0x0000c0161/* Y source */162#define FFB_PPC_YS_VAR 0x000020163#define FFB_PPC_YS_CONST 0x000030164/* X source */165#define FFB_PPC_XS_WID 0x000004166#define FFB_PPC_XS_VAR 0x000008167#define FFB_PPC_XS_CONST 0x00000c168/* Color (BGR) source */169#define FFB_PPC_CS_VAR 0x000002170#define FFB_PPC_CS_CONST 0x000003171 172#define FFB_ROP_NEW 0x83173#define FFB_ROP_OLD 0x85174#define FFB_ROP_NEW_XOR_OLD 0x86175 176#define FFB_UCSR_FIFO_MASK 0x00000fff177#define FFB_UCSR_FB_BUSY 0x01000000178#define FFB_UCSR_RP_BUSY 0x02000000179#define FFB_UCSR_ALL_BUSY (FFB_UCSR_RP_BUSY|FFB_UCSR_FB_BUSY)180#define FFB_UCSR_READ_ERR 0x40000000181#define FFB_UCSR_FIFO_OVFL 0x80000000182#define FFB_UCSR_ALL_ERRORS (FFB_UCSR_READ_ERR|FFB_UCSR_FIFO_OVFL)183 184struct ffb_fbc {185 /* Next vertex registers */186 u32 xxx1[3];187 u32 alpha;188 u32 red;189 u32 green;190 u32 blue;191 u32 depth;192 u32 y;193 u32 x;194 u32 xxx2[2];195 u32 ryf;196 u32 rxf;197 u32 xxx3[2];198 199 u32 dmyf;200 u32 dmxf;201 u32 xxx4[2];202 u32 ebyi;203 u32 ebxi;204 u32 xxx5[2];205 u32 by;206 u32 bx;207 u32 dy;208 u32 dx;209 u32 bh;210 u32 bw;211 u32 xxx6[2];212 213 u32 xxx7[32];214 215 /* Setup unit vertex state register */216 u32 suvtx;217 u32 xxx8[63];218 219 /* Control registers */220 u32 ppc;221 u32 wid;222 u32 fg;223 u32 bg;224 u32 consty;225 u32 constz;226 u32 xclip;227 u32 dcss;228 u32 vclipmin;229 u32 vclipmax;230 u32 vclipzmin;231 u32 vclipzmax;232 u32 dcsf;233 u32 dcsb;234 u32 dczf;235 u32 dczb;236 237 u32 xxx9;238 u32 blendc;239 u32 blendc1;240 u32 blendc2;241 u32 fbramitc;242 u32 fbc;243 u32 rop;244 u32 cmp;245 u32 matchab;246 u32 matchc;247 u32 magnab;248 u32 magnc;249 u32 fbcfg0;250 u32 fbcfg1;251 u32 fbcfg2;252 u32 fbcfg3;253 254 u32 ppcfg;255 u32 pick;256 u32 fillmode;257 u32 fbramwac;258 u32 pmask;259 u32 xpmask;260 u32 ypmask;261 u32 zpmask;262 u32 clip0min;263 u32 clip0max;264 u32 clip1min;265 u32 clip1max;266 u32 clip2min;267 u32 clip2max;268 u32 clip3min;269 u32 clip3max;270 271 /* New 3dRAM III support regs */272 u32 rawblend2;273 u32 rawpreblend;274 u32 rawstencil;275 u32 rawstencilctl;276 u32 threedram1;277 u32 threedram2;278 u32 passin;279 u32 rawclrdepth;280 u32 rawpmask;281 u32 rawcsrc;282 u32 rawmatch;283 u32 rawmagn;284 u32 rawropblend;285 u32 rawcmp;286 u32 rawwac;287 u32 fbramid;288 289 u32 drawop;290 u32 xxx10[2];291 u32 fontlpat;292 u32 xxx11;293 u32 fontxy;294 u32 fontw;295 u32 fontinc;296 u32 font;297 u32 xxx12[3];298 u32 blend2;299 u32 preblend;300 u32 stencil;301 u32 stencilctl;302 303 u32 xxx13[4];304 u32 dcss1;305 u32 dcss2;306 u32 dcss3;307 u32 widpmask;308 u32 dcs2;309 u32 dcs3;310 u32 dcs4;311 u32 xxx14;312 u32 dcd2;313 u32 dcd3;314 u32 dcd4;315 u32 xxx15;316 317 u32 pattern[32];318 319 u32 xxx16[256];320 321 u32 devid;322 u32 xxx17[63];323 324 u32 ucsr;325 u32 xxx18[31];326 327 u32 mer;328};329 330struct ffb_dac {331 u32 type;332 u32 value;333 u32 type2;334 u32 value2;335};336 337#define FFB_DAC_UCTRL 0x1001 /* User Control */338#define FFB_DAC_UCTRL_MANREV 0x00000f00 /* 4-bit Manufacturing Revision */339#define FFB_DAC_UCTRL_MANREV_SHIFT 8340#define FFB_DAC_TGEN 0x6000 /* Timing Generator */341#define FFB_DAC_TGEN_VIDE 0x00000001 /* Video Enable */342#define FFB_DAC_DID 0x8000 /* Device Identification */343#define FFB_DAC_DID_PNUM 0x0ffff000 /* Device Part Number */344#define FFB_DAC_DID_PNUM_SHIFT 12345#define FFB_DAC_DID_REV 0xf0000000 /* Device Revision */346#define FFB_DAC_DID_REV_SHIFT 28347 348#define FFB_DAC_CUR_CTRL 0x100349#define FFB_DAC_CUR_CTRL_P0 0x00000001350#define FFB_DAC_CUR_CTRL_P1 0x00000002351 352struct ffb_par {353 spinlock_t lock;354 struct ffb_fbc __iomem *fbc;355 struct ffb_dac __iomem *dac;356 357 u32 flags;358#define FFB_FLAG_AFB 0x00000001 /* AFB m3 or m6 */359#define FFB_FLAG_BLANKED 0x00000002 /* screen is blanked */360#define FFB_FLAG_INVCURSOR 0x00000004 /* DAC has inverted cursor logic */361 362 u32 fg_cache __attribute__((aligned (8)));363 u32 bg_cache;364 u32 rop_cache;365 366 int fifo_cache;367 368 unsigned long physbase;369 unsigned long fbsize;370 371 int board_type;372 373 u32 pseudo_palette[16];374};375 376static void FFBFifo(struct ffb_par *par, int n)377{378 struct ffb_fbc __iomem *fbc;379 int cache = par->fifo_cache;380 381 if (cache - n < 0) {382 fbc = par->fbc;383 do {384 cache = (upa_readl(&fbc->ucsr) & FFB_UCSR_FIFO_MASK);385 cache -= 8;386 } while (cache - n < 0);387 }388 par->fifo_cache = cache - n;389}390 391static void FFBWait(struct ffb_par *par)392{393 struct ffb_fbc __iomem *fbc;394 int limit = 10000;395 396 fbc = par->fbc;397 do {398 if ((upa_readl(&fbc->ucsr) & FFB_UCSR_ALL_BUSY) == 0)399 break;400 if ((upa_readl(&fbc->ucsr) & FFB_UCSR_ALL_ERRORS) != 0) {401 upa_writel(FFB_UCSR_ALL_ERRORS, &fbc->ucsr);402 }403 udelay(10);404 } while (--limit > 0);405}406 407static int ffb_sync(struct fb_info *p)408{409 struct ffb_par *par = (struct ffb_par *)p->par;410 411 FFBWait(par);412 return 0;413}414 415static __inline__ void ffb_rop(struct ffb_par *par, u32 rop)416{417 if (par->rop_cache != rop) {418 FFBFifo(par, 1);419 upa_writel(rop, &par->fbc->rop);420 par->rop_cache = rop;421 }422}423 424static void ffb_switch_from_graph(struct ffb_par *par)425{426 struct ffb_fbc __iomem *fbc = par->fbc;427 struct ffb_dac __iomem *dac = par->dac;428 unsigned long flags;429 430 spin_lock_irqsave(&par->lock, flags);431 FFBWait(par);432 par->fifo_cache = 0;433 FFBFifo(par, 7);434 upa_writel(FFB_PPC_VCE_DISABLE | FFB_PPC_TBE_OPAQUE |435 FFB_PPC_APE_DISABLE | FFB_PPC_CS_CONST,436 &fbc->ppc);437 upa_writel(0x2000707f, &fbc->fbc);438 upa_writel(par->rop_cache, &fbc->rop);439 upa_writel(0xffffffff, &fbc->pmask);440 upa_writel((1 << 16) | (0 << 0), &fbc->fontinc);441 upa_writel(par->fg_cache, &fbc->fg);442 upa_writel(par->bg_cache, &fbc->bg);443 FFBWait(par);444 445 /* Disable cursor. */446 upa_writel(FFB_DAC_CUR_CTRL, &dac->type2);447 if (par->flags & FFB_FLAG_INVCURSOR)448 upa_writel(0, &dac->value2);449 else450 upa_writel((FFB_DAC_CUR_CTRL_P0 |451 FFB_DAC_CUR_CTRL_P1), &dac->value2);452 453 spin_unlock_irqrestore(&par->lock, flags);454}455 456static int ffb_pan_display(struct fb_var_screeninfo *var, struct fb_info *info)457{458 struct ffb_par *par = (struct ffb_par *)info->par;459 460 /* We just use this to catch switches out of461 * graphics mode.462 */463 ffb_switch_from_graph(par);464 465 if (var->xoffset || var->yoffset || var->vmode)466 return -EINVAL;467 return 0;468}469 470/**471 * ffb_fillrect - Draws a rectangle on the screen.472 *473 * @info: frame buffer structure that represents a single frame buffer474 * @rect: structure defining the rectagle and operation.475 */476static void ffb_fillrect(struct fb_info *info, const struct fb_fillrect *rect)477{478 struct ffb_par *par = (struct ffb_par *)info->par;479 struct ffb_fbc __iomem *fbc = par->fbc;480 unsigned long flags;481 u32 fg;482 483 BUG_ON(rect->rop != ROP_COPY && rect->rop != ROP_XOR);484 485 fg = ((u32 *)info->pseudo_palette)[rect->color];486 487 spin_lock_irqsave(&par->lock, flags);488 489 if (fg != par->fg_cache) {490 FFBFifo(par, 1);491 upa_writel(fg, &fbc->fg);492 par->fg_cache = fg;493 }494 495 ffb_rop(par, rect->rop == ROP_COPY ?496 FFB_ROP_NEW :497 FFB_ROP_NEW_XOR_OLD);498 499 FFBFifo(par, 5);500 upa_writel(FFB_DRAWOP_RECTANGLE, &fbc->drawop);501 upa_writel(rect->dy, &fbc->by);502 upa_writel(rect->dx, &fbc->bx);503 upa_writel(rect->height, &fbc->bh);504 upa_writel(rect->width, &fbc->bw);505 506 spin_unlock_irqrestore(&par->lock, flags);507}508 509/**510 * ffb_copyarea - Copies on area of the screen to another area.511 *512 * @info: frame buffer structure that represents a single frame buffer513 * @area: structure defining the source and destination.514 */515 516static void ffb_copyarea(struct fb_info *info, const struct fb_copyarea *area)517{518 struct ffb_par *par = (struct ffb_par *)info->par;519 struct ffb_fbc __iomem *fbc = par->fbc;520 unsigned long flags;521 522 if (area->dx != area->sx ||523 area->dy == area->sy) {524 cfb_copyarea(info, area);525 return;526 }527 528 spin_lock_irqsave(&par->lock, flags);529 530 ffb_rop(par, FFB_ROP_OLD);531 532 FFBFifo(par, 7);533 upa_writel(FFB_DRAWOP_VSCROLL, &fbc->drawop);534 upa_writel(area->sy, &fbc->by);535 upa_writel(area->sx, &fbc->bx);536 upa_writel(area->dy, &fbc->dy);537 upa_writel(area->dx, &fbc->dx);538 upa_writel(area->height, &fbc->bh);539 upa_writel(area->width, &fbc->bw);540 541 spin_unlock_irqrestore(&par->lock, flags);542}543 544/**545 * ffb_imageblit - Copies a image from system memory to the screen.546 *547 * @info: frame buffer structure that represents a single frame buffer548 * @image: structure defining the image.549 */550static void ffb_imageblit(struct fb_info *info, const struct fb_image *image)551{552 struct ffb_par *par = (struct ffb_par *)info->par;553 struct ffb_fbc __iomem *fbc = par->fbc;554 const u8 *data = image->data;555 unsigned long flags;556 u32 fg, bg, xy;557 u64 fgbg;558 int i, width, stride;559 560 if (image->depth > 1) {561 cfb_imageblit(info, image);562 return;563 }564 565 fg = ((u32 *)info->pseudo_palette)[image->fg_color];566 bg = ((u32 *)info->pseudo_palette)[image->bg_color];567 fgbg = ((u64) fg << 32) | (u64) bg;568 xy = (image->dy << 16) | image->dx;569 width = image->width;570 stride = ((width + 7) >> 3);571 572 spin_lock_irqsave(&par->lock, flags);573 574 if (fgbg != *(u64 *)&par->fg_cache) {575 FFBFifo(par, 2);576 upa_writeq(fgbg, &fbc->fg);577 *(u64 *)&par->fg_cache = fgbg;578 }579 580 if (width >= 32) {581 FFBFifo(par, 1);582 upa_writel(32, &fbc->fontw);583 }584 585 while (width >= 32) {586 const u8 *next_data = data + 4;587 588 FFBFifo(par, 1);589 upa_writel(xy, &fbc->fontxy);590 xy += (32 << 0);591 592 for (i = 0; i < image->height; i++) {593 u32 val = (((u32)data[0] << 24) |594 ((u32)data[1] << 16) |595 ((u32)data[2] << 8) |596 ((u32)data[3] << 0));597 FFBFifo(par, 1);598 upa_writel(val, &fbc->font);599 600 data += stride;601 }602 603 data = next_data;604 width -= 32;605 }606 607 if (width) {608 FFBFifo(par, 2);609 upa_writel(width, &fbc->fontw);610 upa_writel(xy, &fbc->fontxy);611 612 for (i = 0; i < image->height; i++) {613 u32 val = (((u32)data[0] << 24) |614 ((u32)data[1] << 16) |615 ((u32)data[2] << 8) |616 ((u32)data[3] << 0));617 FFBFifo(par, 1);618 upa_writel(val, &fbc->font);619 620 data += stride;621 }622 }623 624 spin_unlock_irqrestore(&par->lock, flags);625}626 627static void ffb_fixup_var_rgb(struct fb_var_screeninfo *var)628{629 var->red.offset = 0;630 var->red.length = 8;631 var->green.offset = 8;632 var->green.length = 8;633 var->blue.offset = 16;634 var->blue.length = 8;635 var->transp.offset = 0;636 var->transp.length = 0;637}638 639/**640 * ffb_setcolreg - Sets a color register.641 *642 * @regno: boolean, 0 copy local, 1 get_user() function643 * @red: frame buffer colormap structure644 * @green: The green value which can be up to 16 bits wide645 * @blue: The blue value which can be up to 16 bits wide.646 * @transp: If supported the alpha value which can be up to 16 bits wide.647 * @info: frame buffer info structure648 */649static int ffb_setcolreg(unsigned regno,650 unsigned red, unsigned green, unsigned blue,651 unsigned transp, struct fb_info *info)652{653 u32 value;654 655 if (regno >= 16)656 return 1;657 658 red >>= 8;659 green >>= 8;660 blue >>= 8;661 662 value = (blue << 16) | (green << 8) | red;663 ((u32 *)info->pseudo_palette)[regno] = value;664 665 return 0;666}667 668/**669 * ffb_blank - Optional function. Blanks the display.670 * @blank: the blank mode we want.671 * @info: frame buffer structure that represents a single frame buffer672 */673static int ffb_blank(int blank, struct fb_info *info)674{675 struct ffb_par *par = (struct ffb_par *)info->par;676 struct ffb_dac __iomem *dac = par->dac;677 unsigned long flags;678 u32 val;679 int i;680 681 spin_lock_irqsave(&par->lock, flags);682 683 FFBWait(par);684 685 upa_writel(FFB_DAC_TGEN, &dac->type);686 val = upa_readl(&dac->value);687 switch (blank) {688 case FB_BLANK_UNBLANK: /* Unblanking */689 val |= FFB_DAC_TGEN_VIDE;690 par->flags &= ~FFB_FLAG_BLANKED;691 break;692 693 case FB_BLANK_NORMAL: /* Normal blanking */694 case FB_BLANK_VSYNC_SUSPEND: /* VESA blank (vsync off) */695 case FB_BLANK_HSYNC_SUSPEND: /* VESA blank (hsync off) */696 case FB_BLANK_POWERDOWN: /* Poweroff */697 val &= ~FFB_DAC_TGEN_VIDE;698 par->flags |= FFB_FLAG_BLANKED;699 break;700 }701 upa_writel(FFB_DAC_TGEN, &dac->type);702 upa_writel(val, &dac->value);703 for (i = 0; i < 10; i++) {704 upa_writel(FFB_DAC_TGEN, &dac->type);705 upa_readl(&dac->value);706 }707 708 spin_unlock_irqrestore(&par->lock, flags);709 710 return 0;711}712 713static const struct sbus_mmap_map ffb_mmap_map[] = {714 {715 .voff = FFB_SFB8R_VOFF,716 .poff = FFB_SFB8R_POFF,717 .size = 0x0400000718 },719 {720 .voff = FFB_SFB8G_VOFF,721 .poff = FFB_SFB8G_POFF,722 .size = 0x0400000723 },724 {725 .voff = FFB_SFB8B_VOFF,726 .poff = FFB_SFB8B_POFF,727 .size = 0x0400000728 },729 {730 .voff = FFB_SFB8X_VOFF,731 .poff = FFB_SFB8X_POFF,732 .size = 0x0400000733 },734 {735 .voff = FFB_SFB32_VOFF,736 .poff = FFB_SFB32_POFF,737 .size = 0x1000000738 },739 {740 .voff = FFB_SFB64_VOFF,741 .poff = FFB_SFB64_POFF,742 .size = 0x2000000743 },744 {745 .voff = FFB_FBC_REGS_VOFF,746 .poff = FFB_FBC_REGS_POFF,747 .size = 0x0002000748 },749 {750 .voff = FFB_BM_FBC_REGS_VOFF,751 .poff = FFB_BM_FBC_REGS_POFF,752 .size = 0x0002000753 },754 {755 .voff = FFB_DFB8R_VOFF,756 .poff = FFB_DFB8R_POFF,757 .size = 0x0400000758 },759 {760 .voff = FFB_DFB8G_VOFF,761 .poff = FFB_DFB8G_POFF,762 .size = 0x0400000763 },764 {765 .voff = FFB_DFB8B_VOFF,766 .poff = FFB_DFB8B_POFF,767 .size = 0x0400000768 },769 {770 .voff = FFB_DFB8X_VOFF,771 .poff = FFB_DFB8X_POFF,772 .size = 0x0400000773 },774 {775 .voff = FFB_DFB24_VOFF,776 .poff = FFB_DFB24_POFF,777 .size = 0x1000000778 },779 {780 .voff = FFB_DFB32_VOFF,781 .poff = FFB_DFB32_POFF,782 .size = 0x1000000783 },784 {785 .voff = FFB_FBC_KREGS_VOFF,786 .poff = FFB_FBC_KREGS_POFF,787 .size = 0x0002000788 },789 {790 .voff = FFB_DAC_VOFF,791 .poff = FFB_DAC_POFF,792 .size = 0x0002000793 },794 {795 .voff = FFB_PROM_VOFF,796 .poff = FFB_PROM_POFF,797 .size = 0x0010000798 },799 {800 .voff = FFB_EXP_VOFF,801 .poff = FFB_EXP_POFF,802 .size = 0x0002000803 },804 {805 .voff = FFB_DFB422A_VOFF,806 .poff = FFB_DFB422A_POFF,807 .size = 0x0800000808 },809 {810 .voff = FFB_DFB422AD_VOFF,811 .poff = FFB_DFB422AD_POFF,812 .size = 0x0800000813 },814 {815 .voff = FFB_DFB24B_VOFF,816 .poff = FFB_DFB24B_POFF,817 .size = 0x1000000818 },819 {820 .voff = FFB_DFB422B_VOFF,821 .poff = FFB_DFB422B_POFF,822 .size = 0x0800000823 },824 {825 .voff = FFB_DFB422BD_VOFF,826 .poff = FFB_DFB422BD_POFF,827 .size = 0x0800000828 },829 {830 .voff = FFB_SFB16Z_VOFF,831 .poff = FFB_SFB16Z_POFF,832 .size = 0x0800000833 },834 {835 .voff = FFB_SFB8Z_VOFF,836 .poff = FFB_SFB8Z_POFF,837 .size = 0x0800000838 },839 {840 .voff = FFB_SFB422_VOFF,841 .poff = FFB_SFB422_POFF,842 .size = 0x0800000843 },844 {845 .voff = FFB_SFB422D_VOFF,846 .poff = FFB_SFB422D_POFF,847 .size = 0x0800000848 },849 { .size = 0 }850};851 852static int ffb_sbusfb_mmap(struct fb_info *info, struct vm_area_struct *vma)853{854 struct ffb_par *par = (struct ffb_par *)info->par;855 856 return sbusfb_mmap_helper(ffb_mmap_map,857 par->physbase, par->fbsize,858 0, vma);859}860 861static int ffb_sbusfb_ioctl(struct fb_info *info, unsigned int cmd, unsigned long arg)862{863 struct ffb_par *par = (struct ffb_par *)info->par;864 865 return sbusfb_ioctl_helper(cmd, arg, info,866 FBTYPE_CREATOR, 24, par->fbsize);867}868 869/*870 * Initialisation871 */872 873static void ffb_init_fix(struct fb_info *info)874{875 struct ffb_par *par = (struct ffb_par *)info->par;876 const char *ffb_type_name;877 878 if (!(par->flags & FFB_FLAG_AFB)) {879 if ((par->board_type & 0x7) == 0x3)880 ffb_type_name = "Creator 3D";881 else882 ffb_type_name = "Creator";883 } else884 ffb_type_name = "Elite 3D";885 886 strscpy(info->fix.id, ffb_type_name, sizeof(info->fix.id));887 888 info->fix.type = FB_TYPE_PACKED_PIXELS;889 info->fix.visual = FB_VISUAL_TRUECOLOR;890 891 /* Framebuffer length is the same regardless of resolution. */892 info->fix.line_length = 8192;893 894 info->fix.accel = FB_ACCEL_SUN_CREATOR;895}896 897static int ffb_probe(struct platform_device *op)898{899 struct device_node *dp = op->dev.of_node;900 struct ffb_fbc __iomem *fbc;901 struct ffb_dac __iomem *dac;902 struct fb_info *info;903 struct ffb_par *par;904 u32 dac_pnum, dac_rev, dac_mrev;905 int err;906 907 info = framebuffer_alloc(sizeof(struct ffb_par), &op->dev);908 909 err = -ENOMEM;910 if (!info)911 goto out_err;912 913 par = info->par;914 915 spin_lock_init(&par->lock);916 par->fbc = of_ioremap(&op->resource[2], 0,917 sizeof(struct ffb_fbc), "ffb fbc");918 if (!par->fbc)919 goto out_release_fb;920 921 par->dac = of_ioremap(&op->resource[1], 0,922 sizeof(struct ffb_dac), "ffb dac");923 if (!par->dac)924 goto out_unmap_fbc;925 926 par->rop_cache = FFB_ROP_NEW;927 par->physbase = op->resource[0].start;928 929 /* Don't mention copyarea, so SCROLL_REDRAW is always930 * used. It is the fastest on this chip.931 */932 info->flags = (/* FBINFO_HWACCEL_COPYAREA | */933 FBINFO_HWACCEL_FILLRECT |934 FBINFO_HWACCEL_IMAGEBLIT);935 936 info->fbops = &ffb_ops;937 938 info->screen_base = (char *) par->physbase + FFB_DFB24_POFF;939 info->pseudo_palette = par->pseudo_palette;940 941 sbusfb_fill_var(&info->var, dp, 32);942 par->fbsize = PAGE_ALIGN(info->var.xres * info->var.yres * 4);943 ffb_fixup_var_rgb(&info->var);944 945 info->var.accel_flags = FB_ACCELF_TEXT;946 947 if (of_node_name_eq(dp, "SUNW,afb"))948 par->flags |= FFB_FLAG_AFB;949 950 par->board_type = of_getintprop_default(dp, "board_type", 0);951 952 fbc = par->fbc;953 if ((upa_readl(&fbc->ucsr) & FFB_UCSR_ALL_ERRORS) != 0)954 upa_writel(FFB_UCSR_ALL_ERRORS, &fbc->ucsr);955 956 dac = par->dac;957 upa_writel(FFB_DAC_DID, &dac->type);958 dac_pnum = upa_readl(&dac->value);959 dac_rev = (dac_pnum & FFB_DAC_DID_REV) >> FFB_DAC_DID_REV_SHIFT;960 dac_pnum = (dac_pnum & FFB_DAC_DID_PNUM) >> FFB_DAC_DID_PNUM_SHIFT;961 962 upa_writel(FFB_DAC_UCTRL, &dac->type);963 dac_mrev = upa_readl(&dac->value);964 dac_mrev = (dac_mrev & FFB_DAC_UCTRL_MANREV) >>965 FFB_DAC_UCTRL_MANREV_SHIFT;966 967 /* Elite3D has different DAC revision numbering, and no DAC revisions968 * have the reversed meaning of cursor enable. Otherwise, Pacifica 1969 * ramdacs with manufacturing revision less than 3 have inverted970 * cursor logic. We identify Pacifica 1 as not Pacifica 2, the971 * latter having a part number value of 0x236e.972 */973 if ((par->flags & FFB_FLAG_AFB) || dac_pnum == 0x236e) {974 par->flags &= ~FFB_FLAG_INVCURSOR;975 } else {976 if (dac_mrev < 3)977 par->flags |= FFB_FLAG_INVCURSOR;978 }979 980 ffb_switch_from_graph(par);981 982 /* Unblank it just to be sure. When there are multiple983 * FFB/AFB cards in the system, or it is not the OBP984 * chosen console, it will have video outputs off in985 * the DAC.986 */987 ffb_blank(FB_BLANK_UNBLANK, info);988 989 if (fb_alloc_cmap(&info->cmap, 256, 0))990 goto out_unmap_dac;991 992 ffb_init_fix(info);993 994 err = register_framebuffer(info);995 if (err < 0)996 goto out_dealloc_cmap;997 998 dev_set_drvdata(&op->dev, info);999 1000 printk(KERN_INFO "%pOF: %s at %016lx, type %d, "1001 "DAC pnum[%x] rev[%d] manuf_rev[%d]\n",1002 dp,1003 ((par->flags & FFB_FLAG_AFB) ? "AFB" : "FFB"),1004 par->physbase, par->board_type,1005 dac_pnum, dac_rev, dac_mrev);1006 1007 return 0;1008 1009out_dealloc_cmap:1010 fb_dealloc_cmap(&info->cmap);1011 1012out_unmap_dac:1013 of_iounmap(&op->resource[1], par->dac, sizeof(struct ffb_dac));1014 1015out_unmap_fbc:1016 of_iounmap(&op->resource[2], par->fbc, sizeof(struct ffb_fbc));1017 1018out_release_fb:1019 framebuffer_release(info);1020 1021out_err:1022 return err;1023}1024 1025static void ffb_remove(struct platform_device *op)1026{1027 struct fb_info *info = dev_get_drvdata(&op->dev);1028 struct ffb_par *par = info->par;1029 1030 unregister_framebuffer(info);1031 fb_dealloc_cmap(&info->cmap);1032 1033 of_iounmap(&op->resource[2], par->fbc, sizeof(struct ffb_fbc));1034 of_iounmap(&op->resource[1], par->dac, sizeof(struct ffb_dac));1035 1036 framebuffer_release(info);1037}1038 1039static const struct of_device_id ffb_match[] = {1040 {1041 .name = "SUNW,ffb",1042 },1043 {1044 .name = "SUNW,afb",1045 },1046 {},1047};1048MODULE_DEVICE_TABLE(of, ffb_match);1049 1050static struct platform_driver ffb_driver = {1051 .driver = {1052 .name = "ffb",1053 .of_match_table = ffb_match,1054 },1055 .probe = ffb_probe,1056 .remove = ffb_remove,1057};1058 1059static int __init ffb_init(void)1060{1061 if (fb_get_options("ffb", NULL))1062 return -ENODEV;1063 1064 return platform_driver_register(&ffb_driver);1065}1066 1067static void __exit ffb_exit(void)1068{1069 platform_driver_unregister(&ffb_driver);1070}1071 1072module_init(ffb_init);1073module_exit(ffb_exit);1074 1075MODULE_DESCRIPTION("framebuffer driver for Creator/Elite3D chipsets");1076MODULE_AUTHOR("David S. Miller <davem@davemloft.net>");1077MODULE_VERSION("2.0");1078MODULE_LICENSE("GPL");1079