nkeynes@185: /** nkeynes@190: * $Id: pvr.c,v 1.2 2006-08-02 04:13:15 nkeynes Exp $ nkeynes@185: * nkeynes@185: * PVR support code nkeynes@185: * nkeynes@185: * Copyright (c) 2006 Nathan Keynes. nkeynes@185: * nkeynes@185: * This program is free software; you can redistribute it and/or modify nkeynes@185: * it under the terms of the GNU General Public License as published by nkeynes@185: * the Free Software Foundation; either version 2 of the License, or nkeynes@185: * (at your option) any later version. nkeynes@185: * nkeynes@185: * This program is distributed in the hope that it will be useful, nkeynes@185: * but WITHOUT ANY WARRANTY; without even the implied warranty of nkeynes@185: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the nkeynes@185: * GNU General Public License for more details. nkeynes@185: */ nkeynes@185: nkeynes@185: #include "lib.h" nkeynes@185: #include "pvr.h" nkeynes@185: nkeynes@185: #define PVR_BASE 0xA05F8000 nkeynes@185: #define PVR_RESET (PVR_BASE+0x008) nkeynes@185: #define TA_INIT (PVR_BASE+0x144) nkeynes@185: #define TA_TILESTART (PVR_BASE+0x124) nkeynes@185: #define TA_OBJSTART (PVR_BASE+0x128) nkeynes@185: #define TA_TILEEND (PVR_BASE+0x12C) nkeynes@185: #define TA_OBJEND (PVR_BASE+0x130) nkeynes@185: #define TA_TILEPOSN (PVR_BASE+0x134) nkeynes@185: #define TA_OBJPOSN (PVR_BASE+0x138) nkeynes@185: #define TA_SIZE (PVR_BASE+0x13C) nkeynes@185: #define TA_TILECFG (PVR_BASE+0x140) nkeynes@185: #define TA_PLISTSTART (PVR_BASE+0x164) nkeynes@185: nkeynes@185: nkeynes@185: void ta_dump_regs( FILE *f ) nkeynes@185: { nkeynes@185: fprintf( stderr, "TA Object start[128]: %08X posn[138]: %08X end[130]: %08X\n", nkeynes@185: long_read(TA_OBJSTART), long_read(TA_OBJPOSN), long_read(TA_OBJEND) ); nkeynes@185: fprintf( stderr, "TA OPB start[124]: %08X posn[134]: %08X end[12c]: %08X init: %08X\n", nkeynes@185: long_read(TA_TILESTART), long_read(TA_TILEPOSN), long_read(TA_TILEEND), nkeynes@185: long_read(TA_PLISTSTART) ); nkeynes@185: fprintf( stderr, "TA Tilesize: %08X config: %08X\n", long_read(TA_SIZE), long_read(TA_TILECFG) ); nkeynes@185: } nkeynes@185: nkeynes@190: nkeynes@190: void ta_init( struct ta_config *config ) nkeynes@190: { nkeynes@190: long_write( PVR_RESET, 1 ); nkeynes@190: long_write( PVR_RESET, 0 ); nkeynes@190: nkeynes@190: long_write( TA_SIZE, config->grid_size ); nkeynes@190: long_write( TA_OBJSTART, config->obj_start & 0x00FFFFFF ); nkeynes@190: long_write( TA_OBJEND, config->obj_end & 0x00FFFFFF ); nkeynes@190: long_write( TA_TILESTART, config->tile_start & 0x00FFFFFF ); nkeynes@190: long_write( TA_TILEEND, config->tile_end & 0x00FFFFFF ); nkeynes@190: long_write( TA_PLISTSTART, config->plist_start & 0x00FFFFFF ); nkeynes@190: long_write( TA_TILECFG, config->ta_cfg ); nkeynes@190: long_write( TA_INIT, 0x80000000 ); nkeynes@190: } nkeynes@190: nkeynes@185: int pvr_get_objbuf_size( ) nkeynes@185: { nkeynes@185: return long_read( TA_OBJPOSN ) - long_read( TA_OBJSTART ); nkeynes@185: } nkeynes@185: nkeynes@190: int pvr_get_plist_posn( ) nkeynes@190: { nkeynes@190: unsigned int addr = long_read( TA_TILEPOSN ) << 2; nkeynes@190: return addr; nkeynes@190: } nkeynes@190: nkeynes@185: void pvr_dump_objbuf( FILE *f ) nkeynes@185: { nkeynes@185: unsigned int start = long_read( TA_OBJSTART ); nkeynes@185: unsigned int posn = long_read( TA_OBJPOSN ); nkeynes@185: unsigned int end = long_read( TA_OBJEND ); nkeynes@185: char *buf; nkeynes@185: unsigned int length; nkeynes@185: if( start < posn ) { nkeynes@185: buf = (char *)(0xA5000000+start); nkeynes@185: length = posn-start; nkeynes@185: } else { nkeynes@185: buf = (char *)(0xA5000000+end); nkeynes@185: length = start-posn; nkeynes@185: } nkeynes@185: nkeynes@185: fprintf( f, "Obj buffer: %08X - %08X - %08X\n", start, posn, end ); nkeynes@185: fwrite_dump( f, buf, length ); nkeynes@185: } nkeynes@185: nkeynes@185: void pvr_dump_tilebuf( FILE *f ) nkeynes@185: { nkeynes@185: unsigned int start = long_read( TA_TILESTART ); nkeynes@185: unsigned int posn = long_read( TA_TILEPOSN ); nkeynes@185: unsigned int end = long_read( TA_TILEEND ); nkeynes@185: char *buf; nkeynes@185: unsigned int length; nkeynes@185: if( start < posn ) { nkeynes@185: buf = (char *)(0xA5000000+start); nkeynes@185: length = posn-start; nkeynes@185: } else { nkeynes@185: buf = (char *)(0xA5000000+end); nkeynes@185: length = start-posn; nkeynes@185: } nkeynes@185: nkeynes@185: fprintf( f, "Tile buffer: %08X - %08X - %08X\n", start, posn, end ); nkeynes@185: fwrite_dump( f, buf, length ); nkeynes@185: } nkeynes@185: nkeynes@185: /************** Stolen from TATEST *************/ nkeynes@185: nkeynes@185: static unsigned int three_d_params[] = { nkeynes@185: 0x80a8, 0x15d1c951, /* M (Unknown magic value) */ nkeynes@185: 0x80a0, 0x00000020, /* M */ nkeynes@185: 0x8008, 0x00000000, /* TA out of reset */ nkeynes@185: 0x8048, 0x00000009, /* alpha config */ nkeynes@185: 0x8068, 0x02800000, /* pixel clipping x */ nkeynes@185: 0x806c, 0x01e00000, /* pixel clipping y */ nkeynes@185: 0x8110, 0x00093f39, /* M */ nkeynes@185: 0x8098, 0x00800408, /* M */ nkeynes@185: 0x804c, 0x000000a0, /* display align (640*2)/8 */ nkeynes@185: 0x8078, 0x3f800000, /* polygon culling (1.0f) */ nkeynes@185: 0x8084, 0x00000000, /* M */ nkeynes@185: 0x8030, 0x00000101, /* M */ nkeynes@185: 0x80b0, 0x007f7f7f, /* Fog table color */ nkeynes@185: 0x80b4, 0x007f7f7f, /* Fog vertex color */ nkeynes@185: 0x80c0, 0x00000000, /* color clamp min */ nkeynes@185: 0x80bc, 0xffffffff, /* color clamp max */ nkeynes@185: 0x8080, 0x00000007, /* M */ nkeynes@185: 0x8074, 0x00000001, /* cheap shadow */ nkeynes@185: 0x807c, 0x0027df77, /* M */ nkeynes@185: 0x8008, 0x00000001, /* TA reset */ nkeynes@185: 0x8008, 0x00000000, /* TA out of reset */ nkeynes@185: 0x80e4, 0x00000000, /* stride width */ nkeynes@185: 0x6884, 0x00000000, /* Disable all interrupt events */ nkeynes@185: 0x6930, 0x00000000, nkeynes@185: 0x6938, 0x00000000, nkeynes@185: 0x6900, 0xffffffff, /* Clear all pending int events */ nkeynes@185: 0x6908, 0xffffffff, nkeynes@185: 0x6930, 0x002807ec, /* Re-enable some events */ nkeynes@185: 0x6938, 0x0000000e, nkeynes@185: 0x80b8, 0x0000ff07, /* fog density */ nkeynes@185: 0x80b4, 0x007f7f7f, /* fog vertex color */ nkeynes@185: 0x80b0, 0x007f7f7f, /* fog table color */ nkeynes@185: 0x8108, 0x00000003 /* 32bit palette */ nkeynes@185: }; nkeynes@185: nkeynes@185: static unsigned int scrn_params[] = { nkeynes@185: 0x80e8, 0x00160000, /* screen control */ nkeynes@185: 0x8044, 0x00800000, /* pixel mode (vb+0x11) */ nkeynes@185: 0x805c, 0x00000000, /* Size modulo and display lines (vb+0x17) */ nkeynes@185: 0x80d0, 0x00000100, /* interlace flags */ nkeynes@185: 0x80d8, 0x020c0359, /* M */ nkeynes@185: 0x80cc, 0x001501fe, /* M */ nkeynes@185: 0x80d4, 0x007e0345, /* horizontal border */ nkeynes@185: 0x80dc, 0x00240204, /* vertical position */ nkeynes@185: 0x80e0, 0x07d6c63f, /* sync control */ nkeynes@185: 0x80ec, 0x000000a4, /* horizontal position */ nkeynes@185: 0x80f0, 0x00120012, /* vertical border */ nkeynes@185: 0x80c8, 0x03450000, /* set to same as border H in 80d4 */ nkeynes@185: 0x8068, 0x027f0000, /* (X resolution - 1) << 16 */ nkeynes@185: 0x806c, 0x01df0000, /* (Y resolution - 1) << 16 */ nkeynes@185: 0x804c, 0x000000a0, /* display align */ nkeynes@185: 0x8118, 0x00008040, /* M */ nkeynes@185: 0x80f4, 0x00000401, /* anti-aliasing */ nkeynes@185: 0x8048, 0x00000009, /* alpha config */ nkeynes@185: 0x7814, 0x00000000, /* More interrupt control stuff (so it seems)*/ nkeynes@185: 0x7834, 0x00000000, nkeynes@185: 0x7854, 0x00000000, nkeynes@185: 0x7874, 0x00000000, nkeynes@185: 0x78bc, 0x4659404f, nkeynes@185: 0x8040, 0x00000000 /* border color */ nkeynes@185: }; nkeynes@185: nkeynes@185: static void set_regs(unsigned int *values, int cnt) nkeynes@185: { nkeynes@185: volatile unsigned char *regs = (volatile unsigned char *)(void *)0xa05f0000; nkeynes@185: unsigned int r, v; nkeynes@185: nkeynes@185: while(cnt--) { nkeynes@185: r = *values++; nkeynes@185: v = *values++; nkeynes@185: *(volatile unsigned int *)(regs+r) = v; nkeynes@185: } nkeynes@185: } nkeynes@185: nkeynes@185: int pvr_check_cable() nkeynes@185: { nkeynes@185: volatile unsigned int *porta = (unsigned int *)0xff80002c; nkeynes@185: nkeynes@185: /* PORT8 and PORT9 is input */ nkeynes@185: *porta = (*porta & ~0xf0000) | 0xa0000; nkeynes@185: nkeynes@185: /* Return PORT8 and PORT9 */ nkeynes@185: return ((*(volatile unsigned short *)(porta+1))>>8)&3; nkeynes@185: } nkeynes@185: void pvr_init_video(int cabletype, int mode, int res) nkeynes@185: { nkeynes@185: volatile unsigned int *videobase=(volatile unsigned int *)(void*)0xa05f8000; nkeynes@185: static int bppshifttab[]= { 1,1,0,2 }; nkeynes@185: int shift, lines, modulo, words_per_line, vpos; nkeynes@185: int laceoffset=0, voffset=0; nkeynes@185: unsigned int videoflags, attribs; nkeynes@185: unsigned int hvcounter = (res<2? 0x01060359 : 0x020c0359); nkeynes@185: nkeynes@185: mode &= 3; nkeynes@185: shift = bppshifttab[mode]; nkeynes@185: nkeynes@185: videobase[8/4]=0; nkeynes@185: videobase[0x40/4]=0; nkeynes@185: nkeynes@185: /* Select pixel clock and colour mode */ nkeynes@185: mode = (mode<<2)|1; nkeynes@185: lines = 240; nkeynes@185: if(!(cabletype&2)) { nkeynes@185: nkeynes@185: /* VGA mode */ nkeynes@185: nkeynes@185: if(res < 2) nkeynes@185: mode |= 2; /* doublescan */ nkeynes@185: nkeynes@185: hvcounter = 0x020c0359; nkeynes@185: nkeynes@185: lines <<= 1; nkeynes@185: mode |= 0x800000; /* fast pixel clock */ nkeynes@185: } nkeynes@185: videobase[0x44/4]=mode; nkeynes@185: nkeynes@185: /* Set video base address. Short fields will be offset by nkeynes@185: 640 pixels, regardless of horizontal resolution. */ nkeynes@185: videobase[0x50/4]=0; nkeynes@185: videobase[0x54/4]=640< skip 320 pixels to keep modulo at 640 pixels */ nkeynes@185: modulo += words_per_line; nkeynes@185: } else { nkeynes@185: if(res!=1) nkeynes@185: /* NTSC lores -> skip 320 pixels to keep modulo at 640 pixels */ nkeynes@185: /* _or_ NTSC hires -> skip every other line due to interlace */ nkeynes@185: modulo += words_per_line; nkeynes@185: nkeynes@185: if(res==2) nkeynes@185: /* interlace mode */ nkeynes@185: videoflags |= 1<<4; nkeynes@185: nkeynes@185: /* enable NTSC */ nkeynes@185: videoflags |= 1<<6; nkeynes@185: } nkeynes@185: nkeynes@185: /* Write screen size and modulo */ nkeynes@185: videobase[0x5c/4]=(((modulo<<10)+lines-1)<<10)+words_per_line-1; nkeynes@185: nkeynes@185: /* Enable video (lace, NTSC) */ nkeynes@185: videobase[0xd0/4]=videoflags; nkeynes@185: nkeynes@185: /* Screen and border position */ nkeynes@185: nkeynes@185: if(!(cabletype&2)) nkeynes@185: /* VGA */ nkeynes@185: voffset += 36; nkeynes@185: else nkeynes@185: voffset += 18; nkeynes@185: nkeynes@185: vpos=(voffset<<16)|(voffset+laceoffset); nkeynes@185: nkeynes@185: videobase[0xf0/4]=vpos; /* V start */ nkeynes@185: videobase[0xdc/4]=vpos+lines; /* start and end border */ nkeynes@185: videobase[0xec/4]=0xa4; /* Horizontal pos */ nkeynes@185: videobase[0xd8/4]=hvcounter; /* HV counter */ nkeynes@185: videobase[0xd4/4]=0x007e0345; /* Horizontal border */ nkeynes@185: nkeynes@185: /* Select horizontal pixel doubling for lowres */ nkeynes@185: if(res==0) nkeynes@185: attribs=((22<<8)+1)<<8; nkeynes@185: else nkeynes@185: attribs=22<<16; nkeynes@185: videobase[0xe8/4]=attribs; nkeynes@185: nkeynes@185: /* Set up vertical blank event */ nkeynes@185: vpos = 260; nkeynes@185: if(!(cabletype&2)) nkeynes@185: vpos = 510; nkeynes@185: videobase[0xcc/4]=(0x21<<16)|vpos; nkeynes@185: nkeynes@185: /* Select RGB/CVBS */ nkeynes@185: if(cabletype&1) nkeynes@185: mode = 3; nkeynes@185: else nkeynes@185: mode = 0; nkeynes@185: *(volatile unsigned int *)(void*)0xa0702c00 = mode << 8; nkeynes@185: nkeynes@185: return; nkeynes@185: } nkeynes@185: nkeynes@185: void pvr_init() nkeynes@185: { nkeynes@185: volatile unsigned int *vbl = (volatile unsigned int *)(void *)0xa05f810c; nkeynes@185: nkeynes@185: set_regs(three_d_params, sizeof(three_d_params)/sizeof(three_d_params[0])/2); nkeynes@185: while (!(*vbl & 0x01ff)); nkeynes@185: while (*vbl & 0x01ff); nkeynes@185: set_regs(scrn_params, sizeof(scrn_params)/sizeof(scrn_params[0])/2); nkeynes@185: pvr_init_video(pvr_check_cable(), 1, 2); nkeynes@185: } nkeynes@185: