2 * $Id: pvr.c,v 1.5 2007-01-24 08:13:18 nkeynes Exp $
6 * Copyright (c) 2006 Nathan Keynes.
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
22 #define PVR_BASE 0xA05F8000
23 #define PVR_RESET (PVR_BASE+0x008)
24 #define TA_INIT (PVR_BASE+0x144)
25 #define TA_TILESTART (PVR_BASE+0x124)
26 #define TA_OBJSTART (PVR_BASE+0x128)
27 #define TA_TILEEND (PVR_BASE+0x12C)
28 #define TA_OBJEND (PVR_BASE+0x130)
29 #define TA_TILEPOSN (PVR_BASE+0x134)
30 #define TA_OBJPOSN (PVR_BASE+0x138)
31 #define TA_SIZE (PVR_BASE+0x13C)
32 #define TA_TILECFG (PVR_BASE+0x140)
33 #define TA_REINIT (PVR_BASE+0x160)
34 #define TA_PLISTSTART (PVR_BASE+0x164)
36 #define RENDER_START (PVR_BASE+0x014)
37 #define RENDER_POLYBASE (PVR_BASE+0x020)
38 #define RENDER_TILEBASE (PVR_BASE+0x02C)
39 #define RENDER_MODE (PVR_BASE+0x048)
40 #define RENDER_SIZE (PVR_BASE+0x04C)
41 #define RENDER_ADDR1 (PVR_BASE+0x060)
42 #define RENDER_ADDR2 (PVR_BASE+0x064)
43 #define RENDER_HCLIP (PVR_BASE+0x068)
44 #define RENDER_VCLIP (PVR_BASE+0x06C)
45 #define RENDER_NEARCLIP (PVR_BASE+0x078)
46 #define RENDER_FARCLIP (PVR_BASE+0x088)
47 #define RENDER_BGPLANE (PVR_BASE+0x08C)
49 #define DISPLAY_MODE (PVR_BASE+0x044)
50 #define DISPLAY_ADDR1 (PVR_BASE+0x050)
51 #define DISPLAY_ADDR2 (PVR_BASE+0x054)
52 #define DISPLAY_SIZE (PVR_BASE+0x05C
54 void ta_dump_regs( FILE *f )
56 fprintf( stderr, "TA Object start[128]: %08X posn[138]: %08X end[130]: %08X\n",
57 long_read(TA_OBJSTART), long_read(TA_OBJPOSN), long_read(TA_OBJEND) );
58 fprintf( stderr, "TA OPB start[124]: %08X posn[134]: %08X end[12c]: %08X init: %08X\n",
59 long_read(TA_TILESTART), long_read(TA_TILEPOSN), long_read(TA_TILEEND),
60 long_read(TA_PLISTSTART) );
61 fprintf( stderr, "TA Tilesize: %08X config: %08X\n", long_read(TA_SIZE), long_read(TA_TILECFG) );
65 void ta_init( struct ta_config *config )
67 long_write( PVR_RESET, 1 );
68 long_write( PVR_RESET, 0 );
70 long_write( TA_SIZE, config->grid_size );
71 long_write( TA_OBJSTART, config->obj_start & 0x00FFFFFF );
72 long_write( TA_OBJEND, config->obj_end & 0x00FFFFFF );
73 long_write( TA_TILESTART, config->tile_start & 0x00FFFFFF );
74 long_write( TA_TILEEND, config->tile_end & 0x00FFFFFF );
75 long_write( TA_PLISTSTART, config->plist_start & 0x00FFFFFF );
76 long_write( TA_TILECFG, config->ta_cfg );
77 long_write( TA_INIT, 0x80000000 );
82 long_write( TA_REINIT, 0x80000000 );
85 int pvr_get_objbuf_size( )
87 return long_read( TA_OBJPOSN ) - long_read( TA_OBJSTART );
90 int pvr_get_objbuf_posn( )
92 return long_read( TA_OBJPOSN );
95 int pvr_get_plist_posn( )
97 unsigned int addr = long_read( TA_TILEPOSN ) << 2;
101 void pvr_dump_objbuf( FILE *f )
103 unsigned int start = long_read( TA_OBJSTART );
104 unsigned int posn = long_read( TA_OBJPOSN );
105 unsigned int end = long_read( TA_OBJEND );
109 buf = (char *)(0xA5000000+start);
112 buf = (char *)(0xA5000000+end);
116 fprintf( f, "Obj buffer: %08X - %08X - %08X\n", start, posn, end );
117 fwrite_dump( f, buf, length );
120 void pvr_dump_tilebuf( FILE *f )
122 unsigned int start = long_read( TA_TILESTART );
123 unsigned int posn = long_read( TA_TILEPOSN );
124 unsigned int end = long_read( TA_TILEEND );
128 buf = (char *)(0xA5000000+start);
131 buf = (char *)(0xA5000000+end);
135 fprintf( f, "Tile buffer: %08X - %08X - %08X\n", start, posn, end );
136 fwrite_dump( f, buf, length );
139 static int ta_tile_sizes[4] = { 0, 32, 64, 128 };
140 #define TILE_SIZE(cfg, tile) ta_tile_sizes[((((cfg->ta_cfg) >> (4*tile))&0x03))]
141 #define TILE_ENABLED(cfg, tile) ((((cfg->ta_cfg) >> (4*tile))&0x03) != 0)
142 void pvr_compute_tilematrix_addr( int *tile_ptrs, struct ta_config *config ) {
143 int tile_sizes[5], i;
144 int hsegs = (config->grid_size & 0xFFFF)+1;
145 int vsegs = (config->grid_size >> 16) + 1;
146 for( i=0; i<5; i++ ) {
147 tile_sizes[i] = TILE_SIZE(config,i);
149 tile_ptrs[0] = config->tile_start;
150 tile_ptrs[1] = tile_ptrs[0] + (hsegs*vsegs*tile_sizes[0]);
151 tile_ptrs[2] = tile_ptrs[1] + (hsegs*vsegs*tile_sizes[1]);
152 tile_ptrs[3] = tile_ptrs[2] + (hsegs*vsegs*tile_sizes[2]);
153 tile_ptrs[4] = tile_ptrs[3] + (hsegs*vsegs*tile_sizes[3]);
156 static uint32_t *pvr_compute_tile_ptrs( uint32_t *target, struct ta_config *config, int x, int y )
159 int cfg = config->ta_cfg;
160 int hsegs = (config->grid_size & 0xFFFF)+1;
161 int vsegs = (config->grid_size >> 16) + 1;
162 int tilematrix = config->tile_start;
163 for( i=0; i<5; i++ ) {
165 int tile_size = ta_tile_sizes[cfg&0x03];
166 *target++ = tilematrix + (((y*hsegs)+x)*tile_size);
167 tilematrix += hsegs*vsegs*tile_size;
169 *target++ = 0x80000000;
176 void pvr_build_tilemap1( uint32_t addr, struct ta_config *config, uint32_t control_word )
178 uint32_t *dest = (uint32_t *)(PVR_VRAM_BASE+addr);
179 int w = (config->grid_size & 0x0000FFFF) + 1;
180 int h = (config->grid_size >> 16) + 1;
183 memset( (char *)(dest-18), 0, 18*4 );
184 *dest++ = 0x10000000;
185 *dest++ = 0x80000000;
186 *dest++ = 0x80000000;
187 *dest++ = 0x80000000;
188 *dest++ = 0x80000000;
189 *dest++ = 0x80000000;
190 for( x=0; x<w; x++ ) {
191 for( y=0; y<h; y++ ) {
192 *dest++ = control_word | (y << 8) | (x << 2);
193 dest = pvr_compute_tile_ptrs(dest, config, x, y);
196 dest[-6] |= 0x80000000; /* End-of-render */
199 void pvr_build_tilemap2( uint32_t addr, struct ta_config *config, uint32_t control_word )
201 uint32_t *dest = (uint32_t *)(PVR_VRAM_BASE+addr);
202 int w = (config->grid_size & 0x0000FFFF) + 1;
203 int h = (config->grid_size >> 16) + 1;
206 *dest++ = 0x10000000;
207 *dest++ = 0x80000000;
208 *dest++ = 0x80000000;
209 *dest++ = 0x80000000;
210 *dest++ = 0x80000000;
211 *dest++ = 0x80000000;
212 for( x=0; x<w; x++ ) {
213 for( y=0; y<h; y++ ) {
214 *dest++ = 0x40000000;
215 *dest++ = 0x80000000;
216 *dest++ = 0x80000000;
217 *dest++ = 0x80000000;
218 *dest++ = 0x80000000;
219 *dest++ = 0x80000000;
220 *dest++ = control_word | (y << 8) | (x << 2);
221 dest = pvr_compute_tile_ptrs(dest, config, x, y);
224 dest[-6] |= 0x80000000; /* End-of-render */
227 void render_set_backplane( uint32_t mode )
229 long_write( RENDER_BGPLANE, mode );
232 int get_line_size( struct render_config *config )
234 int modulo = config->width;
235 switch( config->mode & 0x07 ) {
237 modulo *= 3; /* ??? */
249 void render_start( struct render_config *config )
251 int modulo = get_line_size( config );
252 long_write( RENDER_POLYBASE, config->polybuf );
253 long_write( RENDER_TILEBASE, config->tilemap );
254 long_write( RENDER_ADDR1, config->render_addr );
255 long_write( RENDER_SIZE, modulo >> 3 );
256 long_write( RENDER_ADDR2, config->render_addr + modulo ); /* Not used? */
257 long_write( RENDER_HCLIP, (config->width - 1) << 16 );
258 long_write( RENDER_VCLIP, (config->height - 1) << 16 );
259 long_write( RENDER_MODE, config->mode );
260 float_write( RENDER_FARCLIP, config->farclip );
261 float_write( RENDER_NEARCLIP, config->nearclip );
262 long_write( RENDER_START, 0xFFFFFFFF );
265 void display_render( struct render_config *config )
267 long_write( DISPLAY_ADDR1, config->render_addr );
268 long_write( DISPLAY_ADDR2, config->render_addr + get_line_size(config) );
271 /************** Stolen from TATEST *************/
273 static unsigned int three_d_params[] = {
274 0x80a8, 0x15d1c951, /* M (Unknown magic value) */
275 0x80a0, 0x00000020, /* M */
276 0x8008, 0x00000000, /* TA out of reset */
277 0x8048, 0x00000009, /* alpha config */
278 0x8068, 0x02800000, /* pixel clipping x */
279 0x806c, 0x01e00000, /* pixel clipping y */
280 0x8110, 0x00093f39, /* M */
281 0x8098, 0x00800408, /* M */
282 0x804c, 0x000000a0, /* display align (640*2)/8 */
283 0x8078, 0x3f800000, /* polygon culling (1.0f) */
284 0x8084, 0x00000000, /* M */
285 0x8030, 0x00000101, /* M */
286 0x80b0, 0x007f7f7f, /* Fog table color */
287 0x80b4, 0x007f7f7f, /* Fog vertex color */
288 0x80c0, 0x00000000, /* color clamp min */
289 0x80bc, 0xffffffff, /* color clamp max */
290 0x8080, 0x00000007, /* M */
291 0x8074, 0x00000001, /* cheap shadow */
292 0x807c, 0x0027df77, /* M */
293 0x8008, 0x00000001, /* TA reset */
294 0x8008, 0x00000000, /* TA out of reset */
295 0x80e4, 0x00000000, /* stride width */
296 0x6884, 0x00000000, /* Disable all interrupt events */
299 0x6900, 0xffffffff, /* Clear all pending int events */
301 0x6930, 0x002807ec, /* Re-enable some events */
303 0x80b8, 0x0000ff07, /* fog density */
304 0x80b4, 0x007f7f7f, /* fog vertex color */
305 0x80b0, 0x007f7f7f, /* fog table color */
306 0x8108, 0x00000003 /* 32bit palette */
309 static unsigned int scrn_params[] = {
310 0x80e8, 0x00160000, /* screen control */
311 0x8044, 0x00800000, /* pixel mode (vb+0x11) */
312 0x805c, 0x00000000, /* Size modulo and display lines (vb+0x17) */
313 0x80d0, 0x00000100, /* interlace flags */
314 0x80d8, 0x020c0359, /* M */
315 0x80cc, 0x001501fe, /* M */
316 0x80d4, 0x007e0345, /* horizontal border */
317 0x80dc, 0x00240204, /* vertical position */
318 0x80e0, 0x07d6c63f, /* sync control */
319 0x80ec, 0x000000a4, /* horizontal position */
320 0x80f0, 0x00120012, /* vertical border */
321 0x80c8, 0x03450000, /* set to same as border H in 80d4 */
322 0x8068, 0x027f0000, /* (X resolution - 1) << 16 */
323 0x806c, 0x01df0000, /* (Y resolution - 1) << 16 */
324 0x804c, 0x000000a0, /* display align */
325 0x8118, 0x00008040, /* M */
326 0x80f4, 0x00000401, /* anti-aliasing */
327 0x8048, 0x00000009, /* alpha config */
328 0x7814, 0x00000000, /* More interrupt control stuff (so it seems)*/
333 0x8040, 0x00000000 /* border color */
336 static void set_regs(unsigned int *values, int cnt)
338 volatile unsigned char *regs = (volatile unsigned char *)(void *)0xa05f0000;
344 *(volatile unsigned int *)(regs+r) = v;
348 int pvr_check_cable()
350 volatile unsigned int *porta = (unsigned int *)0xff80002c;
352 /* PORT8 and PORT9 is input */
353 *porta = (*porta & ~0xf0000) | 0xa0000;
355 /* Return PORT8 and PORT9 */
356 return ((*(volatile unsigned short *)(porta+1))>>8)&3;
358 void pvr_init_video(int cabletype, int mode, int res)
360 volatile unsigned int *videobase=(volatile unsigned int *)(void*)0xa05f8000;
361 static int bppshifttab[]= { 1,1,0,2 };
362 int shift, lines, modulo, words_per_line, vpos;
363 int laceoffset=0, voffset=0;
364 unsigned int videoflags, attribs;
365 unsigned int hvcounter = (res<2? 0x01060359 : 0x020c0359);
368 shift = bppshifttab[mode];
373 /* Select pixel clock and colour mode */
381 mode |= 2; /* doublescan */
383 hvcounter = 0x020c0359;
386 mode |= 0x800000; /* fast pixel clock */
388 videobase[0x44/4]=mode;
390 /* Set video base address. Short fields will be offset by
391 640 pixels, regardless of horizontal resolution. */
393 videobase[0x54/4]=640<<shift;
395 /* Set screen size, modulo, and interlace flag */
398 words_per_line=(320/4)<<shift;
400 words_per_line=(640/4)<<shift;
406 /* VGA lores -> skip 320 pixels to keep modulo at 640 pixels */
407 modulo += words_per_line;
410 /* NTSC lores -> skip 320 pixels to keep modulo at 640 pixels */
411 /* _or_ NTSC hires -> skip every other line due to interlace */
412 modulo += words_per_line;
422 /* Write screen size and modulo */
423 videobase[0x5c/4]=(((modulo<<10)+lines-1)<<10)+words_per_line-1;
425 /* Enable video (lace, NTSC) */
426 videobase[0xd0/4]=videoflags;
428 /* Screen and border position */
436 vpos=(voffset<<16)|(voffset+laceoffset);
438 videobase[0xf0/4]=vpos; /* V start */
439 videobase[0xdc/4]=vpos+lines; /* start and end border */
440 videobase[0xec/4]=0xa4; /* Horizontal pos */
441 videobase[0xd8/4]=hvcounter; /* HV counter */
442 videobase[0xd4/4]=0x007e0345; /* Horizontal border */
444 /* Select horizontal pixel doubling for lowres */
446 attribs=((22<<8)+1)<<8;
449 videobase[0xe8/4]=attribs;
451 /* Set up vertical blank event */
455 videobase[0xcc/4]=(0x21<<16)|vpos;
457 /* Select RGB/CVBS */
462 *(volatile unsigned int *)(void*)0xa0702c00 = mode << 8;
469 volatile unsigned int *vbl = (volatile unsigned int *)(void *)0xa05f810c;
471 set_regs(three_d_params, sizeof(three_d_params)/sizeof(three_d_params[0])/2);
472 while (!(*vbl & 0x01ff));
473 while (*vbl & 0x01ff);
474 set_regs(scrn_params, sizeof(scrn_params)/sizeof(scrn_params[0])/2);
475 pvr_init_video(pvr_check_cable(), 1, 2);
478 void draw_grid( unsigned short *addr, unsigned short colour )
481 unsigned int linesize = 640;
482 for( x=0; x<640; x+=32 ) {
483 for( y=0; y<480; y++ ) {
484 addr[(linesize*y) + x] = colour;
487 for( y=0; y<480; y+=32 ) {
488 for( x=0; x<640; x++ ) {
489 addr[(linesize*y) + x] = colour;
494 void draw_grid_24( unsigned char *addr, unsigned int colour )
497 char r = (colour >> 16) & 0xFF;
498 char g = (colour >> 8) & 0xFF;
499 char b = (colour & 0xFF);
500 unsigned int linesize = 640*3;
501 for( x=0; x<640; x+=32 ) {
502 for( y=0; y<480; y++ ) {
503 int a = (linesize*y)+x * 3;
509 for( y=0; y<480; y+=32 ) {
510 for( x=0; x<640; x++ ) {
511 int a = (linesize*y)+x * 3;
.