filename | test/pvr.c |
changeset | 1153:00e507e4025c |
prev | 1151:e1848ca9b5b1 |
author | Nathan Keynes <nkeynes@lxdream.org> |
date | Wed May 11 20:25:49 2011 +1000 (12 years ago) |
permissions | -rw-r--r-- |
last change | Add xlat_get_address to find the SH4 address corresponding to a host code address (for debugging purposes) |
view | annotate | diff | log | raw |
1 /**
2 * $Id$
3 *
4 * PVR support code
5 *
6 * Copyright (c) 2006 Nathan Keynes.
7 *
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.
12 *
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.
17 */
19 #include "lib.h"
20 #include "pvr.h"
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 )
55 {
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) );
62 }
65 void ta_init( struct ta_config *config )
66 {
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 );
78 }
80 void ta_reinit( )
81 {
82 long_write( TA_REINIT, 0x80000000 );
83 }
85 int pvr_get_objbuf_size( )
86 {
87 return long_read( TA_OBJPOSN ) - long_read( TA_OBJSTART );
88 }
90 int pvr_get_objbuf_posn( )
91 {
92 return long_read( TA_OBJPOSN );
93 }
95 int pvr_get_plist_posn( )
96 {
97 unsigned int addr = long_read( TA_TILEPOSN ) << 2;
98 return addr;
99 }
101 void pvr_dump_objbuf( FILE *f )
102 {
103 unsigned int start = long_read( TA_OBJSTART );
104 unsigned int posn = long_read( TA_OBJPOSN );
105 unsigned int end = long_read( TA_OBJEND );
106 char *buf;
107 unsigned int length;
108 if( start < posn ) {
109 buf = (char *)(0xA5000000+start);
110 length = posn-start;
111 } else {
112 buf = (char *)(0xA5000000+end);
113 length = start-posn;
114 }
116 fprintf( f, "Obj buffer: %08X - %08X - %08X\n", start, posn, end );
117 fwrite_dump( f, buf, length );
118 }
120 void pvr_dump_tilebuf( FILE *f )
121 {
122 unsigned int start = long_read( TA_TILESTART );
123 unsigned int posn = long_read( TA_TILEPOSN );
124 unsigned int end = long_read( TA_TILEEND );
125 char *buf;
126 unsigned int length;
127 if( start < posn ) {
128 buf = (char *)(0xA5000000+start);
129 length = posn-start;
130 } else {
131 buf = (char *)(0xA5000000+end);
132 length = start-posn;
133 }
135 fprintf( f, "Tile buffer: %08X - %08X - %08X\n", start, posn, end );
136 fwrite_dump( f, buf, length );
137 }
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);
148 }
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]);
154 }
156 static uint32_t *pvr_compute_tile_ptrs( uint32_t *target, struct ta_config *config, int x, int y )
157 {
158 int i;
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++ ) {
164 if( cfg & 0x03 ) {
165 int tile_size = ta_tile_sizes[cfg&0x03];
166 *target++ = tilematrix + (((y*hsegs)+x)*tile_size);
167 tilematrix += hsegs*vsegs*tile_size;
168 } else {
169 *target++ = 0x80000000;
170 }
171 cfg = cfg >> 4;
172 }
173 return target;
174 }
176 void pvr_build_tilemap1( uint32_t addr, struct ta_config *config, uint32_t control_word )
177 {
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;
182 int x,y;
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);
194 }
195 }
196 dest[-6] |= 0x80000000; /* End-of-render */
197 }
199 void pvr_build_tilemap2( uint32_t addr, struct ta_config *config, uint32_t control_word )
200 {
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;
205 int x,y;
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);
222 }
223 }
224 dest[-6] |= 0x80000000; /* End-of-render */
225 }
227 void render_set_backplane( uint32_t mode )
228 {
229 long_write( RENDER_BGPLANE, mode );
230 }
232 int get_line_size( struct render_config *config )
233 {
234 int modulo = config->width;
235 switch( config->mode & 0x07 ) {
236 case 4:
237 modulo *= 3; /* ??? */
238 break;
239 case 5:
240 case 6:
241 modulo *= 4;
242 break;
243 default:
244 modulo *= 2;
245 }
246 return modulo;
247 }
249 void render_start( struct render_config *config )
250 {
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 );
263 }
265 void display_render( struct render_config *config )
266 {
267 long_write( DISPLAY_ADDR1, config->render_addr );
268 long_write( DISPLAY_ADDR2, config->render_addr + get_line_size(config) );
269 }
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 */
297 0x6930, 0x00000000,
298 0x6938, 0x00000000,
299 0x6900, 0xffffffff, /* Clear all pending int events */
300 0x6908, 0xffffffff,
301 0x6930, 0x002807ec, /* Re-enable some events */
302 0x6938, 0x0000000e,
303 0x80b8, 0x0000ff07, /* fog density */
304 0x80b4, 0x007f7f7f, /* fog vertex color */
305 0x80b0, 0x007f7f7f, /* fog table color */
306 0x8108, 0x00000003 /* 32bit palette */
307 };
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)*/
329 0x7834, 0x00000000,
330 0x7854, 0x00000000,
331 0x7874, 0x00000000,
332 0x78bc, 0x4659404f,
333 0x8040, 0x00000000 /* border color */
334 };
336 static void set_regs(unsigned int *values, int cnt)
337 {
338 volatile unsigned char *regs = (volatile unsigned char *)(void *)0xa05f0000;
339 unsigned int r, v;
341 while(cnt--) {
342 r = *values++;
343 v = *values++;
344 *(volatile unsigned int *)(regs+r) = v;
345 }
346 }
348 int pvr_check_cable()
349 {
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;
357 }
358 void pvr_init_video(int cabletype, int mode, int res)
359 {
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);
367 mode &= 3;
368 shift = bppshifttab[mode];
370 videobase[8/4]=0;
371 videobase[0x40/4]=0;
373 /* Select pixel clock and colour mode */
374 mode = (mode<<2)|1;
375 lines = 240;
376 if(!(cabletype&2)) {
378 /* VGA mode */
380 if(res < 2)
381 mode |= 2; /* doublescan */
383 hvcounter = 0x020c0359;
385 lines <<= 1;
386 mode |= 0x800000; /* fast pixel clock */
387 }
388 videobase[0x44/4]=mode;
390 /* Set video base address. Short fields will be offset by
391 640 pixels, regardless of horizontal resolution. */
392 videobase[0x50/4]=0;
393 videobase[0x54/4]=640<<shift;
395 /* Set screen size, modulo, and interlace flag */
396 videoflags = 1<<8;
397 if(res==0)
398 words_per_line=(320/4)<<shift;
399 else
400 words_per_line=(640/4)<<shift;
401 modulo = 1;
403 if(!(cabletype&2))
404 {
405 if(res==0)
406 /* VGA lores -> skip 320 pixels to keep modulo at 640 pixels */
407 modulo += words_per_line;
408 } else {
409 if(res!=1)
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;
414 if(res==2)
415 /* interlace mode */
416 videoflags |= 1<<4;
418 /* enable NTSC */
419 videoflags |= 1<<6;
420 }
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 */
430 if(!(cabletype&2))
431 /* VGA */
432 voffset += 36;
433 else
434 voffset += 18;
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 */
445 if(res==0)
446 attribs=((22<<8)+1)<<8;
447 else
448 attribs=22<<16;
449 videobase[0xe8/4]=attribs;
451 /* Set up vertical blank event */
452 vpos = 260;
453 if(!(cabletype&2))
454 vpos = 510;
455 videobase[0xcc/4]=(0x21<<16)|vpos;
457 /* Select RGB/CVBS */
458 if(cabletype&1)
459 mode = 3;
460 else
461 mode = 0;
462 *(volatile unsigned int *)(void*)0xa0702c00 = mode << 8;
464 return;
465 }
467 void pvr_init()
468 {
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);
476 }
478 void draw_grid( unsigned short *addr, unsigned short colour )
479 {
480 int x,y;
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;
485 }
486 }
487 for( y=0; y<480; y+=32 ) {
488 for( x=0; x<640; x++ ) {
489 addr[(linesize*y) + x] = colour;
490 }
491 }
492 }
494 void draw_grid_24( unsigned char *addr, unsigned int colour )
495 {
496 int x,y;
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;
504 addr[a++] = r;
505 addr[a++] = g;
506 addr[a++] = b;
507 }
508 }
509 for( y=0; y<480; y+=32 ) {
510 for( x=0; x<640; x++ ) {
511 int a = (linesize*y)+x * 3;
512 addr[a++] = r;
513 addr[a++] = g;
514 addr[a++] = b;
515 }
516 }
517 }
.