help
Say Y if you want support for SBUS or UPA based frame buffer device.
-config FB_CREATOR
- bool "Creator/Creator3D support"
+config FB_FFB
+ bool "Creator/Creator3D/Elite3D support"
depends on FB_SBUS && SPARC64
help
- This is the frame buffer device driver for the Creator and Creator3D
- graphics boards.
+ This is the frame buffer device driver for the Creator, Creator3D,
+ and Elite3D graphics boards.
config FB_TCX
bool "TCX (SS4/SS5 only) support"
obj-$(CONFIG_FB_VIRGE) += virgefb.o
obj-$(CONFIG_FB_G364) += g364fb.o cfbfillrect.o cfbcopyarea.o cfbimgblt.o
obj-$(CONFIG_FB_FM2) += fm2fb.o cfbfillrect.o cfbcopyarea.o cfbimgblt.o
-obj-$(CONFIG_FB_CREATOR) += creatorfb.o sbusfb.o
-obj-$(CONFIG_FB_CGSIX) += cgsixfb.o sbusfb.o
-obj-$(CONFIG_FB_BWTWO) += bwtwofb.o sbusfb.o
-obj-$(CONFIG_FB_CGTHREE) += cgthreefb.o sbusfb.o
-obj-$(CONFIG_FB_TCX) += tcxfb.o sbusfb.o
-obj-$(CONFIG_FB_CGFOURTEEN) += cgfourteenfb.o sbusfb.o
-obj-$(CONFIG_FB_P9100) += p9100fb.o sbusfb.o
-obj-$(CONFIG_FB_LEO) += leofb.o sbusfb.o
obj-$(CONFIG_FB_STI) += stifb.o cfbfillrect.o cfbcopyarea.o cfbimgblt.o
obj-$(CONFIG_FB_PMAG_BA) += pmag-ba-fb.o cfbfillrect.o cfbcopyarea.o cfbimgblt.o
obj-$(CONFIG_FB_PMAGB_B) += pmagb-b-fb.o cfbfillrect.o cfbcopyarea.o cfbimgblt.o
obj-$(CONFIG_FB_PVR2) += pvr2fb.o
obj-$(CONFIG_FB_VOODOO1) += sstfb.o cfbfillrect.o cfbcopyarea.o cfbimgblt.o
+# One by one these are being converted over to the new APIs
+#obj-$(CONFIG_FB_CREATOR) += creatorfb.o sbusfb.o
+#obj-$(CONFIG_FB_CGSIX) += cgsixfb.o sbusfb.o
+#obj-$(CONFIG_FB_BWTWO) += bwtwofb.o sbusfb.o
+#obj-$(CONFIG_FB_CGTHREE) += cgthreefb.o sbusfb.o
+#obj-$(CONFIG_FB_TCX) += tcxfb.o sbusfb.o
+#obj-$(CONFIG_FB_CGFOURTEEN) += cgfourteenfb.o sbusfb.o
+#obj-$(CONFIG_FB_P9100) += p9100fb.o sbusfb.o
+#obj-$(CONFIG_FB_LEO) += leofb.o sbusfb.o
+
+obj-$(CONFIG_FB_FFB) += ffb.o sbuslib.o cfbimgblt.o cfbcopyarea.o
+
# Files generated that shall be removed upon make clean
clean-files := promcon_tbl.c
+++ /dev/null
-/* $Id: creatorfb.c,v 1.37 2001/10/16 05:44:44 davem Exp $
- * creatorfb.c: Creator/Creator3D frame buffer driver
- *
- * Copyright (C) 1997,1998,1999 Jakub Jelinek (jj@ultra.linux.cz)
- */
-
-#include <linux/module.h>
-#include <linux/sched.h>
-#include <linux/kernel.h>
-#include <linux/errno.h>
-#include <linux/string.h>
-#include <linux/mm.h>
-#include <linux/tty.h>
-#include <linux/slab.h>
-#include <linux/vmalloc.h>
-#include <linux/delay.h>
-#include <linux/interrupt.h>
-#include <linux/fb.h>
-#include <linux/init.h>
-#include <linux/selection.h>
-
-#include <video/sbusfb.h>
-
-#include <asm/upa.h>
-
-#define FFB_SFB8R_VOFF 0x00000000
-#define FFB_SFB8G_VOFF 0x00400000
-#define FFB_SFB8B_VOFF 0x00800000
-#define FFB_SFB8X_VOFF 0x00c00000
-#define FFB_SFB32_VOFF 0x01000000
-#define FFB_SFB64_VOFF 0x02000000
-#define FFB_FBC_REGS_VOFF 0x04000000
-#define FFB_BM_FBC_REGS_VOFF 0x04002000
-#define FFB_DFB8R_VOFF 0x04004000
-#define FFB_DFB8G_VOFF 0x04404000
-#define FFB_DFB8B_VOFF 0x04804000
-#define FFB_DFB8X_VOFF 0x04c04000
-#define FFB_DFB24_VOFF 0x05004000
-#define FFB_DFB32_VOFF 0x06004000
-#define FFB_DFB422A_VOFF 0x07004000 /* DFB 422 mode write to A */
-#define FFB_DFB422AD_VOFF 0x07804000 /* DFB 422 mode with line doubling */
-#define FFB_DFB24B_VOFF 0x08004000 /* DFB 24bit mode write to B */
-#define FFB_DFB422B_VOFF 0x09004000 /* DFB 422 mode write to B */
-#define FFB_DFB422BD_VOFF 0x09804000 /* DFB 422 mode with line doubling */
-#define FFB_SFB16Z_VOFF 0x0a004000 /* 16bit mode Z planes */
-#define FFB_SFB8Z_VOFF 0x0a404000 /* 8bit mode Z planes */
-#define FFB_SFB422_VOFF 0x0ac04000 /* SFB 422 mode write to A/B */
-#define FFB_SFB422D_VOFF 0x0b404000 /* SFB 422 mode with line doubling */
-#define FFB_FBC_KREGS_VOFF 0x0bc04000
-#define FFB_DAC_VOFF 0x0bc06000
-#define FFB_PROM_VOFF 0x0bc08000
-#define FFB_EXP_VOFF 0x0bc18000
-
-#define FFB_SFB8R_POFF 0x04000000UL
-#define FFB_SFB8G_POFF 0x04400000UL
-#define FFB_SFB8B_POFF 0x04800000UL
-#define FFB_SFB8X_POFF 0x04c00000UL
-#define FFB_SFB32_POFF 0x05000000UL
-#define FFB_SFB64_POFF 0x06000000UL
-#define FFB_FBC_REGS_POFF 0x00600000UL
-#define FFB_BM_FBC_REGS_POFF 0x00600000UL
-#define FFB_DFB8R_POFF 0x01000000UL
-#define FFB_DFB8G_POFF 0x01400000UL
-#define FFB_DFB8B_POFF 0x01800000UL
-#define FFB_DFB8X_POFF 0x01c00000UL
-#define FFB_DFB24_POFF 0x02000000UL
-#define FFB_DFB32_POFF 0x03000000UL
-#define FFB_FBC_KREGS_POFF 0x00610000UL
-#define FFB_DAC_POFF 0x00400000UL
-#define FFB_PROM_POFF 0x00000000UL
-#define FFB_EXP_POFF 0x00200000UL
-#define FFB_DFB422A_POFF 0x09000000UL
-#define FFB_DFB422AD_POFF 0x09800000UL
-#define FFB_DFB24B_POFF 0x0a000000UL
-#define FFB_DFB422B_POFF 0x0b000000UL
-#define FFB_DFB422BD_POFF 0x0b800000UL
-#define FFB_SFB16Z_POFF 0x0c800000UL
-#define FFB_SFB8Z_POFF 0x0c000000UL
-#define FFB_SFB422_POFF 0x0d000000UL
-#define FFB_SFB422D_POFF 0x0d800000UL
-
-/* Draw operations */
-#define FFB_DRAWOP_DOT 0x00
-#define FFB_DRAWOP_AADOT 0x01
-#define FFB_DRAWOP_BRLINECAP 0x02
-#define FFB_DRAWOP_BRLINEOPEN 0x03
-#define FFB_DRAWOP_DDLINE 0x04
-#define FFB_DRAWOP_AALINE 0x05
-#define FFB_DRAWOP_TRIANGLE 0x06
-#define FFB_DRAWOP_POLYGON 0x07
-#define FFB_DRAWOP_RECTANGLE 0x08
-#define FFB_DRAWOP_FASTFILL 0x09
-#define FFB_DRAWOP_BCOPY 0x0a
-#define FFB_DRAWOP_VSCROLL 0x0b
-
-/* Pixel processor control */
-/* Force WID */
-#define FFB_PPC_FW_DISABLE 0x800000
-#define FFB_PPC_FW_ENABLE 0xc00000
-/* Auxiliary clip */
-#define FFB_PPC_ACE_DISABLE 0x040000
-#define FFB_PPC_ACE_AUX_SUB 0x080000
-#define FFB_PPC_ACE_AUX_ADD 0x0c0000
-/* Depth cue */
-#define FFB_PPC_DCE_DISABLE 0x020000
-#define FFB_PPC_DCE_ENABLE 0x030000
-/* Alpha blend */
-#define FFB_PPC_ABE_DISABLE 0x008000
-#define FFB_PPC_ABE_ENABLE 0x00c000
-/* View clip */
-#define FFB_PPC_VCE_DISABLE 0x001000
-#define FFB_PPC_VCE_2D 0x002000
-#define FFB_PPC_VCE_3D 0x003000
-/* Area pattern */
-#define FFB_PPC_APE_DISABLE 0x000800
-#define FFB_PPC_APE_ENABLE 0x000c00
-/* Transparent background */
-#define FFB_PPC_TBE_OPAQUE 0x000200
-#define FFB_PPC_TBE_TRANSPARENT 0x000300
-/* Z source */
-#define FFB_PPC_ZS_VAR 0x000080
-#define FFB_PPC_ZS_CONST 0x0000c0
-/* Y source */
-#define FFB_PPC_YS_VAR 0x000020
-#define FFB_PPC_YS_CONST 0x000030
-/* X source */
-#define FFB_PPC_XS_WID 0x000004
-#define FFB_PPC_XS_VAR 0x000008
-#define FFB_PPC_XS_CONST 0x00000c
-/* Color (BGR) source */
-#define FFB_PPC_CS_VAR 0x000002
-#define FFB_PPC_CS_CONST 0x000003
-
-#define FFB_ROP_NEW 0x83
-
-#define FFB_UCSR_FIFO_MASK 0x00000fff
-#define FFB_UCSR_FB_BUSY 0x01000000
-#define FFB_UCSR_RP_BUSY 0x02000000
-#define FFB_UCSR_ALL_BUSY (FFB_UCSR_RP_BUSY|FFB_UCSR_FB_BUSY)
-#define FFB_UCSR_READ_ERR 0x40000000
-#define FFB_UCSR_FIFO_OVFL 0x80000000
-#define FFB_UCSR_ALL_ERRORS (FFB_UCSR_READ_ERR|FFB_UCSR_FIFO_OVFL)
-
-struct ffb_fbc {
- /* Next vertex registers */
- u32 xxx1[3];
- volatile u32 alpha;
- volatile u32 red;
- volatile u32 green;
- volatile u32 blue;
- volatile u32 depth;
- volatile u32 y;
- volatile u32 x;
- u32 xxx2[2];
- volatile u32 ryf;
- volatile u32 rxf;
- u32 xxx3[2];
-
- volatile u32 dmyf;
- volatile u32 dmxf;
- u32 xxx4[2];
- volatile u32 ebyi;
- volatile u32 ebxi;
- u32 xxx5[2];
- volatile u32 by;
- volatile u32 bx;
- u32 dy;
- u32 dx;
- volatile u32 bh;
- volatile u32 bw;
- u32 xxx6[2];
-
- u32 xxx7[32];
-
- /* Setup unit vertex state register */
- volatile u32 suvtx;
- u32 xxx8[63];
-
- /* Control registers */
- volatile u32 ppc;
- volatile u32 wid;
- volatile u32 fg;
- volatile u32 bg;
- volatile u32 consty;
- volatile u32 constz;
- volatile u32 xclip;
- volatile u32 dcss;
- volatile u32 vclipmin;
- volatile u32 vclipmax;
- volatile u32 vclipzmin;
- volatile u32 vclipzmax;
- volatile u32 dcsf;
- volatile u32 dcsb;
- volatile u32 dczf;
- volatile u32 dczb;
-
- u32 xxx9;
- volatile u32 blendc;
- volatile u32 blendc1;
- volatile u32 blendc2;
- volatile u32 fbramitc;
- volatile u32 fbc;
- volatile u32 rop;
- volatile u32 cmp;
- volatile u32 matchab;
- volatile u32 matchc;
- volatile u32 magnab;
- volatile u32 magnc;
- volatile u32 fbcfg0;
- volatile u32 fbcfg1;
- volatile u32 fbcfg2;
- volatile u32 fbcfg3;
-
- u32 ppcfg;
- volatile u32 pick;
- volatile u32 fillmode;
- volatile u32 fbramwac;
- volatile u32 pmask;
- volatile u32 xpmask;
- volatile u32 ypmask;
- volatile u32 zpmask;
- volatile u32 clip0min;
- volatile u32 clip0max;
- volatile u32 clip1min;
- volatile u32 clip1max;
- volatile u32 clip2min;
- volatile u32 clip2max;
- volatile u32 clip3min;
- volatile u32 clip3max;
-
- /* New 3dRAM III support regs */
- volatile u32 rawblend2;
- volatile u32 rawpreblend;
- volatile u32 rawstencil;
- volatile u32 rawstencilctl;
- volatile u32 threedram1;
- volatile u32 threedram2;
- volatile u32 passin;
- volatile u32 rawclrdepth;
- volatile u32 rawpmask;
- volatile u32 rawcsrc;
- volatile u32 rawmatch;
- volatile u32 rawmagn;
- volatile u32 rawropblend;
- volatile u32 rawcmp;
- volatile u32 rawwac;
- volatile u32 fbramid;
-
- volatile u32 drawop;
- u32 xxx10[2];
- volatile u32 fontlpat;
- u32 xxx11;
- volatile u32 fontxy;
- volatile u32 fontw;
- volatile u32 fontinc;
- volatile u32 font;
- u32 xxx12[3];
- volatile u32 blend2;
- volatile u32 preblend;
- volatile u32 stencil;
- volatile u32 stencilctl;
-
- u32 xxx13[4];
- volatile u32 dcss1;
- volatile u32 dcss2;
- volatile u32 dcss3;
- volatile u32 widpmask;
- volatile u32 dcs2;
- volatile u32 dcs3;
- volatile u32 dcs4;
- u32 xxx14;
- volatile u32 dcd2;
- volatile u32 dcd3;
- volatile u32 dcd4;
- u32 xxx15;
-
- volatile u32 pattern[32];
-
- u32 xxx16[256];
-
- volatile u32 devid;
- u32 xxx17[63];
-
- volatile u32 ucsr;
- u32 xxx18[31];
-
- volatile u32 mer;
-};
-
-static __inline__ void FFBFifo(struct fb_info_sbusfb *fb, int n)
-{
- struct ffb_fbc *fbc;
- int cache = fb->s.ffb.fifo_cache;
-
- if (cache - n < 0) {
- fbc = fb->s.ffb.fbc;
- do { cache = (upa_readl(&fbc->ucsr) & FFB_UCSR_FIFO_MASK) - 8;
- } while (cache - n < 0);
- }
- fb->s.ffb.fifo_cache = cache - n;
-}
-
-static __inline__ void FFBWait(struct ffb_fbc *ffb)
-{
- int limit = 10000;
-
- do {
- if ((upa_readl(&ffb->ucsr) & FFB_UCSR_ALL_BUSY) == 0)
- break;
- if ((upa_readl(&ffb->ucsr) & FFB_UCSR_ALL_ERRORS) != 0) {
- upa_writel(FFB_UCSR_ALL_ERRORS, &ffb->ucsr);
- }
- } while(--limit > 0);
-}
-
-struct ffb_dac {
- volatile u32 type;
- volatile u32 value;
- volatile u32 type2;
- volatile u32 value2;
-};
-
-static struct sbus_mmap_map ffb_mmap_map[] = {
- { FFB_SFB8R_VOFF, FFB_SFB8R_POFF, 0x0400000 },
- { FFB_SFB8G_VOFF, FFB_SFB8G_POFF, 0x0400000 },
- { FFB_SFB8B_VOFF, FFB_SFB8B_POFF, 0x0400000 },
- { FFB_SFB8X_VOFF, FFB_SFB8X_POFF, 0x0400000 },
- { FFB_SFB32_VOFF, FFB_SFB32_POFF, 0x1000000 },
- { FFB_SFB64_VOFF, FFB_SFB64_POFF, 0x2000000 },
- { FFB_FBC_REGS_VOFF, FFB_FBC_REGS_POFF, 0x0002000 },
- { FFB_BM_FBC_REGS_VOFF, FFB_BM_FBC_REGS_POFF, 0x0002000 },
- { FFB_DFB8R_VOFF, FFB_DFB8R_POFF, 0x0400000 },
- { FFB_DFB8G_VOFF, FFB_DFB8G_POFF, 0x0400000 },
- { FFB_DFB8B_VOFF, FFB_DFB8B_POFF, 0x0400000 },
- { FFB_DFB8X_VOFF, FFB_DFB8X_POFF, 0x0400000 },
- { FFB_DFB24_VOFF, FFB_DFB24_POFF, 0x1000000 },
- { FFB_DFB32_VOFF, FFB_DFB32_POFF, 0x1000000 },
- { FFB_FBC_KREGS_VOFF, FFB_FBC_KREGS_POFF, 0x0002000 },
- { FFB_DAC_VOFF, FFB_DAC_POFF, 0x0002000 },
- { FFB_PROM_VOFF, FFB_PROM_POFF, 0x0010000 },
- { FFB_EXP_VOFF, FFB_EXP_POFF, 0x0002000 },
- { FFB_DFB422A_VOFF, FFB_DFB422A_POFF, 0x0800000 },
- { FFB_DFB422AD_VOFF, FFB_DFB422AD_POFF, 0x0800000 },
- { FFB_DFB24B_VOFF, FFB_DFB24B_POFF, 0x1000000 },
- { FFB_DFB422B_VOFF, FFB_DFB422B_POFF, 0x0800000 },
- { FFB_DFB422BD_VOFF, FFB_DFB422BD_POFF, 0x0800000 },
- { FFB_SFB16Z_VOFF, FFB_SFB16Z_POFF, 0x0800000 },
- { FFB_SFB8Z_VOFF, FFB_SFB8Z_POFF, 0x0800000 },
- { FFB_SFB422_VOFF, FFB_SFB422_POFF, 0x0800000 },
- { FFB_SFB422D_VOFF, FFB_SFB422D_POFF, 0x0800000 },
- { 0, 0, 0 }
-};
-
-static void ffb_setup(struct display *p)
-{
- p->next_line = 8192;
- p->next_plane = 0;
-}
-
-static void ffb_clear(struct vc_data *conp, struct display *p, int sy, int sx,
- int height, int width)
-{
- struct fb_info_sbusfb *fb = sbusfbinfo(p->fb_info);
- register struct ffb_fbc *fbc = fb->s.ffb.fbc;
- unsigned long flags;
- u64 yx, hw;
- int fg;
-
- spin_lock_irqsave(&fb->lock, flags);
- fg = ((u32 *)p->dispsw_data)[attr_bgcol_ec(p,conp)];
- if (fg != fb->s.ffb.fg_cache) {
- FFBFifo(fb, 5);
- upa_writel(fg, &fbc->fg);
- fb->s.ffb.fg_cache = fg;
- } else
- FFBFifo(fb, 4);
-
- if (fontheightlog(p)) {
- yx = (u64)sy << (fontheightlog(p) + 32); hw = (u64)height << (fontheightlog(p) + 32);
- } else {
- yx = (u64)(sy * fontheight(p)) << 32; hw = (u64)(height * fontheight(p)) << 32;
- }
- if (fontwidthlog(p)) {
- yx += sx << fontwidthlog(p); hw += width << fontwidthlog(p);
- } else {
- yx += sx * fontwidth(p); hw += width * fontwidth(p);
- }
- upa_writeq(yx + fb->s.ffb.yx_margin, &fbc->by);
- upa_writeq(hw, &fbc->bh);
- spin_unlock_irqrestore(&fb->lock, flags);
-}
-
-static void ffb_fill(struct fb_info_sbusfb *fb, struct display *p, int s,
- int count, unsigned short *boxes)
-{
- register struct ffb_fbc *fbc = fb->s.ffb.fbc;
- unsigned long flags;
- int fg;
-
- spin_lock_irqsave(&fb->lock, flags);
- fg = ((u32 *)p->dispsw_data)[attr_bgcol(p,s)];
- if (fg != fb->s.ffb.fg_cache) {
- FFBFifo(fb, 1);
- upa_writel(fg, &fbc->fg);
- fb->s.ffb.fg_cache = fg;
- }
- while (count-- > 0) {
- FFBFifo(fb, 4);
- upa_writel(boxes[1], &fbc->by);
- upa_writel(boxes[0], &fbc->bx);
- upa_writel(boxes[3] - boxes[1], &fbc->bh);
- upa_writel(boxes[2] - boxes[0], &fbc->bw);
- boxes += 4;
- }
- spin_unlock_irqrestore(&fb->lock, flags);
-}
-
-static void ffb_putc(struct vc_data *conp, struct display *p, int c, int yy, int xx)
-{
- struct fb_info_sbusfb *fb = sbusfbinfo(p->fb_info);
- register struct ffb_fbc *fbc = fb->s.ffb.fbc;
- unsigned long flags;
- int i, xy;
- u8 *fd;
- u64 fgbg;
-
- spin_lock_irqsave(&fb->lock, flags);
- if (fontheightlog(p)) {
- xy = (yy << (16 + fontheightlog(p)));
- i = ((c & p->charmask) << fontheightlog(p));
- } else {
- xy = ((yy * fontheight(p)) << 16);
- i = (c & p->charmask) * fontheight(p);
- }
- if (fontwidth(p) <= 8)
- fd = p->fontdata + i;
- else
- fd = p->fontdata + (i << 1);
- if (fontwidthlog(p))
- xy += (xx << fontwidthlog(p)) + fb->s.ffb.xy_margin;
- else
- xy += (xx * fontwidth(p)) + fb->s.ffb.xy_margin;
- fgbg = (((u64)(((u32 *)p->dispsw_data)[attr_fgcol(p,c)])) << 32) |
- ((u32 *)p->dispsw_data)[attr_bgcol(p,c)];
- if (fgbg != *(u64 *)&fb->s.ffb.fg_cache) {
- FFBFifo(fb, 2);
- upa_writeq(fgbg, &fbc->fg);
- *(u64 *)&fb->s.ffb.fg_cache = fgbg;
- }
- FFBFifo(fb, 2 + fontheight(p));
- upa_writel(xy, &fbc->fontxy);
- upa_writel(fontwidth(p), &fbc->fontw);
- if (fontwidth(p) <= 8) {
- for (i = 0; i < fontheight(p); i++) {
- u32 val = *fd++ << 24;
-
- upa_writel(val, &fbc->font);
- }
- } else {
- for (i = 0; i < fontheight(p); i++) {
- u32 val = *(u16 *)fd << 16;
-
- upa_writel(val, &fbc->font);
- fd += 2;
- }
- }
- spin_unlock_irqrestore(&fb->lock, flags);
-}
-
-static void ffb_putcs(struct vc_data *conp, struct display *p, const unsigned short *s,
- int count, int yy, int xx)
-{
- struct fb_info_sbusfb *fb = sbusfbinfo(p->fb_info);
- register struct ffb_fbc *fbc = fb->s.ffb.fbc;
- unsigned long flags;
- int i, xy;
- u8 *fd1, *fd2, *fd3, *fd4;
- u16 c;
- u64 fgbg;
-
- spin_lock_irqsave(&fb->lock, flags);
- c = scr_readw(s);
- fgbg = (((u64)(((u32 *)p->dispsw_data)[attr_fgcol(p, c)])) << 32) |
- ((u32 *)p->dispsw_data)[attr_bgcol(p, c)];
- if (fgbg != *(u64 *)&fb->s.ffb.fg_cache) {
- FFBFifo(fb, 2);
- upa_writeq(fgbg, &fbc->fg);
- *(u64 *)&fb->s.ffb.fg_cache = fgbg;
- }
- xy = fb->s.ffb.xy_margin;
- if (fontwidthlog(p))
- xy += (xx << fontwidthlog(p));
- else
- xy += xx * fontwidth(p);
- if (fontheightlog(p))
- xy += (yy << (16 + fontheightlog(p)));
- else
- xy += ((yy * fontheight(p)) << 16);
- if (fontwidth(p) <= 8) {
- while (count >= 4) {
- count -= 4;
- FFBFifo(fb, 2 + fontheight(p));
- upa_writel(4 * fontwidth(p), &fbc->fontw);
- upa_writel(xy, &fbc->fontxy);
- if (fontheightlog(p)) {
- fd1 = p->fontdata + ((scr_readw(s++) & p->charmask) << fontheightlog(p));
- fd2 = p->fontdata + ((scr_readw(s++) & p->charmask) << fontheightlog(p));
- fd3 = p->fontdata + ((scr_readw(s++) & p->charmask) << fontheightlog(p));
- fd4 = p->fontdata + ((scr_readw(s++) & p->charmask) << fontheightlog(p));
- } else {
- fd1 = p->fontdata + ((scr_readw(s++) & p->charmask) * fontheight(p));
- fd2 = p->fontdata + ((scr_readw(s++) & p->charmask) * fontheight(p));
- fd3 = p->fontdata + ((scr_readw(s++) & p->charmask) * fontheight(p));
- fd4 = p->fontdata + ((scr_readw(s++) & p->charmask) * fontheight(p));
- }
- if (fontwidth(p) == 8) {
- for (i = 0; i < fontheight(p); i++) {
- u32 val;
-
- val = ((u32)*fd4++) | ((((u32)*fd3++) | ((((u32)*fd2++) | (((u32)*fd1++)
- << 8)) << 8)) << 8);
- upa_writel(val, &fbc->font);
- }
- xy += 32;
- } else {
- for (i = 0; i < fontheight(p); i++) {
- u32 val = (((u32)*fd4++) | ((((u32)*fd3++) | ((((u32)*fd2++) | (((u32)*fd1++)
- << fontwidth(p))) << fontwidth(p))) << fontwidth(p))) << (24 - 3 * fontwidth(p));
- upa_writel(val, &fbc->font);
- }
- xy += 4 * fontwidth(p);
- }
- }
- } else {
- while (count >= 2) {
- count -= 2;
- FFBFifo(fb, 2 + fontheight(p));
- upa_writel(2 * fontwidth(p), &fbc->fontw);
- upa_writel(xy, &fbc->fontxy);
- if (fontheightlog(p)) {
- fd1 = p->fontdata + ((scr_readw(s++) & p->charmask) << (fontheightlog(p) + 1));
- fd2 = p->fontdata + ((scr_readw(s++) & p->charmask) << (fontheightlog(p) + 1));
- } else {
- fd1 = p->fontdata + (((scr_readw(s++) & p->charmask) * fontheight(p)) << 1);
- fd2 = p->fontdata + (((scr_readw(s++) & p->charmask) * fontheight(p)) << 1);
- }
- for (i = 0; i < fontheight(p); i++) {
- u32 val = ((((u32)*(u16 *)fd1) << fontwidth(p)) | ((u32)*(u16 *)fd2)) << (16 - fontwidth(p));
-
- upa_writel(val, &fbc->font);
- fd1 += 2; fd2 += 2;
- }
- xy += 2 * fontwidth(p);
- }
- }
- while (count) {
- count--;
- FFBFifo(fb, 2 + fontheight(p));
- upa_writel(fontwidth(p), &fbc->fontw);
- upa_writel(xy, &fbc->fontxy);
- if (fontheightlog(p))
- i = ((scr_readw(s++) & p->charmask) << fontheightlog(p));
- else
- i = ((scr_readw(s++) & p->charmask) * fontheight(p));
- if (fontwidth(p) <= 8) {
- fd1 = p->fontdata + i;
- for (i = 0; i < fontheight(p); i++) {
- u32 val = *fd1++ << 24;
-
- upa_writel(val, &fbc->font);
- }
- } else {
- fd1 = p->fontdata + (i << 1);
- for (i = 0; i < fontheight(p); i++) {
- u32 val = *(u16 *)fd1 << 16;
-
- upa_writel(val, &fbc->font);
- fd1 += 2;
- }
- }
- xy += fontwidth(p);
- }
- spin_unlock_irqrestore(&fb->lock, flags);
-}
-
-static void ffb_revc(struct display *p, int xx, int yy)
-{
- /* Not used if hw cursor */
-}
-
-#if 0
-static int ffb_blank(struct fb_info_sbusfb *fb)
-{
- struct ffb_dac *dac = fb->s.ffb.dac;
- unsigned long flags;
- u32 tmp;
-
- spin_lock_irqsave(&fb->lock, flags);
- upa_writel(0x6000, &dac->type);
- tmp = (upa_readl(&dac->value) & ~0x1);
- upa_writel(0x6000, &dac->type);
- upa_writel(tmp, &dac->value);
- spin_unlock_irqrestore(&fb->lock, flags);
- return 0;
-}
-#endif
-
-static int ffb_unblank(struct fb_info_sbusfb *fb)
-{
- struct ffb_dac *dac = fb->s.ffb.dac;
- unsigned long flags;
- u32 tmp;
-
- spin_lock_irqsave(&fb->lock, flags);
- upa_writel(0x6000, &dac->type);
- tmp = (upa_readl(&dac->value) | 0x1);
- upa_writel(0x6000, &dac->type);
- upa_writel(tmp, &dac->value);
- spin_unlock_irqrestore(&fb->lock, flags);
- return 0;
-}
-
-static void ffb_loadcmap (struct fb_info_sbusfb *fb, struct display *p, int index, int count)
-{
- struct ffb_dac *dac = fb->s.ffb.dac;
- unsigned long flags;
- int i, j = count;
-
- spin_lock_irqsave(&fb->lock, flags);
- upa_writel(0x2000 | index, &dac->type);
- for (i = index; j--; i++) {
- u32 val;
-
- /* Feed the colors in :)) */
- val = ((fb->color_map CM(i,0))) |
- ((fb->color_map CM(i,1)) << 8) |
- ((fb->color_map CM(i,2)) << 16);
- upa_writel(val, &dac->value);
- }
- if (!p)
- goto out;
- for (i = index, j = count; i < 16 && j--; i++)
- ((u32 *)p->dispsw_data)[i] = ((fb->color_map CM(i,0))) |
- ((fb->color_map CM(i,1)) << 8) |
- ((fb->color_map CM(i,2)) << 16);
-out:
- spin_unlock_irqrestore(&fb->lock, flags);
-}
-
-static struct display_switch ffb_dispsw __initdata = {
- .setup = ffb_setup,
- .bmove = fbcon_redraw_bmove,
- .clear = ffb_clear,
- .putc = ffb_putc,
- .putcs = ffb_putcs,
- .revc = ffb_revc,
- .fontwidthmask =FONTWIDTHRANGE(1,16) /* Allow fontwidths up to 16 */
-};
-
-static void ffb_margins (struct fb_info_sbusfb *fb, struct display *p, int x_margin, int y_margin)
-{
- register struct ffb_fbc *fbc = fb->s.ffb.fbc;
- unsigned long flags;
-
- spin_lock_irqsave(&fb->lock, flags);
- fb->s.ffb.xy_margin = (y_margin << 16) + x_margin;
- fb->s.ffb.yx_margin = (((u64)y_margin) << 32) + x_margin;
- fb->info.screen_base += 8192 * (y_margin - fb->y_margin) + 4 * (x_margin - fb->x_margin);
- FFBWait(fbc);
- spin_unlock_irqrestore(&fb->lock, flags);
-}
-
-static __inline__ void __ffb_curs_enable (struct fb_info_sbusfb *fb, int enable)
-{
- struct ffb_dac *dac = fb->s.ffb.dac;
- u32 val;
-
- upa_writel(0x100, &dac->type2);
- if (fb->s.ffb.dac_rev <= 2) {
- val = enable ? 3 : 0;
- } else {
- val = enable ? 0 : 3;
- }
- upa_writel(val, &dac->value2);
-}
-
-static void ffb_setcursormap (struct fb_info_sbusfb *fb, u8 *red, u8 *green, u8 *blue)
-{
- struct ffb_dac *dac = fb->s.ffb.dac;
- unsigned long flags;
-
- spin_lock_irqsave(&fb->lock, flags);
- __ffb_curs_enable (fb, 0);
- upa_writel(0x102, &dac->type2);
- upa_writel((red[0] | (green[0]<<8) | (blue[0]<<16)), &dac->value2);
- upa_writel((red[1] | (green[1]<<8) | (blue[1]<<16)), &dac->value2);
- spin_unlock_irqrestore(&fb->lock, flags);
-}
-
-/* Set cursor shape */
-static void ffb_setcurshape (struct fb_info_sbusfb *fb)
-{
- struct ffb_dac *dac = fb->s.ffb.dac;
- unsigned long flags;
- int i, j;
-
- spin_lock_irqsave(&fb->lock, flags);
- __ffb_curs_enable (fb, 0);
- for (j = 0; j < 2; j++) {
- u32 val = j ? 0 : 0x80;
-
- upa_writel(val, &dac->type2);
- for (i = 0; i < 0x40; i++) {
- if (fb->cursor.size.fbx <= 32) {
- upa_writel(fb->cursor.bits [j][i], &dac->value2);
- upa_writel(0, &dac->value2);
- } else {
- upa_writel(fb->cursor.bits [j][2*i], &dac->value2);
- upa_writel(fb->cursor.bits [j][2*i+1], &dac->value2);
- }
- }
- }
- spin_unlock_irqrestore(&fb->lock, flags);
-}
-
-/* Load cursor information */
-static void ffb_setcursor (struct fb_info_sbusfb *fb)
-{
- struct ffb_dac *dac = fb->s.ffb.dac;
- struct cg_cursor *c = &fb->cursor;
- unsigned long flags;
- u32 val;
-
- spin_lock_irqsave(&fb->lock, flags);
- upa_writel(0x104, &dac->type2);
- /* Should this be just 0x7ff??
- Should I do some margin handling and setcurshape in that case? */
- val = (((c->cpos.fby - c->chot.fby) & 0xffff) << 16)
- |((c->cpos.fbx - c->chot.fbx) & 0xffff);
- upa_writel(val, &dac->value2);
- __ffb_curs_enable (fb, fb->cursor.enable);
- spin_unlock_irqrestore(&fb->lock, flags);
-}
-
-static void ffb_switch_from_graph (struct fb_info_sbusfb *fb)
-{
- register struct ffb_fbc *fbc = fb->s.ffb.fbc;
- unsigned long flags;
-
- spin_lock_irqsave(&fb->lock, flags);
- FFBWait(fbc);
- fb->s.ffb.fifo_cache = 0;
- FFBFifo(fb, 8);
- upa_writel(FFB_PPC_VCE_DISABLE|FFB_PPC_TBE_OPAQUE|
- FFB_PPC_APE_DISABLE|FFB_PPC_CS_CONST,
- &fbc->ppc);
- upa_writel(0x2000707f, &fbc->fbc);
- upa_writel(FFB_ROP_NEW, &fbc->rop);
- upa_writel(FFB_DRAWOP_RECTANGLE, &fbc->drawop);
- upa_writel(0xffffffff, &fbc->pmask);
- upa_writel(0x10000, &fbc->fontinc);
- upa_writel(fb->s.ffb.fg_cache, &fbc->fg);
- upa_writel(fb->s.ffb.bg_cache, &fbc->bg);
- FFBWait(fbc);
- spin_unlock_irqrestore(&fb->lock, flags);
-}
-
-static int __init ffb_rasterimg (struct fb_info *info, int start)
-{
- ffb_switch_from_graph (sbusfbinfo(info));
- return 0;
-}
-
-static char idstring[60] __initdata = { 0 };
-
-static int __init creator_apply_upa_parent_ranges(int parent, struct linux_prom64_registers *regs)
-{
- struct linux_prom64_ranges ranges[PROMREG_MAX];
- char name[128];
- int len, i;
-
- prom_getproperty(parent, "name", name, sizeof(name));
- if (strcmp(name, "upa") != 0)
- return 0;
-
- len = prom_getproperty(parent, "ranges", (void *) ranges, sizeof(ranges));
- if (len <= 0)
- return 1;
-
- len /= sizeof(struct linux_prom64_ranges);
- for (i = 0; i < len; i++) {
- struct linux_prom64_ranges *rng = &ranges[i];
- u64 phys_addr = regs->phys_addr;
-
- if (phys_addr >= rng->ot_child_base &&
- phys_addr < (rng->ot_child_base + rng->or_size)) {
- regs->phys_addr -= rng->ot_child_base;
- regs->phys_addr += rng->ot_parent_base;
- return 0;
- }
- }
-
- return 1;
-}
-
-char __init *creatorfb_init(struct fb_info_sbusfb *fb)
-{
- struct fb_fix_screeninfo *fix = &fb->info.fix;
- struct fb_var_screeninfo *var = &fb->info.var;
- struct display *disp = &fb->disp;
- struct fbtype *type = &fb->type;
- struct linux_prom64_registers regs[2*PROMREG_MAX];
- int i, afb = 0;
- unsigned int btype;
- char name[64];
- struct fb_ops *fbops;
-
- if (prom_getproperty(fb->prom_node, "reg", (void *) regs, sizeof(regs)) <= 0)
- return NULL;
-
- if (creator_apply_upa_parent_ranges(fb->prom_parent, ®s[0]))
- return NULL;
-
- disp->dispsw_data = (void *)kmalloc(16 * sizeof(u32), GFP_KERNEL);
- if (disp->dispsw_data == NULL)
- return NULL;
- memset(disp->dispsw_data, 0, 16 * sizeof(u32));
-
- fbops = kmalloc(sizeof(*fbops), GFP_KERNEL);
- if (fbops == NULL) {
- kfree(disp->dispsw_data);
- return NULL;
- }
-
- *fbops = *fb->info.fbops;
- fbops->fb_rasterimg = ffb_rasterimg;
- fb->info.fbops = fbops;
-
- prom_getstring(fb->prom_node, "name", name, sizeof(name));
- if (!strcmp(name, "SUNW,afb"))
- afb = 1;
-
- btype = prom_getintdefault(fb->prom_node, "board_type", 0);
-
- strcpy(fb->info.modename, "Creator");
- if (!afb) {
- if ((btype & 7) == 3)
- strcpy(fix->id, "Creator 3D");
- else
- strcpy(fix->id, "Creator");
- } else
- strcpy(fix->id, "Elite 3D");
-
- fix->visual = FB_VISUAL_TRUECOLOR;
- fix->line_length = 8192;
- fix->accel = FB_ACCEL_SUN_CREATOR;
-
- var->bits_per_pixel = 32;
- var->green.offset = 8;
- var->blue.offset = 16;
- var->accel_flags = FB_ACCELF_TEXT;
-
- disp->scrollmode = SCROLL_YREDRAW;
- fb->info.screen_base = (char *)(regs[0].phys_addr) + FFB_DFB24_POFF + 8192 * fb->y_margin + 4 * fb->x_margin;
- fb->s.ffb.xy_margin = (fb->y_margin << 16) + fb->x_margin;
- fb->s.ffb.yx_margin = (((u64)fb->y_margin) << 32) + fb->x_margin;
- fb->s.ffb.fbc = (struct ffb_fbc *)(regs[0].phys_addr + FFB_FBC_REGS_POFF);
- fb->s.ffb.dac = (struct ffb_dac *)(regs[0].phys_addr + FFB_DAC_POFF);
- fb->dispsw = ffb_dispsw;
-
- fb->margins = ffb_margins;
- fb->loadcmap = ffb_loadcmap;
- fb->setcursor = ffb_setcursor;
- fb->setcursormap = ffb_setcursormap;
- fb->setcurshape = ffb_setcurshape;
- fb->switch_from_graph = ffb_switch_from_graph;
- fb->fill = ffb_fill;
-#if 0
- /* XXX Can't enable this for now, I've seen cases
- * XXX where the VC was blanked, and Xsun24 was started
- * XXX via a remote login, the sunfb code did not
- * XXX unblank creator when it was mmap'd for some
- * XXX reason, investigate later... -DaveM
- */
- fb->blank = ffb_blank;
- fb->unblank = ffb_unblank;
-#endif
-
- /* If there are any read errors or fifo overflow conditions,
- * clear them now.
- */
- if((upa_readl(&fb->s.ffb.fbc->ucsr) & FFB_UCSR_ALL_ERRORS) != 0)
- upa_writel(FFB_UCSR_ALL_ERRORS, &fb->s.ffb.fbc->ucsr);
-
- ffb_switch_from_graph(fb);
-
- fb->physbase = regs[0].phys_addr;
- fb->mmap_map = ffb_mmap_map;
-
- fb->cursor.hwsize.fbx = 64;
- fb->cursor.hwsize.fby = 64;
-
- type->fb_depth = 24;
-
- upa_writel(0x8000, &fb->s.ffb.dac->type);
- fb->s.ffb.dac_rev = (upa_readl(&fb->s.ffb.dac->value) >> 0x1c);
-
- i = prom_getintdefault (fb->prom_node, "board_type", 8);
-
- sprintf(idstring, "%s at %016lx type %d DAC %d",
- fix->id, regs[0].phys_addr, i, fb->s.ffb.dac_rev);
-
- /* Elite3D has different DAC revision numbering, and no DAC revisions
- have the reversed meaning of cursor enable */
- if (afb)
- fb->s.ffb.dac_rev = 10;
-
- /* Unblank it just to be sure. When there are multiple
- * FFB/AFB cards in the system, or it is not the OBP
- * chosen console, it will have video outputs off in
- * the DAC.
- */
- ffb_unblank(fb);
-
- return idstring;
-}
-
-MODULE_LICENSE("GPL");
extern int matroxfb_init(void);
extern int matroxfb_setup(char*);
extern int hpfb_init(void);
-extern int sbusfb_init(void);
-extern int sbusfb_setup(char*);
extern int control_init(void);
extern int control_setup(char*);
extern int platinum_init(void);
extern int sstfb_setup(char*);
extern int i810fb_init(void);
extern int i810fb_setup(char*);
+extern int ffb_init(void);
+extern int ffb_setup(char*);
static struct {
const char *name;
int (*setup)(char*);
} fb_drivers[] __initdata = {
-#ifdef CONFIG_FB_SBUS
- /*
- * Sbusfb must be initialized _before_ other frame buffer devices that
- * use PCI probing
- */
- { "sbus", sbusfb_init, sbusfb_setup },
-#endif
/*
* Chipset specific drivers that use resource management
*/
#ifdef CONFIG_FB_STI
{ "stifb", stifb_init, stifb_setup },
#endif
+#ifdef CONFIG_FB_FFB
+ { "ffb", ffb_init, ffb_setup },
+#endif
/*
* Generic drivers that are used as fallbacks
--- /dev/null
+/* ffb.c: Creator/Elite3D frame buffer driver
+ *
+ * Copyright (C) 2003 David S. Miller (davem@redhat.com)
+ * Copyright (C) 1997,1998,1999 Jakub Jelinek (jj@ultra.linux.cz)
+ *
+ * Driver layout based loosely on tgafb.c, see that file for credits.
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/string.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
+#include <linux/init.h>
+#include <linux/fb.h>
+#include <linux/mm.h>
+#include <linux/timer.h>
+
+#include <asm/io.h>
+#include <asm/upa.h>
+#include <asm/oplib.h>
+
+#include "sbuslib.h"
+
+/*
+ * Local functions.
+ */
+
+static int ffb_check_var(struct fb_var_screeninfo *, struct fb_info *);
+static int ffb_set_par(struct fb_info *);
+static int ffb_setcolreg(unsigned, unsigned, unsigned, unsigned,
+ unsigned, struct fb_info *);
+static int ffb_blank(int, struct fb_info *);
+static void ffb_init_fix(struct fb_info *);
+
+static void ffb_imageblit(struct fb_info *, struct fb_image *);
+static void ffb_fillrect(struct fb_info *, struct fb_fillrect *);
+static void ffb_copyarea(struct fb_info *, struct fb_copyarea *);
+static int ffb_sync(struct fb_info *);
+static int ffb_mmap(struct fb_info *, struct file *, struct vm_area_struct *);
+
+/*
+ * Frame buffer operations
+ */
+
+static struct fb_ops ffb_ops = {
+ .owner = THIS_MODULE,
+ .fb_check_var = ffb_check_var,
+ .fb_set_par = ffb_set_par,
+ .fb_setcolreg = ffb_setcolreg,
+ .fb_blank = ffb_blank,
+ .fb_fillrect = ffb_fillrect,
+ .fb_copyarea = ffb_copyarea,
+ .fb_imageblit = ffb_imageblit,
+ .fb_sync = ffb_sync,
+ .fb_mmap = ffb_mmap,
+
+ /* XXX Use FFB hw cursor once fb cursor API is better understood... */
+ .fb_cursor = soft_cursor,
+};
+
+/* Register layout and definitions */
+#define FFB_SFB8R_VOFF 0x00000000
+#define FFB_SFB8G_VOFF 0x00400000
+#define FFB_SFB8B_VOFF 0x00800000
+#define FFB_SFB8X_VOFF 0x00c00000
+#define FFB_SFB32_VOFF 0x01000000
+#define FFB_SFB64_VOFF 0x02000000
+#define FFB_FBC_REGS_VOFF 0x04000000
+#define FFB_BM_FBC_REGS_VOFF 0x04002000
+#define FFB_DFB8R_VOFF 0x04004000
+#define FFB_DFB8G_VOFF 0x04404000
+#define FFB_DFB8B_VOFF 0x04804000
+#define FFB_DFB8X_VOFF 0x04c04000
+#define FFB_DFB24_VOFF 0x05004000
+#define FFB_DFB32_VOFF 0x06004000
+#define FFB_DFB422A_VOFF 0x07004000 /* DFB 422 mode write to A */
+#define FFB_DFB422AD_VOFF 0x07804000 /* DFB 422 mode with line doubling */
+#define FFB_DFB24B_VOFF 0x08004000 /* DFB 24bit mode write to B */
+#define FFB_DFB422B_VOFF 0x09004000 /* DFB 422 mode write to B */
+#define FFB_DFB422BD_VOFF 0x09804000 /* DFB 422 mode with line doubling */
+#define FFB_SFB16Z_VOFF 0x0a004000 /* 16bit mode Z planes */
+#define FFB_SFB8Z_VOFF 0x0a404000 /* 8bit mode Z planes */
+#define FFB_SFB422_VOFF 0x0ac04000 /* SFB 422 mode write to A/B */
+#define FFB_SFB422D_VOFF 0x0b404000 /* SFB 422 mode with line doubling */
+#define FFB_FBC_KREGS_VOFF 0x0bc04000
+#define FFB_DAC_VOFF 0x0bc06000
+#define FFB_PROM_VOFF 0x0bc08000
+#define FFB_EXP_VOFF 0x0bc18000
+
+#define FFB_SFB8R_POFF 0x04000000UL
+#define FFB_SFB8G_POFF 0x04400000UL
+#define FFB_SFB8B_POFF 0x04800000UL
+#define FFB_SFB8X_POFF 0x04c00000UL
+#define FFB_SFB32_POFF 0x05000000UL
+#define FFB_SFB64_POFF 0x06000000UL
+#define FFB_FBC_REGS_POFF 0x00600000UL
+#define FFB_BM_FBC_REGS_POFF 0x00600000UL
+#define FFB_DFB8R_POFF 0x01000000UL
+#define FFB_DFB8G_POFF 0x01400000UL
+#define FFB_DFB8B_POFF 0x01800000UL
+#define FFB_DFB8X_POFF 0x01c00000UL
+#define FFB_DFB24_POFF 0x02000000UL
+#define FFB_DFB32_POFF 0x03000000UL
+#define FFB_FBC_KREGS_POFF 0x00610000UL
+#define FFB_DAC_POFF 0x00400000UL
+#define FFB_PROM_POFF 0x00000000UL
+#define FFB_EXP_POFF 0x00200000UL
+#define FFB_DFB422A_POFF 0x09000000UL
+#define FFB_DFB422AD_POFF 0x09800000UL
+#define FFB_DFB24B_POFF 0x0a000000UL
+#define FFB_DFB422B_POFF 0x0b000000UL
+#define FFB_DFB422BD_POFF 0x0b800000UL
+#define FFB_SFB16Z_POFF 0x0c800000UL
+#define FFB_SFB8Z_POFF 0x0c000000UL
+#define FFB_SFB422_POFF 0x0d000000UL
+#define FFB_SFB422D_POFF 0x0d800000UL
+
+/* Draw operations */
+#define FFB_DRAWOP_DOT 0x00
+#define FFB_DRAWOP_AADOT 0x01
+#define FFB_DRAWOP_BRLINECAP 0x02
+#define FFB_DRAWOP_BRLINEOPEN 0x03
+#define FFB_DRAWOP_DDLINE 0x04
+#define FFB_DRAWOP_AALINE 0x05
+#define FFB_DRAWOP_TRIANGLE 0x06
+#define FFB_DRAWOP_POLYGON 0x07
+#define FFB_DRAWOP_RECTANGLE 0x08
+#define FFB_DRAWOP_FASTFILL 0x09
+#define FFB_DRAWOP_BCOPY 0x0a
+#define FFB_DRAWOP_VSCROLL 0x0b
+
+/* Pixel processor control */
+/* Force WID */
+#define FFB_PPC_FW_DISABLE 0x800000
+#define FFB_PPC_FW_ENABLE 0xc00000
+/* Auxiliary clip */
+#define FFB_PPC_ACE_DISABLE 0x040000
+#define FFB_PPC_ACE_AUX_SUB 0x080000
+#define FFB_PPC_ACE_AUX_ADD 0x0c0000
+/* Depth cue */
+#define FFB_PPC_DCE_DISABLE 0x020000
+#define FFB_PPC_DCE_ENABLE 0x030000
+/* Alpha blend */
+#define FFB_PPC_ABE_DISABLE 0x008000
+#define FFB_PPC_ABE_ENABLE 0x00c000
+/* View clip */
+#define FFB_PPC_VCE_DISABLE 0x001000
+#define FFB_PPC_VCE_2D 0x002000
+#define FFB_PPC_VCE_3D 0x003000
+/* Area pattern */
+#define FFB_PPC_APE_DISABLE 0x000800
+#define FFB_PPC_APE_ENABLE 0x000c00
+/* Transparent background */
+#define FFB_PPC_TBE_OPAQUE 0x000200
+#define FFB_PPC_TBE_TRANSPARENT 0x000300
+/* Z source */
+#define FFB_PPC_ZS_VAR 0x000080
+#define FFB_PPC_ZS_CONST 0x0000c0
+/* Y source */
+#define FFB_PPC_YS_VAR 0x000020
+#define FFB_PPC_YS_CONST 0x000030
+/* X source */
+#define FFB_PPC_XS_WID 0x000004
+#define FFB_PPC_XS_VAR 0x000008
+#define FFB_PPC_XS_CONST 0x00000c
+/* Color (BGR) source */
+#define FFB_PPC_CS_VAR 0x000002
+#define FFB_PPC_CS_CONST 0x000003
+
+#define FFB_ROP_NEW 0x83
+#define FFB_ROP_OLD 0x85
+#define FFB_ROP_NEW_XOR_OLD 0x86
+
+#define FFB_UCSR_FIFO_MASK 0x00000fff
+#define FFB_UCSR_FB_BUSY 0x01000000
+#define FFB_UCSR_RP_BUSY 0x02000000
+#define FFB_UCSR_ALL_BUSY (FFB_UCSR_RP_BUSY|FFB_UCSR_FB_BUSY)
+#define FFB_UCSR_READ_ERR 0x40000000
+#define FFB_UCSR_FIFO_OVFL 0x80000000
+#define FFB_UCSR_ALL_ERRORS (FFB_UCSR_READ_ERR|FFB_UCSR_FIFO_OVFL)
+
+struct ffb_fbc {
+ /* Next vertex registers */
+ u32 xxx1[3];
+ volatile u32 alpha;
+ volatile u32 red;
+ volatile u32 green;
+ volatile u32 blue;
+ volatile u32 depth;
+ volatile u32 y;
+ volatile u32 x;
+ u32 xxx2[2];
+ volatile u32 ryf;
+ volatile u32 rxf;
+ u32 xxx3[2];
+
+ volatile u32 dmyf;
+ volatile u32 dmxf;
+ u32 xxx4[2];
+ volatile u32 ebyi;
+ volatile u32 ebxi;
+ u32 xxx5[2];
+ volatile u32 by;
+ volatile u32 bx;
+ u32 dy;
+ u32 dx;
+ volatile u32 bh;
+ volatile u32 bw;
+ u32 xxx6[2];
+
+ u32 xxx7[32];
+
+ /* Setup unit vertex state register */
+ volatile u32 suvtx;
+ u32 xxx8[63];
+
+ /* Control registers */
+ volatile u32 ppc;
+ volatile u32 wid;
+ volatile u32 fg;
+ volatile u32 bg;
+ volatile u32 consty;
+ volatile u32 constz;
+ volatile u32 xclip;
+ volatile u32 dcss;
+ volatile u32 vclipmin;
+ volatile u32 vclipmax;
+ volatile u32 vclipzmin;
+ volatile u32 vclipzmax;
+ volatile u32 dcsf;
+ volatile u32 dcsb;
+ volatile u32 dczf;
+ volatile u32 dczb;
+
+ u32 xxx9;
+ volatile u32 blendc;
+ volatile u32 blendc1;
+ volatile u32 blendc2;
+ volatile u32 fbramitc;
+ volatile u32 fbc;
+ volatile u32 rop;
+ volatile u32 cmp;
+ volatile u32 matchab;
+ volatile u32 matchc;
+ volatile u32 magnab;
+ volatile u32 magnc;
+ volatile u32 fbcfg0;
+ volatile u32 fbcfg1;
+ volatile u32 fbcfg2;
+ volatile u32 fbcfg3;
+
+ u32 ppcfg;
+ volatile u32 pick;
+ volatile u32 fillmode;
+ volatile u32 fbramwac;
+ volatile u32 pmask;
+ volatile u32 xpmask;
+ volatile u32 ypmask;
+ volatile u32 zpmask;
+ volatile u32 clip0min;
+ volatile u32 clip0max;
+ volatile u32 clip1min;
+ volatile u32 clip1max;
+ volatile u32 clip2min;
+ volatile u32 clip2max;
+ volatile u32 clip3min;
+ volatile u32 clip3max;
+
+ /* New 3dRAM III support regs */
+ volatile u32 rawblend2;
+ volatile u32 rawpreblend;
+ volatile u32 rawstencil;
+ volatile u32 rawstencilctl;
+ volatile u32 threedram1;
+ volatile u32 threedram2;
+ volatile u32 passin;
+ volatile u32 rawclrdepth;
+ volatile u32 rawpmask;
+ volatile u32 rawcsrc;
+ volatile u32 rawmatch;
+ volatile u32 rawmagn;
+ volatile u32 rawropblend;
+ volatile u32 rawcmp;
+ volatile u32 rawwac;
+ volatile u32 fbramid;
+
+ volatile u32 drawop;
+ u32 xxx10[2];
+ volatile u32 fontlpat;
+ u32 xxx11;
+ volatile u32 fontxy;
+ volatile u32 fontw;
+ volatile u32 fontinc;
+ volatile u32 font;
+ u32 xxx12[3];
+ volatile u32 blend2;
+ volatile u32 preblend;
+ volatile u32 stencil;
+ volatile u32 stencilctl;
+
+ u32 xxx13[4];
+ volatile u32 dcss1;
+ volatile u32 dcss2;
+ volatile u32 dcss3;
+ volatile u32 widpmask;
+ volatile u32 dcs2;
+ volatile u32 dcs3;
+ volatile u32 dcs4;
+ u32 xxx14;
+ volatile u32 dcd2;
+ volatile u32 dcd3;
+ volatile u32 dcd4;
+ u32 xxx15;
+
+ volatile u32 pattern[32];
+
+ u32 xxx16[256];
+
+ volatile u32 devid;
+ u32 xxx17[63];
+
+ volatile u32 ucsr;
+ u32 xxx18[31];
+
+ volatile u32 mer;
+};
+
+struct ffb_dac {
+ volatile u32 type;
+ volatile u32 value;
+ volatile u32 type2;
+ volatile u32 value2;
+};
+
+struct ffb_par {
+ spinlock_t lock;
+ struct ffb_fbc *fbc;
+ struct ffb_dac *dac;
+
+ u32 flags;
+#define FFB_FLAG_AFB 0x00000001
+#define FFB_FLAG_BLANKED 0x00000002
+
+ u32 fg_cache __attribute__((aligned (8)));
+ u32 bg_cache;
+ u32 rop_cache;
+
+ int fifo_cache;
+
+ unsigned long physbase;
+ unsigned long fbsize;
+
+ char name[64];
+ int prom_node;
+ int prom_parent_node;
+ int dac_rev;
+ int board_type;
+ struct list_head list;
+};
+
+#undef FFB_DO_DEBUG_LOG
+
+#ifdef FFB_DO_DEBUG_LOG
+#define FFB_DEBUG_LOG_ENTS 32
+static struct ffb_log {
+ int op;
+#define OP_FILLRECT 1
+#define OP_IMAGEBLIT 2
+
+ int depth, x, y, w, h;
+} ffb_debug_log[FFB_DEBUG_LOG_ENTS];
+static int ffb_debug_log_ent;
+
+static void ffb_do_log(unsigned long unused)
+{
+ int i;
+
+ for (i = 0; i < FFB_DEBUG_LOG_ENTS; i++) {
+ struct ffb_log *p = &ffb_debug_log[i];
+
+ printk("FFB_LOG: OP[%s] depth(%d) x(%d) y(%d) w(%d) h(%d)\n",
+ (p->op == OP_FILLRECT ? "FILLRECT" : "IMAGEBLIT"),
+ p->depth, p->x, p->y, p->w, p->h);
+ }
+}
+static struct timer_list ffb_log_timer =
+ TIMER_INITIALIZER(ffb_do_log, 0, 0);
+
+static void ffb_log(int op, int depth, int x, int y, int w, int h)
+{
+ if (ffb_debug_log_ent < FFB_DEBUG_LOG_ENTS) {
+ struct ffb_log *p = &ffb_debug_log[ffb_debug_log_ent];
+
+ if (ffb_debug_log_ent != 0 &&
+ p[-1].op == op && p[-1].depth == depth)
+ return;
+ p->op = op;
+ p->depth = depth;
+ p->x = x;
+ p->y = y;
+ p->w = w;
+ p->h = h;
+
+ if (++ffb_debug_log_ent == FFB_DEBUG_LOG_ENTS) {
+ ffb_log_timer.expires = jiffies + 2;
+ add_timer(&ffb_log_timer);
+ }
+ }
+}
+#else
+#define ffb_log(a,b,c,d,e,f) do { } while(0)
+#endif
+
+#undef FORCE_WAIT_EVERY_ROP
+
+static void FFBFifo(struct ffb_par *par, int n)
+{
+ struct ffb_fbc *fbc;
+ int cache = par->fifo_cache;
+
+ if (cache - n < 0) {
+ fbc = par->fbc;
+ do { cache = (upa_readl(&fbc->ucsr) & FFB_UCSR_FIFO_MASK) - 8;
+ } while (cache - n < 0);
+ }
+ par->fifo_cache = cache - n;
+}
+
+static void FFBWait(struct ffb_par *par)
+{
+ struct ffb_fbc *fbc;
+ int limit = 10000;
+
+ fbc = par->fbc;
+ do {
+ if ((upa_readl(&fbc->ucsr) & FFB_UCSR_ALL_BUSY) == 0)
+ break;
+ if ((upa_readl(&fbc->ucsr) & FFB_UCSR_ALL_ERRORS) != 0) {
+ upa_writel(FFB_UCSR_ALL_ERRORS, &fbc->ucsr);
+ }
+ udelay(10);
+ } while(--limit > 0);
+}
+
+static int ffb_sync(struct fb_info *p)
+{
+ struct ffb_par *par = (struct ffb_par *) p->par;
+
+ FFBWait(par);
+ return 0;
+}
+
+static __inline__ void ffb_rop(struct ffb_par *par, u32 rop)
+{
+ if (par->rop_cache != rop) {
+ FFBFifo(par, 1);
+ upa_writel(rop, &par->fbc->rop);
+ par->rop_cache = rop;
+ }
+}
+
+static void ffb_switch_from_graph(struct ffb_par *par)
+{
+ struct ffb_fbc *fbc = par->fbc;
+ unsigned long flags;
+
+ spin_lock_irqsave(&par->lock, flags);
+ FFBWait(par);
+ par->fifo_cache = 0;
+ FFBFifo(par, 7);
+ upa_writel(FFB_PPC_VCE_DISABLE|FFB_PPC_TBE_OPAQUE|
+ FFB_PPC_APE_DISABLE|FFB_PPC_CS_CONST,
+ &fbc->ppc);
+ upa_writel(0x2000707f, &fbc->fbc);
+ upa_writel(par->rop_cache, &fbc->rop);
+ upa_writel(0xffffffff, &fbc->pmask);
+ upa_writel((0 << 16) | (32 << 0), &fbc->fontinc);
+ upa_writel(par->fg_cache, &fbc->fg);
+ upa_writel(par->bg_cache, &fbc->bg);
+ FFBWait(par);
+ spin_unlock_irqrestore(&par->lock, flags);
+}
+
+/**
+ * ffb_fillrect - REQUIRED function. Can use generic routines if
+ * non acclerated hardware and packed pixel based.
+ * Draws a rectangle on the screen.
+ *
+ * @info: frame buffer structure that represents a single frame buffer
+ * @rect: structure defining the rectagle and operation.
+ */
+static void ffb_fillrect(struct fb_info *info, struct fb_fillrect *rect)
+{
+ struct ffb_par *par = (struct ffb_par *) info->par;
+ struct ffb_fbc *fbc = par->fbc;
+ unsigned long flags;
+ u32 fg;
+
+ if (rect->rop != ROP_COPY && rect->rop != ROP_XOR)
+ BUG();
+
+ ffb_log(OP_FILLRECT, 0, rect->dx, rect->dy, rect->width, rect->height);
+
+ fg = ((u32 *)info->pseudo_palette)[rect->color];
+
+ spin_lock_irqsave(&par->lock, flags);
+
+ if (fg != par->fg_cache) {
+ FFBFifo(par, 1);
+ upa_writel(fg, &fbc->fg);
+ par->fg_cache = fg;
+ }
+
+ ffb_rop(par, (rect->rop == ROP_COPY ?
+ FFB_ROP_NEW :
+ FFB_ROP_NEW_XOR_OLD));
+
+ FFBFifo(par, 5);
+ upa_writel(FFB_DRAWOP_RECTANGLE, &fbc->drawop);
+ upa_writel(rect->dy, &fbc->by);
+ upa_writel(rect->dx, &fbc->bx);
+ upa_writel(rect->height, &fbc->bh);
+ upa_writel(rect->width, &fbc->bw);
+#ifdef FORCE_WAIT_EVERY_ROP
+ FFBWait(par);
+#endif
+
+ spin_unlock_irqrestore(&par->lock, flags);
+}
+
+/**
+ * ffb_copyarea - REQUIRED function. Can use generic routines if
+ * non acclerated hardware and packed pixel based.
+ * Copies on area of the screen to another area.
+ *
+ * @info: frame buffer structure that represents a single frame buffer
+ * @area: structure defining the source and destination.
+ */
+
+static void
+ffb_copyarea(struct fb_info *info, struct fb_copyarea *area)
+{
+ struct ffb_par *par = (struct ffb_par *) info->par;
+ struct ffb_fbc *fbc = par->fbc;
+ unsigned long flags;
+
+ if (area->dx != area->sx ||
+ area->dy == area->dy) {
+ cfb_copyarea(info, area);
+ return;
+ }
+
+ spin_lock_irqsave(&par->lock, flags);
+
+ ffb_rop(par, FFB_ROP_OLD);
+
+ FFBFifo(par, 7);
+ upa_writel(FFB_DRAWOP_VSCROLL, &fbc->drawop);
+ upa_writel(area->sy, &fbc->by);
+ upa_writel(area->sx, &fbc->bx);
+ upa_writel(area->dy, &fbc->dy);
+ upa_writel(area->dx, &fbc->dx);
+ upa_writel(area->height, &fbc->bh);
+ upa_writel(area->width, &fbc->bw);
+
+ spin_unlock_irqrestore(&par->lock, flags);
+}
+
+/**
+ * ffb_imageblit - REQUIRED function. Can use generic routines if
+ * non acclerated hardware and packed pixel based.
+ * Copies a image from system memory to the screen.
+ *
+ * @info: frame buffer structure that represents a single frame buffer
+ * @image: structure defining the image.
+ */
+static void ffb_imageblit(struct fb_info *info, struct fb_image *image)
+{
+ struct ffb_par *par = (struct ffb_par *) info->par;
+ struct ffb_fbc *fbc = par->fbc;
+ u8 *data = (u8 *) image->data;
+ unsigned long flags;
+ u32 fg, bg, xy;
+ u64 fgbg;
+ int i, width;
+
+ ffb_log(OP_IMAGEBLIT, image->depth,
+ image->dx, image->dy, image->width, image->height);
+
+ if (image->depth > 1) {
+ cfb_imageblit(info, image);
+ return;
+ }
+
+ fg = ((u32 *)info->pseudo_palette)[image->fg_color];
+ bg = ((u32 *)info->pseudo_palette)[image->bg_color];
+ fgbg = ((u64) fg << 32) | (u64) bg;
+ xy = (image->dy << 16) | image->dx;
+
+ spin_lock_irqsave(&par->lock, flags);
+
+ if (fgbg != *(u64 *)&par->fg_cache) {
+ FFBFifo(par, 2);
+ upa_writeq(fgbg, &fbc->fg);
+ *(u64 *)&par->fg_cache = fgbg;
+ }
+
+ ffb_rop(par, FFB_ROP_NEW);
+
+ for (i = 0; i < image->height; i++) {
+ width = image->width;
+
+ FFBFifo(par, 1);
+ upa_writel(xy, &fbc->fontxy);
+ xy += (1 << 16);
+
+ while (width >= 32) {
+ u32 val;
+
+ FFBFifo(par, 2);
+ upa_writel(32, &fbc->fontw);
+
+ val = ((u32)data[0] << 24) |
+ ((u32)data[1] << 16) |
+ ((u32)data[2] << 8) |
+ ((u32)data[3] << 0);
+ upa_writel(val, &fbc->font);
+
+ data += 4;
+ width -= 32;
+ }
+
+ if (width) {
+ u32 val;
+
+ FFBFifo(par, 2);
+ upa_writel(width, &fbc->fontw);
+ if (width <= 8) {
+ val = (u32) data[0] << 24;
+ data += 1;
+ } else if (width <= 16) {
+ val = ((u32) data[0] << 24) |
+ ((u32) data[1] << 16);
+ data += 2;
+ } else {
+ val = ((u32) data[0] << 24) |
+ ((u32) data[1] << 16) |
+ ((u32) data[2] << 8);
+ data += 3;
+ }
+ upa_writel(val, &fbc->font);
+ }
+ }
+#ifdef FORCE_WAIT_EVERY_ROP
+ FFBWait(par);
+#endif
+
+ spin_unlock_irqrestore(&par->lock, flags);
+}
+
+static void ffb_fixup_var_rgb(struct fb_var_screeninfo *var)
+{
+ var->red.offset = 0;
+ var->red.length = 8;
+ var->green.offset = 8;
+ var->green.length = 8;
+ var->blue.offset = 16;
+ var->blue.length = 8;
+ var->transp.offset = 0;
+ var->transp.length = 0;
+}
+
+/**
+ * ffb_check_var - Optional function. Validates a var passed in.
+ * @var: frame buffer variable screen structure
+ * @info: frame buffer structure that represents a single frame buffer
+ */
+static int ffb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
+{
+ if (var->bits_per_pixel != 32)
+ return -EINVAL;
+
+ if (var->xres_virtual != var->xres || var->yres_virtual != var->yres)
+ return -EINVAL;
+ if (var->nonstd)
+ return -EINVAL;
+ if ((var->vmode & FB_VMODE_MASK) != FB_VMODE_NONINTERLACED)
+ return -EINVAL;
+
+ if (var->xres != info->var.xres || var->yres != info->var.yres)
+ return -EINVAL;
+
+ ffb_fixup_var_rgb(var);
+
+ return 0;
+}
+
+/**
+ * ffb_set_par - Optional function. Alters the hardware state.
+ * @info: frame buffer structure that represents a single frame buffer
+ */
+static int
+ffb_set_par(struct fb_info *info)
+{
+ return 0;
+}
+
+/**
+ * ffb_setcolreg - Optional function. Sets a color register.
+ * @regno: boolean, 0 copy local, 1 get_user() function
+ * @red: frame buffer colormap structure
+ * @green: The green value which can be up to 16 bits wide
+ * @blue: The blue value which can be up to 16 bits wide.
+ * @transp: If supported the alpha value which can be up to 16 bits wide.
+ * @info: frame buffer info structure
+ */
+static int ffb_setcolreg(unsigned regno,
+ unsigned red, unsigned green, unsigned blue,
+ unsigned transp, struct fb_info *info)
+{
+ u32 value;
+
+ if (regno >= 256)
+ return 1;
+
+ red >>= 8;
+ green >>= 8;
+ blue >>= 8;
+
+ value = (blue << 16) | (green << 8) | red;
+ ((u32 *)info->pseudo_palette)[regno] = value;
+
+ return 0;
+}
+
+/**
+ * ffb_blank - Optional function. Blanks the display.
+ * @blank_mode: the blank mode we want.
+ * @info: frame buffer structure that represents a single frame buffer
+ */
+static int
+ffb_blank(int blank, struct fb_info *info)
+{
+ struct ffb_par *par = (struct ffb_par *) info->par;
+ struct ffb_dac *dac = par->dac;
+ unsigned long flags;
+ u32 tmp;
+
+ spin_lock_irqsave(&par->lock, flags);
+
+ FFBWait(par);
+
+ switch (blank) {
+ case 0: /* Unblanking */
+ upa_writel(0x6000, &dac->type);
+ tmp = (upa_readl(&dac->value) | 0x1);
+ upa_writel(0x6000, &dac->type);
+ upa_writel(tmp, &dac->value);
+ par->flags &= ~FFB_FLAG_BLANKED;
+ break;
+
+ case 1: /* Normal blanking */
+ case 2: /* VESA blank (vsync off) */
+ case 3: /* VESA blank (hsync off) */
+ case 4: /* Poweroff */
+ upa_writel(0x6000, &dac->type);
+ tmp = (upa_readl(&dac->value) & ~0x1);
+ upa_writel(0x6000, &dac->type);
+ upa_writel(tmp, &dac->value);
+ par->flags |= FFB_FLAG_BLANKED;
+ break;
+ }
+
+ spin_unlock_irqrestore(&par->lock, flags);
+
+ return 0;
+}
+
+static struct sbus_mmap_map ffb_mmap_map[] = {
+ { FFB_SFB8R_VOFF, FFB_SFB8R_POFF, 0x0400000 },
+ { FFB_SFB8G_VOFF, FFB_SFB8G_POFF, 0x0400000 },
+ { FFB_SFB8B_VOFF, FFB_SFB8B_POFF, 0x0400000 },
+ { FFB_SFB8X_VOFF, FFB_SFB8X_POFF, 0x0400000 },
+ { FFB_SFB32_VOFF, FFB_SFB32_POFF, 0x1000000 },
+ { FFB_SFB64_VOFF, FFB_SFB64_POFF, 0x2000000 },
+ { FFB_FBC_REGS_VOFF, FFB_FBC_REGS_POFF, 0x0002000 },
+ { FFB_BM_FBC_REGS_VOFF, FFB_BM_FBC_REGS_POFF, 0x0002000 },
+ { FFB_DFB8R_VOFF, FFB_DFB8R_POFF, 0x0400000 },
+ { FFB_DFB8G_VOFF, FFB_DFB8G_POFF, 0x0400000 },
+ { FFB_DFB8B_VOFF, FFB_DFB8B_POFF, 0x0400000 },
+ { FFB_DFB8X_VOFF, FFB_DFB8X_POFF, 0x0400000 },
+ { FFB_DFB24_VOFF, FFB_DFB24_POFF, 0x1000000 },
+ { FFB_DFB32_VOFF, FFB_DFB32_POFF, 0x1000000 },
+ { FFB_FBC_KREGS_VOFF, FFB_FBC_KREGS_POFF, 0x0002000 },
+ { FFB_DAC_VOFF, FFB_DAC_POFF, 0x0002000 },
+ { FFB_PROM_VOFF, FFB_PROM_POFF, 0x0010000 },
+ { FFB_EXP_VOFF, FFB_EXP_POFF, 0x0002000 },
+ { FFB_DFB422A_VOFF, FFB_DFB422A_POFF, 0x0800000 },
+ { FFB_DFB422AD_VOFF, FFB_DFB422AD_POFF, 0x0800000 },
+ { FFB_DFB24B_VOFF, FFB_DFB24B_POFF, 0x1000000 },
+ { FFB_DFB422B_VOFF, FFB_DFB422B_POFF, 0x0800000 },
+ { FFB_DFB422BD_VOFF, FFB_DFB422BD_POFF, 0x0800000 },
+ { FFB_SFB16Z_VOFF, FFB_SFB16Z_POFF, 0x0800000 },
+ { FFB_SFB8Z_VOFF, FFB_SFB8Z_POFF, 0x0800000 },
+ { FFB_SFB422_VOFF, FFB_SFB422_POFF, 0x0800000 },
+ { FFB_SFB422D_VOFF, FFB_SFB422D_POFF, 0x0800000 },
+ { 0, 0, 0 }
+};
+
+static int ffb_mmap(struct fb_info *info, struct file *file, struct vm_area_struct *vma)
+{
+ struct ffb_par *par = (struct ffb_par *)info->par;
+
+ return sbusfb_mmap_helper(ffb_mmap_map,
+ par->physbase, par->fbsize,
+ 0, vma);
+}
+
+/*
+ * Initialisation
+ */
+
+static void
+ffb_init_fix(struct fb_info *info)
+{
+ struct ffb_par *par = (struct ffb_par *)info->par;
+ const char *ffb_type_name;
+
+ if (!(par->flags & FFB_FLAG_AFB)) {
+ if ((par->board_type & 0x7) == 0x3)
+ ffb_type_name = "Creator 3D";
+ else
+ ffb_type_name = "Creator";
+ } else
+ ffb_type_name = "Elite 3D";
+
+ strncpy(info->fix.id, ffb_type_name, sizeof(info->fix.id) - 1);
+ info->fix.id[sizeof(info->fix.id)-1] = 0;
+
+ info->fix.type = FB_TYPE_PACKED_PIXELS;
+ info->fix.visual = FB_VISUAL_TRUECOLOR;
+
+ /* Framebuffer length is the same regardless of resolution. */
+ info->fix.line_length = 8192;
+
+ info->fix.accel = FB_ACCEL_SUN_CREATOR;
+}
+
+static int ffb_apply_upa_parent_ranges(int parent,
+ struct linux_prom64_registers *regs)
+{
+ struct linux_prom64_ranges ranges[PROMREG_MAX];
+ char name[128];
+ int len, i;
+
+ prom_getproperty(parent, "name", name, sizeof(name));
+ if (strcmp(name, "upa") != 0)
+ return 0;
+
+ len = prom_getproperty(parent, "ranges", (void *) ranges, sizeof(ranges));
+ if (len <= 0)
+ return 1;
+
+ len /= sizeof(struct linux_prom64_ranges);
+ for (i = 0; i < len; i++) {
+ struct linux_prom64_ranges *rng = &ranges[i];
+ u64 phys_addr = regs->phys_addr;
+
+ if (phys_addr >= rng->ot_child_base &&
+ phys_addr < (rng->ot_child_base + rng->or_size)) {
+ regs->phys_addr -= rng->ot_child_base;
+ regs->phys_addr += rng->ot_parent_base;
+ return 0;
+ }
+ }
+
+ return 1;
+}
+
+struct all_info {
+ struct fb_info info;
+ struct ffb_par par;
+ u32 pseudo_palette[256];
+ struct list_head list;
+};
+static LIST_HEAD(ffb_list);
+
+static void ffb_init_one(int node, int parent)
+{
+ struct linux_prom64_registers regs[2*PROMREG_MAX];
+ struct ffb_fbc *fbc;
+ struct ffb_dac *dac;
+ struct all_info *all;
+
+ if (prom_getproperty(node, "reg", (void *) regs, sizeof(regs)) <= 0) {
+ printk("ffb: Cannot get reg device node property.\n");
+ return;
+ }
+
+ if (ffb_apply_upa_parent_ranges(parent, ®s[0])) {
+ printk("ffb: Cannot apply parent ranges to regs.\n");
+ return;
+ }
+
+ all = kmalloc(sizeof(*all), GFP_KERNEL);
+ if (!all) {
+ printk(KERN_ERR "ffb: Cannot allocate memory.\n");
+ return;
+ }
+ memset(all, 0, sizeof(*all));
+
+ INIT_LIST_HEAD(&all->list);
+
+ spin_lock_init(&all->par.lock);
+ all->par.fbc = (struct ffb_fbc *)(regs[0].phys_addr + FFB_FBC_REGS_POFF);
+ all->par.dac = (struct ffb_dac *)(regs[0].phys_addr + FFB_DAC_POFF);
+ all->par.rop_cache = FFB_ROP_NEW;
+ all->par.physbase = regs[0].phys_addr;
+ all->par.prom_node = node;
+ all->par.prom_parent_node = parent;
+
+ all->info.node = NODEV;
+ all->info.flags = FBINFO_FLAG_DEFAULT;
+ all->info.fbops = &ffb_ops;
+ all->info.screen_base = (char *) all->par.physbase + FFB_DFB24_POFF;
+ all->info.currcon = -1;
+ all->info.par = &all->par;
+ all->info.pseudo_palette = all->pseudo_palette;
+
+ sbusfb_fill_var(&all->info.var, all->par.prom_node, 32);
+ all->par.fbsize = PAGE_ALIGN(all->info.var.xres *
+ all->info.var.yres *
+ 4);
+ ffb_fixup_var_rgb(&all->info.var);
+
+ all->info.var.accel_flags = FB_ACCELF_TEXT;
+
+ prom_getstring(node, "name", all->par.name, sizeof(all->par.name));
+ if (!strcmp(all->par.name, "SUNW,afb"))
+ all->par.flags |= FFB_FLAG_AFB;
+
+ all->par.board_type = prom_getintdefault(node, "board_type", 0);
+
+ fbc = all->par.fbc;
+ if((upa_readl(&fbc->ucsr) & FFB_UCSR_ALL_ERRORS) != 0)
+ upa_writel(FFB_UCSR_ALL_ERRORS, &fbc->ucsr);
+
+ ffb_switch_from_graph(&all->par);
+
+ dac = all->par.dac;
+ upa_writel(0x8000, &dac->type);
+ all->par.dac_rev = upa_readl(&dac->value) >> 0x1c;
+
+ /* Elite3D has different DAC revision numbering, and no DAC revisions
+ * have the reversed meaning of cursor enable.
+ */
+ if (all->par.flags & FFB_FLAG_AFB)
+ all->par.dac_rev = 10;
+
+ /* Unblank it just to be sure. When there are multiple
+ * FFB/AFB cards in the system, or it is not the OBP
+ * chosen console, it will have video outputs off in
+ * the DAC.
+ */
+ ffb_blank(0, &all->info);
+
+ if (fb_alloc_cmap(&all->info.cmap, 256, 0)) {
+ printk(KERN_ERR "ffb: Could not allocate color map.\n");
+ kfree(all);
+ return;
+ }
+
+ ffb_set_par(&all->info);
+ ffb_init_fix(&all->info);
+
+ if (register_framebuffer(&all->info) < 0) {
+ printk(KERN_ERR "ffb: Could not register framebuffer.\n");
+ fb_dealloc_cmap(&all->info.cmap);
+ kfree(all);
+ return;
+ }
+
+ list_add(&all->list, &ffb_list);
+
+ printk("ffb: %s at %016lx type %d DAC %d\n",
+ ((all->par.flags & FFB_FLAG_AFB) ? "AFB" : "FFB"),
+ regs[0].phys_addr, all->par.board_type, all->par.dac_rev);
+}
+
+static void ffb_scan_siblings(int root)
+{
+ int node, child;
+
+ child = prom_getchild(root);
+ for (node = prom_searchsiblings(child, "SUNW,ffb"); node;
+ node = prom_searchsiblings(prom_getsibling(node), "SUNW,ffb"))
+ ffb_init_one(node, root);
+ for (node = prom_searchsiblings(child, "SUNW,afb"); node;
+ node = prom_searchsiblings(prom_getsibling(node), "SUNW,afb"))
+ ffb_init_one(node, root);
+}
+
+int __init ffb_init(void)
+{
+ int root;
+
+ ffb_scan_siblings(prom_root_node);
+
+ root = prom_getchild(prom_root_node);
+ for (root = prom_searchsiblings(root, "upa"); root;
+ root = prom_searchsiblings(prom_getsibling(root), "upa"))
+ ffb_scan_siblings(root);
+
+ return 0;
+}
+
+void __exit ffb_exit(void)
+{
+ struct list_head *pos, *tmp;
+
+ list_for_each_safe(pos, tmp, &ffb_list) {
+ struct all_info *all = list_entry(pos, typeof(*all), list);
+
+ unregister_framebuffer(&all->info);
+ fb_dealloc_cmap(&all->info.cmap);
+ kfree(all);
+ }
+}
+
+int __init
+ffb_setup(char *arg)
+{
+ /* No cmdline options yet... */
+ return 0;
+}
+
+#ifdef MODULE
+module_init(ffb_init);
+module_exit(ffb_exit);
+#endif
+
+MODULE_DESCRIPTION("framebuffer driver for Creator/Elite3D chipsets");
+MODULE_AUTHOR("David S. Miller <davem@redhat.com>");
+MODULE_LICENSE("GPL");
+++ /dev/null
-/*
- * linux/drivers/video/sbusfb.c -- SBUS or UPA based frame buffer device
- *
- * Copyright (C) 1998 Jakub Jelinek
- *
- * This driver is partly based on the Open Firmware console driver
- *
- * Copyright (C) 1997 Geert Uytterhoeven
- *
- * and SPARC console subsystem
- *
- * Copyright (C) 1995 Peter Zaitcev (zaitcev@yahoo.com)
- * Copyright (C) 1995-1997 David S. Miller (davem@caip.rutgers.edu)
- * Copyright (C) 1995-1996 Miguel de Icaza (miguel@nuclecu.unam.mx)
- * Copyright (C) 1996 Dave Redman (djhr@tadpole.co.uk)
- * Copyright (C) 1996-1998 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
- * Copyright (C) 1996 Eddie C. Dost (ecd@skynet.be)
- *
- * This file is subject to the terms and conditions of the GNU General Public
- * License. See the file COPYING in the main directory of this archive for
- * more details.
- */
-
-#include <linux/config.h>
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/errno.h>
-#include <linux/string.h>
-#include <linux/mm.h>
-#include <linux/tty.h>
-#include <linux/slab.h>
-#include <linux/vmalloc.h>
-#include <linux/delay.h>
-#include <linux/interrupt.h>
-#include <linux/fb.h>
-#include <linux/selection.h>
-#include <linux/init.h>
-#include <linux/console.h>
-#include <linux/kd.h>
-#include <linux/vt_kern.h>
-
-#include <asm/uaccess.h>
-#include <asm/pgtable.h> /* io_remap_page_range() */
-
-#include <video/sbusfb.h>
-
-#define DEFAULT_CURSOR_BLINK_RATE (2*HZ/5)
-
-#define CURSOR_SHAPE 1
-#define CURSOR_BLINK 2
-
- /*
- * Interface used by the world
- */
-
-int sbusfb_init(void);
-int sbusfb_setup(char*);
-
-static int defx_margin = -1, defy_margin = -1;
-static char fontname[40] __initdata = { 0 };
-static int curblink __initdata = 1;
-static struct {
- int depth;
- int xres, yres;
- int x_margin, y_margin;
-} def_margins [] = {
- { 8, 1280, 1024, 64, 80 },
- { 8, 1152, 1024, 64, 80 },
- { 8, 1152, 900, 64, 18 },
- { 8, 1024, 768, 0, 0 },
- { 8, 800, 600, 16, 12 },
- { 8, 640, 480, 0, 0 },
- { 1, 1152, 900, 8, 18 },
- { 0 },
-};
-
-static int sbusfb_open(struct fb_info *info, int user);
-static int sbusfb_release(struct fb_info *info, int user);
-static int sbusfb_mmap(struct fb_info *info, struct file *file,
- struct vm_area_struct *vma);
-static int sbusfb_set_var(struct fb_var_screeninfo *var, int con,
- struct fb_info *info);
-static int sbusfb_get_cmap(struct fb_cmap *cmap, int kspc, int con,
- struct fb_info *info);
-static int sbusfb_set_cmap(struct fb_cmap *cmap, int kspc, int con,
- struct fb_info *info);
-static int sbusfb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
- u_int transp, struct fb_info *info);
-static int sbusfb_blank(int blank, struct fb_info *info);
-static int sbusfb_ioctl(struct inode *inode, struct file *file, u_int cmd,
- u_long arg, int con, struct fb_info *info);
-static void sbusfb_cursor(struct display *p, int mode, int x, int y);
-static void sbusfb_clear_margin(struct display *p, int s);
-
-
- /*
- * Interface to the low level console driver
- */
-
-static int sbusfbcon_switch(int con, struct fb_info *info);
-static int sbusfbcon_updatevar(int con, struct fb_info *info);
-
- /*
- * Internal routines
- */
-
-static int sbusfb_getcolreg(u_int regno, u_int *red, u_int *green, u_int *blue,
- u_int *transp, struct fb_info *info);
-
-static struct fb_ops sbusfb_ops = {
- .owner = THIS_MODULE,
- .fb_open = sbusfb_open,
- .fb_release = sbusfb_release,
- .fb_set_var = sbusfb_set_var,
- .fb_get_cmap = sbusfb_get_cmap,
- .fb_set_cmap = sbusfb_set_cmap,
- .fb_setcolreg = sbusfb_setcolreg,
- .fb_blank = sbusfb_blank,
- .fb_ioctl = sbusfb_ioctl,
- .fb_mmap = sbusfb_mmap,
-};
-
- /*
- * Open/Release the frame buffer device
- */
-
-static int sbusfb_open(struct fb_info *info, int user)
-{
- struct fb_info_sbusfb *fb = sbusfbinfo(info);
-
- if (user) {
- if (fb->open == 0) {
- fb->mmaped = 0;
- fb->vtconsole = -1;
- }
- fb->open++;
- } else
- fb->consolecnt++;
- return 0;
-}
-
-static int sbusfb_release(struct fb_info *info, int user)
-{
- struct fb_info_sbusfb *fb = sbusfbinfo(info);
-
- if (user) {
- fb->open--;
- if (fb->open == 0) {
- if (fb->vtconsole != -1) {
- vt_cons[fb->vtconsole]->vc_mode = KD_TEXT;
- if (fb->mmaped) {
- fb->graphmode--;
- sbusfb_clear_margin(&fb_display[fb->vtconsole], 0);
- }
- }
- if (fb->reset)
- fb->reset(fb);
- }
- } else
- fb->consolecnt--;
- return 0;
-}
-
-static unsigned long sbusfb_mmapsize(struct fb_info_sbusfb *fb, long size)
-{
- if (size == SBUS_MMAP_EMPTY) return 0;
- if (size >= 0) return size;
- return fb->type.fb_size * (-size);
-}
-
-static int sbusfb_mmap(struct fb_info *info, struct file *file,
- struct vm_area_struct *vma)
-{
- struct fb_info_sbusfb *fb = sbusfbinfo(info);
- unsigned int size, page, r, map_size;
- unsigned long map_offset = 0;
- unsigned long off;
- int i;
-
- size = vma->vm_end - vma->vm_start;
- if (vma->vm_pgoff > (~0UL >> PAGE_SHIFT))
- return -EINVAL;
-
- off = vma->vm_pgoff << PAGE_SHIFT;
-
- /* To stop the swapper from even considering these pages */
- vma->vm_flags |= (VM_SHM| VM_LOCKED);
-
-
- /* Each page, see which map applies */
- for (page = 0; page < size; ){
- map_size = 0;
- for (i = 0; fb->mmap_map[i].size; i++)
- if (fb->mmap_map[i].voff == off+page) {
- map_size = sbusfb_mmapsize(fb,fb->mmap_map[i].size);
-#ifdef __sparc_v9__
-#define POFF_MASK (PAGE_MASK|0x1UL)
-#else
-#define POFF_MASK (PAGE_MASK)
-#endif
- map_offset = (fb->physbase + fb->mmap_map[i].poff) & POFF_MASK;
- break;
- }
- if (!map_size){
- page += PAGE_SIZE;
- continue;
- }
- if (page + map_size > size)
- map_size = size - page;
- r = io_remap_page_range(vma, vma->vm_start+page, map_offset, map_size, vma->vm_page_prot, fb->iospace);
- if (r)
- return -EAGAIN;
- page += map_size;
- }
-
- vma->vm_flags |= VM_IO;
- if (!fb->mmaped) {
- int lastconsole = 0;
-
- if (info->display_fg)
- lastconsole = info->display_fg->vc_num;
- fb->mmaped = 1;
- if (fb->consolecnt && fb_display[lastconsole].fb_info == info) {
- fb->vtconsole = lastconsole;
- fb->graphmode++;
- vt_cons [lastconsole]->vc_mode = KD_GRAPHICS;
- vc_cons[lastconsole].d->vc_sw->con_cursor(vc_cons[lastconsole].d,CM_ERASE);
- } else if (fb->unblank && !fb->blanked)
- (*fb->unblank)(fb);
- }
- return 0;
-}
-
-static void sbusfb_clear_margin(struct display *p, int s)
-{
- struct fb_info_sbusfb *fb = sbusfbinfod(p);
-
- if (fb->switch_from_graph)
- (*fb->switch_from_graph)(fb);
- if (fb->fill) {
- unsigned short rects [16];
-
- rects [0] = 0;
- rects [1] = 0;
- rects [2] = fb->info.var.xres_virtual;
- rects [3] = fb->y_margin;
- rects [4] = 0;
- rects [5] = fb->y_margin;
- rects [6] = fb->x_margin;
- rects [7] = fb->info.var.yres_virtual;
- rects [8] = fb->info.var.xres_virtual - fb->x_margin;
- rects [9] = fb->y_margin;
- rects [10] = fb->info.var.xres_virtual;
- rects [11] = fb->info.var.yres_virtual;
- rects [12] = fb->x_margin;
- rects [13] = fb->info.var.yres_virtual - fb->y_margin;
- rects [14] = fb->info.var.xres_virtual - fb->x_margin;
- rects [15] = fb->info.var.yres_virtual;
- (*fb->fill)(fb, p, s, 4, rects);
- } else {
- unsigned char *fb_base = fb->info.screen_base, *q;
- int skip_bytes = fb->y_margin * fb->info.var.xres_virtual;
- int scr_size = fb->info.var.xres_virtual
- * fb->info.var.yres_virtual;
- int h, he, incr, size;
-
- he = fb->info.var.yres;
- if (fb->info.var.bits_per_pixel == 1) {
- fb_base -= (skip_bytes + fb->x_margin) / 8;
- skip_bytes /= 8;
- scr_size /= 8;
- fb_memset255 (fb_base, skip_bytes - fb->x_margin / 8);
- fb_memset255 (fb_base + scr_size - skip_bytes + fb->x_margin / 8, skip_bytes - fb->x_margin / 8);
- incr = fb->info.var.xres_virtual / 8;
- size = fb->x_margin / 8 * 2;
- for (q = fb_base + skip_bytes - fb->x_margin / 8, h = 0;
- h <= he; q += incr, h++)
- fb_memset255 (q, size);
- } else {
- fb_base -= (skip_bytes + fb->x_margin);
- fb_memset (fb_base, attr_bgcol(p,s), skip_bytes - fb->x_margin);
- fb_memset (fb_base + scr_size - skip_bytes + fb->x_margin, attr_bgcol(p,s), skip_bytes - fb->x_margin);
- incr = fb->info.var.xres_virtual;
- size = fb->x_margin * 2;
- for (q = fb_base + skip_bytes - fb->x_margin, h = 0;
- h <= he; q += incr, h++)
- fb_memset (q, attr_bgcol(p,s), size);
- }
- }
-}
-
-static void sbusfb_disp_setup(struct display *p)
-{
- struct fb_info_sbusfb *fb = sbusfbinfod(p);
-
- if (fb->setup)
- fb->setup(p);
- sbusfb_clear_margin(p, 0);
-}
-
-
- /*
- * Set the User Defined Part of the Display
- */
-
-static int sbusfb_set_var(struct fb_var_screeninfo *var, int con,
- struct fb_info *info)
-{
- struct display *display;
- int activate = var->activate;
-
- if(con >= 0)
- display = &fb_display[con];
- else
- display = info->disp;
-
- /* simple check for equality until fully implemented -E */
- if ((activate & FB_ACTIVATE_MASK) == FB_ACTIVATE_NOW) {
- if (display->var.xres != var->xres ||
- display->var.yres != var->yres ||
- display->var.xres_virtual != var->xres_virtual ||
- display->var.yres_virtual != var->yres_virtual ||
- display->var.bits_per_pixel != var->bits_per_pixel ||
- display->var.accel_flags != var->accel_flags) {
- return -EINVAL;
- }
- }
- return 0;
-
-}
-
- /*
- * Hardware cursor
- */
-
-static int sbus_hw_scursor (struct fbcursor *cursor, struct fb_info_sbusfb *fb)
-{
- int op;
- int i, bytes = 0;
- struct fbcursor f;
- char red[2], green[2], blue[2];
-
- if (copy_from_user (&f, cursor, sizeof(struct fbcursor)))
- return -EFAULT;
- op = f.set;
- if (op & FB_CUR_SETSHAPE){
- if ((u32) f.size.fbx > fb->cursor.hwsize.fbx)
- return -EINVAL;
- if ((u32) f.size.fby > fb->cursor.hwsize.fby)
- return -EINVAL;
- if (f.size.fbx > 32)
- bytes = f.size.fby << 3;
- else
- bytes = f.size.fby << 2;
- }
- if (op & FB_CUR_SETCMAP){
- if (f.cmap.index || f.cmap.count != 2)
- return -EINVAL;
- if (copy_from_user (red, f.cmap.red, 2) ||
- copy_from_user (green, f.cmap.green, 2) ||
- copy_from_user (blue, f.cmap.blue, 2))
- return -EFAULT;
- }
- if (op & FB_CUR_SETCMAP)
- (*fb->setcursormap) (fb, red, green, blue);
- if (op & FB_CUR_SETSHAPE){
- u32 u;
-
- fb->cursor.size = f.size;
- memset ((void *)&fb->cursor.bits, 0, sizeof (fb->cursor.bits));
- if (copy_from_user (fb->cursor.bits [0], f.mask, bytes) ||
- copy_from_user (fb->cursor.bits [1], f.image, bytes))
- return -EFAULT;
- if (f.size.fbx <= 32) {
- u = 0xffffffff << (32 - f.size.fbx);
- for (i = fb->cursor.size.fby - 1; i >= 0; i--) {
- fb->cursor.bits [0][i] &= u;
- fb->cursor.bits [1][i] &= fb->cursor.bits [0][i];
- }
- } else {
- u = 0xffffffff << (64 - f.size.fbx);
- for (i = fb->cursor.size.fby - 1; i >= 0; i--) {
- fb->cursor.bits [0][2*i+1] &= u;
- fb->cursor.bits [1][2*i] &= fb->cursor.bits [0][2*i];
- fb->cursor.bits [1][2*i+1] &= fb->cursor.bits [0][2*i+1];
- }
- }
- (*fb->setcurshape) (fb);
- }
- if (op & (FB_CUR_SETCUR | FB_CUR_SETPOS | FB_CUR_SETHOT)){
- if (op & FB_CUR_SETCUR)
- fb->cursor.enable = f.enable;
- if (op & FB_CUR_SETPOS)
- fb->cursor.cpos = f.pos;
- if (op & FB_CUR_SETHOT)
- fb->cursor.chot = f.hot;
- (*fb->setcursor) (fb);
- }
- return 0;
-}
-
-static unsigned char hw_cursor_cmap[2] = { 0, 0xff };
-
-static void
-sbusfb_cursor_timer_handler(unsigned long dev_addr)
-{
- struct fb_info_sbusfb *fb = (struct fb_info_sbusfb *)dev_addr;
-
- if (!fb->setcursor) return;
-
- if (fb->cursor.mode & CURSOR_BLINK) {
- fb->cursor.enable ^= 1;
- fb->setcursor(fb);
- }
-
- fb->cursor.timer.expires = jiffies + fb->cursor.blink_rate;
- add_timer(&fb->cursor.timer);
-}
-
-static void sbusfb_cursor(struct display *p, int mode, int x, int y)
-{
- struct fb_info_sbusfb *fb = sbusfbinfod(p);
-
- switch (mode) {
- case CM_ERASE:
- fb->cursor.mode &= ~CURSOR_BLINK;
- fb->cursor.enable = 0;
- (*fb->setcursor)(fb);
- break;
-
- case CM_MOVE:
- case CM_DRAW:
- if (fb->cursor.mode & CURSOR_SHAPE) {
- fb->cursor.size.fbx = fontwidth(p);
- fb->cursor.size.fby = fontheight(p);
- fb->cursor.chot.fbx = 0;
- fb->cursor.chot.fby = 0;
- fb->cursor.enable = 1;
- memset (fb->cursor.bits, 0, sizeof (fb->cursor.bits));
- fb->cursor.bits[0][fontheight(p) - 2] = (0xffffffff << (32 - fontwidth(p)));
- fb->cursor.bits[1][fontheight(p) - 2] = (0xffffffff << (32 - fontwidth(p)));
- fb->cursor.bits[0][fontheight(p) - 1] = (0xffffffff << (32 - fontwidth(p)));
- fb->cursor.bits[1][fontheight(p) - 1] = (0xffffffff << (32 - fontwidth(p)));
- (*fb->setcursormap) (fb, hw_cursor_cmap, hw_cursor_cmap, hw_cursor_cmap);
- (*fb->setcurshape) (fb);
- }
- fb->cursor.mode = CURSOR_BLINK;
- if (fontwidthlog(p))
- fb->cursor.cpos.fbx = (x << fontwidthlog(p)) + fb->x_margin;
- else
- fb->cursor.cpos.fbx = (x * fontwidth(p)) + fb->x_margin;
- if (fontheightlog(p))
- fb->cursor.cpos.fby = (y << fontheightlog(p)) + fb->y_margin;
- else
- fb->cursor.cpos.fby = (y * fontheight(p)) + fb->y_margin;
- (*fb->setcursor)(fb);
- break;
- }
-}
-
- /*
- * Get the Colormap
- */
-
-static int sbusfb_get_cmap(struct fb_cmap *cmap, int kspc, int con,
- struct fb_info *info)
-{
- if (!info->display_fg || con == info->display_fg->vc_num) /* current console? */
- return fb_get_cmap(cmap, kspc, sbusfb_getcolreg, info);
- else if (fb_display[con].cmap.len) /* non default colormap? */
- fb_copy_cmap(&fb_display[con].cmap, cmap, kspc ? 0 : 2);
- else
- fb_copy_cmap(fb_default_cmap(1<<fb_display[con].var.bits_per_pixel), cmap, kspc ? 0 : 2);
- return 0;
-}
-
- /*
- * Set the Colormap
- */
-
-static int sbusfb_set_cmap(struct fb_cmap *cmap, int kspc, int con,
- struct fb_info *info)
-{
- int err;
- struct display *disp;
-
- if (con >= 0)
- disp = &fb_display[con];
- else
- disp = info->disp;
- if (!disp->cmap.len) { /* no colormap allocated? */
- if ((err = fb_alloc_cmap(&disp->cmap, 1<<disp->var.bits_per_pixel, 0)))
- return err;
- }
- if (con == info->currcon) { /* current console? */
- err = fb_set_cmap(cmap, kspc, info);
- if (!err) {
- struct fb_info_sbusfb *fb = sbusfbinfo(info);
-
- if (fb->loadcmap)
- (*fb->loadcmap)(fb, &fb_display[con], cmap->start, cmap->len);
- }
- return err;
- } else
- fb_copy_cmap(cmap, &disp->cmap, kspc ? 0 : 1);
- return 0;
-}
-
-static int sbusfb_ioctl(struct inode *inode, struct file *file, u_int cmd,
- u_long arg, int con, struct fb_info *info)
-{
- struct fb_info_sbusfb *fb = sbusfbinfo(info);
- int i;
- int lastconsole;
-
- switch (cmd){
- case FBIOGTYPE: /* return frame buffer type */
- if (copy_to_user((struct fbtype *)arg, &fb->type, sizeof(struct fbtype)))
- return -EFAULT;
- break;
- case FBIOGATTR: {
- struct fbgattr *fba = (struct fbgattr *) arg;
-
- i = verify_area (VERIFY_WRITE, (void *) arg, sizeof (struct fbgattr));
- if (i) return i;
- if (__put_user(fb->emulations[0], &fba->real_type) ||
- __put_user(0, &fba->owner) ||
- __copy_to_user(&fba->fbtype, &fb->type,
- sizeof(struct fbtype)) ||
- __put_user(0, &fba->sattr.flags) ||
- __put_user(fb->type.fb_type, &fba->sattr.emu_type) ||
- __put_user(-1, &fba->sattr.dev_specific[0]))
- return -EFAULT;
- for (i = 0; i < 4; i++) {
- if (put_user(fb->emulations[i], &fba->emu_types[i]))
- return -EFAULT;
- }
- break;
- }
- case FBIOSATTR:
- i = verify_area (VERIFY_READ, (void *) arg, sizeof (struct fbsattr));
- if (i) return i;
- return -EINVAL;
- case FBIOSVIDEO:
- if (fb->consolecnt) {
- lastconsole = info->display_fg->vc_num;
- if (vt_cons[lastconsole]->vc_mode == KD_TEXT)
- break;
- }
- if (get_user(i, (int *)arg))
- return -EFAULT;
- if (i){
- if (!fb->blanked || !fb->unblank)
- break;
- if (fb->consolecnt || (fb->open && fb->mmaped))
- (*fb->unblank)(fb);
- fb->blanked = 0;
- } else {
- if (fb->blanked || !fb->blank)
- break;
- (*fb->blank)(fb);
- fb->blanked = 1;
- }
- break;
- case FBIOGVIDEO:
- if (put_user(fb->blanked, (int *) arg))
- return -EFAULT;
- break;
- case FBIOGETCMAP_SPARC: {
- char *rp, *gp, *bp;
- int end, count, index;
- struct fbcmap *cmap;
-
- if (!fb->loadcmap)
- return -EINVAL;
- i = verify_area (VERIFY_READ, (void *) arg, sizeof (struct fbcmap));
- if (i) return i;
- cmap = (struct fbcmap *) arg;
- if (__get_user(count, &cmap->count) ||
- __get_user(index, &cmap->index))
- return -EFAULT;
- if ((index < 0) || (index > 255))
- return -EINVAL;
- if (index + count > 256)
- count = 256 - index;
- if (__get_user(rp, &cmap->red) ||
- __get_user(gp, &cmap->green) ||
- __get_user(bp, &cmap->blue))
- return -EFAULT;
- if (verify_area (VERIFY_WRITE, rp, count))
- return -EFAULT;
- if (verify_area (VERIFY_WRITE, gp, count))
- return -EFAULT;
- if (verify_area (VERIFY_WRITE, bp, count))
- return -EFAULT;
- end = index + count;
- for (i = index; i < end; i++){
- if (__put_user(fb->color_map CM(i,0), rp) ||
- __put_user(fb->color_map CM(i,1), gp) ||
- __put_user(fb->color_map CM(i,2), bp))
- return -EFAULT;
- rp++; gp++; bp++;
- }
- (*fb->loadcmap)(fb, NULL, index, count);
- break;
- }
- case FBIOPUTCMAP_SPARC: { /* load color map entries */
- char *rp, *gp, *bp;
- int end, count, index;
- struct fbcmap *cmap;
-
- if (!fb->loadcmap || !fb->color_map)
- return -EINVAL;
- i = verify_area (VERIFY_READ, (void *) arg, sizeof (struct fbcmap));
- if (i) return i;
- cmap = (struct fbcmap *) arg;
- if (__get_user(count, &cmap->count) ||
- __get_user(index, &cmap->index))
- return -EFAULT;
- if ((index < 0) || (index > 255))
- return -EINVAL;
- if (index + count > 256)
- count = 256 - index;
- if (__get_user(rp, &cmap->red) ||
- __get_user(gp, &cmap->green) ||
- __get_user(bp, &cmap->blue))
- return -EFAULT;
- if (verify_area (VERIFY_READ, rp, count))
- return -EFAULT;
- if (verify_area (VERIFY_READ, gp, count))
- return -EFAULT;
- if (verify_area (VERIFY_READ, bp, count))
- return -EFAULT;
-
- end = index + count;
- for (i = index; i < end; i++){
- if (__get_user(fb->color_map CM(i,0), rp))
- return -EFAULT;
- if (__get_user(fb->color_map CM(i,1), gp))
- return -EFAULT;
- if (__get_user(fb->color_map CM(i,2), bp))
- return -EFAULT;
- rp++; gp++; bp++;
- }
- (*fb->loadcmap)(fb, NULL, index, count);
- break;
- }
- case FBIOGCURMAX: {
- struct fbcurpos *p = (struct fbcurpos *) arg;
- if (!fb->setcursor) return -EINVAL;
- if(verify_area (VERIFY_WRITE, p, sizeof (struct fbcurpos)))
- return -EFAULT;
- if (__put_user(fb->cursor.hwsize.fbx, &p->fbx) ||
- __put_user(fb->cursor.hwsize.fby, &p->fby))
- return -EFAULT;
- break;
- }
- case FBIOSCURSOR:
- if (!fb->setcursor) return -EINVAL;
- if (fb->consolecnt) {
- lastconsole = info->display_fg->vc_num;
- if (vt_cons[lastconsole]->vc_mode == KD_TEXT)
- return -EINVAL; /* Don't let graphics programs hide our nice text cursor */
- fb->cursor.mode = CURSOR_SHAPE; /* Forget state of our text cursor */
- }
- return sbus_hw_scursor ((struct fbcursor *) arg, fb);
-
- case FBIOSCURPOS:
- if (!fb->setcursor) return -EINVAL;
- /* Don't let graphics programs move our nice text cursor */
- if (fb->consolecnt) {
- lastconsole = info->display_fg->vc_num;
- if (vt_cons[lastconsole]->vc_mode == KD_TEXT)
- return -EINVAL; /* Don't let graphics programs move our nice text cursor */
- }
- if (copy_from_user(&fb->cursor.cpos, (void *)arg, sizeof(struct fbcurpos)))
- return -EFAULT;
- (*fb->setcursor) (fb);
- break;
- default:
- if (fb->ioctl)
- return fb->ioctl(fb, cmd, arg);
- return -EINVAL;
- }
- return 0;
-}
-
- /*
- * Setup: parse used options
- */
-
-int __init sbusfb_setup(char *options)
-{
- char *p;
-
- for (p = options;;) {
- if (!strncmp(p, "nomargins", 9)) {
- defx_margin = 0; defy_margin = 0;
- } else if (!strncmp(p, "margins=", 8)) {
- int i, j;
- char *q;
-
- i = simple_strtoul(p+8,&q,10);
- if (i >= 0 && *q == 'x') {
- j = simple_strtoul(q+1,&q,10);
- if (j >= 0 && (*q == ' ' || !*q)) {
- defx_margin = i; defy_margin = j;
- }
- }
- } else if (!strncmp(p, "font=", 5)) {
- int i;
-
- for (i = 0; i < sizeof(fontname) - 1; i++)
- if (p[i+5] == ' ' || !p[i+5])
- break;
- memcpy(fontname, p+5, i);
- fontname[i] = 0;
- } else if (!strncmp(p, "noblink", 7))
- curblink = 0;
- while (*p && *p != ' ' && *p != ',') p++;
- if (*p != ',') break;
- p++;
- }
- return 0;
-}
-
-static int sbusfbcon_switch(int con, struct fb_info *info)
-{
- int x_margin, y_margin;
- struct fb_info_sbusfb *fb = sbusfbinfo(info);
- int lastconsole;
-
- /* Do we have to save the colormap? */
- if (fb_display[info->currcon].cmap.len)
- fb_get_cmap(&fb_display[info->currcon].cmap, 1, sbusfb_getcolreg, info);
-
- if (info->display_fg) {
- lastconsole = info->display_fg->vc_num;
- if (lastconsole != con &&
- (fontwidth(&fb_display[lastconsole]) != fontwidth(&fb_display[con]) ||
- fontheight(&fb_display[lastconsole]) != fontheight(&fb_display[con])))
- fb->cursor.mode |= CURSOR_SHAPE;
- }
- x_margin = (fb_display[con].var.xres_virtual - fb_display[con].var.xres) / 2;
- y_margin = (fb_display[con].var.yres_virtual - fb_display[con].var.yres) / 2;
- if (fb->margins)
- fb->margins(fb, &fb_display[con], x_margin, y_margin);
- if (fb->graphmode || fb->x_margin != x_margin || fb->y_margin != y_margin) {
- fb->x_margin = x_margin; fb->y_margin = y_margin;
- sbusfb_clear_margin(&fb_display[con], 0);
- }
- info->currcon = con;
- /* Install new colormap */
- do_install_cmap(con, info);
- return 0;
-}
-
- /*
- * Update the `var' structure (called by fbcon.c)
- */
-
-static int sbusfbcon_updatevar(int con, struct fb_info *info)
-{
- /* Nothing */
- return 0;
-}
-
- /*
- * Blank the display.
- */
-
-static int sbusfb_blank(int blank, struct fb_info *info)
-{
- struct fb_info_sbusfb *fb = sbusfbinfo(info);
-
- if (blank && fb->blank)
- return fb->blank(fb);
- else if (!blank && fb->unblank)
- return fb->unblank(fb);
- return 0;
-}
-
- /*
- * Read a single color register and split it into
- * colors/transparent. Return != 0 for invalid regno.
- */
-
-static int sbusfb_getcolreg(u_int regno, u_int *red, u_int *green, u_int *blue,
- u_int *transp, struct fb_info *info)
-{
- struct fb_info_sbusfb *fb = sbusfbinfo(info);
-
- if (!fb->color_map || regno > 255)
- return 1;
- *red = (fb->color_map CM(regno, 0)<<8) | fb->color_map CM(regno, 0);
- *green = (fb->color_map CM(regno, 1)<<8) | fb->color_map CM(regno, 1);
- *blue = (fb->color_map CM(regno, 2)<<8) | fb->color_map CM(regno, 2);
- *transp = 0;
- return 0;
-}
-
-
- /*
- * Set a single color register. The values supplied are already
- * rounded down to the hardware's capabilities (according to the
- * entries in the var structure). Return != 0 for invalid regno.
- */
-
-static int sbusfb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
- u_int transp, struct fb_info *info)
-{
- struct fb_info_sbusfb *fb = sbusfbinfo(info);
-
- if (!fb->color_map || regno > 255)
- return 1;
- red >>= 8;
- green >>= 8;
- blue >>= 8;
- fb->color_map CM(regno, 0) = red;
- fb->color_map CM(regno, 1) = green;
- fb->color_map CM(regno, 2) = blue;
- return 0;
-}
-
-static int sbusfb_set_font(struct display *p, int width, int height)
-{
- int margin;
- int w = p->var.xres_virtual, h = p->var.yres_virtual;
- int depth = p->var.bits_per_pixel;
- struct fb_info_sbusfb *fb = sbusfbinfod(p);
- int x_margin, y_margin;
-
- if (depth > 8) depth = 8;
- x_margin = 0;
- y_margin = 0;
- if (defx_margin < 0 || defy_margin < 0) {
- for (margin = 0; def_margins[margin].depth; margin++)
- if (w == def_margins[margin].xres &&
- h == def_margins[margin].yres &&
- depth == def_margins[margin].depth) {
- x_margin = def_margins[margin].x_margin;
- y_margin = def_margins[margin].y_margin;
- break;
- }
- } else {
- x_margin = defx_margin;
- y_margin = defy_margin;
- }
- x_margin += ((w - 2*x_margin) % width) / 2;
- y_margin += ((h - 2*y_margin) % height) / 2;
-
- p->var.xres = w - 2*x_margin;
- p->var.yres = h - 2*y_margin;
-
- fb->cursor.mode |= CURSOR_SHAPE;
-
- if (fb->margins)
- fb->margins(fb, p, x_margin, y_margin);
- if (fb->x_margin != x_margin || fb->y_margin != y_margin) {
- fb->x_margin = x_margin; fb->y_margin = y_margin;
- sbusfb_clear_margin(p, 0);
- }
-
- return 1;
-}
-
-void sbusfb_palette(int enter)
-{
- int i;
- struct display *p;
-
- for (i = 0; i < MAX_NR_CONSOLES; i++) {
- p = &fb_display[i];
- if (p->dispsw && p->dispsw->setup == sbusfb_disp_setup &&
- p->fb_info->display_fg &&
- p->fb_info->display_fg->vc_num == i) {
- struct fb_info_sbusfb *fb = sbusfbinfod(p);
-
- if (fb->restore_palette) {
- if (enter)
- fb->restore_palette(fb);
- else if (vt_cons[i]->vc_mode != KD_GRAPHICS)
- vc_cons[i].d->vc_sw->con_set_palette(vc_cons[i].d, color_table);
- }
- }
- }
-}
-
- /*
- * Initialisation
- */
-
-extern void (*prom_palette)(int);
-
-static void __init sbusfb_init_fb(int node, int parent, int fbtype,
- struct sbus_dev *sbdp)
-{
- struct fb_fix_screeninfo *fix;
- struct fb_var_screeninfo *var;
- struct display *disp;
- struct fb_info_sbusfb *fb;
- struct fbtype *type;
- int linebytes, w, h, depth;
- char *p = NULL;
- int margin;
-
- fb = kmalloc(sizeof(struct fb_info_sbusfb), GFP_ATOMIC);
- if (!fb) {
- prom_printf("Could not allocate sbusfb structure\n");
- return;
- }
-
- if (!prom_palette)
- prom_palette = sbusfb_palette;
-
- memset(fb, 0, sizeof(struct fb_info_sbusfb));
- fix = &fb->info.fix;
- var = &fb->info.var;
- disp = &fb->disp;
- type = &fb->type;
-
- spin_lock_init(&fb->lock);
- fb->prom_node = node;
- fb->prom_parent = parent;
- fb->sbdp = sbdp;
- if (sbdp)
- fb->iospace = sbdp->reg_addrs[0].which_io;
-
- type->fb_type = fbtype;
- memset(&fb->emulations, 0xff, sizeof(fb->emulations));
- fb->emulations[0] = fbtype;
-
-#ifdef CONFIG_SPARC32
- fb->info.screen_base = (unsigned char *)prom_getintdefault(node, "address", 0);
-#endif
-
- type->fb_height = h = prom_getintdefault(node, "height", 900);
- type->fb_width = w = prom_getintdefault(node, "width", 1152);
-sizechange:
- type->fb_depth = depth = (fbtype == FBTYPE_SUN2BW) ? 1 : 8;
- linebytes = prom_getintdefault(node, "linebytes", w * depth / 8);
- type->fb_size = PAGE_ALIGN((linebytes) * h);
-
- if (defx_margin < 0 || defy_margin < 0) {
- for (margin = 0; def_margins[margin].depth; margin++)
- if (w == def_margins[margin].xres &&
- h == def_margins[margin].yres &&
- depth == def_margins[margin].depth) {
- fb->x_margin = def_margins[margin].x_margin;
- fb->y_margin = def_margins[margin].y_margin;
- break;
- }
- } else {
- fb->x_margin = defx_margin;
- fb->y_margin = defy_margin;
- }
- fb->x_margin += ((w - 2*fb->x_margin) & 7) / 2;
- fb->y_margin += ((h - 2*fb->y_margin) & 15) / 2;
-
- var->xres_virtual = w;
- var->yres_virtual = h;
- var->xres = w - 2*fb->x_margin;
- var->yres = h - 2*fb->y_margin;
-
- var->bits_per_pixel = depth;
- var->height = var->width = -1;
- var->pixclock = 10000;
- var->vmode = FB_VMODE_NONINTERLACED;
- var->red.length = var->green.length = var->blue.length = 8;
-
- fix->line_length = linebytes;
- fix->smem_len = type->fb_size;
- fix->type = FB_TYPE_PACKED_PIXELS;
- fix->visual = FB_VISUAL_PSEUDOCOLOR;
-
- fb->info.node = NODEV;
- fb->info.fbops = &sbusfb_ops;
- fb->info.disp = disp;
- fb->info.currcon = -1;
- strcpy(fb->info.fontname, fontname);
- fb->info.changevar = NULL;
- fb->info.switch_con = &sbusfbcon_switch;
- fb->info.updatevar = &sbusfbcon_updatevar;
- fb->info.flags = FBINFO_FLAG_DEFAULT;
-
- fb->cursor.hwsize.fbx = 32;
- fb->cursor.hwsize.fby = 32;
-
- if (depth > 1 && !fb->color_map)
- fb->color_map = kmalloc(256 * 3, GFP_ATOMIC);
-
- switch(fbtype) {
-#ifdef CONFIG_FB_CREATOR
- case FBTYPE_CREATOR:
- p = creatorfb_init(fb); break;
-#endif
-#ifdef CONFIG_FB_CGSIX
- case FBTYPE_SUNFAST_COLOR:
- p = cgsixfb_init(fb); break;
-#endif
-#ifdef CONFIG_FB_CGTHREE
- case FBTYPE_SUN3COLOR:
- p = cgthreefb_init(fb); break;
-#endif
-#ifdef CONFIG_FB_TCX
- case FBTYPE_TCXCOLOR:
- p = tcxfb_init(fb); break;
-#endif
-#ifdef CONFIG_FB_LEO
- case FBTYPE_SUNLEO:
- p = leofb_init(fb); break;
-#endif
-#ifdef CONFIG_FB_BWTWO
- case FBTYPE_SUN2BW:
- p = bwtwofb_init(fb); break;
-#endif
-#ifdef CONFIG_FB_CGFOURTEEN
- case FBTYPE_MDICOLOR:
- p = cgfourteenfb_init(fb); break;
-#endif
-#ifdef CONFIG_FB_P9100
- case FBTYPE_P9100COLOR:
- /* Temporary crock. For now we are a cg3 */
- p = p9100fb_init(fb); type->fb_type = FBTYPE_SUN3COLOR; break;
-#endif
- }
-
- if (!p) {
- if (fb->color_map)
- kfree(fb->color_map);
- kfree(fb);
- return;
- }
-
- if (p == SBUSFBINIT_SIZECHANGE)
- goto sizechange;
-
- disp->dispsw = &fb->dispsw;
- if (fb->setcursor) {
- fb->dispsw.cursor = sbusfb_cursor;
- if (curblink) {
- fb->cursor.blink_rate = DEFAULT_CURSOR_BLINK_RATE;
- init_timer(&fb->cursor.timer);
- fb->cursor.timer.expires = jiffies + fb->cursor.blink_rate;
- fb->cursor.timer.data = (unsigned long)fb;
- fb->cursor.timer.function = sbusfb_cursor_timer_handler;
- add_timer(&fb->cursor.timer);
- }
- }
- fb->cursor.mode = CURSOR_SHAPE;
- fb->dispsw.set_font = sbusfb_set_font;
- fb->setup = fb->dispsw.setup;
- fb->dispsw.setup = sbusfb_disp_setup;
- fb->dispsw.clear_margins = NULL;
-
- disp->var = *var;
-
- if (fb->blank)
- disp->can_soft_blank = 1;
-
- sbusfb_set_var(var, -1, &fb->info);
-
- if (register_framebuffer(&fb->info) < 0) {
- if (fb->color_map)
- kfree(fb->color_map);
- kfree(fb);
- return;
- }
- printk(KERN_INFO "fb%d: %s\n", minor(fb->info.node), p);
-}
-
-static inline int known_card(char *name)
-{
- char *p;
- for (p = name; *p && *p != ','; p++);
- if (*p == ',') name = p + 1;
- if (!strcmp(name, "cgsix") || !strcmp(name, "cgthree+"))
- return FBTYPE_SUNFAST_COLOR;
- if (!strcmp(name, "cgthree") || !strcmp(name, "cgRDI"))
- return FBTYPE_SUN3COLOR;
- if (!strcmp(name, "cgfourteen"))
- return FBTYPE_MDICOLOR;
- if (!strcmp(name, "leo"))
- return FBTYPE_SUNLEO;
- if (!strcmp(name, "bwtwo"))
- return FBTYPE_SUN2BW;
- if (!strcmp(name, "tcx"))
- return FBTYPE_TCXCOLOR;
- if (!strcmp(name, "p9100"))
- return FBTYPE_P9100COLOR;
- return FBTYPE_NOTYPE;
-}
-
-#ifdef CONFIG_FB_CREATOR
-static void creator_fb_scan_siblings(int root)
-{
- int node, child;
-
- child = prom_getchild(root);
- for (node = prom_searchsiblings(child, "SUNW,ffb"); node;
- node = prom_searchsiblings(prom_getsibling(node), "SUNW,ffb"))
- sbusfb_init_fb(node, root, FBTYPE_CREATOR, NULL);
- for (node = prom_searchsiblings(child, "SUNW,afb"); node;
- node = prom_searchsiblings(prom_getsibling(node), "SUNW,afb"))
- sbusfb_init_fb(node, root, FBTYPE_CREATOR, NULL);
-}
-
-static void creator_fb_scan(void)
-{
- int root;
-
- creator_fb_scan_siblings(prom_root_node);
-
- root = prom_getchild(prom_root_node);
- for (root = prom_searchsiblings(root, "upa"); root;
- root = prom_searchsiblings(prom_getsibling(root), "upa"))
- creator_fb_scan_siblings(root);
-}
-#endif
-
-int __init sbusfb_init(void)
-{
- int type;
- struct sbus_dev *sbdp;
- struct sbus_bus *sbus;
- char prom_name[40];
- extern int con_is_present(void);
-
- if (!con_is_present()) return -ENXIO;
-
-#ifdef CONFIG_FB_CREATOR
- creator_fb_scan();
-#endif
-#ifdef CONFIG_SUN4
- sbusfb_init_fb(0, 0, FBTYPE_SUN2BW, NULL);
-#endif
-#if defined(CONFIG_FB_CGFOURTEEN) && !defined(__sparc_v9__)
- {
- int root, node;
- root = prom_getchild(prom_root_node);
- root = prom_searchsiblings(root, "obio");
- if (root &&
- (node = prom_searchsiblings(prom_getchild(root), "cgfourteen"))) {
- sbusfb_init_fb(node, root, FBTYPE_MDICOLOR, NULL);
- }
- }
-#endif
- if (sbus_root == NULL)
- return 0;
- for_all_sbusdev(sbdp, sbus) {
- type = known_card(sbdp->prom_name);
- if (type == FBTYPE_NOTYPE)
- continue;
- if (prom_getproperty(sbdp->prom_node, "emulation",
- prom_name, sizeof(prom_name)) > 0) {
- type = known_card(prom_name);
- if (type == FBTYPE_NOTYPE)
- type = known_card(sbdp->prom_name);
- }
- sbusfb_init_fb(sbdp->prom_node, sbdp->bus->prom_node, type, sbdp);
- }
- return 0;
-}
-
-MODULE_LICENSE("GPL");
--- /dev/null
+/* sbuslib.c: Helper library for SBUS framebuffer drivers.
+ *
+ * Copyright (C) 2003 David S. Miller (davem@redhat.com)
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/string.h>
+#include <linux/fb.h>
+
+#include <asm/oplib.h>
+
+#include "sbuslib.h"
+
+void sbusfb_fill_var(struct fb_var_screeninfo *var, int prom_node, int bpp)
+{
+ memset(var, 0, sizeof(*var));
+
+ var->xres = prom_getintdefault(prom_node, "width", 1152);
+ var->yres = prom_getintdefault(prom_node, "height", 900);
+ var->xres_virtual = var->xres;
+ var->yres_virtual = var->yres;
+ var->bits_per_pixel = bpp;
+}
+
+EXPORT_SYMBOL(sbusfb_fill_var);
+
+static unsigned long sbusfb_mmapsize(long size, unsigned long fbsize)
+{
+ if (size == SBUS_MMAP_EMPTY) return 0;
+ if (size >= 0) return size;
+ return fbsize * (-size);
+}
+
+int sbusfb_mmap_helper(struct sbus_mmap_map *map,
+ unsigned long physbase,
+ unsigned long fbsize,
+ unsigned long iospace,
+ struct vm_area_struct *vma)
+{
+ unsigned int size, page, r, map_size;
+ unsigned long map_offset = 0;
+ unsigned long off;
+ int i;
+
+ size = vma->vm_end - vma->vm_start;
+ if (vma->vm_pgoff > (~0UL >> PAGE_SHIFT))
+ return -EINVAL;
+
+ off = vma->vm_pgoff << PAGE_SHIFT;
+
+ /* To stop the swapper from even considering these pages */
+ vma->vm_flags |= (VM_SHM | VM_IO | VM_LOCKED);
+
+ /* Each page, see which map applies */
+ for (page = 0; page < size; ){
+ map_size = 0;
+ for (i = 0; map[i].size; i++)
+ if (map[i].voff == off+page) {
+ map_size = sbusfb_mmapsize(map[i].size, fbsize);
+#ifdef __sparc_v9__
+#define POFF_MASK (PAGE_MASK|0x1UL)
+#else
+#define POFF_MASK (PAGE_MASK)
+#endif
+ map_offset = (physbase + map[i].poff) & POFF_MASK;
+ break;
+ }
+ if (!map_size){
+ page += PAGE_SIZE;
+ continue;
+ }
+ if (page + map_size > size)
+ map_size = size - page;
+ r = io_remap_page_range(vma,
+ vma->vm_start + page,
+ map_offset, map_size,
+ vma->vm_page_prot, iospace);
+ if (r)
+ return -EAGAIN;
+ page += map_size;
+ }
+
+ return 0;
+}
--- /dev/null
+/* sbuslib.h: SBUS fb helper library interfaces */
+#ifndef _SBUSLIB_H
+#define _SBUSLIB_H
+
+struct sbus_mmap_map {
+ unsigned long voff;
+ unsigned long poff;
+ unsigned long size;
+};
+
+#define SBUS_MMAP_FBSIZE(n) (-n)
+#define SBUS_MMAP_EMPTY 0x80000000
+
+extern void sbusfb_fill_var(struct fb_var_screeninfo *var, int prom_node, int bpp);
+struct vm_area_struct;
+extern int sbusfb_mmap_helper(struct sbus_mmap_map *map,
+ unsigned long physbase, unsigned long fbsize,
+ unsigned long iospace,
+ struct vm_area_struct *vma);
+
+#endif /* _SBUSLIB_H */
+++ /dev/null
-#include <linux/timer.h>
-#include <asm/sbus.h>
-#include <asm/oplib.h>
-#include <asm/fbio.h>
-
-#include <video/fbcon.h>
-
-struct bt_regs {
- volatile unsigned int addr; /* address register */
- volatile unsigned int color_map; /* color map */
- volatile unsigned int control; /* control register */
- volatile unsigned int cursor; /* cursor map register */
-};
-
-struct fb_info_creator {
- struct ffb_fbc *fbc;
- struct ffb_dac *dac;
- int xy_margin;
- int fifo_cache;
- u64 yx_margin;
- int fg_cache;
- int bg_cache;
- int dac_rev;
-};
-struct fb_info_cgsix {
- struct bt_regs *bt;
- struct cg6_fbc *fbc;
- struct cg6_thc *thc;
- struct cg6_tec *tec;
- volatile u32 *fhc;
-};
-struct fb_info_bwtwo {
- struct bw2_regs *regs;
-};
-struct fb_info_cgthree {
- struct cg3_regs *regs;
-};
-struct fb_info_tcx {
- struct bt_regs *bt;
- struct tcx_thc *thc;
- struct tcx_tec *tec;
- u32 *cplane;
-};
-struct fb_info_leo {
- struct leo_lx_krn *lx_krn;
- struct leo_lc_ss0_usr *lc_ss0_usr;
- struct leo_ld_ss0 *ld_ss0;
- struct leo_ld_ss1 *ld_ss1;
- struct leo_cursor *cursor;
- unsigned int extent;
-};
-struct fb_info_cgfourteen {
- struct cg14_regs *regs;
- struct cg14_cursor *cursor;
- struct cg14_clut *clut;
- int ramsize;
- int mode;
-};
-struct fb_info_p9100 {
- struct p9100_ctrl *ctrl;
- volatile u32 *fbmem;
-};
-
-struct cg_cursor {
- char enable; /* cursor is enabled */
- char mode; /* cursor mode */
- struct fbcurpos cpos; /* position */
- struct fbcurpos chot; /* hot-spot */
- struct fbcurpos size; /* size of mask & image fields */
- struct fbcurpos hwsize; /* hw max size */
- int bits[2][128]; /* space for mask & image bits */
- char color [6]; /* cursor colors */
- struct timer_list timer; /* cursor timer */
- int blink_rate; /* cursor blink rate */
-};
-
-struct sbus_mmap_map {
- unsigned long voff;
- unsigned long poff;
- unsigned long size;
-};
-
-#define SBUS_MMAP_FBSIZE(n) (-n)
-#define SBUS_MMAP_EMPTY 0x80000000
-
-struct fb_info_sbusfb {
- struct fb_info info;
- struct display disp;
- struct display_switch dispsw;
- struct fbtype type;
- struct sbus_dev *sbdp;
- spinlock_t lock;
- int prom_node, prom_parent;
- union {
- struct fb_info_creator ffb;
- struct fb_info_cgsix cg6;
- struct fb_info_bwtwo bw2;
- struct fb_info_cgthree cg3;
- struct fb_info_tcx tcx;
- struct fb_info_leo leo;
- struct fb_info_cgfourteen cg14;
- struct fb_info_p9100 p9100;
- } s;
- unsigned char *color_map;
- struct cg_cursor cursor;
- unsigned char open;
- unsigned char mmaped;
- unsigned char blanked;
- int x_margin;
- int y_margin;
- int vtconsole;
- int consolecnt;
- int graphmode;
- int emulations[4];
- struct sbus_mmap_map *mmap_map;
- unsigned long physbase;
- int iospace;
- /* Methods */
- void (*setup)(struct display *);
- void (*setcursor)(struct fb_info_sbusfb *);
- void (*setcurshape)(struct fb_info_sbusfb *);
- void (*setcursormap)(struct fb_info_sbusfb *, unsigned char *, unsigned char *, unsigned char *);
- void (*loadcmap)(struct fb_info_sbusfb *, struct display *, int, int);
- int (*blank)(struct fb_info_sbusfb *);
- int (*unblank)(struct fb_info_sbusfb *);
- void (*margins)(struct fb_info_sbusfb *, struct display *, int, int);
- void (*reset)(struct fb_info_sbusfb *);
- void (*fill)(struct fb_info_sbusfb *, struct display *, int, int, unsigned short *);
- void (*switch_from_graph)(struct fb_info_sbusfb *);
- void (*restore_palette)(struct fb_info_sbusfb *);
- int (*ioctl)(struct fb_info_sbusfb *, unsigned int, unsigned long);
-};
-
-extern char *creatorfb_init(struct fb_info_sbusfb *);
-extern char *cgsixfb_init(struct fb_info_sbusfb *);
-extern char *cgthreefb_init(struct fb_info_sbusfb *);
-extern char *tcxfb_init(struct fb_info_sbusfb *);
-extern char *leofb_init(struct fb_info_sbusfb *);
-extern char *bwtwofb_init(struct fb_info_sbusfb *);
-extern char *cgfourteenfb_init(struct fb_info_sbusfb *);
-extern char *p9100fb_init(struct fb_info_sbusfb *);
-
-#define sbusfbinfod(disp) ((struct fb_info_sbusfb *)(disp->fb_info))
-#define sbusfbinfo(info) ((struct fb_info_sbusfb *)(info))
-#define CM(i, j) [3*(i)+(j)]
-
-#define SBUSFBINIT_SIZECHANGE ((char *)-1)