Here's an attempt to bloat the linux source a bit more ;-) This patch brings, yet missing, parts that make a Linux-driven Indigo2 Impact (IP28 and most probably IP22-Impact) an usable desktop-machine "out of the box". The driver provides the framebuffer console and an interface for the Xserver (mmap'ing a DMA-pool to the shadow framebuffer and doing the necessary cacheflush). Meanwhile only a few files are affected and obviously no side-effects to other parts of the kernel are to be expected. BTW: it would be appreciated, if someone could verify, that this driver also works for IP22 Impact. Signed-off-by: peter fuerst <post@xxxxxxxx> --- 1) Preparation drivers/video/Kconfig | 6 ++++++ drivers/video/Makefile | 1 + drivers/video/logo/Kconfig | 2 +- arch/mips/sgi-ip22/ip22-setup.c | 37 +++++++++++++++++++++++++++++++++++++ arch/mips/configs/ip28_defconfig | 1 + 5 files changed, 46 insertions(+), 1 deletions(-) diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig index 549b960..43dbc9f 100644 --- a/drivers/video/Kconfig Thu Jan 1 00:00:00 1970 +++ b/drivers/video/Kconfig Thu Mar 10 23:37:58 2011 @@ -2383,6 +2383,12 @@ config FB_PUV3_UNIGFX Choose this option if you want to use the Unigfx device as a framebuffer device. Without the support of PCI & AGP. +config FB_IMPACT + tristate "SGI Indigo2 Impact graphics support" + depends on FB && (SGI_IP22 || SGI_IP28 || SGI_IP30) + help + SGI Indigo2 Impact (SI/HI/MI) graphics card support. + source "drivers/video/omap/Kconfig" source "drivers/video/omap2/Kconfig" diff --git a/drivers/video/Makefile b/drivers/video/Makefile index 8b83129..278c8fa 100644 --- a/drivers/video/Makefile Thu Jan 1 00:00:00 1970 +++ b/drivers/video/Makefile Thu Mar 10 23:44:40 2011 @@ -141,6 +141,7 @@ obj-$(CONFIG_FB_MSM) += msm/ obj-$(CONFIG_FB_NUC900) += nuc900fb.o obj-$(CONFIG_FB_JZ4740) += jz4740_fb.o obj-$(CONFIG_FB_PUV3_UNIGFX) += fb-puv3.o +obj-$(CONFIG_FB_IMPACT) += impact.o # Platform or fallback drivers go here obj-$(CONFIG_FB_UVESA) += uvesafb.o diff --git a/drivers/video/logo/Kconfig b/drivers/video/logo/Kconfig index 39ac49e..3ac6da4 100644 --- a/drivers/video/logo/Kconfig Thu Jan 1 00:00:00 1970 +++ b/drivers/video/logo/Kconfig Fri May 8 00:51:01 2009 @@ -54,7 +54,7 @@ config LOGO_PARISC_CLUT224 config LOGO_SGI_CLUT224 bool "224-color SGI Linux logo" - depends on SGI_IP22 || SGI_IP27 || SGI_IP32 || X86_VISWS + depends on SGI_IP22 || SGI_IP27 || SGI_IP28 || SGI_IP30 || SGI_IP32 || X86_VISWS default y config LOGO_SUN_CLUT224 diff --git a/arch/mips/sgi-ip22/ip22-setup.c b/arch/mips/sgi-ip22/ip22-setup.c index 5e66213..085b612 100644 --- a/arch/mips/sgi-ip22/ip22-setup.c Thu Jan 1 00:00:00 1970 +++ b/arch/mips/sgi-ip22/ip22-setup.c Fri May 8 01:05:13 2009 @@ -96,4 +96,41 @@ void __init plat_mem_setup(void) } } #endif +#if defined(CONFIG_FB_IMPACT) + { + extern void setup_impact_earlycons(void); + /* + * Get graphics info before it is overwritten... + * E.g. @ 9000000020f02f78: ffffffff9fc6d770,900000001f000000 + */ +#ifdef CONFIG_ARC64 + ULONG * (*__vec)(void) = (typeof(__vec)) + ((ULONG*)PROMBLOCK->pvector)[8]; + ULONG *gfxinfo = (*__vec)(); +#else + /* supposed to work on both 32/64-bit kernels. */ + int (*__vec)(void) = (typeof(__vec)) + (long) ((int*)PROMBLOCK->pvector)[8]; + int *gfxinfo = (typeof(gfxinfo)) (*__vec)(); +#endif + /* See note on __pa() in impact.c */ + sgi_gfxaddr = __pa((void*)gfxinfo[1]); + if (sgi_gfxaddr < 0x1f000000 || 0x1fa00000 <= sgi_gfxaddr) + sgi_gfxaddr = 0; + /* + * Early params are not yet avaialble, so this setting + * must be done in the ARCS environment. + */ + ctype = ArcGetEnvironmentVariable("OSLoadOptions"); + if (!ctype || !strstr(ctype, "impact=noearly")) +#ifndef CONFIG_EARLY_PRINTK + if (ctype && strstr(ctype, "impact=early")) +#endif + setup_impact_earlycons(); + + printk(KERN_DEBUG "ARCS gfx info @ %p: %p,%p\n", + gfxinfo, (void*)gfxinfo[0], (void*)gfxinfo[1]); + printk(KERN_INFO "SGI graphics system @ 0x%08lx\n", sgi_gfxaddr); + } +#endif } diff --git a/arch/mips/configs/ip28_defconfig b/arch/mips/configs/ip28_defconfig index 4dbf626..b316c86 100644 --- a/arch/mips/configs/ip28_defconfig +++ b/arch/mips/configs/ip28_defconfig @@ -78,3 +78,4 @@ CONFIG_MAGIC_SYSRQ=y CONFIG_CRYPTO_MANAGER=y # CONFIG_CRYPTO_HW is not set # CONFIG_CRC32 is not set +CONFIG_FB_IMPACT=y 2) The driver drivers/video/impact.c | 1154 ++++++++++++++++++++++++++++++++++++++++++++++++ include/video/impact.h | 210 +++++++++ 2 files changed, 1364 insertions(+), 0 deletions(-) diff --git a/drivers/video/impact.c b/drivers/video/impact.c new file mode 100644 index 0000000..5ffc948 --- /dev/null Wed Dec 8 00:46:04 2004 +++ b/drivers/video/impact.c Mon Jul 25 00:06:58 2011 @@ -0,0 +1,1154 @@ +/* + * linux/drivers/video/impactsr.c -- SGI Octane MardiGras (IMPACTSR) graphics + * linux/drivers/video/impact.c -- SGI Indigo2 MardiGras (IMPACT) graphics + * + * Copyright (c) 2004-2006 by Stanislaw Skowronek (skylark@xxxxxxxxxxxxxx) + * Adapted to Indigo2 by pf, 2005,2006,2009,2011 (post@xxxxxxxx) + * + * Based on linux/drivers/video/skeletonfb.c + * + * This driver, as most of the IP30 (SGI Octane) port, is a result of massive + * amounts of reverse engineering and trial-and-error. If anyone is interested + * in helping with it, please contact me: <skylark@xxxxxxxxxxxxxx>. + * + * The basic functions of this driver are filling and blitting rectangles. + * To achieve the latter, two DMA operations are used on Impact. It is unclear + * to me, why is it so, but even Xsgi (the IRIX X11 server) does it this way. + * It seems that fb->fb operations are not operational on these cards. + * + * For this purpose, a kernel DMA pool is allocated (pool number 0). This pool + * is (by default) 64kB in size. An ioctl could be used to set the value at + * run-time. Applications can use this pool, however proper locking has to be + * guaranteed. Kernel should be locked out from this pool by an ioctl. + * + * The IMPACTSR is quite well worked-out currently, except for the Geometry + * Engines (GE11). Any information about use of those devices would be very + * useful. It would enable a Linux OpenGL driver, as most of OpenGL calls are + * supported directly by the hardware. So far, I can't initialize the GE11. + * Verification of microcode crashes the graphics. + * + * 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/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/delay.h> +#include <linux/fb.h> +#include <linux/init.h> +#include <linux/vmalloc.h> +#include <linux/module.h> +#include <linux/dma-mapping.h> +#include <linux/spinlock.h> +#include <linux/font.h> +#include <linux/platform_device.h> +#include <linux/console.h> +#include <linux/version.h> + +#ifndef CONFIG_64BIT +#error (S)he, who can afford Impact-graphics, shall afford a 64bit-kernel also! +#endif +#ifdef CONFIG_SGI_IP30 +# include <asm/mach-ip30/xtalk.h> +# define IPNR 30 +#else +# if defined(CONFIG_SGI_IP22) +# define IPNR 22 +# elif defined(CONFIG_SGI_IP26) +# define IPNR 26 +# else +# define IPNR 28 +# endif +#endif +#define isSR (IPNR > 28) /* avoid nasty #if... where possible. */ +#include <video/impact.h> + +/* Some fixed register values. */ + +#if isSR /* ImpactSR (HQ4) registers */ +#define VAL_CFIFO_HW 0x47 +#define VAL_CFIFO_LW 0x14 +#define VAL_CFIFO_DELAY 0x64 +#define VAL_DFIFO_HW 0x40 +#define VAL_DFIFO_LW 0x10 +#define VAL_DFIFO_DELAY 0 +#define MSK_CFIFO_CNT 0xff +#define USEPOOLS 5 +#else /* Impact (HQ3) registers */ +#define VAL_CFIFO_HW 0x20 /* 0x18 ? */ +#define VAL_CFIFO_LW 0x14 +#define VAL_CFIFO_DELAY 0x64 +#define VAL_DFIFO_HW 0x28 +#define VAL_DFIFO_LW 0x14 +#define VAL_DFIFO_DELAY 0xfff +#define MSK_CFIFO_CNT 0x7f +#define USEPOOLS 4 +#endif +#define POOLS 5 + +#define IMPACT_KPOOL_SIZE 65536 + +struct impact_par { + /* physical mmio base in HEART XTalk space */ + unsigned long mmio_base; + /* virtual mmio base in kernel space */ + unsigned long mmio_virt; + struct { + /* DMA pool management, txtbl[0..num-1] passed to card */ + unsigned int *txtbl; /* txtbl[i] = pgidx(phys[i]) */ + unsigned int txnum; /* valid: txtbl[0..txnum-1] */ + unsigned int txmax; /* alloc: txtbl[0..txmax-1] */ + unsigned long txphys; /* txphys = dma_addr(txtbl) */ + /* kernel DMA pools, the actual DMA-buffers */ + void* *virt; /* virt[0..txnum-1]: dma-page-addresses */ + unsigned long *phys; /* phys[i] = dma_addr(virt[i]) */ + unsigned int size; + unsigned long uaddr; /* DMA-buffer's userland-address */ + } pools[POOLS]; + /* board config */ + unsigned int num_ge, num_rss; + /* locks to prevent simultaneous user and kernel access */ + int open_flag; + int mmap_flag; + spinlock_t lock; + unsigned xoffset; /* fb_var_screeninfo.[xy]offset, are ... */ + unsigned yoffset; /* ...used inconsistently (at the best). */ +}; + +static struct fb_fix_screeninfo impact_fix = { + .id = "ImpactSR 0RSS", + .smem_start = 0, + .smem_len = 0, + .type = FB_TYPE_PACKED_PIXELS, + .visual = FB_VISUAL_TRUECOLOR, + .xpanstep = 0, + .ypanstep = 0, + .ywrapstep = 0, + .line_length = 0, + .accel = FB_ACCEL_NONE, +}; + +static struct fb_var_screeninfo impact_var = { + .xres = 960, + .yres = 960, + .xres_virtual = 1280, + .yres_virtual = 1024, + .bits_per_pixel = 24, + .red = { .offset = 0, .length = 8 }, + .green = { .offset = 8, .length = 8 }, + .blue = { .offset = 16, .length = 8 }, + .transp = { .offset = 24, .length = 8 }, +}; + +static struct fb_info info; + +static unsigned int pseudo_palette[256]; + +static struct impact_par current_par; + +/* --------------------- Gory Details --------------------- */ +#define PAR(p) (*((struct impact_par *)(p)->par)) +#define MMIO(p) (PAR(p).mmio_virt) + +static void impact_wait_cfifo(unsigned long mmio, int nslots) +{ + while ((IMPACT_FIFOSTATUS(mmio) & MSK_CFIFO_CNT) > (IMPACT_CFIFO_MAX-nslots)); +} +static void impact_wait_cfifo_empty(unsigned long mmio) +{ + while (IMPACT_FIFOSTATUS(mmio) & MSK_CFIFO_CNT); +} +static void impact_wait_bfifo(unsigned long mmio, int nslots) +{ + while ((IMPACT_GIOSTATUS(mmio) & 0x1f) > (IMPACT_BFIFO_MAX-nslots)); +} +static void impact_wait_bfifo_empty(unsigned long mmio) +{ + while (IMPACT_GIOSTATUS(mmio) & 0x1f); +} +static void impact_wait_dma(unsigned long mmio) +{ + while (IMPACT_DMABUSY(mmio) & 0x1f); + while (!(IMPACT_STATUS(mmio) & 1)); + while (!(IMPACT_STATUS(mmio) & 2)); + while (!(IMPACT_RESTATUS(mmio) & 0x100)); +} +static void impact_wait_dmaready(unsigned long mmio) +{ + IMPACT_CFIFOW(mmio) = 0x000e0100; + while (IMPACT_DMABUSY(mmio) & 0x1eff); + while (!(IMPACT_STATUS(mmio) & 2)); +} +#define impact_wait_rss_idle impact_wait_dmaready + +static void impact_inithq(unsigned long mmio) +{ + /* Not really needed, the friendly PROM did this already for us... */ + /* CFIFO parameters */ + IMPACT_CFIFO_HW(mmio) = VAL_CFIFO_HW; + IMPACT_CFIFO_LW(mmio) = VAL_CFIFO_LW; + IMPACT_CFIFO_DELAY(mmio) = VAL_CFIFO_DELAY; + /* DFIFO parameters */ + IMPACT_DFIFO_HW(mmio) = VAL_DFIFO_HW; + IMPACT_DFIFO_LW(mmio) = VAL_DFIFO_LW; + IMPACT_DFIFO_DELAY(mmio) = VAL_DFIFO_DELAY; +} + +static void impact_initrss(unsigned long mmio) +{ + volatile typeof(IMPACT_CFIFO(0)) *cfifo = &IMPACT_CFIFO(mmio); + /* transfer mask registers */ + *cfifo = IMPACT_CMD_COLORMASKLSBSA(0xffffff); + *cfifo = IMPACT_CMD_COLORMASKLSBSB(0xffffff); + *cfifo = IMPACT_CMD_COLORMASKMSBS(0); + *cfifo = IMPACT_CMD_XFRMASKLO(0xffffff); + *cfifo = IMPACT_CMD_XFRMASKHI(0xffffff); + /* use the main plane */ + *cfifo = IMPACT_CMD_DRBPOINTERS(0xc8240); + /* set the RE into vertical flip mode */ + *cfifo = IMPACT_CMD_CONFIG(0xcac); + *cfifo = IMPACT_CMD_XYWIN(0, 0x3ff); +} + +static void impact_initxmap(unsigned long mmio) +{ + /* set XMAP into 24-bpp mode */ + IMPACT_XMAP_PP1SELECT(mmio) = 0x01; + IMPACT_XMAP_INDEX(mmio) = 0x00; + IMPACT_XMAP_MAIN_MODE(mmio) = 0x07a4; +} + +static void impact_initvc3(unsigned long mmio) +{ + /* cursor-b-gone (disable DISPLAY bit) */ + IMPACT_VC3_INDEXDATA(mmio) = 0x1d000100; +} + +static void impact_detachtxtbl(unsigned long mmio, unsigned long pool) +{ + volatile typeof(IMPACT_CFIFOP(0)) *cfifop = &IMPACT_CFIFOP(mmio); + /* clear DMA pool */ + impact_wait_cfifo_empty(mmio); + impact_wait_dma(mmio); + IMPACT_CFIFOPW1(mmio) = IMPACT_CMD_HQ_TXBASE(pool); + *cfifop = 9; + *cfifop = IMPACT_CMD_HQ_TXMAX(pool, 0); + *cfifop = IMPACT_CMD_HQ_PGBITS(pool, 0); + if (isSR) + *cfifop = IMPACT_CMD_HQ_484B(pool, 0x00080000); + impact_wait_cfifo_empty(mmio); + impact_wait_dmaready(mmio); +} + +static void impact_initdma(struct fb_info *p) +{ + volatile typeof(IMPACT_CFIFOPW(0)) *cfifopw = &IMPACT_CFIFOPW(MMIO(p)); + volatile typeof(IMPACT_CFIFOP(0)) *cfifop = &IMPACT_CFIFOP(MMIO(p)); + int pool; + /* clear DMA pools */ + for (pool = 0; pool < POOLS; pool++) { + impact_detachtxtbl(MMIO(p), pool); + PAR(p).pools[pool].txmax = 0; + PAR(p).pools[pool].txnum = 0; + } + /* set DMA parameters */ + impact_wait_cfifo_empty(MMIO(p)); + *cfifop = IMPACT_CMD_HQ_PGSIZE(0); + *cfifop = IMPACT_CMD_HQ_STACKPTR(0); + if (isSR) + *cfifop = IMPACT_CMD_HQ_484A(0, 0x00180000); + *cfifopw = 0x000e0100; + *cfifopw = 0x000e0100; + *cfifopw = 0x000e0100; + *cfifopw = 0x000e0100; + *cfifopw = 0x000e0100; + if (isSR) { + IMPACT_REG32(MMIO(p), 0x40918) = 0x00680000; + IMPACT_REG32(MMIO(p), 0x40920) = 0x80280000; + IMPACT_REG32(MMIO(p), 0x40928) = 0x00000000; + } +} + +static void impact_alloctxtbl(struct fb_info *p, int pool, int pages) +{ + /* realloc array of pool's page-indices to be passed to the card. */ + dma_addr_t dma_handle; + int alloc_count; + if (pages > PAR(p).pools[pool].txmax) { /* grow the pool - unlikely but supported */ + alloc_count = pages; + if (alloc_count < 1024) + alloc_count = 1024; + if (PAR(p).pools[pool].txmax) + dma_free_noncoherent(NULL, PAR(p).pools[pool].txmax*4, + PAR(p).pools[pool].txtbl, PAR(p).pools[pool].txphys); + PAR(p).pools[pool].txtbl = + dma_alloc_noncoherent(NULL, alloc_count*4, &dma_handle, GFP_KERNEL); + PAR(p).pools[pool].txphys = dma_handle; + PAR(p).pools[pool].txmax = alloc_count; + } + PAR(p).pools[pool].txnum = pages; +} + +static void impact_writetxtbl(struct fb_info *p, int pool) +{ + volatile typeof(IMPACT_CFIFOPW(0)) *cfifopw = &IMPACT_CFIFOPW(MMIO(p)); + volatile typeof(IMPACT_CFIFOP(0)) *cfifop = &IMPACT_CFIFOP(MMIO(p)); + impact_wait_cfifo_empty(MMIO(p)); + impact_wait_dma(MMIO(p)); + /* inform the card about a new DMA pool */ + IMPACT_CFIFOPW1(MMIO(p)) = IMPACT_CMD_HQ_TXBASE(pool); + *cfifop = PAR(p).pools[pool].txphys; + *cfifop = IMPACT_CMD_HQ_TXMAX(pool, PAR(p).pools[pool].txnum); + *cfifop = IMPACT_CMD_HQ_PGBITS(pool, 0x0a); + if (isSR) + *cfifop = IMPACT_CMD_HQ_484B(pool, 0x00180000); + *cfifopw = 0x000e0100; + *cfifopw = 0x000e0100; + *cfifopw = 0x000e0100; + *cfifopw = 0x000e0100; + *cfifopw = 0x000e0100; + impact_wait_cfifo_empty(MMIO(p)); + impact_wait_dmaready(MMIO(p)); +} + +static void +impact_settxtbl(struct fb_info *p, int pool, unsigned *txtbl, int txmax) +{ + impact_alloctxtbl(p, pool, txmax); + memcpy(PAR(p).pools[pool].txtbl, txtbl, txmax*4); + dma_cache_wback_inv((unsigned long)PAR(p).pools[pool].txtbl, txmax*4); + impact_writetxtbl(p, pool); +} + +/* + * Screw the vaddress, or this damned virt_to_page() will blow up the + * driver for DMA_NONCOHERENT (i.e. on any Indigo2). + * (For 64Bit, though not for 32Bit, __pa() now does the right thing, + * and with a bit of luck there will be no regression...) + */ +static inline struct page *dma_virt_to_page(void *virt) +{ + return virt_to_page(phys_to_virt(__pa(virt))); +} + +static void +impact_resizekpool(struct fb_info *p, int pool, int size, int growonly) +{ + int pages; + int i; + dma_addr_t dma_handle; + if (growonly && PAR(p).pools[pool].size >= size) + return; + if (size < 8192) /* single line smallcopy (1280*4) *must* work */ + size = 8192; + pages = (size + PAGE_SIZE - 1) >> PAGE_SHIFT; + /* before manipulating the tbl, make it unknown to the card! */ + impact_detachtxtbl(MMIO(p), pool); + if (PAR(p).pools[pool].size > 0) { + for (i = 0; i < PAR(p).pools[pool].txnum; i++) { + ClearPageReserved(dma_virt_to_page(PAR(p).pools[pool].virt[i])); + dma_free_coherent(NULL, PAGE_SIZE, PAR(p).pools[pool].virt[i], + PAR(p).pools[pool].phys[i]); + } + vfree(PAR(p).pools[pool].phys); + vfree(PAR(p).pools[pool].virt); + } + impact_alloctxtbl(p, pool, pages); + PAR(p).pools[pool].virt = vmalloc(pages*sizeof(unsigned long)); + PAR(p).pools[pool].phys = vmalloc(pages*sizeof(unsigned long)); + for (i = 0; i < PAR(p).pools[pool].txnum; i++) { + PAR(p).pools[pool].virt[i] = + dma_alloc_coherent(NULL, PAGE_SIZE, &dma_handle, GFP_KERNEL); + SetPageReserved(dma_virt_to_page(PAR(p).pools[pool].virt[i])); + PAR(p).pools[pool].phys[i] = dma_handle; + PAR(p).pools[pool].txtbl[i] = dma_handle >> PAGE_SHIFT; + } + i = sizeof(*PAR(p).pools[pool].txtbl) * PAR(p).pools[pool].txnum; + dma_cache_wback_inv((unsigned long)PAR(p).pools[pool].txtbl, i); + impact_writetxtbl(p, pool); /* finally attach the tbl to the card. */ + PAR(p).pools[pool].size = pages * PAGE_SIZE; +} + +static void +impact_rect(unsigned long mmio, int x, int y, int w, int h, unsigned c, int lo) +{ + volatile typeof(IMPACT_CFIFO(0)) *cfifo = &IMPACT_CFIFO(mmio); + unsigned mode = lo != IMPACT_LO_COPY ? 0x6304:0x6300; + impact_wait_cfifo_empty(mmio); + impact_wait_rss_idle(mmio); + *cfifo = IMPACT_CMD_PP1FILLMODE(mode, lo); + *cfifo = IMPACT_CMD_FILLMODE(0); + *cfifo = IMPACT_CMD_PACKEDCOLOR(c); + *cfifo = IMPACT_CMD_BLOCKXYSTARTI(x, y); + *cfifo = IMPACT_CMD_BLOCKXYENDI(x+w-1, y+h-1); + *cfifo = IMPACT_CMD_IR_ALIAS(0x18); +} + +static void +impact_framerect(unsigned long mmio, int x, int y, int w, int h, + int bx, int by, unsigned c) +{ + impact_rect(mmio, x, y, w, by, c, IMPACT_LO_COPY); + impact_rect(mmio, x, y+h-by, w, by, c, IMPACT_LO_COPY); + impact_rect(mmio, x, y, bx, h, c, IMPACT_LO_COPY); + impact_rect(mmio, x+w-bx, y, bx, h, c, IMPACT_LO_COPY); +} + +static unsigned long dcntr; +static void impact_debug(struct fb_info *p, int v) +{ + int i; + IMPACT_CFIFO(MMIO(p)) = IMPACT_CMD_PIXCMD(3); + IMPACT_CFIFO(MMIO(p)) = IMPACT_CMD_HQ_PIXELFORMAT(0xe00); + switch(v) { + case 0: + for (i = 0; i < 64; i++) + impact_rect(MMIO(p), 4*(i&7), 28-4*(i>>3), 4, 4, + dcntr & (1L<<i) ? 0xa080ff:0x100030, IMPACT_LO_COPY); + break; + case 1: + dcntr++; + for (i = 0; i < 64; i++) + impact_rect(MMIO(p), 4*(i&7), 28-4*(i>>3), 4, 4, + dcntr & (1L<<i) ? 0xff80a0:0x300010, IMPACT_LO_COPY); + break; + case 2: + for (i = 0; i < 64; i++) + impact_rect(MMIO(p), 4*(i&7), 28-4*(i>>3), 4, 4, + dcntr & (1L<<i) ? 0xa0ff80:0x103000, IMPACT_LO_COPY); + } +} + +static void impact_smallcopy(struct fb_info *p, unsigned sx, unsigned sy, + unsigned dx, unsigned dy, unsigned w, unsigned h) +{ + volatile typeof(IMPACT_CFIFO(0)) *cfifo = &IMPACT_CFIFO(MMIO(p)); + if (w < 1 || h < 1) + return; + w = (w+1) & ~1; + impact_wait_cfifo_empty(MMIO(p)); + /* setup and perform DMA from RE to HOST */ + impact_wait_dma(MMIO(p)); + if (PAR(p).num_rss == 2 && (sy & 1)) + *cfifo = IMPACT_CMD_CONFIG(0xca5); + else /* Beware, only I2 MaxImpact has 2 REs, SI, HI will hang ! */ + *cfifo = IMPACT_CMD_CONFIG(0xca4); + *cfifo = IMPACT_CMD_PIXCMD(2); + *cfifo = IMPACT_CMD_PP1FILLMODE(0x2200, IMPACT_LO_COPY); + *cfifo = IMPACT_CMD_COLORMASKLSBSA(0xffffff); + *cfifo = IMPACT_CMD_COLORMASKLSBSB(0xffffff); + *cfifo = IMPACT_CMD_COLORMASKMSBS(0); + *cfifo = IMPACT_CMD_DRBPOINTERS(0xc8240); + *cfifo = IMPACT_CMD_BLOCKXYSTARTI(sx, sy+h-1); + *cfifo = IMPACT_CMD_BLOCKXYENDI(sx+w-1, sy); + *cfifo = IMPACT_CMD_XFRMASKLO(0xffffff); + *cfifo = IMPACT_CMD_XFRMASKHI(0xffffff); + *cfifo = IMPACT_CMD_XFRSIZE(w, h); + *cfifo = IMPACT_CMD_XFRCOUNTERS(w, h); + *cfifo = IMPACT_CMD_XFRMODE(0x00080); + *cfifo = IMPACT_CMD_FILLMODE(0x01000000); + *cfifo = IMPACT_CMD_HQ_PIXELFORMAT(0x200); + *cfifo = IMPACT_CMD_HQ_SCANWIDTH(w << 2); + *cfifo = IMPACT_CMD_HQ_DMATYPE(0x0a); + *cfifo = IMPACT_CMD_HQ_PG_LIST_0(0x80000000); + *cfifo = IMPACT_CMD_HQ_PG_WIDTH(w << 2); + *cfifo = IMPACT_CMD_HQ_PG_OFFSET(0); + *cfifo = IMPACT_CMD_HQ_PG_STARTADDR(0); + *cfifo = IMPACT_CMD_HQ_PG_LINECNT(h); + *cfifo = IMPACT_CMD_HQ_PG_WIDTHA(w << 2); + *cfifo = IMPACT_CMD_XFRCONTROL(8); + *cfifo = IMPACT_CMD_GLINE_XSTARTF(1); + *cfifo = IMPACT_CMD_IR_ALIAS(0x18); + *cfifo = IMPACT_CMD_HQ_DMACTRL_0(8); + *cfifo = IMPACT_CMD_XFRCONTROL(9); + impact_wait_dmaready(MMIO(p)); + *cfifo = IMPACT_CMD_GLINE_XSTARTF(0); + *cfifo = IMPACT_CMD_RE_TOGGLECNTX(0); + *cfifo = IMPACT_CMD_XFRCOUNTERS(0, 0); + /* setup and perform DMA from HOST to RE */ + impact_wait_dma(MMIO(p)); + *cfifo = IMPACT_CMD_CONFIG(0xca4); + *cfifo = IMPACT_CMD_PP1FILLMODE(0x6200, IMPACT_LO_COPY); + *cfifo = IMPACT_CMD_BLOCKXYSTARTI(dx, dy+h-1); + *cfifo = IMPACT_CMD_BLOCKXYENDI(dx+w-1, dy); + *cfifo = IMPACT_CMD_FILLMODE(0x01400000); + *cfifo = IMPACT_CMD_XFRMODE(0x00080); + *cfifo = IMPACT_CMD_HQ_PIXELFORMAT(0x600); + *cfifo = IMPACT_CMD_HQ_SCANWIDTH(w << 2); + *cfifo = IMPACT_CMD_HQ_DMATYPE(0x0c); + *cfifo = IMPACT_CMD_PIXCMD(3); + *cfifo = IMPACT_CMD_XFRSIZE(w, h); + *cfifo = IMPACT_CMD_XFRCOUNTERS(w, h); + *cfifo = IMPACT_CMD_GLINE_XSTARTF(1); + *cfifo = IMPACT_CMD_IR_ALIAS(0x18); + *cfifo = IMPACT_CMD_XFRCONTROL(1); + *cfifo = IMPACT_CMD_HQ_PG_LIST_0(0x80000000); + *cfifo = IMPACT_CMD_HQ_PG_OFFSET(0); + *cfifo = IMPACT_CMD_HQ_PG_STARTADDR(0); + *cfifo = IMPACT_CMD_HQ_PG_LINECNT(h); + *cfifo = IMPACT_CMD_HQ_PG_WIDTHA(w << 2); + *cfifo = IMPACT_CMD_HQ_DMACTRL_0(0); + IMPACT_CFIFOW1(MMIO(p)) = 0x000e0400; + impact_wait_dma(MMIO(p)); + *cfifo = IMPACT_CMD_GLINE_XSTARTF(0); + *cfifo = IMPACT_CMD_RE_TOGGLECNTX(0); + *cfifo = IMPACT_CMD_XFRCOUNTERS(0, 0); +} + +static unsigned impact_getpalreg(struct fb_info *p, unsigned i) +{ + return ((unsigned *)p->pseudo_palette)[i]; +} + +/* ------------ Accelerated Functions --------------------- */ + +static void impact_fillrect(struct fb_info *p, const struct fb_fillrect *region) +{ + unsigned long flags; + unsigned x = region->dx+PAR(p).xoffset; + unsigned y = region->dy+PAR(p).yoffset; + spin_lock_irqsave(&PAR(p).lock, flags); + if (!PAR(p).open_flag) + switch(region->rop) { + case ROP_XOR: + impact_rect(MMIO(p), x, y, region->width, region->height, + impact_getpalreg(p, region->color), IMPACT_LO_XOR); + break; + case ROP_COPY: + default: + impact_rect(MMIO(p), x, y, region->width, region->height, + impact_getpalreg(p, region->color), IMPACT_LO_COPY); + break; + } + spin_unlock_irqrestore(&PAR(p).lock, flags); +} + +static void impact_copyarea(struct fb_info *p, const struct fb_copyarea *area) +{ + volatile typeof(IMPACT_CFIFO(0)) *cfifo = &IMPACT_CFIFO(MMIO(p)); + unsigned sx, sy, dx, dy, w, h; + unsigned th, ah; + unsigned long flags; + w = area->width; + h = area->height; + if (w < 1 || h < 1) + return; + spin_lock_irqsave(&PAR(p).lock, flags); + if (PAR(p).open_flag) { + spin_unlock_irqrestore(&PAR(p).lock, flags); + return; + } + sx = area->sx + PAR(p).xoffset; + sy = 0x3ff - (area->sy + h - 1 + PAR(p).yoffset); + dx = area->dx + PAR(p).xoffset; + dy = 0x3ff - (area->dy + h - 1 + PAR(p).yoffset); + th = PAR(p).pools[0].size / (w*4); + *cfifo = IMPACT_CMD_XYWIN(0, 0); + if (dy > sy) { + dy += h; + sy += h; + while (h > 0) { + ah = th > h ? h:th; + impact_smallcopy(p, sx, sy-ah, dx, dy-ah, w, ah); + dy -= ah; + sy -= ah; + h -= ah; + } + } else { + while (h > 0) { + ah = th > h ? h:th; + impact_smallcopy(p, sx, sy, dx, dy, w, ah); + dy += ah; + sy += ah; + h -= ah; + } + } + *cfifo = IMPACT_CMD_PIXCMD(0); + *cfifo = IMPACT_CMD_HQ_PIXELFORMAT(0xe00); + *cfifo = IMPACT_CMD_CONFIG(0xcac); + *cfifo = IMPACT_CMD_XYWIN(0, 0x3ff); + spin_unlock_irqrestore(&PAR(p).lock, flags); +} + +/* 8-bpp blits are done as PIO draw operation; the pixels are unpacked into + 32-bpp values from the current palette in software */ +static void +impact_imageblit_8bpp(struct fb_info *p, const struct fb_image *image) +{ + volatile typeof(IMPACT_CFIFO(0)) *cfifo = &IMPACT_CFIFO(MMIO(p)); + int i, u, v; + const unsigned char *dp; + unsigned pix; + unsigned pal[256]; + unsigned x = image->dx + PAR(p).xoffset; + unsigned y = image->dy + PAR(p).yoffset; + /* setup PIO to RE */ + impact_wait_cfifo_empty(MMIO(p)); + impact_wait_rss_idle(MMIO(p)); + *cfifo = IMPACT_CMD_PP1FILLMODE(0x6300, IMPACT_LO_COPY); + *cfifo = IMPACT_CMD_BLOCKXYSTARTI(x, y); + *cfifo = IMPACT_CMD_BLOCKXYENDI(x+image->width-1, y+image->height-1); + *cfifo = IMPACT_CMD_FILLMODE(0x00c00000); + *cfifo = IMPACT_CMD_XFRMODE(0x00080); + *cfifo = IMPACT_CMD_XFRSIZE(image->width, image->height); + *cfifo = IMPACT_CMD_XFRCOUNTERS(image->width, image->height); + *cfifo = IMPACT_CMD_GLINE_XSTARTF(1); + *cfifo = IMPACT_CMD_IR_ALIAS(0x18); + /* another workaround.. 33 writes to alpha... hmm... */ + for (i = 0; i < 33; i++) + *cfifo = IMPACT_CMD_ALPHA(0); + *cfifo = IMPACT_CMD_XFRCONTROL(2); + /* pairs of pixels are sent in two writes to the RE */ + i = 0; + dp = image->data; + for (v = 0; v < 256; v++) + pal[v] = impact_getpalreg(p, v); + for (v = 0; v < image->height; v++) { + for (u = 0; u < image->width; u++) { + pix = pal[*(dp++)]; + if (i) + *cfifo = IMPACT_CMD_CHAR_L(pix); + else + *cfifo = IMPACT_CMD_CHAR_H(pix); + i ^= 1; + } + } + if (i) + *cfifo = IMPACT_CMD_CHAR_L(0); + *cfifo = IMPACT_CMD_GLINE_XSTARTF(0); + *cfifo = IMPACT_CMD_RE_TOGGLECNTX(0); + *cfifo = IMPACT_CMD_XFRCOUNTERS(0, 0); +} + +/* 1-bpp blits are done as character drawing; the bitmaps are drawn as 8-bit wide + strips; technically, Impact supports 16-pixel wide characters, but Linux bitmap + alignment is 8 bits and most draws are 8 pixels wide (font width), anyway */ +static void +impact_imageblit_1bpp(struct fb_info *p, const struct fb_image *image) +{ + volatile typeof(IMPACT_CFIFO(0)) *cfifo = &IMPACT_CFIFO(MMIO(p)); + int x, y, w, h, b; + int u, v, a; + const unsigned char *d; + impact_wait_cfifo_empty(MMIO(p)); + impact_wait_rss_idle(MMIO(p)); + *cfifo = IMPACT_CMD_PP1FILLMODE(0x6300, IMPACT_LO_COPY); + *cfifo = IMPACT_CMD_FILLMODE(0x400018); + a = impact_getpalreg(p, image->fg_color); + *cfifo = IMPACT_CMD_PACKEDCOLOR(a); + a = impact_getpalreg(p, image->bg_color); + /* Hmm, only the lower 4 bits are taken from red and blue. */ + if (!isSR) a = (a>>4) & 0x0f000f | a & 0x00ff00; + *cfifo = IMPACT_CMD_BKGRD_RG(a & 0xffff); + *cfifo = IMPACT_CMD_BKGRD_BA((a & 0xff0000) >> 16); + x = image->dx + PAR(p).xoffset; + y = image->dy + PAR(p).yoffset; + w = image->width; + h = image->height; + b = (w+7) / 8; + for (u = 0; u < b; u++) { + impact_wait_cfifo_empty(MMIO(p)); + a = (w<8) ? w:8; + d = image->data+u; + *cfifo = IMPACT_CMD_BLOCKXYSTARTI(x, y); + *cfifo = IMPACT_CMD_BLOCKXYENDI(x+a-1, y+h-1); + *cfifo = IMPACT_CMD_IR_ALIAS(0x18); + for (v = 0; v < h; v++) { + *cfifo = IMPACT_CMD_CHAR(*d << 24); + d += b; + } + w -= a; + x += a; + } +} + +static void impact_imageblit(struct fb_info *p, const struct fb_image *image) +{ + unsigned long flags; + spin_lock_irqsave(&PAR(p).lock, flags); + if (!PAR(p).open_flag) + switch(image->depth) { + case 1: + impact_imageblit_1bpp(p, image); + break; + case 8: + impact_imageblit_8bpp(p, image); + break; + } + spin_unlock_irqrestore(&PAR(p).lock, flags); +} + +static int impact_sync(struct fb_info *info) +{ + return 0; +} + +static int impact_blank(int blank_mode, struct fb_info *info) +{ + /* TODO */ + return 0; +} + +static int impact_setcolreg(unsigned regno, unsigned red, unsigned green, + unsigned blue, unsigned transp, struct fb_info *info) +{ + if (regno > 255) + return 1; + ((unsigned *)info->pseudo_palette)[regno] = + (red >> 8) | (green & 0xff00) | ((blue << 8) & 0xff0000); + return 0; +} + +/* ------------------- Framebuffer Access -------------------- */ + +static ssize_t +impact_read(struct file *file, char __user *buf, size_t count, loff_t *ppos) +{ + return -EINVAL; +} + +static ssize_t +impact_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos) +{ + return -EINVAL; +} + +/* --------------------- Userland Access --------------------- */ + +static int +impact_cacheflush(struct fb_info *p, int pool, const struct impact_cf_args *arg) +{ + unsigned short w = arg->box.ws_xpixel << 2; + unsigned short h = arg->box.ws_ypixel; + + if (w && h) + { unsigned long a = arg->bpitch*arg->box.ws_row + (arg->box.ws_col << 2); + unsigned long b = arg->base + PAR(p).pools[pool].size - w; + + for (a += arg->base; h; h--, a += arg->bpitch) + { if (!access_ok(VERIFY_WRITE, (void __user*)a, w)) + return -EFAULT; + if (b <= a) + return -EINVAL; + (*_dma_cache_wback_inv)(a, w); + } + } + return 0; +} + +static int +impact_ioctl(struct fb_info *info, unsigned int cmd, unsigned long arg) +{ + if (!isSR && IPNR != 22 && TCFLSH == cmd) { + static struct impact_cf_args cfpar; + int i; + + if ( copy_from_user(&cfpar,(void __user*)arg,sizeof(cfpar)) ) + return -EFAULT; + + if (!cfpar.base) + return -EINVAL; + + for (i = 0; i < POOLS; i++) + if (cfpar.base == PAR(info).pools[i].uaddr) { + int r = impact_cacheflush(info, i, &cfpar); + /* Might be munmapped behind our back. */ + if (-EFAULT == r) { + printk(KERN_INFO "impact_ioctl: shut down user" + " cache-flush for DMA-pool %d (%p)\n", + i, cfpar.base); + PAR(info).pools[i].uaddr = 0; + } + return r; + } + } + return -EINVAL; +} + +static int impact_mmap(struct fb_info *p, struct vm_area_struct *vma) +{ + unsigned pool, i, n; + unsigned long size = vma->vm_end - vma->vm_start; + unsigned long offset = vma->vm_pgoff << PAGE_SHIFT; + unsigned long start; + + switch(offset) { + case 0x0000000: /* map Impact-registers */ + if (size > (isSR ? 0x200000:0x400000)) + return -EINVAL; + if (vma->vm_pgoff > (~0UL >> PAGE_SHIFT)) + return -EINVAL; + vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); + vma->vm_flags |= VM_IO; + if (remap_pfn_range(vma, vma->vm_start, (MMIO(p)+offset)>>PAGE_SHIFT, + size, vma->vm_page_prot)) + return -EAGAIN; + PAR(p).mmap_flag = 1; + break; + case 0x1000000: /* map e.g. shadow-frame-buffer */ + case 0x2000000: + case 0x3000000: + case 0x8000000: + case 0x9000000: + case 0xa000000: + case 0xb000000: + if (size > (isSR ? 0x1000000:0xc00000)) + return -EINVAL; + pool = (offset >> 24) & 3; /* growonly = (offset>>24) & 8 */ + n = (size + PAGE_SIZE - 1) >> PAGE_SHIFT; + if (n*PAGE_SIZE != PAR(p).pools[pool].size) + impact_resizekpool(p, pool, size, offset & 0x8000000); + if (22 == IPNR) /* IP22 memory may be written uncached */ + vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); + for (start = vma->vm_start, i = 0; i < n; i++) { + if (remap_pfn_range(vma, start, + PAR(p).pools[pool].phys[i] >> PAGE_SHIFT, + PAGE_SIZE, vma->vm_page_prot)) { + PAR(p).pools[pool].uaddr = 0; + return -EAGAIN; + } + start += PAGE_SIZE; + } + PAR(p).pools[pool].uaddr = vma->vm_start; + PAR(p).mmap_flag = 1; + break; + default: + return -EINVAL; + } + return 0; +} + +static int impact_open(struct fb_info *p, int user) +{ + unsigned long flags; + spin_lock_irqsave(&PAR(p).lock, flags); + if (user) + PAR(p).open_flag++; + spin_unlock_irqrestore(&PAR(p).lock, flags); + return 0; +} + +static int impact_release(struct fb_info *p, int user) +{ + unsigned long flags; + spin_lock_irqsave(&PAR(p).lock, flags); + if (user && PAR(p).open_flag) + PAR(p).open_flag--; + spin_unlock_irqrestore(&PAR(p).lock, flags); + return 0; +} + + +/* ------------------------------------------------------------------------- */ + + /* + * Frame buffer operations + */ + +static struct fb_ops impact_ops = { + .owner = THIS_MODULE, + .fb_read = impact_read, + .fb_write = impact_write, + .fb_blank = impact_blank, + .fb_fillrect = impact_fillrect, + .fb_copyarea = impact_copyarea, + .fb_imageblit = impact_imageblit, + .fb_sync = impact_sync, + .fb_ioctl = impact_ioctl, + .fb_setcolreg = impact_setcolreg, + .fb_mmap = impact_mmap, + .fb_open = impact_open, + .fb_release = impact_release, +}; + +/* ------------------------------------------------------------------------- */ + + /* + * Private early console + */ + +#define MMIO_FIXED (isSR ? 0x900000001c000000LL:0x900000001f000000LL) + +static inline void impact_earlyrect(int x, int y, int w, int h, unsigned c) +{ + impact_rect(MMIO_FIXED, x, y, w, h, c, IMPACT_LO_COPY); +} + +static void +impact_paintchar(int x, int y, unsigned char *b, unsigned c, unsigned a) +{ + volatile typeof(IMPACT_CFIFO(0)) *cfifo = &IMPACT_CFIFO(MMIO_FIXED); + int v; + /* Hmm, only the lower 4 bits are taken from red and blue. */ + if (!isSR) a = (a>>4) & 0x0f000f | a & 0x00ff00; + impact_wait_cfifo_empty(MMIO_FIXED); + *cfifo = IMPACT_CMD_PP1FILLMODE(0x6300, IMPACT_LO_COPY); + *cfifo = IMPACT_CMD_FILLMODE(0x400018); + *cfifo = IMPACT_CMD_PACKEDCOLOR(c); + *cfifo = IMPACT_CMD_BKGRD_RG(a & 0xffff); + *cfifo = IMPACT_CMD_BKGRD_BA((a & 0xff0000) >> 16); + *cfifo = IMPACT_CMD_BLOCKXYSTARTI(x, y); + *cfifo = IMPACT_CMD_BLOCKXYENDI(x+7, y+15); + *cfifo = IMPACT_CMD_IR_ALIAS(0x18); + for (v = 0; v < 16; v++) + *cfifo = IMPACT_CMD_CHAR(*b++ << 24); +} +static void impact_earlyhwinit(void) +{ + impact_inithq(MMIO_FIXED); + impact_initrss(MMIO_FIXED); + impact_initxmap(MMIO_FIXED); + impact_initvc3(MMIO_FIXED); +} + +static inline unsigned char *p8x16(unsigned char c) +{ + return ((unsigned char(*)[16])font_vga_8x16.data)[c]; +} + +static void impact_earlywrite(struct console*, const char*, unsigned); +enum { + LightBlue = (230<<16)|(216<<8)|173, + DarkViolet2 = (105<<16)|74, LightGoldenrod = (130<<16)|(221<<8)|238, +}; +#define EARLYBG 0x3f3f3f + +static struct { + int posx, posy; + spinlock_t lock; + struct console console; +} +early = { + .posx = -1, + .lock = __SPIN_LOCK_UNLOCKED(early.lock), + .console = { + .name = "earlyimpact", + .write = impact_earlywrite, + /* + * Omit CON_BOOT, so 'early' shall persist until fbcon takes over! + * Add CON_CONSDEV to detach a possibly active arc boot-console. + */ + .flags = CON_CONSDEV | CON_PRINTBUFFER, + .index = -1, + }, +}; + +void impact_earlychar(unsigned char c) +{ + if (early.posx != -1) { + unsigned long flags; + spin_lock_irqsave(&early.lock, flags); + if (c == '\n') { + early.posy += 16; + if (early.posy >= 800) + early.posy = 0; + early.posx = 0; + goto out; + } + if (early.posx == 0) { + impact_earlyrect(240, 112+early.posy, 800, 16, EARLYBG); + if (early.posy+16*2 < 800) + impact_earlyrect(240, 112+16+early.posy, 800, 16, EARLYBG); + } + impact_paintchar(240+early.posx, 112+early.posy, p8x16(c), 0xffffff, EARLYBG); + early.posx += 8; + if (early.posx >= 800) { + early.posx = 0; + early.posy += 16; + if (early.posy >= 800) + early.posy = 0; + } +out: + spin_unlock_irqrestore(&early.lock, flags); + } +} +void impact_earlystring(char *s) +{ + while (*s) + impact_earlychar(*s++); +} +static void impact_earlywrite(struct console *con, const char *s, unsigned n) +{ + while (n-- && *s) + impact_earlychar(*s++); +} +void __init impact_earlyinit(void) +{ + static int up; + if (!up) { + impact_earlyhwinit(); + impact_framerect(MMIO_FIXED, 0, 0, 1280, 1024, 240, 112, LightBlue); + impact_framerect(MMIO_FIXED, 240-4, 112-4, 800+8, 800+8, 4, 4, LightGoldenrod); + impact_earlyrect(240, 112, 800, 800, EARLYBG); + early.posx = 0; + early.posy = 0; + impact_earlystring("ImpactSR early console ready.\n"); + up++; + } +} +void __init setup_impact_earlycons(void) +{ + static int up; + if (!up) { + impact_earlyinit(); + register_console(&early.console); + up++; + } +} + +/* ------------------------------------------------------------------------- */ + + /* + * Initialization + */ + +static inline unsigned long gfxphysaddr(void) +{ +#if isSR + /* first card in Octane? */ + int xwid = ip30_xtalk_find(IMPACT_XTALK_MFGR, IMPACT_XTALK_PART, + IP30_XTALK_NUM_WID); + return xwid == -1 ? 0:ip30_xtalk_swin(xwid); +#else + extern unsigned long sgi_gfxaddr; /* provided by ARCS */ + return sgi_gfxaddr; +#endif +} + +static void __init impact_hwinit(struct fb_info *info) +{ + early.posx = -1; + /* initialize hardware */ + impact_inithq(MMIO(info)); + impact_initvc3(MMIO(info)); + impact_initrss(MMIO(info)); + impact_initxmap(MMIO(info)); + impact_initdma(info); +} + +static int __init impact_devinit(void) +{ + int i, x, y; + current_par.open_flag = 0; + current_par.mmap_flag = 0; + current_par.lock = __SPIN_LOCK_UNLOCKED(current_par.lock); + + current_par.mmio_base = gfxphysaddr(); + if (!current_par.mmio_base) { + printk(KERN_INFO "impact_devinit: !gfxaddr\n"); + return -EINVAL; + } + current_par.mmio_virt = (unsigned long) + ioremap(current_par.mmio_base, 0x200000); + impact_fix.mmio_start = current_par.mmio_base; + impact_fix.mmio_len = 0x200000; + + /* get board config */ + current_par.num_ge = IMPACT_BDVERS1(current_par.mmio_virt) & 3; + if (!isSR) { + /* To do: desirably remove "... = 1; ". BDVERS1 fits on + * Solid-Impact, but couldn't check High-/Max- yet. + */ + current_par.num_ge = 1; + /* Caveat: XImpact depends on the 'S' in id[6] to distinguish + * between ImpactSR and Impact by examining /proc/fb! + */ + impact_fix.id[6] = '2'; + impact_fix.id[7] = '0' + IPNR - 20; + } + current_par.num_rss = current_par.num_ge; + impact_fix.id[9] = '0' + current_par.num_rss; + + info.flags = FBINFO_FLAG_DEFAULT; + info.screen_base = NULL; + info.fbops = &impact_ops; + info.fix = impact_fix; + info.var = impact_var; + info.par = ¤t_par; + info.pseudo_palette = pseudo_palette; + + /* Can't wait any longer to switch off the early stuff */ + unregister_console(&early.console); + + impact_hwinit(&info); + /* initialize buffers */ + impact_resizekpool(&info, 0, 65536, 0); + for (i = 1; i < USEPOOLS; ++i) + impact_resizekpool(&info, i, 8192, 0); + + /* This has to been done !!! */ + fb_alloc_cmap(&info.cmap, 256, 0); + + if (register_framebuffer(&info) < 0) { + fb_dealloc_cmap(&info.cmap); + return -EINVAL; + } + x = (1280 - impact_var.xres) / 2; + y = (1024 - impact_var.yres) / 2; + + /* Now we can take care of the nice-to-have stuff :-) */ + impact_framerect(MMIO(&info), 0, 0, 1280, 1024, x, y, DarkViolet2); + impact_framerect(MMIO(&info), x-4, y-4, impact_var.xres+8, + impact_var.yres+8, 4, 4, LightGoldenrod); + +#if defined(CONFIG_LOGO) + if (fb_prepare_logo(&info, 0)) { + fb_set_cmap(&info.cmap, &info); + fb_show_logo(&info, 0); + } +#endif + current_par.xoffset = x; + current_par.yoffset = y; + + printk(KERN_INFO "fb%d: %s frame buffer device\n", info.node, info.fix.id); + return 0; +} + +static int __init impact_probe(struct device *dev) +{ + return impact_devinit(); +} + +static struct platform_driver impact_driver = { + .driver = { + .name = (isSR ? "impactsr":"impact"), + .bus = &platform_bus_type, + .probe = impact_probe, + /* add remove someday */ + }, +}; + +static struct platform_device impact_device = { + .name = (isSR ? "impactsr":"impact"), +}; + +static int __init impact_init(void) +{ + int ret = driver_register(&impact_driver.driver); + if (!ret) { + ret = platform_device_register(&impact_device); + if (ret) + driver_unregister(&impact_driver.driver); + } + return ret; +} + +static void __exit impact_exit(void) +{ + driver_unregister(&impact_driver.driver); +} + +module_init(impact_init); +module_exit(impact_exit); + +MODULE_AUTHOR("Stanislaw Skowronek <skylark@xxxxxxxxxxxxxx>, "\ + "Indigo2-adaption: pf <post@xxxxxxxx>"); +MODULE_DESCRIPTION("SGI Octane ImpactSR HQ4, Indigo2 Impact HQ3 Video Driver"); +MODULE_VERSION("R28/R1.7"); +MODULE_LICENSE("GPL"); diff --git a/include/video/impact.h b/include/video/impact.h new file mode 100644 index 0000000..e4b013c --- /dev/null Wed Dec 8 00:46:04 2004 +++ b/include/video/impact.h Mon Jul 25 00:06:58 2011 @@ -0,0 +1,210 @@ +/* + * linux/drivers/video/impactsr.h -- SGI Octane MardiGras (IMPACTSR) graphics + * linux/include/video/impact.h -- SGI Indigo2 MardiGras (IMPACT) graphics + * + * Copyright (c) 2004-2006 by Stanislaw Skowronek (skylark@xxxxxxxxxxxxxx) + * Adapted to Indigo2 by pf, 2005,2006,2009 (post@xxxxxxxx) + * + * 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. + */ + +#ifndef IMPACT_H +#define IMPACT_H + +/* Convenient access macros */ +#define IMPACT_REG64(vma,off) (*(volatile unsigned long long *)((vma)+(off))) +#define IMPACT_REG32(vma,off) (*(volatile unsigned int *)((vma)+(off))) +#define IMPACT_REG16(vma,off) (*(volatile unsigned short *)((vma)+(off))) +#define IMPACT_REG8(vma,off) (*(volatile unsigned char *)((vma)+(off))) + +#if defined(CONFIG_SGI_IP30) /* Octane: Impact for "SpeedRacer" */ + +/* Xtalk */ +#define IMPACTSR_XTALK_MFGR 0x2aa +#define IMPACTSR_XTALK_PART 0xc003 + +/* ImpactSR (HQ4) register offsets */ +#define IMPACT_CFIFO(vma) IMPACT_REG64(vma,0x20400) +#define IMPACT_CFIFOW(vma) IMPACT_REG32(vma,0x20400) +#define IMPACT_CFIFOW1 IMPACT_CFIFOW /* ? ? ? */ +#define IMPACT_CFIFOP(vma) IMPACT_REG64(vma,0x130400) +#define IMPACT_CFIFOPW(vma) IMPACT_REG32(vma,0x130400) +#define IMPACT_CFIFOPW1 IMPACT_CFIFOPW /* ? ? ? */ + +#define IMPACT_STATUS(vma) IMPACT_REG32(vma,0x20000) +#define IMPACT_FIFOSTATUS(vma) IMPACT_REG32(vma,0x20008) +#define IMPACT_GIOSTATUS(vma) IMPACT_REG32(vma,0x20100) +#define IMPACT_DMABUSY(vma) IMPACT_REG32(vma,0x20200) + +#define IMPACT_CFIFO_HW(vma) IMPACT_REG32(vma,0x40000) +#define IMPACT_CFIFO_LW(vma) IMPACT_REG32(vma,0x40008) +#define IMPACT_CFIFO_DELAY(vma) IMPACT_REG32(vma,0x40010) +#define IMPACT_DFIFO_HW(vma) IMPACT_REG32(vma,0x40020) +#define IMPACT_DFIFO_LW(vma) IMPACT_REG32(vma,0x40028) +#define IMPACT_DFIFO_DELAY(vma) IMPACT_REG32(vma,0x40030) + +#define IMPACT_XMAP_OFF(off) (0x71c00+(off)) +#define IMPACT_VC3_OFF(off) (0x72000+(off)) +#define IMPACT_RSS_OFF(off) (0x2c000+(off)) + +#else /* Indigo2: IP28, IP26, IP22: Impact graphics */ + +/* Impact (HQ3) register offsets */ +#define IMPACT_CFIFO(vma) IMPACT_REG64(vma,0x70080) +#define IMPACT_CFIFOW(vma) IMPACT_REG32(vma,0x70080) +#define IMPACT_CFIFOW1(vma) IMPACT_REG32(vma,0x70084) +#define IMPACT_CFIFOP(vma) IMPACT_REG64(vma,0x50080) +#define IMPACT_CFIFOPW(vma) IMPACT_REG32(vma,0x50080) +#define IMPACT_CFIFOPW1(vma) IMPACT_REG32(vma,0x50084) + +#define IMPACT_STATUS(vma) IMPACT_REG32(vma,0x70000) +#define IMPACT_FIFOSTATUS(vma) IMPACT_REG32(vma,0x70004) +#define IMPACT_GIOSTATUS(vma) IMPACT_REG32(vma,0x70100) +#define IMPACT_DMABUSY(vma) IMPACT_REG32(vma,0x70104) + +#define IMPACT_CFIFO_HW(vma) IMPACT_REG32(vma,0x50020) +#define IMPACT_CFIFO_LW(vma) IMPACT_REG32(vma,0x50024) +#define IMPACT_CFIFO_DELAY(vma) IMPACT_REG32(vma,0x50028) +#define IMPACT_DFIFO_HW(vma) IMPACT_REG32(vma,0x5002c) +#define IMPACT_DFIFO_LW(vma) IMPACT_REG32(vma,0x50030) +#define IMPACT_DFIFO_DELAY(vma) IMPACT_REG32(vma,0x50034) + +#define IMPACT_XMAP_OFF(off) (0x61c00+(off)) +#define IMPACT_VC3_OFF(off) (0x62000+(off)) +#define IMPACT_RSS_OFF(off) (0x7c000+(off)) + +#endif + +#define IMPACT_RESTATUS(vma) IMPACT_REG32(vma,IMPACT_RSS_OFF(0x578)) + +#define IMPACT_XMAP_PP1SELECT(vma) IMPACT_REG8(vma,IMPACT_XMAP_OFF(0x008)) +#define IMPACT_XMAP_INDEX(vma) IMPACT_REG8(vma,IMPACT_XMAP_OFF(0x088)) +#define IMPACT_XMAP_CONFIG(vma) IMPACT_REG32(vma,IMPACT_XMAP_OFF(0x100)) +#define IMPACT_XMAP_CONFIGB(vma) IMPACT_REG8(vma,IMPACT_XMAP_OFF(0x108)) +#define IMPACT_XMAP_BUF_SELECT(vma) IMPACT_REG32(vma,IMPACT_XMAP_OFF(0x180)) +#define IMPACT_XMAP_MAIN_MODE(vma) IMPACT_REG32(vma,IMPACT_XMAP_OFF(0x200)) +#define IMPACT_XMAP_OVERLAY_MODE(vma) IMPACT_REG32(vma,IMPACT_XMAP_OFF(0x280)) +#define IMPACT_XMAP_DIB(vma) IMPACT_REG32(vma,IMPACT_XMAP_OFF(0x300)) +#define IMPACT_XMAP_DIB_DW(vma) IMPACT_REG32(vma,IMPACT_XMAP_OFF(0x340)) +#define IMPACT_XMAP_RE_RAC(vma) IMPACT_REG32(vma,IMPACT_XMAP_OFF(0x380)) + +#define IMPACT_VC3_INDEX(vma) IMPACT_REG8(vma,IMPACT_VC3_OFF(0x008)) +#define IMPACT_VC3_INDEXDATA(vma) IMPACT_REG32(vma,IMPACT_VC3_OFF(0x038)) +#define IMPACT_VC3_DATA(vma) IMPACT_REG16(vma,IMPACT_VC3_OFF(0x0b0)) +#define IMPACT_VC3_RAM(vma) IMPACT_REG16(vma,IMPACT_VC3_OFF(0x190)) + +#define IMPACT_BDVERS0(vma) IMPACT_REG8(vma,IMPACT_VC3_OFF(0x408)) +#define IMPACT_BDVERS1(vma) IMPACT_REG8(vma,IMPACT_VC3_OFF(0x488)) + +/* FIFO status */ +#if defined(CONFIG_SGI_IP30) +#define IMPACT_CFIFO_MAX 128 +#else +#define IMPACT_CFIFO_MAX 64 +#endif +#define IMPACT_BFIFO_MAX 16 + +/* Commands for CFIFO */ +static __inline__ +unsigned long long ImpactCmdCFifo64( unsigned cmd, unsigned reg, unsigned val ) +{ + return (unsigned long long)(cmd | reg<<8) << 32 | val; +} +static __inline__ +unsigned long long ImpactCmdWriteRSS( unsigned reg, unsigned val ) +{ + return (0x00180004LL | reg<<8) << 32 | val; +} +static __inline__ +unsigned long long ImpactCmdExecRSS( unsigned reg, unsigned val ) +{ + return (0x001c0004LL | reg<<8) << 32 | val; +} + +#define IMPACT_CMD_GLINE_XSTARTF(v) ImpactCmdWriteRSS(0x00c,v) +#define IMPACT_CMD_IR_ALIAS(v) ImpactCmdExecRSS(0x045,v) +#define IMPACT_CMD_BLOCKXYSTARTI(x,y) ImpactCmdWriteRSS(0x046,((x)<<16)|(y)) +#define IMPACT_CMD_BLOCKXYENDI(x,y) ImpactCmdWriteRSS(0x047,((x)<<16)|(y)) +#define IMPACT_CMD_PACKEDCOLOR(v) ImpactCmdWriteRSS(0x05b,v) +#define IMPACT_CMD_RED(v) ImpactCmdWriteRSS(0x05c,v) +#define IMPACT_CMD_ALPHA(v) ImpactCmdWriteRSS(0x05f,v) +#define IMPACT_CMD_CHAR(v) ImpactCmdExecRSS(0x070,v) +#define IMPACT_CMD_CHAR_H(v) ImpactCmdWriteRSS(0x070,v) +#define IMPACT_CMD_CHAR_L(v) ImpactCmdExecRSS(0x071,v) +#define IMPACT_CMD_XFRCONTROL(v) ImpactCmdWriteRSS(0x102,v) +#define IMPACT_CMD_FILLMODE(v) ImpactCmdWriteRSS(0x110,v) +#define IMPACT_CMD_CONFIG(v) ImpactCmdWriteRSS(0x112,v) +#define IMPACT_CMD_XYWIN(x,y) ImpactCmdWriteRSS(0x115,((y)<<16)|(x)) +#define IMPACT_CMD_BKGRD_RG(v) ImpactCmdWriteRSS(0x140,((v)<<8)) +#define IMPACT_CMD_BKGRD_BA(v) ImpactCmdWriteRSS(0x141,((v)<<8)) +#define IMPACT_CMD_WINMODE(v) ImpactCmdWriteRSS(0x14f,v) +#define IMPACT_CMD_XFRSIZE(x,y) ImpactCmdWriteRSS(0x153,((y)<<16)|(x)) +#define IMPACT_CMD_XFRMASKLO(v) ImpactCmdWriteRSS(0x156,v) +#define IMPACT_CMD_XFRMASKHI(v) ImpactCmdWriteRSS(0x157,v) +#define IMPACT_CMD_XFRCOUNTERS(x,y) ImpactCmdWriteRSS(0x158,((y)<<16)|(x)) +#define IMPACT_CMD_XFRMODE(v) ImpactCmdWriteRSS(0x159,v) +#define IMPACT_CMD_RE_TOGGLECNTX(v) ImpactCmdWriteRSS(0x15f,v) +#define IMPACT_CMD_PIXCMD(v) ImpactCmdWriteRSS(0x160,v) +#define IMPACT_CMD_PP1FILLMODE(m,o) ImpactCmdWriteRSS(0x161,(m)|(o<<26)) +#define IMPACT_CMD_COLORMASKMSBS(v) ImpactCmdWriteRSS(0x162,v) +#define IMPACT_CMD_COLORMASKLSBSA(v) ImpactCmdWriteRSS(0x163,v) +#define IMPACT_CMD_COLORMASKLSBSB(v) ImpactCmdWriteRSS(0x164,v) +#define IMPACT_CMD_BLENDFACTOR(v) ImpactCmdWriteRSS(0x165,v) +#define IMPACT_CMD_DRBPOINTERS(v) ImpactCmdWriteRSS(0x16d,v) + +#define IMPACT_CMD_HQ_PIXELFORMAT(v) ImpactCmdCFifo64(0x000c0004,0,v) +#define IMPACT_CMD_HQ_SCANWIDTH(v) ImpactCmdCFifo64(0x000a0204,0,v) +#define IMPACT_CMD_HQ_DMATYPE(v) ImpactCmdCFifo64(0x000a0604,0,v) +#define IMPACT_CMD_HQ_PG_LIST_0(v) ImpactCmdCFifo64(0x00080004,0,v) +#define IMPACT_CMD_HQ_PG_WIDTH(v) ImpactCmdCFifo64(0x00080404,0,v) +#define IMPACT_CMD_HQ_PG_OFFSET(v) ImpactCmdCFifo64(0x00080504,0,v) +#define IMPACT_CMD_HQ_PG_STARTADDR(v) ImpactCmdCFifo64(0x00080604,0,v) +#define IMPACT_CMD_HQ_PG_LINECNT(v) ImpactCmdCFifo64(0x00080704,0,v) +#define IMPACT_CMD_HQ_PG_WIDTHA(v) ImpactCmdCFifo64(0x00080804,0,v) +#define IMPACT_CMD_HQ_DMACTRL_0(v) (0x00080b04000000b1LL|(v)&8) +#define IMPACT_CMD_HQ_TXBASE(p) (0x00482008|((p)<<9)) +#define IMPACT_CMD_HQ_TXMAX(p,v) ImpactCmdCFifo64(0x00483004,p,v) +#define IMPACT_CMD_HQ_PGBITS(p,v) ImpactCmdCFifo64(0x00482b04,p,v) +#define IMPACT_CMD_HQ_PGSIZE(v) ImpactCmdCFifo64(0x00482a04,0,v) +#define IMPACT_CMD_HQ_STACKPTR(v) ImpactCmdCFifo64(0x00483a04,0,v) +#define IMPACT_CMD_HQ_484A(p,v) ImpactCmdCFifo64(0x00484a04,p,v) +#define IMPACT_CMD_HQ_484B(p,v) ImpactCmdCFifo64(0x00484b04,p,v) + +/* Logic operations for the PP1 (SI=source invert, DI=dest invert, RI=result invert) */ +#define IMPACT_LO_CLEAR 0 +#define IMPACT_LO_AND 1 +#define IMPACT_LO_DIAND 2 +#define IMPACT_LO_COPY 3 +#define IMPACT_LO_SIAND 4 +#define IMPACT_LO_NOP 5 +#define IMPACT_LO_XOR 6 +#define IMPACT_LO_OR 7 +#define IMPACT_LO_RIOR 8 +#define IMPACT_LO_RIXOR 9 +#define IMPACT_LO_RINOP 10 +#define IMPACT_LO_DIOR 11 +#define IMPACT_LO_RICOPY 12 +#define IMPACT_LO_SIOR 13 +#define IMPACT_LO_RIAND 14 +#define IMPACT_LO_SET 15 + +/* Blending factors */ +#define IMPACT_BLEND_ALPHA 0x0704c900 + +#ifdef __KERNEL__ +extern void impact_earlychar(unsigned char c); +extern void impact_earlystring(char *s); +extern void impact_earlyinit(void); +extern void setup_impact_earlycons(void); +#endif + +struct impact_cf_args +{ + struct winsize box; /* termios.h */ + unsigned long long base; + unsigned bpitch; +}; + +#endif /* IMPACT_H */