nkeynes@185 | 1 | /**
|
nkeynes@185 | 2 | * $Id: pvr.c,v 1.1 2006-07-11 01:35:23 nkeynes Exp $
|
nkeynes@185 | 3 | *
|
nkeynes@185 | 4 | * PVR support code
|
nkeynes@185 | 5 | *
|
nkeynes@185 | 6 | * Copyright (c) 2006 Nathan Keynes.
|
nkeynes@185 | 7 | *
|
nkeynes@185 | 8 | * This program is free software; you can redistribute it and/or modify
|
nkeynes@185 | 9 | * it under the terms of the GNU General Public License as published by
|
nkeynes@185 | 10 | * the Free Software Foundation; either version 2 of the License, or
|
nkeynes@185 | 11 | * (at your option) any later version.
|
nkeynes@185 | 12 | *
|
nkeynes@185 | 13 | * This program is distributed in the hope that it will be useful,
|
nkeynes@185 | 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
nkeynes@185 | 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
nkeynes@185 | 16 | * GNU General Public License for more details.
|
nkeynes@185 | 17 | */
|
nkeynes@185 | 18 |
|
nkeynes@185 | 19 | #include "lib.h"
|
nkeynes@185 | 20 | #include "pvr.h"
|
nkeynes@185 | 21 |
|
nkeynes@185 | 22 | #define PVR_BASE 0xA05F8000
|
nkeynes@185 | 23 | #define PVR_RESET (PVR_BASE+0x008)
|
nkeynes@185 | 24 | #define TA_INIT (PVR_BASE+0x144)
|
nkeynes@185 | 25 | #define TA_TILESTART (PVR_BASE+0x124)
|
nkeynes@185 | 26 | #define TA_OBJSTART (PVR_BASE+0x128)
|
nkeynes@185 | 27 | #define TA_TILEEND (PVR_BASE+0x12C)
|
nkeynes@185 | 28 | #define TA_OBJEND (PVR_BASE+0x130)
|
nkeynes@185 | 29 | #define TA_TILEPOSN (PVR_BASE+0x134)
|
nkeynes@185 | 30 | #define TA_OBJPOSN (PVR_BASE+0x138)
|
nkeynes@185 | 31 | #define TA_SIZE (PVR_BASE+0x13C)
|
nkeynes@185 | 32 | #define TA_TILECFG (PVR_BASE+0x140)
|
nkeynes@185 | 33 | #define TA_PLISTSTART (PVR_BASE+0x164)
|
nkeynes@185 | 34 |
|
nkeynes@185 | 35 |
|
nkeynes@185 | 36 |
|
nkeynes@185 | 37 | void ta_init( unsigned int hres, unsigned int vres,
|
nkeynes@185 | 38 | unsigned int polybuf, unsigned int polybuflen,
|
nkeynes@185 | 39 | unsigned int tilebuf, unsigned int tilebuflen )
|
nkeynes@185 | 40 | {
|
nkeynes@185 | 41 | unsigned int hsegs = ((hres+31) / 32)-1;
|
nkeynes@185 | 42 | unsigned int vsegs = ((vres+31) / 32)-1;
|
nkeynes@185 | 43 | unsigned int size = (vsegs<<16)|hsegs;
|
nkeynes@185 | 44 |
|
nkeynes@185 | 45 | fprintf(stderr, "Setting tilemap: %08X\n", size);
|
nkeynes@185 | 46 |
|
nkeynes@185 | 47 | long_write( PVR_RESET, 1 );
|
nkeynes@185 | 48 | long_write( PVR_RESET, 0 );
|
nkeynes@185 | 49 |
|
nkeynes@185 | 50 | long_write( TA_SIZE, size );
|
nkeynes@185 | 51 | long_write( TA_OBJSTART, polybuf & 0x00FFFFFF );
|
nkeynes@185 | 52 | long_write( TA_OBJEND, (polybuf + polybuflen) & 0x00FFFFFF );
|
nkeynes@185 | 53 | long_write( TA_TILESTART, (tilebuf + tilebuflen) & 0x00FFFFFF );
|
nkeynes@185 | 54 | long_write( TA_TILEEND, tilebuf & 0x00FFFFFF );
|
nkeynes@185 | 55 | long_write( TA_PLISTSTART, (tilebuf + tilebuflen) & 0x00FFFFFF );
|
nkeynes@185 | 56 | long_write( TA_TILECFG, 0x00100002 );
|
nkeynes@185 | 57 | long_write( TA_INIT, 0x80000000 );
|
nkeynes@185 | 58 | }
|
nkeynes@185 | 59 |
|
nkeynes@185 | 60 | void ta_dump_regs( FILE *f )
|
nkeynes@185 | 61 | {
|
nkeynes@185 | 62 | fprintf( stderr, "TA Object start[128]: %08X posn[138]: %08X end[130]: %08X\n",
|
nkeynes@185 | 63 | long_read(TA_OBJSTART), long_read(TA_OBJPOSN), long_read(TA_OBJEND) );
|
nkeynes@185 | 64 | fprintf( stderr, "TA OPB start[124]: %08X posn[134]: %08X end[12c]: %08X init: %08X\n",
|
nkeynes@185 | 65 | long_read(TA_TILESTART), long_read(TA_TILEPOSN), long_read(TA_TILEEND),
|
nkeynes@185 | 66 | long_read(TA_PLISTSTART) );
|
nkeynes@185 | 67 | fprintf( stderr, "TA Tilesize: %08X config: %08X\n", long_read(TA_SIZE), long_read(TA_TILECFG) );
|
nkeynes@185 | 68 | }
|
nkeynes@185 | 69 |
|
nkeynes@185 | 70 | int pvr_get_objbuf_size( )
|
nkeynes@185 | 71 | {
|
nkeynes@185 | 72 | return long_read( TA_OBJPOSN ) - long_read( TA_OBJSTART );
|
nkeynes@185 | 73 | }
|
nkeynes@185 | 74 |
|
nkeynes@185 | 75 | void pvr_dump_objbuf( FILE *f )
|
nkeynes@185 | 76 | {
|
nkeynes@185 | 77 | unsigned int start = long_read( TA_OBJSTART );
|
nkeynes@185 | 78 | unsigned int posn = long_read( TA_OBJPOSN );
|
nkeynes@185 | 79 | unsigned int end = long_read( TA_OBJEND );
|
nkeynes@185 | 80 | char *buf;
|
nkeynes@185 | 81 | unsigned int length;
|
nkeynes@185 | 82 | if( start < posn ) {
|
nkeynes@185 | 83 | buf = (char *)(0xA5000000+start);
|
nkeynes@185 | 84 | length = posn-start;
|
nkeynes@185 | 85 | } else {
|
nkeynes@185 | 86 | buf = (char *)(0xA5000000+end);
|
nkeynes@185 | 87 | length = start-posn;
|
nkeynes@185 | 88 | }
|
nkeynes@185 | 89 |
|
nkeynes@185 | 90 | fprintf( f, "Obj buffer: %08X - %08X - %08X\n", start, posn, end );
|
nkeynes@185 | 91 | fwrite_dump( f, buf, length );
|
nkeynes@185 | 92 | }
|
nkeynes@185 | 93 |
|
nkeynes@185 | 94 | void pvr_dump_tilebuf( FILE *f )
|
nkeynes@185 | 95 | {
|
nkeynes@185 | 96 | unsigned int start = long_read( TA_TILESTART );
|
nkeynes@185 | 97 | unsigned int posn = long_read( TA_TILEPOSN );
|
nkeynes@185 | 98 | unsigned int end = long_read( TA_TILEEND );
|
nkeynes@185 | 99 | char *buf;
|
nkeynes@185 | 100 | unsigned int length;
|
nkeynes@185 | 101 | if( start < posn ) {
|
nkeynes@185 | 102 | buf = (char *)(0xA5000000+start);
|
nkeynes@185 | 103 | length = posn-start;
|
nkeynes@185 | 104 | } else {
|
nkeynes@185 | 105 | buf = (char *)(0xA5000000+end);
|
nkeynes@185 | 106 | length = start-posn;
|
nkeynes@185 | 107 | }
|
nkeynes@185 | 108 |
|
nkeynes@185 | 109 | fprintf( f, "Tile buffer: %08X - %08X - %08X\n", start, posn, end );
|
nkeynes@185 | 110 | fwrite_dump( f, buf, length );
|
nkeynes@185 | 111 | }
|
nkeynes@185 | 112 |
|
nkeynes@185 | 113 | /************** Stolen from TATEST *************/
|
nkeynes@185 | 114 |
|
nkeynes@185 | 115 | static unsigned int three_d_params[] = {
|
nkeynes@185 | 116 | 0x80a8, 0x15d1c951, /* M (Unknown magic value) */
|
nkeynes@185 | 117 | 0x80a0, 0x00000020, /* M */
|
nkeynes@185 | 118 | 0x8008, 0x00000000, /* TA out of reset */
|
nkeynes@185 | 119 | 0x8048, 0x00000009, /* alpha config */
|
nkeynes@185 | 120 | 0x8068, 0x02800000, /* pixel clipping x */
|
nkeynes@185 | 121 | 0x806c, 0x01e00000, /* pixel clipping y */
|
nkeynes@185 | 122 | 0x8110, 0x00093f39, /* M */
|
nkeynes@185 | 123 | 0x8098, 0x00800408, /* M */
|
nkeynes@185 | 124 | 0x804c, 0x000000a0, /* display align (640*2)/8 */
|
nkeynes@185 | 125 | 0x8078, 0x3f800000, /* polygon culling (1.0f) */
|
nkeynes@185 | 126 | 0x8084, 0x00000000, /* M */
|
nkeynes@185 | 127 | 0x8030, 0x00000101, /* M */
|
nkeynes@185 | 128 | 0x80b0, 0x007f7f7f, /* Fog table color */
|
nkeynes@185 | 129 | 0x80b4, 0x007f7f7f, /* Fog vertex color */
|
nkeynes@185 | 130 | 0x80c0, 0x00000000, /* color clamp min */
|
nkeynes@185 | 131 | 0x80bc, 0xffffffff, /* color clamp max */
|
nkeynes@185 | 132 | 0x8080, 0x00000007, /* M */
|
nkeynes@185 | 133 | 0x8074, 0x00000001, /* cheap shadow */
|
nkeynes@185 | 134 | 0x807c, 0x0027df77, /* M */
|
nkeynes@185 | 135 | 0x8008, 0x00000001, /* TA reset */
|
nkeynes@185 | 136 | 0x8008, 0x00000000, /* TA out of reset */
|
nkeynes@185 | 137 | 0x80e4, 0x00000000, /* stride width */
|
nkeynes@185 | 138 | 0x6884, 0x00000000, /* Disable all interrupt events */
|
nkeynes@185 | 139 | 0x6930, 0x00000000,
|
nkeynes@185 | 140 | 0x6938, 0x00000000,
|
nkeynes@185 | 141 | 0x6900, 0xffffffff, /* Clear all pending int events */
|
nkeynes@185 | 142 | 0x6908, 0xffffffff,
|
nkeynes@185 | 143 | 0x6930, 0x002807ec, /* Re-enable some events */
|
nkeynes@185 | 144 | 0x6938, 0x0000000e,
|
nkeynes@185 | 145 | 0x80b8, 0x0000ff07, /* fog density */
|
nkeynes@185 | 146 | 0x80b4, 0x007f7f7f, /* fog vertex color */
|
nkeynes@185 | 147 | 0x80b0, 0x007f7f7f, /* fog table color */
|
nkeynes@185 | 148 | 0x8108, 0x00000003 /* 32bit palette */
|
nkeynes@185 | 149 | };
|
nkeynes@185 | 150 |
|
nkeynes@185 | 151 | static unsigned int scrn_params[] = {
|
nkeynes@185 | 152 | 0x80e8, 0x00160000, /* screen control */
|
nkeynes@185 | 153 | 0x8044, 0x00800000, /* pixel mode (vb+0x11) */
|
nkeynes@185 | 154 | 0x805c, 0x00000000, /* Size modulo and display lines (vb+0x17) */
|
nkeynes@185 | 155 | 0x80d0, 0x00000100, /* interlace flags */
|
nkeynes@185 | 156 | 0x80d8, 0x020c0359, /* M */
|
nkeynes@185 | 157 | 0x80cc, 0x001501fe, /* M */
|
nkeynes@185 | 158 | 0x80d4, 0x007e0345, /* horizontal border */
|
nkeynes@185 | 159 | 0x80dc, 0x00240204, /* vertical position */
|
nkeynes@185 | 160 | 0x80e0, 0x07d6c63f, /* sync control */
|
nkeynes@185 | 161 | 0x80ec, 0x000000a4, /* horizontal position */
|
nkeynes@185 | 162 | 0x80f0, 0x00120012, /* vertical border */
|
nkeynes@185 | 163 | 0x80c8, 0x03450000, /* set to same as border H in 80d4 */
|
nkeynes@185 | 164 | 0x8068, 0x027f0000, /* (X resolution - 1) << 16 */
|
nkeynes@185 | 165 | 0x806c, 0x01df0000, /* (Y resolution - 1) << 16 */
|
nkeynes@185 | 166 | 0x804c, 0x000000a0, /* display align */
|
nkeynes@185 | 167 | 0x8118, 0x00008040, /* M */
|
nkeynes@185 | 168 | 0x80f4, 0x00000401, /* anti-aliasing */
|
nkeynes@185 | 169 | 0x8048, 0x00000009, /* alpha config */
|
nkeynes@185 | 170 | 0x7814, 0x00000000, /* More interrupt control stuff (so it seems)*/
|
nkeynes@185 | 171 | 0x7834, 0x00000000,
|
nkeynes@185 | 172 | 0x7854, 0x00000000,
|
nkeynes@185 | 173 | 0x7874, 0x00000000,
|
nkeynes@185 | 174 | 0x78bc, 0x4659404f,
|
nkeynes@185 | 175 | 0x8040, 0x00000000 /* border color */
|
nkeynes@185 | 176 | };
|
nkeynes@185 | 177 |
|
nkeynes@185 | 178 | static void set_regs(unsigned int *values, int cnt)
|
nkeynes@185 | 179 | {
|
nkeynes@185 | 180 | volatile unsigned char *regs = (volatile unsigned char *)(void *)0xa05f0000;
|
nkeynes@185 | 181 | unsigned int r, v;
|
nkeynes@185 | 182 |
|
nkeynes@185 | 183 | while(cnt--) {
|
nkeynes@185 | 184 | r = *values++;
|
nkeynes@185 | 185 | v = *values++;
|
nkeynes@185 | 186 | *(volatile unsigned int *)(regs+r) = v;
|
nkeynes@185 | 187 | }
|
nkeynes@185 | 188 | }
|
nkeynes@185 | 189 |
|
nkeynes@185 | 190 | int pvr_check_cable()
|
nkeynes@185 | 191 | {
|
nkeynes@185 | 192 | volatile unsigned int *porta = (unsigned int *)0xff80002c;
|
nkeynes@185 | 193 |
|
nkeynes@185 | 194 | /* PORT8 and PORT9 is input */
|
nkeynes@185 | 195 | *porta = (*porta & ~0xf0000) | 0xa0000;
|
nkeynes@185 | 196 |
|
nkeynes@185 | 197 | /* Return PORT8 and PORT9 */
|
nkeynes@185 | 198 | return ((*(volatile unsigned short *)(porta+1))>>8)&3;
|
nkeynes@185 | 199 | }
|
nkeynes@185 | 200 | void pvr_init_video(int cabletype, int mode, int res)
|
nkeynes@185 | 201 | {
|
nkeynes@185 | 202 | volatile unsigned int *videobase=(volatile unsigned int *)(void*)0xa05f8000;
|
nkeynes@185 | 203 | static int bppshifttab[]= { 1,1,0,2 };
|
nkeynes@185 | 204 | int shift, lines, modulo, words_per_line, vpos;
|
nkeynes@185 | 205 | int laceoffset=0, voffset=0;
|
nkeynes@185 | 206 | unsigned int videoflags, attribs;
|
nkeynes@185 | 207 | unsigned int hvcounter = (res<2? 0x01060359 : 0x020c0359);
|
nkeynes@185 | 208 |
|
nkeynes@185 | 209 | mode &= 3;
|
nkeynes@185 | 210 | shift = bppshifttab[mode];
|
nkeynes@185 | 211 |
|
nkeynes@185 | 212 | videobase[8/4]=0;
|
nkeynes@185 | 213 | videobase[0x40/4]=0;
|
nkeynes@185 | 214 |
|
nkeynes@185 | 215 | /* Select pixel clock and colour mode */
|
nkeynes@185 | 216 | mode = (mode<<2)|1;
|
nkeynes@185 | 217 | lines = 240;
|
nkeynes@185 | 218 | if(!(cabletype&2)) {
|
nkeynes@185 | 219 |
|
nkeynes@185 | 220 | /* VGA mode */
|
nkeynes@185 | 221 |
|
nkeynes@185 | 222 | if(res < 2)
|
nkeynes@185 | 223 | mode |= 2; /* doublescan */
|
nkeynes@185 | 224 |
|
nkeynes@185 | 225 | hvcounter = 0x020c0359;
|
nkeynes@185 | 226 |
|
nkeynes@185 | 227 | lines <<= 1;
|
nkeynes@185 | 228 | mode |= 0x800000; /* fast pixel clock */
|
nkeynes@185 | 229 | }
|
nkeynes@185 | 230 | videobase[0x44/4]=mode;
|
nkeynes@185 | 231 |
|
nkeynes@185 | 232 | /* Set video base address. Short fields will be offset by
|
nkeynes@185 | 233 | 640 pixels, regardless of horizontal resolution. */
|
nkeynes@185 | 234 | videobase[0x50/4]=0;
|
nkeynes@185 | 235 | videobase[0x54/4]=640<<shift;
|
nkeynes@185 | 236 |
|
nkeynes@185 | 237 | /* Set screen size, modulo, and interlace flag */
|
nkeynes@185 | 238 | videoflags = 1<<8;
|
nkeynes@185 | 239 | if(res==0)
|
nkeynes@185 | 240 | words_per_line=(320/4)<<shift;
|
nkeynes@185 | 241 | else
|
nkeynes@185 | 242 | words_per_line=(640/4)<<shift;
|
nkeynes@185 | 243 | modulo = 1;
|
nkeynes@185 | 244 |
|
nkeynes@185 | 245 | if(!(cabletype&2))
|
nkeynes@185 | 246 | {
|
nkeynes@185 | 247 | if(res==0)
|
nkeynes@185 | 248 | /* VGA lores -> skip 320 pixels to keep modulo at 640 pixels */
|
nkeynes@185 | 249 | modulo += words_per_line;
|
nkeynes@185 | 250 | } else {
|
nkeynes@185 | 251 | if(res!=1)
|
nkeynes@185 | 252 | /* NTSC lores -> skip 320 pixels to keep modulo at 640 pixels */
|
nkeynes@185 | 253 | /* _or_ NTSC hires -> skip every other line due to interlace */
|
nkeynes@185 | 254 | modulo += words_per_line;
|
nkeynes@185 | 255 |
|
nkeynes@185 | 256 | if(res==2)
|
nkeynes@185 | 257 | /* interlace mode */
|
nkeynes@185 | 258 | videoflags |= 1<<4;
|
nkeynes@185 | 259 |
|
nkeynes@185 | 260 | /* enable NTSC */
|
nkeynes@185 | 261 | videoflags |= 1<<6;
|
nkeynes@185 | 262 | }
|
nkeynes@185 | 263 |
|
nkeynes@185 | 264 | /* Write screen size and modulo */
|
nkeynes@185 | 265 | videobase[0x5c/4]=(((modulo<<10)+lines-1)<<10)+words_per_line-1;
|
nkeynes@185 | 266 |
|
nkeynes@185 | 267 | /* Enable video (lace, NTSC) */
|
nkeynes@185 | 268 | videobase[0xd0/4]=videoflags;
|
nkeynes@185 | 269 |
|
nkeynes@185 | 270 | /* Screen and border position */
|
nkeynes@185 | 271 |
|
nkeynes@185 | 272 | if(!(cabletype&2))
|
nkeynes@185 | 273 | /* VGA */
|
nkeynes@185 | 274 | voffset += 36;
|
nkeynes@185 | 275 | else
|
nkeynes@185 | 276 | voffset += 18;
|
nkeynes@185 | 277 |
|
nkeynes@185 | 278 | vpos=(voffset<<16)|(voffset+laceoffset);
|
nkeynes@185 | 279 |
|
nkeynes@185 | 280 | videobase[0xf0/4]=vpos; /* V start */
|
nkeynes@185 | 281 | videobase[0xdc/4]=vpos+lines; /* start and end border */
|
nkeynes@185 | 282 | videobase[0xec/4]=0xa4; /* Horizontal pos */
|
nkeynes@185 | 283 | videobase[0xd8/4]=hvcounter; /* HV counter */
|
nkeynes@185 | 284 | videobase[0xd4/4]=0x007e0345; /* Horizontal border */
|
nkeynes@185 | 285 |
|
nkeynes@185 | 286 | /* Select horizontal pixel doubling for lowres */
|
nkeynes@185 | 287 | if(res==0)
|
nkeynes@185 | 288 | attribs=((22<<8)+1)<<8;
|
nkeynes@185 | 289 | else
|
nkeynes@185 | 290 | attribs=22<<16;
|
nkeynes@185 | 291 | videobase[0xe8/4]=attribs;
|
nkeynes@185 | 292 |
|
nkeynes@185 | 293 | /* Set up vertical blank event */
|
nkeynes@185 | 294 | vpos = 260;
|
nkeynes@185 | 295 | if(!(cabletype&2))
|
nkeynes@185 | 296 | vpos = 510;
|
nkeynes@185 | 297 | videobase[0xcc/4]=(0x21<<16)|vpos;
|
nkeynes@185 | 298 |
|
nkeynes@185 | 299 | /* Select RGB/CVBS */
|
nkeynes@185 | 300 | if(cabletype&1)
|
nkeynes@185 | 301 | mode = 3;
|
nkeynes@185 | 302 | else
|
nkeynes@185 | 303 | mode = 0;
|
nkeynes@185 | 304 | *(volatile unsigned int *)(void*)0xa0702c00 = mode << 8;
|
nkeynes@185 | 305 |
|
nkeynes@185 | 306 | return;
|
nkeynes@185 | 307 | }
|
nkeynes@185 | 308 |
|
nkeynes@185 | 309 | void pvr_init()
|
nkeynes@185 | 310 | {
|
nkeynes@185 | 311 | volatile unsigned int *vbl = (volatile unsigned int *)(void *)0xa05f810c;
|
nkeynes@185 | 312 |
|
nkeynes@185 | 313 | set_regs(three_d_params, sizeof(three_d_params)/sizeof(three_d_params[0])/2);
|
nkeynes@185 | 314 | while (!(*vbl & 0x01ff));
|
nkeynes@185 | 315 | while (*vbl & 0x01ff);
|
nkeynes@185 | 316 | set_regs(scrn_params, sizeof(scrn_params)/sizeof(scrn_params[0])/2);
|
nkeynes@185 | 317 | pvr_init_video(pvr_check_cable(), 1, 2);
|
nkeynes@185 | 318 | }
|
nkeynes@185 | 319 |
|