diff options
Diffstat (limited to 'xorg-server/hw/kdrive/i810/i810.c')
-rw-r--r-- | xorg-server/hw/kdrive/i810/i810.c | 2112 |
1 files changed, 2112 insertions, 0 deletions
diff --git a/xorg-server/hw/kdrive/i810/i810.c b/xorg-server/hw/kdrive/i810/i810.c new file mode 100644 index 000000000..49090f9eb --- /dev/null +++ b/xorg-server/hw/kdrive/i810/i810.c @@ -0,0 +1,2112 @@ +/* COPYRIGHT AND PERMISSION NOTICE + +Copyright (c) 2000, 2001 Nokia Home Communications + +All rights reserved. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, and/or sell copies of the Software, and to permit persons +to whom the Software is furnished to do so, provided that the above +copyright notice(s) and this permission notice appear in all copies of +the Software and that both the above copyright notice(s) and this +permission notice appear in supporting documentation. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT +OF THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR +HOLDERS INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY +SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER +RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF +CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN +CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + +Except as contained in this notice, the name of a copyright holder +shall not be used in advertising or otherwise to promote the sale, use +or other dealings in this Software without prior written authorization +of the copyright holder. + +X Window System is a trademark of The Open Group */ + +/* + * i810.c - KDrive driver for the i810 chipset + * + * Authors: + * Pontus Lidman <pontus.lidman@nokia.com> + * + */ + +#ifdef HAVE_CONFIG_H +#include <kdrive-config.h> +#endif +#include "kdrive.h" +#include "kxv.h" +#include "klinux.h" + +#include "i810.h" +#include "agp.h" + +#include "i810draw.h" + +#ifndef I810_DEBUG +int I810_DEBUG = (0 +/* | DEBUG_ALWAYS_SYNC */ +/* | DEBUG_VERBOSE_ACCEL */ +/* | DEBUG_VERBOSE_SYNC */ +/* | DEBUG_VERBOSE_VGA */ +/* | DEBUG_VERBOSE_RING */ +/* | DEBUG_VERBOSE_OUTREG */ +/* | DEBUG_VERBOSE_MEMORY */ +/* | DEBUG_VERBOSE_CURSOR */ + ); +#endif + + +static Bool +i810ModeInit(KdScreenInfo *screen, const KdMonitorTiming *t); + +static void +i810PrintMode( vgaRegPtr vgaReg, I810RegPtr mode ); + +Bool +i810CardInit (KdCardInfo *card) +{ + int i; + + I810CardInfo *i810c; + +/* fprintf(stderr,"i810CardInit\n"); */ + + i810c = (I810CardInfo *) xalloc (sizeof (I810CardInfo)); + + if (!i810c) + return FALSE; + + /* 2MB Video RAM */ + i810c->videoRam=2048; + + /* Find FB address */ + + if (card->attr.address[1] != 0) { + i810c->LinearAddr = card->attr.address[0] & 0xFF000000; + + if (!i810c->LinearAddr) { + fprintf(stderr,"No valid FB address in PCI config space(1)\n"); + xfree(i810c); + return FALSE; + } else { +/* fprintf(stderr,"Linear framebuffer at %lx\n",i810c->LinearAddr); */ + } + } else { + fprintf(stderr,"No valid FB address in PCI config space(2)\n"); + xfree(i810c); + return FALSE; + } + + if (card->attr.address[1]) { + + i810c->MMIOAddr = card->attr.address[1] & 0xFFF80000; + + i810c->MMIOBase = + KdMapDevice (i810c->MMIOAddr, I810_REG_SIZE); + if (!i810c->MMIOBase) { + fprintf(stderr,"No valid MMIO address in PCI config space(1)\n"); + xfree(i810c); + return FALSE; + } else { + + } + } else { + fprintf(stderr,"No valid MMIO address in PCI config space(2)\n"); + xfree(i810c); + return FALSE; + } + +/* fprintf(stderr,"Mapped 0x%x bytes of MMIO regs at phys 0x%lx virt %p\n", */ +/* I810_REG_SIZE,i810c->MMIOAddr,i810c->MMIOBase); */ + + /* Find out memory bus frequency. + */ + + { + unsigned long *p; + + if (!(p= (unsigned long *) LinuxGetPciCfg(&card->attr))) + return FALSE; + +/* fprintf(stderr,"Frequency long %lx\n",p[WHTCFG_PAMR_DRP]); */ + + if ( (p[WHTCFG_PAMR_DRP] & LM_FREQ_MASK) == LM_FREQ_133 ) + i810c->LmFreqSel = 133; + else + i810c->LmFreqSel = 100; + + xfree(p); + +/* fprintf(stderr,"Selected frequency %d\n",i810c->LmFreqSel); */ + } + +/* fprintf(stderr,"Will alloc AGP framebuffer: %d kByte\n",i810c->videoRam); */ + + /* Since we always want write combining on first 32 mb of framebuffer + * we pass a mapsize of 32 mb */ + i810c->FbMapSize = 32*1024*1024; + + for (i = 2 ; i < i810c->FbMapSize ; i <<= 1); + i810c->FbMapSize = i; + + i810c->FbBase = + KdMapDevice (i810c->LinearAddr, i810c->FbMapSize); + + if (!i810c->FbBase) return FALSE; +/* fprintf(stderr,"Mapped 0x%lx bytes of framebuffer at %p\n", */ +/* i810c->FbMapSize,i810c->FbBase); */ + + card->driver=i810c; + + return TRUE; +} + +static void +i810ScreenFini (KdScreenInfo *screen) +{ + I810ScreenInfo *i810s = (I810ScreenInfo *) screen->driver; + + xfree (i810s); + screen->driver = 0; +} + +static Bool +i810InitScreen (ScreenPtr pScreen) { + +#ifdef XV + i810InitVideo(pScreen); +#endif + return TRUE; +} + +static Bool +i810FinishInitScreen(ScreenPtr pScreen) +{ + /* XXX: RandR init */ + return TRUE; +} + +static void +i810CardFini (KdCardInfo *card) +{ + I810CardInfo *i810c = (I810CardInfo *) card->driver; + + KdUnmapDevice (i810c->FbBase, i810c->FbMapSize); + KdUnmapDevice (i810c->MMIOBase, I810_REG_SIZE); + xfree (i810c); + card->driver = 0; +} + +struct wm_info { + double freq; + unsigned int wm; +}; + +struct wm_info i810_wm_8_100[] = { + { 0, 0x22003000 }, + { 25.2, 0x22003000 }, + { 28.0, 0x22003000 }, + { 31.5, 0x22003000 }, + { 36.0, 0x22007000 }, + { 40.0, 0x22007000 }, + { 45.0, 0x22007000 }, + { 49.5, 0x22008000 }, + { 50.0, 0x22008000 }, + { 56.3, 0x22008000 }, + { 65.0, 0x22008000 }, + { 75.0, 0x22008000 }, + { 78.8, 0x22008000 }, + { 80.0, 0x22008000 }, + { 94.0, 0x22008000 }, + { 96.0, 0x22107000 }, + { 99.0, 0x22107000 }, + { 108.0, 0x22107000 }, + { 121.0, 0x22107000 }, + { 128.9, 0x22107000 }, + { 132.0, 0x22109000 }, + { 135.0, 0x22109000 }, + { 157.5, 0x2210b000 }, + { 162.0, 0x2210b000 }, + { 175.5, 0x2210b000 }, + { 189.0, 0x2220e000 }, + { 202.5, 0x2220e000 } +}; + +struct wm_info i810_wm_16_100[] = { + { 0, 0x22004000 }, + { 25.2, 0x22006000 }, + { 28.0, 0x22006000 }, + { 31.5, 0x22007000 }, + { 36.0, 0x22007000 }, + { 40.0, 0x22007000 }, + { 45.0, 0x22007000 }, + { 49.5, 0x22009000 }, + { 50.0, 0x22009000 }, + { 56.3, 0x22108000 }, + { 65.0, 0x2210e000 }, + { 75.0, 0x2210e000 }, + { 78.8, 0x2210e000 }, + { 80.0, 0x22210000 }, + { 94.5, 0x22210000 }, + { 96.0, 0x22210000 }, + { 99.0, 0x22210000 }, + { 108.0, 0x22210000 }, + { 121.0, 0x22210000 }, + { 128.9, 0x22210000 }, + { 132.0, 0x22314000 }, + { 135.0, 0x22314000 }, + { 157.5, 0x22415000 }, + { 162.0, 0x22416000 }, + { 175.5, 0x22416000 }, + { 189.0, 0x22416000 }, + { 195.0, 0x22416000 }, + { 202.5, 0x22416000 } +}; + + +struct wm_info i810_wm_24_100[] = { + { 0, 0x22006000 }, + { 25.2, 0x22009000 }, + { 28.0, 0x22009000 }, + { 31.5, 0x2200a000 }, + { 36.0, 0x2210c000 }, + { 40.0, 0x2210c000 }, + { 45.0, 0x2210c000 }, + { 49.5, 0x22111000 }, + { 50.0, 0x22111000 }, + { 56.3, 0x22111000 }, + { 65.0, 0x22214000 }, + { 75.0, 0x22214000 }, + { 78.8, 0x22215000 }, + { 80.0, 0x22216000 }, + { 94.5, 0x22218000 }, + { 96.0, 0x22418000 }, + { 99.0, 0x22418000 }, + { 108.0, 0x22418000 }, + { 121.0, 0x22418000 }, + { 128.9, 0x22419000 }, + { 132.0, 0x22519000 }, + { 135.0, 0x4441d000 }, + { 157.5, 0x44419000 }, + { 162.0, 0x44419000 }, + { 175.5, 0x44419000 }, + { 189.0, 0x44419000 }, + { 195.0, 0x44419000 }, + { 202.5, 0x44419000 } +}; + +struct wm_info i810_wm_32_100[] = { + { 0, 0x2210b000 }, + { 60, 0x22415000 }, /* 0x314000 works too */ + { 80, 0x22419000 } /* 0x518000 works too */ +}; + + +struct wm_info i810_wm_8_133[] = { + { 0, 0x22003000 }, + { 25.2, 0x22003000 }, + { 28.0, 0x22003000 }, + { 31.5, 0x22003000 }, + { 36.0, 0x22007000 }, + { 40.0, 0x22007000 }, + { 45.0, 0x22007000 }, + { 49.5, 0x22008000 }, + { 50.0, 0x22008000 }, + { 56.3, 0x22008000 }, + { 65.0, 0x22008000 }, + { 75.0, 0x22008000 }, + { 78.8, 0x22008000 }, + { 80.0, 0x22008000 }, + { 94.0, 0x22008000 }, + { 96.0, 0x22107000 }, + { 99.0, 0x22107000 }, + { 108.0, 0x22107000 }, + { 121.0, 0x22107000 }, + { 128.9, 0x22107000 }, + { 132.0, 0x22109000 }, + { 135.0, 0x22109000 }, + { 157.5, 0x2210b000 }, + { 162.0, 0x2210b000 }, + { 175.5, 0x2210b000 }, + { 189.0, 0x2220e000 }, + { 202.5, 0x2220e000 } +}; + + +struct wm_info i810_wm_16_133[] = { + { 0, 0x22004000 }, + { 25.2, 0x22006000 }, + { 28.0, 0x22006000 }, + { 31.5, 0x22007000 }, + { 36.0, 0x22007000 }, + { 40.0, 0x22007000 }, + { 45.0, 0x22007000 }, + { 49.5, 0x22009000 }, + { 50.0, 0x22009000 }, + { 56.3, 0x22108000 }, + { 65.0, 0x2210e000 }, + { 75.0, 0x2210e000 }, + { 78.8, 0x2210e000 }, + { 80.0, 0x22210000 }, + { 94.5, 0x22210000 }, + { 96.0, 0x22210000 }, + { 99.0, 0x22210000 }, + { 108.0, 0x22210000 }, + { 121.0, 0x22210000 }, + { 128.9, 0x22210000 }, + { 132.0, 0x22314000 }, + { 135.0, 0x22314000 }, + { 157.5, 0x22415000 }, + { 162.0, 0x22416000 }, + { 175.5, 0x22416000 }, + { 189.0, 0x22416000 }, + { 195.0, 0x22416000 }, + { 202.5, 0x22416000 } +}; + +struct wm_info i810_wm_24_133[] = { + { 0, 0x22006000 }, + { 25.2, 0x22009000 }, + { 28.0, 0x22009000 }, + { 31.5, 0x2200a000 }, + { 36.0, 0x2210c000 }, + { 40.0, 0x2210c000 }, + { 45.0, 0x2210c000 }, + { 49.5, 0x22111000 }, + { 50.0, 0x22111000 }, + { 56.3, 0x22111000 }, + { 65.0, 0x22214000 }, + { 75.0, 0x22214000 }, + { 78.8, 0x22215000 }, + { 80.0, 0x22216000 }, + { 94.5, 0x22218000 }, + { 96.0, 0x22418000 }, + { 99.0, 0x22418000 }, + { 108.0, 0x22418000 }, + { 121.0, 0x22418000 }, + { 128.9, 0x22419000 }, + { 132.0, 0x22519000 }, + { 135.0, 0x4441d000 }, + { 157.5, 0x44419000 }, + { 162.0, 0x44419000 }, + { 175.5, 0x44419000 }, + { 189.0, 0x44419000 }, + { 195.0, 0x44419000 }, + { 202.5, 0x44419000 } +}; + +static void +i810WriteControlMMIO(I810CardInfo *i810c, int addr, CARD8 index, CARD8 val) { + moutb(addr, index); + moutb(addr+1, val); +} + +static CARD8 +i810ReadControlMMIO(I810CardInfo *i810c, int addr, CARD8 index) { + moutb(addr, index); + return minb(addr+1); +} + +static Bool +i810ModeSupported (KdScreenInfo *screen, const KdMonitorTiming *t) +{ + /* This is just a guess. */ + if (t->horizontal > 1600 || t->horizontal < 640) return FALSE; + if (t->vertical > 1200 || t->horizontal < 350) return FALSE; + return TRUE; +} + +static Bool +i810ModeUsable (KdScreenInfo *screen) +{ + KdCardInfo *card = screen->card; + I810CardInfo *i810c = (I810CardInfo *) card->driver; + int byte_width, pixel_width, screen_size; + +/* fprintf(stderr,"i810ModeUsable\n"); */ + + if (screen->fb[0].depth >= 24) + { + screen->fb[0].depth = 24; + screen->fb[0].bitsPerPixel = 24; + screen->dumb = TRUE; + } + else if (screen->fb[0].depth >= 16) + { + screen->fb[0].depth = 16; + screen->fb[0].bitsPerPixel = 16; + } + else if (screen->fb[0].depth >= 15) + { + screen->fb[0].depth = 15; + screen->fb[0].bitsPerPixel = 16; + } + else + { + screen->fb[0].depth = 8; + screen->fb[0].bitsPerPixel = 8; + } + byte_width = screen->width * (screen->fb[0].bitsPerPixel >> 3); + pixel_width = screen->width; + + screen->fb[0].pixelStride = pixel_width; + screen->fb[0].byteStride = byte_width; + + screen_size = byte_width * screen->height; + + return screen_size <= (i810c->videoRam * 1024); +} + +static int i810AllocateGARTMemory( KdScreenInfo *screen ) +{ + KdCardInfo *card = screen->card; + I810CardInfo *i810c = (I810CardInfo *) card->driver; + unsigned long size = i810c->videoRam * 1024; + + int key; + long tom = 0; + unsigned long physical; + + if (!KdAgpGARTSupported()) + return FALSE; + + if (!KdAcquireGART(screen->mynum)) + return FALSE; + + /* This allows the 2d only Xserver to regen */ + i810c->agpAcquired2d = TRUE; + + /* Treat the gart like video memory - we assume we own all that is + * there, so ignore EBUSY errors. Don't try to remove it on + * failure, either, as other X server may be using it. + */ + + if ((key = KdAllocateGARTMemory(screen->mynum, size, 0, NULL)) == -1) + return FALSE; + + i810c->VramOffset = 0; + i810c->VramKey = key; + + if (!KdBindGARTMemory(screen->mynum, key, 0)) + return FALSE; + + + i810c->SysMem.Start = 0; + i810c->SysMem.Size = size; + i810c->SysMem.End = size; + i810c->SavedSysMem = i810c->SysMem; + + tom = i810c->SysMem.End; + + i810c->DcacheMem.Start = 0; + i810c->DcacheMem.End = 0; + i810c->DcacheMem.Size = 0; + i810c->CursorPhysical = 0; + + /* Dcache - half the speed of normal ram, so not really useful for + * a 2d server. Don't bother reporting its presence. This is + * mapped in addition to the requested amount of system ram. + */ + size = 1024 * 4096; + + /* Keep it 512K aligned for the sake of tiled regions. + */ + tom += 0x7ffff; + tom &= ~0x7ffff; + + if ((key = KdAllocateGARTMemory(screen->mynum, size, AGP_DCACHE_MEMORY, NULL)) != -1) { + i810c->DcacheOffset= tom; + i810c->DcacheKey = key; + if (!KdBindGARTMemory(screen->mynum, key, tom)) { + fprintf(stderr,"Allocation of %ld bytes for DCACHE failed\n", size); + i810c->DcacheKey = -1; + } else { + i810c->DcacheMem.Start = tom; + i810c->DcacheMem.Size = size; + i810c->DcacheMem.End = i810c->DcacheMem.Start + i810c->DcacheMem.Size; + tom = i810c->DcacheMem.End; + } + } else { + fprintf(stderr, + "No physical memory available for %ld bytes of DCACHE\n", + size); + i810c->DcacheKey = -1; + } + + /* Mouse cursor -- The i810 (crazy) needs a physical address in + * system memory from which to upload the cursor. We get this from + * the agpgart module using a special memory type. + */ + + /* 4k for the cursor is excessive, I'm going to steal 3k for + * overlay registers later + */ + + size = 4096; + + if ((key = KdAllocateGARTMemory(screen->mynum, size, AGP_PHYS_MEMORY, + &physical)) == -1) { + fprintf(stderr, + "No physical memory available for HW cursor\n"); + i810c->HwcursKey = -1; + } else { + i810c->HwcursOffset= tom; + i810c->HwcursKey = key; + if (!KdBindGARTMemory(screen->mynum, key, tom)) { + fprintf(stderr, + "Allocation of %ld bytes for HW cursor failed\n", + size); + i810c->HwcursKey = -1; + } else { + i810c->CursorPhysical = physical; + i810c->CursorStart = tom; + tom += size; + } + } + + /* Overlay register buffer -- Just like the cursor, the i810 needs a + * physical address in system memory from which to upload the overlay + * registers. + */ + if (i810c->CursorStart != 0) { + i810c->OverlayPhysical = i810c->CursorPhysical + 1024; + i810c->OverlayStart = i810c->CursorStart + 1024; + } + + + i810c->GttBound = 1; + + return TRUE; +} + +/* Allocate from a memrange, returns success */ + +static int i810AllocLow( I810MemRange *result, I810MemRange *pool, int size ) +{ + if (size > pool->Size) return FALSE; + + pool->Size -= size; + result->Size = size; + result->Start = pool->Start; + result->End = pool->Start += size; + return TRUE; +} + +static int i810AllocHigh( I810MemRange *result, I810MemRange *pool, int size ) +{ + if (size > pool->Size) return 0; + + pool->Size -= size; + result->Size = size; + result->End = pool->End; + result->Start = pool->End -= size; + return 1; +} + +static Bool +i810AllocateFront(KdScreenInfo *screen) { + + KdCardInfo *card = screen->card; + I810CardInfo *i810c = (I810CardInfo *) card->driver; + + int cache_lines = -1; + + if(i810c->DoneFrontAlloc) + return TRUE; + + memset(&(i810c->FbMemBox), 0, sizeof(BoxRec)); + /* Alloc FrontBuffer/Ring/Accel memory */ + i810c->FbMemBox.x1=0; + i810c->FbMemBox.x2=screen->width; + i810c->FbMemBox.y1=0; + i810c->FbMemBox.y2=screen->height; + + /* This could be made a command line option */ + cache_lines = 0; + + if(cache_lines >= 0) + i810c->FbMemBox.y2 += cache_lines; + else { + /* make sure there is enough for two DVD sized YUV buffers */ + i810c->FbMemBox.y2 += (screen->fb[0].depth == 24) ? 256 : 384; + if (screen->width <= 1024) + i810c->FbMemBox.y2 += (screen->fb[0].depth == 24) ? 256 : 384; + cache_lines = i810c->FbMemBox.y2 - screen->height; + } + + if (I810_DEBUG) + ErrorF("Adding %i scanlines for pixmap caching\n", cache_lines); + + /* Reserve room for the framebuffer and pixcache. Put at the top + * of memory so we can have nice alignment for the tiled regions at + * the start of memory. + */ + i810AllocLow( &(i810c->FrontBuffer), + &(i810c->SysMem), + ((i810c->FbMemBox.x2 * + i810c->FbMemBox.y2 * + i810c->cpp) + 4095) & ~4095); + + memset( &(i810c->LpRing), 0, sizeof( I810RingBuffer ) ); + if(i810AllocLow( &(i810c->LpRing.mem), &(i810c->SysMem), 16*4096 )) { + if (I810_DEBUG & DEBUG_VERBOSE_MEMORY) + ErrorF( "ring buffer at local %lx\n", + i810c->LpRing.mem.Start); + + i810c->LpRing.tail_mask = i810c->LpRing.mem.Size - 1; + i810c->LpRing.virtual_start = i810c->FbBase + i810c->LpRing.mem.Start; + i810c->LpRing.head = 0; + i810c->LpRing.tail = 0; + i810c->LpRing.space = 0; + } + + if ( i810AllocLow( &i810c->Scratch, &(i810c->SysMem), 64*1024 ) || + i810AllocLow( &i810c->Scratch, &(i810c->SysMem), 16*1024 ) ) { + if (I810_DEBUG & DEBUG_VERBOSE_MEMORY) + ErrorF("Allocated Scratch Memory\n"); + } + +#ifdef XV + /* 720x720 is just how much memory the mpeg player needs for overlays */ + + if ( i810AllocHigh( &i810c->XvMem, &(i810c->SysMem), 720*720*2 )) { + if (I810_DEBUG & DEBUG_VERBOSE_MEMORY) + ErrorF("Allocated overlay Memory\n"); + } +#endif + + i810c->DoneFrontAlloc = TRUE; + return TRUE; +} + +static Bool +i810MapMem(KdScreenInfo *screen) +{ + + KdCardInfo *card = screen->card; + I810CardInfo *i810c = (I810CardInfo *) card->driver; + + i810c->LpRing.virtual_start = i810c->FbBase + i810c->LpRing.mem.Start; + + return TRUE; +} + + +Bool +i810ScreenInit (KdScreenInfo *screen) +{ + KdCardInfo *card = screen->card; + I810CardInfo *i810c = (I810CardInfo *) card->driver; + I810ScreenInfo *i810s; + + int i; + + const KdMonitorTiming *t; + +/* fprintf(stderr,"i810ScreenInit\n"); */ + + i810s = (I810ScreenInfo *) xalloc (sizeof (I810ScreenInfo)); + if (!i810s) + return FALSE; + + memset (i810s, '\0', sizeof (I810ScreenInfo)); + + i810s->i810c = i810c; + + /* Default dimensions */ + if (!screen->width || !screen->height) + { + screen->width = 720; + screen->height = 576; + screen->rate = 52; +#if 0 + screen->width = 1024; + screen->height = 768; + screen->rate = 72; +#endif + } + + if (!screen->fb[0].depth) + screen->fb[0].depth = 16; + + t = KdFindMode (screen, i810ModeSupported); + + screen->rate = t->rate; + screen->width = t->horizontal; + screen->height = t->vertical; + + if (!KdTuneMode (screen, i810ModeUsable, i810ModeSupported)) + { + xfree (i810c); + return FALSE; + } + +/* fprintf(stderr,"Screen rate %d horiz %d vert %d\n",t->rate,t->horizontal,t->vertical); */ + + switch (screen->fb[0].depth) { + case 8: + screen->fb[0].visuals = ((1 << StaticGray) | + (1 << GrayScale) | + (1 << StaticColor) | + (1 << PseudoColor) | + (1 << TrueColor) | + (1 << DirectColor)); + screen->fb[0].blueMask = 0x00; + screen->fb[0].greenMask = 0x00; + screen->fb[0].redMask = 0x00; + break; + case 15: + screen->fb[0].visuals = (1 << TrueColor); + screen->fb[0].blueMask = 0x001f; + screen->fb[0].greenMask = 0x03e0; + screen->fb[0].redMask = 0x7c00; + + i810c->colorKey = 0x043f; + + break; + case 16: + screen->fb[0].visuals = (1 << TrueColor); + screen->fb[0].blueMask = 0x001f; + screen->fb[0].greenMask = 0x07e0; + screen->fb[0].redMask = 0xf800; + + i810c->colorKey = 0x083f; + + break; + case 24: + screen->fb[0].visuals = (1 << TrueColor); + screen->fb[0].blueMask = 0x0000ff; + screen->fb[0].greenMask = 0x00ff00; + screen->fb[0].redMask = 0xff0000; + + i810c->colorKey = 0x0101ff; + + break; + default: + fprintf(stderr,"Unsupported depth %d\n",screen->fb[0].depth); + return FALSE; + } + + + + /* Set all colours to black */ + for (i=0; i<768; i++) i810c->vga.ModeReg.DAC[i] = 0x00; + + /* ... and the overscan */ + if (screen->fb[0].depth >= 4) + i810c->vga.ModeReg.Attribute[OVERSCAN] = 0xFF; + + /* Could be made a command-line option */ + +#ifdef I810CFG_SHOW_OVERSCAN + i810c->vga.ModeReg.DAC[765] = 0x3F; + i810c->vga.ModeReg.DAC[766] = 0x00; + i810c->vga.ModeReg.DAC[767] = 0x3F; + i810c->vga.ModeReg.Attribute[OVERSCAN] = 0xFF; + i810c->vga.ShowOverscan = TRUE; +#else + i810c->vga.ShowOverscan = FALSE; +#endif + + i810c->vga.paletteEnabled = FALSE; + i810c->vga.cmapSaved = FALSE; + i810c->vga.MMIOBase = i810c->MMIOBase; + + i810c->cpp = screen->fb[0].bitsPerPixel/8; + + /* move to initscreen? */ + + switch (screen->fb[0].bitsPerPixel) { + case 8: + i810c->MaxClock = 203000; + break; + case 16: + i810c->MaxClock = 163000; + break; + case 24: + i810c->MaxClock = 136000; + break; + case 32: /* not supported */ + i810c->MaxClock = 86000; + default: + fprintf(stderr,"Unsupported bpp %d\n",screen->fb[0].bitsPerPixel); + return FALSE; + } + + if (!i810AllocateGARTMemory( screen )) { + return FALSE; + } + + i810AllocateFront(screen); + + /* Map LpRing memory */ + if (!i810MapMem(screen)) return FALSE; + + screen->fb[0].frameBuffer = i810c->FbBase; + + screen->driver = i810s; + + return TRUE; +} + +/* + * I810Save -- + * + * This function saves the video state. It reads all of the SVGA registers + * into the vgaI810Rec data structure. There is in general no need to + * mask out bits here - just read the registers. + */ +static void +DoSave(KdCardInfo *card, vgaRegPtr vgaReg, I810RegPtr i810Reg, Bool saveFonts) +{ + + I810CardInfo *i810c = card->driver; + i810VGAPtr vgap = &i810c->vga; + + int i; + + /* Save VGA registers */ + + vgaReg->MiscOutReg = mmioReadMiscOut(vgap); + if (vgaReg->MiscOutReg & 0x01) + vgap->IOBase = VGA_IOBASE_COLOR; + else + vgap->IOBase = VGA_IOBASE_MONO; + + for (i = 0; i < VGA_NUM_CRTC; i++) { + vgaReg->CRTC[i] = mmioReadCrtc(vgap, i); + } + + mmioEnablePalette(vgap); + for (i = 0; i < VGA_NUM_ATTR; i++) { + vgaReg->Attribute[i] = mmioReadAttr(vgap, i); + } + mmioDisablePalette(vgap); + + for (i = 0; i < VGA_NUM_GFX; i++) { + vgaReg->Graphics[i] = mmioReadGr(vgap, i); + } + + for (i = 1; i < VGA_NUM_SEQ; i++) { + vgaReg->Sequencer[i] = mmioReadSeq(vgap, i); + } + + /* + * The port I/O code necessary to read in the extended registers + * into the fields of the I810Rec structure goes here. + */ + i810Reg->IOControl = mmioReadCrtc(vgap, IO_CTNL); + i810Reg->AddressMapping = i810ReadControlMMIO(i810c, GRX, ADDRESS_MAPPING); + i810Reg->BitBLTControl = INREG8(BITBLT_CNTL); + i810Reg->VideoClk2_M = INREG16(VCLK2_VCO_M); + i810Reg->VideoClk2_N = INREG16(VCLK2_VCO_N); + i810Reg->VideoClk2_DivisorSel = INREG8(VCLK2_VCO_DIV_SEL); + + i810Reg->ExtVertTotal=mmioReadCrtc(vgap, EXT_VERT_TOTAL); + i810Reg->ExtVertDispEnd=mmioReadCrtc(vgap, EXT_VERT_DISPLAY); + i810Reg->ExtVertSyncStart=mmioReadCrtc(vgap, EXT_VERT_SYNC_START); + i810Reg->ExtVertBlankStart=mmioReadCrtc(vgap, EXT_VERT_BLANK_START); + i810Reg->ExtHorizTotal=mmioReadCrtc(vgap, EXT_HORIZ_TOTAL); + i810Reg->ExtHorizBlank=mmioReadCrtc(vgap, EXT_HORIZ_BLANK); + i810Reg->ExtOffset=mmioReadCrtc(vgap, EXT_OFFSET); + i810Reg->InterlaceControl=mmioReadCrtc(vgap, INTERLACE_CNTL); + + i810Reg->PixelPipeCfg0 = INREG8(PIXPIPE_CONFIG_0); + i810Reg->PixelPipeCfg1 = INREG8(PIXPIPE_CONFIG_1); + i810Reg->PixelPipeCfg2 = INREG8(PIXPIPE_CONFIG_2); + i810Reg->DisplayControl = INREG8(DISPLAY_CNTL); + i810Reg->LMI_FIFO_Watermark = INREG(FWATER_BLC); + + for (i = 0 ; i < 8 ; i++) + i810Reg->Fence[i] = INREG(FENCE+i*4); + + i810Reg->LprbTail = INREG(LP_RING + RING_TAIL); + i810Reg->LprbHead = INREG(LP_RING + RING_HEAD); + i810Reg->LprbStart = INREG(LP_RING + RING_START); + i810Reg->LprbLen = INREG(LP_RING + RING_LEN); + + if ((i810Reg->LprbTail & TAIL_ADDR) != (i810Reg->LprbHead & HEAD_ADDR) && + i810Reg->LprbLen & RING_VALID) { + i810PrintErrorState( i810c ); + FatalError( "Active ring not flushed\n"); + } + + if (I810_DEBUG) { + fprintf(stderr,"Got mode in I810Save:\n"); + i810PrintMode( vgaReg, i810Reg ); + } +} + +static void +i810Preserve(KdCardInfo *card) +{ + I810CardInfo *i810c = card->driver; + i810VGAPtr vgap = &i810c->vga; + +/* fprintf(stderr,"i810Preserve\n"); */ + DoSave(card, &vgap->SavedReg, &i810c->SavedReg, TRUE); +} + +/* Famous last words + */ +void +i810PrintErrorState(i810CardInfo *i810c) +{ + + fprintf(stderr, "pgetbl_ctl: 0x%lx pgetbl_err: 0x%lx\n", + INREG(PGETBL_CTL), + INREG(PGE_ERR)); + + fprintf(stderr, "ipeir: %lx iphdr: %lx\n", + INREG(IPEIR), + INREG(IPEHR)); + + fprintf(stderr, "LP ring tail: %lx head: %lx len: %lx start %lx\n", + INREG(LP_RING + RING_TAIL), + INREG(LP_RING + RING_HEAD) & HEAD_ADDR, + INREG(LP_RING + RING_LEN), + INREG(LP_RING + RING_START)); + + fprintf(stderr, "eir: %x esr: %x emr: %x\n", + INREG16(EIR), + INREG16(ESR), + INREG16(EMR)); + + fprintf(stderr, "instdone: %x instpm: %x\n", + INREG16(INST_DONE), + INREG8(INST_PM)); + + fprintf(stderr, "memmode: %lx instps: %lx\n", + INREG(MEMMODE), + INREG(INST_PS)); + + fprintf(stderr, "hwstam: %x ier: %x imr: %x iir: %x\n", + INREG16(HWSTAM), + INREG16(IER), + INREG16(IMR), + INREG16(IIR)); +} + +static Bool +i810BindGARTMemory( KdScreenInfo *screen ) +{ + + KdCardInfo *card = screen->card; + I810CardInfo *i810c = card->driver; + + if (!i810c->GttBound) { + if (!KdAcquireGART(screen->mynum)) + return FALSE; + if (!KdBindGARTMemory(screen->mynum, i810c->VramKey, + i810c->VramOffset)) + + return FALSE; + if (i810c->DcacheKey != -1) { + if (!KdBindGARTMemory(screen->mynum, i810c->DcacheKey, + i810c->DcacheOffset)) + return FALSE; + } + if (i810c->HwcursKey != -1) { + if (!KdBindGARTMemory(screen->mynum, i810c->HwcursKey, + i810c->HwcursOffset)) + return FALSE; + } + i810c->GttBound = 1; + } + return TRUE; +} + +static Bool +i810UnbindGARTMemory(KdScreenInfo *screen) +{ + KdCardInfo *card = screen->card; + I810CardInfo *i810c = card->driver; + + + if (KdAgpGARTSupported() && i810c->GttBound) { + if (!KdUnbindGARTMemory(screen->mynum, i810c->VramKey)) + return FALSE; + if (i810c->DcacheKey != -1) { + if (!KdUnbindGARTMemory(screen->mynum, i810c->DcacheKey)) + return FALSE; + } + if (i810c->HwcursKey != -1) { + if (!KdUnbindGARTMemory(screen->mynum, i810c->HwcursKey)) + return FALSE; + } + if (!KdReleaseGART(screen->mynum)) + return FALSE; + i810c->GttBound = 0; + } + return TRUE; +} + +/* + * I810CalcVCLK -- + * + * Determine the closest clock frequency to the one requested. + */ + +#define MAX_VCO_FREQ 600.0 +#define TARGET_MAX_N 30 +#define REF_FREQ 24.0 + +#define CALC_VCLK(m,n,p) \ + (double)m / ((double)n * (1 << p)) * 4 * REF_FREQ + +static void +i810CalcVCLK( KdScreenInfo *screen, double freq ) +{ + + KdCardInfo *card = screen->card; + I810CardInfo *i810c = card->driver; + I810RegPtr i810Reg = &i810c->ModeReg; + + int m, n, p; + double f_out, f_best; + double f_err; + double f_vco; + int m_best = 0, n_best = 0, p_best = 0; + double f_target = freq; + double err_max = 0.005; + double err_target = 0.001; + double err_best = 999999.0; + + p_best = p = log(MAX_VCO_FREQ/f_target)/log((double)2); + f_vco = f_target * (1 << p); + + n = 2; + do { + n++; + m = f_vco / (REF_FREQ / (double)n) / (double)4.0 + 0.5; + if (m < 3) m = 3; + f_out = CALC_VCLK(m,n,p); + f_err = 1.0 - (f_target/f_out); + if (fabs(f_err) < err_max) { + m_best = m; + n_best = n; + f_best = f_out; + err_best = f_err; + } + } while ((fabs(f_err) >= err_target) && + ((n <= TARGET_MAX_N) || (fabs(err_best) > err_max))); + + if (fabs(f_err) < err_target) { + m_best = m; + n_best = n; + } + + i810Reg->VideoClk2_M = (m_best-2) & 0x3FF; + i810Reg->VideoClk2_N = (n_best-2) & 0x3FF; + i810Reg->VideoClk2_DivisorSel = (p_best << 4); + +/* fprintf(stderr, "Setting dot clock to %.1f MHz " */ +/* "[ 0x%x 0x%x 0x%x ] " */ +/* "[ %d %d %d ]\n", */ +/* CALC_VCLK(m_best,n_best,p_best), */ +/* i810Reg->VideoClk2_M, */ +/* i810Reg->VideoClk2_N, */ +/* i810Reg->VideoClk2_DivisorSel, */ +/* m_best, n_best, p_best); */ +} + +/* + * I810CalcFIFO -- + * + * Calculate burst length and FIFO watermark. + */ + +#define Elements(x) (sizeof(x)/sizeof(*x)) + +static unsigned int +i810CalcWatermark( KdScreenInfo *screen, double freq, Bool dcache ) +{ + + KdCardInfo *card = screen->card; + I810CardInfo *i810c = card->driver; + + + struct wm_info *tab; + int nr; + int i; + + if (i810c->LmFreqSel == 100) { + switch(screen->fb[0].bitsPerPixel) { + case 8: + tab = i810_wm_8_100; + nr = Elements(i810_wm_8_100); + break; + case 16: + tab = i810_wm_16_100; + nr = Elements(i810_wm_16_100); + break; + case 24: + tab = i810_wm_24_100; + nr = Elements(i810_wm_24_100); + break; + default: + return 0; + } + } else { + switch(screen->fb[0].bitsPerPixel) { + case 8: + tab = i810_wm_8_133; + nr = Elements(i810_wm_8_133); + break; + case 16: + tab = i810_wm_16_133; + nr = Elements(i810_wm_16_133); + break; + case 24: + tab = i810_wm_24_133; + nr = Elements(i810_wm_24_133); + break; + default: + return 0; + } + } + + for (i = 0 ; i < nr && tab[i].freq < freq ; i++); + + if (i == nr) + i--; + +/* fprintf(stderr,"chose watermark 0x%x: (tab.freq %.1f)\n", */ +/* tab[i].wm, tab[i].freq); */ + + /* None of these values (sourced from intel) have watermarks for + * the dcache memory. Fake it for now by using the same watermark + * for both... + * + * Update: this is probably because dcache isn't real useful as + * framebuffer memory, so intel's drivers don't need watermarks + * for that memory because they never use it to feed the ramdacs. + * We do use it in the fallback mode, so keep the watermarks for + * now. + */ + if (dcache) + return (tab[i].wm & ~0xffffff) | ((tab[i].wm>>12) & 0xfff); + else + return tab[i].wm; +} + +static void i810PrintMode( vgaRegPtr vgaReg, I810RegPtr mode ) +{ + int i; + + fprintf(stderr," MiscOut: %x\n", vgaReg->MiscOutReg); + + + fprintf(stderr,"SEQ: "); + for (i = 0 ; i < VGA_NUM_SEQ ; i++) { + if ((i&7)==0) fprintf(stderr,"\n"); + fprintf(stderr," %d: %x", i, vgaReg->Sequencer[i]); + } + fprintf(stderr,"\n"); + + fprintf(stderr,"CRTC: "); + for (i = 0 ; i < VGA_NUM_CRTC ; i++) { + if ((i&3)==0) fprintf(stderr,"\n"); + fprintf(stderr," CR%02x: %2x", i, vgaReg->CRTC[i]); + } + fprintf(stderr,"\n"); + + fprintf(stderr,"GFX: "); + for (i = 0 ; i < VGA_NUM_GFX ; i++) { + if ((i&3)==0) fprintf(stderr,"\n"); + fprintf(stderr," GR%02x: %02x", i, vgaReg->Graphics[i]); + } + fprintf(stderr,"\n"); + + fprintf(stderr,"ATTR: "); + for (i = 0 ; i < VGA_NUM_ATTR ; i++) { + if ((i&7)==0) fprintf(stderr,"\n"); + fprintf(stderr," %d: %x", i, vgaReg->Attribute[i]); + } + fprintf(stderr,"\n"); + + + fprintf(stderr," DisplayControl: %x\n", mode->DisplayControl); + fprintf(stderr," PixelPipeCfg0: %x\n", mode->PixelPipeCfg0); + fprintf(stderr," PixelPipeCfg1: %x\n", mode->PixelPipeCfg1); + fprintf(stderr," PixelPipeCfg2: %x\n", mode->PixelPipeCfg2); + fprintf(stderr," VideoClk2_M: %x\n", mode->VideoClk2_M); + fprintf(stderr," VideoClk2_N: %x\n", mode->VideoClk2_N); + fprintf(stderr," VideoClk2_DivisorSel: %x\n", mode->VideoClk2_DivisorSel); + fprintf(stderr," AddressMapping: %x\n", mode->AddressMapping); + fprintf(stderr," IOControl: %x\n", mode->IOControl); + fprintf(stderr," BitBLTControl: %x\n", mode->BitBLTControl); + fprintf(stderr," ExtVertTotal: %x\n", mode->ExtVertTotal); + fprintf(stderr," ExtVertDispEnd: %x\n", mode->ExtVertDispEnd); + fprintf(stderr," ExtVertSyncStart: %x\n", mode->ExtVertSyncStart); + fprintf(stderr," ExtVertBlankStart: %x\n", mode->ExtVertBlankStart); + fprintf(stderr," ExtHorizTotal: %x\n", mode->ExtHorizTotal); + fprintf(stderr," ExtHorizBlank: %x\n", mode->ExtHorizBlank); + fprintf(stderr," ExtOffset: %x\n", mode->ExtOffset); + fprintf(stderr," InterlaceControl: %x\n", mode->InterlaceControl); + fprintf(stderr," LMI_FIFO_Watermark: %x\n", mode->LMI_FIFO_Watermark); + fprintf(stderr," LprbTail: %x\n", mode->LprbTail); + fprintf(stderr," LprbHead: %x\n", mode->LprbHead); + fprintf(stderr," LprbStart: %x\n", mode->LprbStart); + fprintf(stderr," LprbLen: %x\n", mode->LprbLen); + fprintf(stderr," OverlayActiveStart: %x\n", mode->OverlayActiveStart); + fprintf(stderr," OverlayActiveEnd: %x\n", mode->OverlayActiveEnd); +} + + +/* + * i810VGASeqReset + * perform a sequencer reset. + * + * The i815 documentation states that these bits are not used by the + * HW, but still warns about not programming them... + */ + +static void +i810VGASeqReset(i810VGAPtr vgap, Bool start) +{ + if (start) + { + mmioWriteSeq(vgap, 0x00, 0x01); /* Synchronous Reset */ + } + else + { + mmioWriteSeq(vgap, 0x00, 0x03); /* End Reset */ + } +} + +static void +i810VGAProtect(KdCardInfo *card, Bool on) +{ + + I810CardInfo *i810c = card->driver; + i810VGAPtr vgap = &i810c->vga; + + unsigned char tmp; + + if (on) { + /* + * Turn off screen and disable sequencer. + */ + tmp = mmioReadSeq(vgap, 0x01); + + i810VGASeqReset(vgap, TRUE); /* start synchronous reset */ + mmioWriteSeq(vgap, 0x01, tmp | 0x20); /* disable the display */ + + mmioEnablePalette(vgap); + } else { + /* + * Reenable sequencer, then turn on screen. + */ + + tmp = mmioReadSeq(vgap, 0x01); + + mmioWriteSeq(vgap, 0x01, tmp & ~0x20); /* reenable display */ + i810VGASeqReset(vgap, FALSE); /* clear synchronousreset */ + + mmioDisablePalette(vgap); + } +} + +/* + * i810VGABlankScreen -- blank the screen. + */ + +void +i810VGABlankScreen(KdCardInfo *card, Bool on) +{ + I810CardInfo *i810c = card->driver; + i810VGAPtr vgap = &i810c->vga; + + unsigned char scrn; + + scrn = mmioReadSeq(vgap, 0x01); + + if (on) { + scrn &= ~0x20; /* enable screen */ + } else { + scrn |= 0x20; /* blank screen */ + } + + mmioWriteSeq(vgap,0x00,0x01); + mmioWriteSeq(vgap, 0x01, scrn); /* change mode */ + mmioWriteSeq(vgap,0x00,0x03); +} + +/* Restore hardware state */ + +static void +DoRestore(KdCardInfo *card, vgaRegPtr vgaReg, I810RegPtr i810Reg, + Bool restoreFonts) { + + + I810CardInfo *i810c = card->driver; + + i810VGAPtr vgap = &i810c->vga; + + unsigned char temp; + unsigned int itemp; + int i; + + if (I810_DEBUG & DEBUG_VERBOSE_VGA) { + fprintf(stderr,"Setting mode in DoRestore:\n"); + i810PrintMode( vgaReg, i810Reg ); + } + + /* Blank screen (i810vgaprotect) */ + i810VGAProtect(card, TRUE); + + /* Should wait for at least two hsync and no more than two vsync + before writing PIXCONF and turning the display on (?) */ + usleep(50000); + + /* Turn off DRAM Refresh */ + temp = INREG8( DRAM_ROW_CNTL_HI ); + temp &= ~DRAM_REFRESH_RATE; + temp |= DRAM_REFRESH_DISABLE; + OUTREG8( DRAM_ROW_CNTL_HI, temp ); + + usleep(1000); /* Wait 1 ms */ + + /* Write the M, N and P values */ + OUTREG16( VCLK2_VCO_M, i810Reg->VideoClk2_M); + OUTREG16( VCLK2_VCO_N, i810Reg->VideoClk2_N); + OUTREG8( VCLK2_VCO_DIV_SEL, i810Reg->VideoClk2_DivisorSel); + + /* + * Turn on 8 bit dac mode, if requested. This is needed to make + * sure that vgaHWRestore writes the values into the DAC properly. + * The problem occurs if 8 bit dac mode is requested and the HW is + * in 6 bit dac mode. If this happens, all the values are + * automatically shifted left twice by the HW and incorrect colors + * will be displayed on the screen. The only time this can happen + * is at server startup time and when switching back from a VT. + */ + temp = INREG8(PIXPIPE_CONFIG_0); + temp &= 0x7F; /* Save all but the 8 bit dac mode bit */ + temp |= (i810Reg->PixelPipeCfg0 & DAC_8_BIT); + OUTREG8( PIXPIPE_CONFIG_0, temp ); + + /* + * Code to restore any SVGA registers that have been saved/modified + * goes here. Note that it is allowable, and often correct, to + * only modify certain bits in a register by a read/modify/write cycle. + * + * A special case - when using an external clock-setting program, + * this function must not change bits associated with the clock + * selection. This condition can be checked by the condition: + * + * if (i810Reg->std.NoClock >= 0) + * restore clock-select bits. + */ + + /* VGA restore */ + if (vgaReg->MiscOutReg & 0x01) + vgap->IOBase = VGA_IOBASE_COLOR; + else + vgap->IOBase = VGA_IOBASE_MONO; + + mmioWriteMiscOut(vgap, vgaReg->MiscOutReg); + + for (i = 1; i < VGA_NUM_SEQ; i++) + mmioWriteSeq(vgap, i, vgaReg->Sequencer[i]); + + /* Ensure CRTC registers 0-7 are unlocked by clearing bit 7 or CRTC[17] */ + /* = CR11 */ + mmioWriteCrtc(vgap, 17, vgaReg->CRTC[17] & ~0x80); + + for (i = 0; i < VGA_NUM_CRTC; i++) { + mmioWriteCrtc(vgap, i, vgaReg->CRTC[i]); + } + + for (i = 0; i < VGA_NUM_GFX; i++) + mmioWriteGr(vgap, i, vgaReg->Graphics[i]); + + mmioEnablePalette(vgap); + for (i = 0; i < VGA_NUM_ATTR; i++) + mmioWriteAttr(vgap, i, vgaReg->Attribute[i]); + mmioDisablePalette(vgap); + + + mmioWriteCrtc(vgap, EXT_VERT_TOTAL, i810Reg->ExtVertTotal); + mmioWriteCrtc(vgap, EXT_VERT_DISPLAY, i810Reg->ExtVertDispEnd); + mmioWriteCrtc(vgap, EXT_VERT_SYNC_START, i810Reg->ExtVertSyncStart); + mmioWriteCrtc(vgap, EXT_VERT_BLANK_START, i810Reg->ExtVertBlankStart); + mmioWriteCrtc(vgap, EXT_HORIZ_TOTAL, i810Reg->ExtHorizTotal); + mmioWriteCrtc(vgap, EXT_HORIZ_BLANK, i810Reg->ExtHorizBlank); + + /* write CR40, CR42 first etc to get CR13 written as described in PRM */ + + mmioWriteCrtc(vgap, EXT_START_ADDR_HI, 0); + mmioWriteCrtc(vgap, EXT_START_ADDR, EXT_START_ADDR_ENABLE); + + mmioWriteCrtc(vgap, EXT_OFFSET, i810Reg->ExtOffset); + mmioWriteCrtc(vgap, 0x13, vgaReg->CRTC[0x13]); + + temp=mmioReadCrtc(vgap, INTERLACE_CNTL); + temp &= ~INTERLACE_ENABLE; + temp |= i810Reg->InterlaceControl; + mmioWriteCrtc(vgap, INTERLACE_CNTL, temp); + + temp=i810ReadControlMMIO(i810c, GRX, ADDRESS_MAPPING); + temp &= 0xE0; /* Save reserved bits 7:5 */ + temp |= i810Reg->AddressMapping; + i810WriteControlMMIO(i810c, GRX, ADDRESS_MAPPING, temp); + + /* Setting the OVRACT Register for video overlay*/ + OUTREG(0x6001C, (i810Reg->OverlayActiveEnd << 16) | i810Reg->OverlayActiveStart); + + /* Turn on DRAM Refresh */ + temp = INREG8( DRAM_ROW_CNTL_HI ); + temp &= ~DRAM_REFRESH_RATE; + temp |= DRAM_REFRESH_60HZ; + OUTREG8( DRAM_ROW_CNTL_HI, temp ); + + temp = INREG8( BITBLT_CNTL ); + temp &= ~COLEXP_MODE; + temp |= i810Reg->BitBLTControl; + OUTREG8( BITBLT_CNTL, temp ); + + temp = INREG8( DISPLAY_CNTL ); + temp &= ~(VGA_WRAP_MODE | GUI_MODE); + temp |= i810Reg->DisplayControl; + OUTREG8( DISPLAY_CNTL, temp ); + + + temp = INREG8( PIXPIPE_CONFIG_0 ); + temp &= 0x64; /* Save reserved bits 6:5,2 */ + temp |= i810Reg->PixelPipeCfg0; + OUTREG8( PIXPIPE_CONFIG_0, temp ); + + temp = INREG8( PIXPIPE_CONFIG_2 ); + temp &= 0xF3; /* Save reserved bits 7:4,1:0 */ + temp |= i810Reg->PixelPipeCfg2; + OUTREG8( PIXPIPE_CONFIG_2, temp ); + + temp = INREG8( PIXPIPE_CONFIG_1 ); + temp &= ~DISPLAY_COLOR_MODE; + temp &= 0xEF; /* Restore the CRT control bit */ + temp |= i810Reg->PixelPipeCfg1; + OUTREG8( PIXPIPE_CONFIG_1, temp ); + + OUTREG16(EIR, 0); + + itemp = INREG(FWATER_BLC); + itemp &= ~(LM_BURST_LENGTH | LM_FIFO_WATERMARK | + MM_BURST_LENGTH | MM_FIFO_WATERMARK ); + itemp |= i810Reg->LMI_FIFO_Watermark; + OUTREG(FWATER_BLC, itemp); + + + for (i = 0 ; i < 8 ; i++) { + OUTREG( FENCE+i*4, i810Reg->Fence[i] ); + if (I810_DEBUG & DEBUG_VERBOSE_VGA) + fprintf(stderr,"Fence Register : %x\n", i810Reg->Fence[i]); + } + + /* First disable the ring buffer (Need to wait for empty first?, if so + * should probably do it before entering this section) + */ + itemp = INREG(LP_RING + RING_LEN); + itemp &= ~RING_VALID_MASK; + OUTREG(LP_RING + RING_LEN, itemp ); + + /* Set up the low priority ring buffer. + */ + OUTREG(LP_RING + RING_TAIL, 0 ); + OUTREG(LP_RING + RING_HEAD, 0 ); + + i810c->LpRing.head = 0; + i810c->LpRing.tail = 0; + + itemp = INREG(LP_RING + RING_START); + itemp &= ~(START_ADDR); + itemp |= i810Reg->LprbStart; + OUTREG(LP_RING + RING_START, itemp ); + + itemp = INREG(LP_RING + RING_LEN); + itemp &= ~(RING_NR_PAGES | RING_REPORT_MASK | RING_VALID_MASK); + itemp |= i810Reg->LprbLen; + OUTREG(LP_RING + RING_LEN, itemp ); + + i810VGAProtect(card, FALSE); + + temp=mmioReadCrtc(vgap, IO_CTNL); + temp &= ~(EXTENDED_ATTR_CNTL | EXTENDED_CRTC_CNTL); + temp |= i810Reg->IOControl; + mmioWriteCrtc(vgap, IO_CTNL, temp); + /* Protect CRTC[0-7] */ + mmioWriteCrtc(vgap, 0x11, mmioReadCrtc(vgap, 0x11) | 0x80); +} + + +static Bool +i810SetMode(KdScreenInfo *screen, const KdMonitorTiming *t) +{ + + KdCardInfo *card = screen->card; + I810CardInfo *i810c = card->driver; + i810VGAPtr vgap = &i810c->vga; + + I810RegPtr i810Reg = &i810c->ModeReg; + vgaRegPtr pVga = &vgap->ModeReg; + + double dclk = t->clock/1000.0; + + switch (screen->fb[0].bitsPerPixel) { + case 8: + pVga->CRTC[0x13] = screen->width >> 3; + i810Reg->ExtOffset = screen->width >> 11; + i810Reg->PixelPipeCfg1 = DISPLAY_8BPP_MODE; + i810Reg->BitBLTControl = COLEXP_8BPP; + break; + case 16: + i810Reg->PixelPipeCfg1 = DISPLAY_16BPP_MODE; + pVga->CRTC[0x13] = screen->width >> 2; + i810Reg->ExtOffset = screen->width >> 10; + i810Reg->BitBLTControl = COLEXP_16BPP; + break; + case 24: + pVga->CRTC[0x13] = (screen->width * 3) >> 3; + i810Reg->ExtOffset = (screen->width * 3) >> 11; + + i810Reg->PixelPipeCfg1 = DISPLAY_24BPP_MODE; + i810Reg->BitBLTControl = COLEXP_24BPP; + break; + default: + break; + } + + i810Reg->PixelPipeCfg0 = DAC_8_BIT; + + /* Do not delay CRT Blank: needed for video overlay */ + i810Reg->PixelPipeCfg1 |= 0x10; + + /* Turn on Extended VGA Interpretation */ + i810Reg->IOControl = EXTENDED_CRTC_CNTL; + + /* Turn on linear and page mapping */ + i810Reg->AddressMapping = (LINEAR_MODE_ENABLE | + GTT_MEM_MAP_ENABLE); + + /* Turn on GUI mode */ + i810Reg->DisplayControl = HIRES_MODE; + + i810Reg->OverlayActiveStart = t->horizontal + t->hblank - 32; + i810Reg->OverlayActiveEnd = t->horizontal - 32; + + /* Turn on interlaced mode if necessary (it's not) */ + i810Reg->InterlaceControl = INTERLACE_DISABLE; + + /* + * Set the overscan color to 0. + * NOTE: This only affects >8bpp mode. + */ + pVga->Attribute[0x11] = 0; + + /* + * Calculate the VCLK that most closely matches the requested dot + * clock. + */ + i810CalcVCLK(screen, dclk); + + /* Since we program the clocks ourselves, always use VCLK2. */ + pVga->MiscOutReg |= 0x0C; + + /* Calculate the FIFO Watermark and Burst Length. */ + i810Reg->LMI_FIFO_Watermark = i810CalcWatermark(screen, dclk, FALSE); + + /* Setup the ring buffer */ + i810Reg->LprbTail = 0; + i810Reg->LprbHead = 0; + i810Reg->LprbStart = i810c->LpRing.mem.Start; + + if (i810Reg->LprbStart) + i810Reg->LprbLen = ((i810c->LpRing.mem.Size-4096) | + RING_NO_REPORT | RING_VALID); + else + i810Reg->LprbLen = RING_INVALID; + + return TRUE; +} + +static Bool +i810ModeInit(KdScreenInfo *screen, const KdMonitorTiming *t) +{ + + KdCardInfo *card = screen->card; + I810CardInfo *i810c = card->driver; + i810VGAPtr vgap = &i810c->vga; + vgaRegPtr pVga; + +/* fprintf(stderr,"i810ModeInit\n"); */ + + i810VGAUnlock(vgap); + + if (!i810VGAInit(screen, t)) return FALSE; + pVga = &vgap->ModeReg; + + if (!i810SetMode(screen, t)) return FALSE; + + DoRestore(screen->card, &vgap->ModeReg, &i810c->ModeReg, FALSE); + + return TRUE; +} + +Bool +i810VGAInit(KdScreenInfo *screen, const KdMonitorTiming *t) +{ + unsigned int i; + + int hactive, hblank, hbp, hfp; + int vactive, vblank, vbp, vfp; + int h_screen_off = 0, h_adjust = 0, h_total, h_display_end, h_blank_start; + int h_blank_end, h_sync_start, h_sync_end, v_total, v_retrace_start; + int v_retrace_end, v_display_end, v_blank_start, v_blank_end; + + KdCardInfo *card = screen->card; + I810CardInfo *i810c = card->driver; + + i810VGAPtr vgap = &i810c->vga; + I810RegPtr ireg = &i810c->ModeReg; + + + vgaRegPtr regp; + int depth = screen->fb[0].depth; + + regp = &vgap->ModeReg; + + /* + * compute correct Hsync & Vsync polarity + */ + + regp->MiscOutReg = 0x23; + if (t->vpol == KdSyncNegative) regp->MiscOutReg |= 0x40; + if (t->hpol == KdSyncNegative) regp->MiscOutReg |= 0x80; + + /* + * Time Sequencer + */ + if (depth == 4) + regp->Sequencer[0] = 0x02; + else + regp->Sequencer[0] = 0x00; + /* No support for 320 or 360 x resolution */ + regp->Sequencer[1] = 0x01; + + if (depth == 1) + regp->Sequencer[2] = 1 << BIT_PLANE; + else + regp->Sequencer[2] = 0x0F; + + regp->Sequencer[3] = 0x00; /* Font select */ + + if (depth < 8) + regp->Sequencer[4] = 0x06; /* Misc */ + else + regp->Sequencer[4] = 0x0E; /* Misc */ + + hactive = t->horizontal; + hblank = t->hblank; + hbp = t->hbp; + hfp = t->hfp; + + vactive = t->vertical; + vblank = t->vblank; + vbp = t->vbp; + vfp = t->vfp; + + switch (screen->fb[0].bitsPerPixel) { + case 8: + hactive /= 8; + hblank /= 8; + hfp /= 8; + hbp /= 8; + h_screen_off = hactive; + h_adjust = 1; + break; + case 16: + hactive /= 8; + hblank /= 8; + hfp /= 8; + hbp /= 8; + + h_screen_off = hactive * 2; + h_adjust = 1; + break; + case 24: + hactive /= 8; + hblank /= 8; + hfp /= 8; + hbp /= 8; + + h_screen_off = hactive * 3; + h_adjust = 1; + break; + case 32: + hactive /= 8; + hblank /= 8; + hfp /= 8; + hbp /= 8; + + h_screen_off = hactive * 4; + h_adjust = 1; + break; + } + + /* + * Compute horizontal register values from timings + */ + h_total = hactive + hblank - 5; + h_display_end = hactive - 1; + h_blank_start = h_display_end; + h_blank_end = h_blank_start + hblank; + + h_sync_start = hactive + hfp + h_adjust; + h_sync_end = h_sync_start + hblank - hbp - hfp; + + /* Set CRTC regs for horizontal timings */ + regp->CRTC[0x0] = h_total; + ireg->ExtHorizTotal=(h_total & 0x100) >> 8; + + regp->CRTC[0x1] = h_display_end; + + regp->CRTC[0x2] = h_blank_start; + + regp->CRTC[0x3] = 0x80 | (h_blank_end & 0x1f); + regp->CRTC[0x5] = (h_blank_end & 0x20) << 2; + + regp->CRTC[0x4] = h_sync_start; + + regp->CRTC[0x5] |= h_sync_end & 0x1f; + + regp->CRTC[0x13] = h_screen_off; + ireg->ExtOffset = h_screen_off >> 8; + + /* Compute vertical timings */ + v_total = vactive + vblank - 2; + v_retrace_start = vactive + vfp - 1; + v_retrace_end = v_retrace_start + vblank - vbp - vfp; + v_display_end = vactive - 1; + v_blank_start = vactive - 1; + v_blank_end = v_blank_start + vblank /* - 1 */; + + regp->CRTC[0x6] = v_total; + ireg->ExtVertTotal = v_total >> 8; + + regp->CRTC[0x10] = v_retrace_start; + ireg->ExtVertSyncStart = v_retrace_start >> 8; + + regp->CRTC[0x11] = v_retrace_end; + + regp->CRTC[0x12] = v_display_end; + ireg->ExtVertDispEnd = v_display_end >> 8; + + regp->CRTC[0x15] = v_blank_start; + ireg->ExtVertBlankStart = v_blank_start >> 8; + + regp->CRTC[0x16] = v_blank_end; + + if (depth < 8) + regp->CRTC[23] = 0xE3; + else + regp->CRTC[23] = 0xC3; + regp->CRTC[24] = 0xFF; + + /* + * Graphics Display Controller + */ + regp->Graphics[0] = 0x00; + regp->Graphics[1] = 0x00; + regp->Graphics[2] = 0x00; + regp->Graphics[3] = 0x00; + if (depth == 1) { + regp->Graphics[4] = BIT_PLANE; + regp->Graphics[5] = 0x00; + } else { + regp->Graphics[4] = 0x00; + if (depth == 4) + regp->Graphics[5] = 0x02; + else + regp->Graphics[5] = 0x40; + } + regp->Graphics[6] = 0x05; + regp->Graphics[7] = 0x0F; + regp->Graphics[8] = 0xFF; + + if (depth == 1) { + /* Initialise the Mono map according to which bit-plane gets used */ + + Bool flipPixels = FALSE; /* maybe support this in the future? */ + + for (i=0; i<16; i++) + if (((i & (1 << BIT_PLANE)) != 0) != flipPixels) + regp->Attribute[i] = WHITE_VALUE; + else + regp->Attribute[i] = BLACK_VALUE; + + regp->Attribute[16] = 0x01; /* -VGA2- */ + if (!vgap->ShowOverscan) + regp->Attribute[OVERSCAN] = OVERSCAN_VALUE; /* -VGA2- */ + } else { + regp->Attribute[0] = 0x00; /* standard colormap translation */ + regp->Attribute[1] = 0x01; + regp->Attribute[2] = 0x02; + regp->Attribute[3] = 0x03; + regp->Attribute[4] = 0x04; + regp->Attribute[5] = 0x05; + regp->Attribute[6] = 0x06; + regp->Attribute[7] = 0x07; + regp->Attribute[8] = 0x08; + regp->Attribute[9] = 0x09; + regp->Attribute[10] = 0x0A; + regp->Attribute[11] = 0x0B; + regp->Attribute[12] = 0x0C; + regp->Attribute[13] = 0x0D; + regp->Attribute[14] = 0x0E; + regp->Attribute[15] = 0x0F; + if (depth == 4) + regp->Attribute[16] = 0x81; + else + regp->Attribute[16] = 0x41; + /* Attribute[17] (overscan) was initialised earlier */ + } + regp->Attribute[18] = 0x0F; + regp->Attribute[19] = 0x00; + regp->Attribute[20] = 0x00; + + return(TRUE); +} + +void +i810VGALock(i810VGAPtr vgap) +{ + /* Protect CRTC[0-7] */ + mmioWriteCrtc(vgap, 0x11, mmioReadCrtc(vgap, 0x11) & ~0x80); +} + +void +i810VGAUnlock(i810VGAPtr vgap) +{ + /* Unprotect CRTC[0-7] */ + mmioWriteCrtc(vgap, 0x11, mmioReadCrtc(vgap, 0x11) | 0x80); +} + +static void +i810Restore(KdCardInfo *card) { + + I810CardInfo *i810c = card->driver; + + i810VGAPtr vgap = &i810c->vga; + + if (I810_DEBUG) + fprintf(stderr,"i810Restore\n"); + + DoRestore(card, &vgap->SavedReg, &i810c->SavedReg, TRUE); +} + +static Bool +i810Enable (ScreenPtr pScreen) +{ + KdScreenPriv(pScreen); + KdScreenInfo *screen = pScreenPriv->screen; + KdCardInfo *card = pScreenPriv->card; + I810CardInfo *i810c = card->driver; + i810VGAPtr vgap = &i810c->vga; + const KdMonitorTiming *t; + + if (I810_DEBUG) + fprintf(stderr,"i810Enable\n"); + + vgap->IOBase = (mmioReadMiscOut(vgap) & 0x01) ? + VGA_IOBASE_COLOR : VGA_IOBASE_MONO; + + { + I810RegPtr i810Reg = &i810c->ModeReg; + int i; + + for (i = 0 ; i < 8 ; i++) + i810Reg->Fence[i] = 0; + } + + t = KdFindMode (screen, i810ModeSupported); + + if (!i810BindGARTMemory(screen)) + return FALSE; + + if (!i810ModeInit(screen, t)) return FALSE; + + { + /* DPMS power on state */ + + unsigned char SEQ01=0; + int DPMSSyncSelect=0; + + SEQ01 = 0x00; + DPMSSyncSelect = HSYNC_ON | VSYNC_ON; + + SEQ01 |= i810ReadControlMMIO(i810c, SRX, 0x01) & ~0x20; + i810WriteControlMMIO(i810c, SRX, 0x01, SEQ01); + + /* Set the DPMS mode */ + OUTREG8(DPMS_SYNC_SELECT, DPMSSyncSelect); + } +#ifdef XV + KdXVEnable (pScreen); +#endif + return TRUE; +} + + +static void +i810Disable(ScreenPtr pScreen) { + + KdScreenPriv(pScreen); + KdScreenInfo *screen = pScreenPriv->screen; + KdCardInfo *card = pScreenPriv->card; + I810CardInfo *i810c = card->driver; + + i810VGAPtr vgap = &i810c->vga; + + if (I810_DEBUG) + fprintf(stderr,"i810Disable\n"); + +#ifdef XV + KdXVDisable (pScreen); +#endif + i810Restore(screen->card); + + if (!i810UnbindGARTMemory(screen)) + return; + + i810VGALock(vgap); +} + + +static Bool +i810DPMS(ScreenPtr pScreen, int mode) +{ + KdScreenPriv(pScreen); + KdCardInfo *card = pScreenPriv->card; + I810CardInfo *i810c = card->driver; + + unsigned char SEQ01=0; + int DPMSSyncSelect=0; + + if (I810_DEBUG) + fprintf(stderr,"i810DPMS: %d\n",mode); + + switch (mode) { + case KD_DPMS_NORMAL: + /* Screen: On; HSync: On, VSync: On */ + SEQ01 = 0x00; + DPMSSyncSelect = HSYNC_ON | VSYNC_ON; + break; + case KD_DPMS_STANDBY: + /* Screen: Off; HSync: Off, VSync: On */ + SEQ01 = 0x20; + DPMSSyncSelect = HSYNC_OFF | VSYNC_ON; + break; + case KD_DPMS_SUSPEND: + /* Screen: Off; HSync: On, VSync: Off */ + SEQ01 = 0x20; + DPMSSyncSelect = HSYNC_ON | VSYNC_OFF; + break; + case KD_DPMS_POWERDOWN: + /* Screen: Off; HSync: Off, VSync: Off */ + SEQ01 = 0x20; + DPMSSyncSelect = HSYNC_OFF | VSYNC_OFF; + break; + } + + /* Turn the screen on/off */ + SEQ01 |= i810ReadControlMMIO(i810c, SRX, 0x01) & ~0x20; + i810WriteControlMMIO(i810c, SRX, 0x01, SEQ01); + + /* Set the DPMS mode */ + OUTREG8(DPMS_SYNC_SELECT, DPMSSyncSelect); + return TRUE; +} + + +static void +i810GetColors (ScreenPtr pScreen, int fb, int ndefs, xColorItem *c) +{ + + if (I810_DEBUG) + fprintf(stderr,"i810GetColors (NOT IMPLEMENTED)\n"); +} + +#define DACDelay(hw) \ + do { \ + unsigned char temp = Vminb((hw)->IOBase + VGA_IN_STAT_1_OFFSET); \ + temp = Vminb((hw)->IOBase + VGA_IN_STAT_1_OFFSET); \ + } while (0) + +static void +i810PutColors (ScreenPtr pScreen, int fb, int ndef, xColorItem *pdefs) +{ + + KdScreenPriv(pScreen); + KdScreenInfo *screen = pScreenPriv->screen; + KdCardInfo *card = screen->card; + I810CardInfo *i810c = (I810CardInfo *) card->driver; + + i810VGAPtr vgap = &i810c->vga; + + if (I810_DEBUG) + fprintf(stderr,"i810PutColors\n"); + + while (ndef--) + { + mmioWriteDacWriteAddr(vgap, pdefs->pixel); + DACDelay(vgap); + mmioWriteDacData(vgap, pdefs->red); + DACDelay(vgap); + mmioWriteDacData(vgap, pdefs->green); + DACDelay(vgap); + mmioWriteDacData(vgap, pdefs->blue); + DACDelay(vgap); + + pdefs++; + } +} + + +KdCardFuncs i810Funcs = { + i810CardInit, /* cardinit */ + i810ScreenInit, /* scrinit */ + i810InitScreen, /* initScreen */ + i810FinishInitScreen, /* finishInitScreen */ + NULL, /* createResources */ + i810Preserve, /* preserve */ + i810Enable, /* enable */ + i810DPMS, /* dpms */ + i810Disable, /* disable */ + i810Restore, /* restore */ + i810ScreenFini, /* scrfini */ + i810CardFini, /* cardfini */ + + i810CursorInit, /* initCursor */ + i810CursorEnable, /* enableCursor */ + i810CursorDisable, /* disableCursor */ + i810CursorFini, /* finiCursor */ + NULL, /* recolorCursor */ + + i810InitAccel, /* initAccel */ + i810EnableAccel, /* enableAccel */ + i810DisableAccel, /* disableAccel */ + i810FiniAccel, /* finiAccel */ + + i810GetColors, /* getColors */ + i810PutColors, /* putColors */ +}; |