nkeynes@263: /** nkeynes@267: * $Id: testdisp.c,v 1.2 2007-01-06 04:08:11 nkeynes Exp $ nkeynes@263: * nkeynes@263: * Display (2D) tests. Mainly tests video timing / sync (obviously nkeynes@263: * it can't actually test display output since there's no way of nkeynes@263: * reading the results) nkeynes@263: * nkeynes@263: * These tests use TMU2 to determine absolute time nkeynes@263: * Copyright (c) 2006 Nathan Keynes. nkeynes@263: * nkeynes@263: * This program is free software; you can redistribute it and/or modify nkeynes@263: * it under the terms of the GNU General Public License as published by nkeynes@263: * the Free Software Foundation; either version 2 of the License, or nkeynes@263: * (at your option) any later version. nkeynes@263: * nkeynes@263: * This program is distributed in the hope that it will be useful, nkeynes@263: * but WITHOUT ANY WARRANTY; without even the implied warranty of nkeynes@263: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the nkeynes@263: * GNU General Public License for more details. nkeynes@263: */ nkeynes@263: #include nkeynes@263: #include nkeynes@263: #include "lib.h" nkeynes@263: #include "asic.h" nkeynes@263: nkeynes@263: #define PVR_BASE 0xA05F8000 nkeynes@263: nkeynes@263: #define BORDERCOL (PVR_BASE+0x040) nkeynes@263: #define DISPCFG1 (PVR_BASE+0x044) nkeynes@263: #define DISPADDR1 (PVR_BASE+0x050) nkeynes@263: #define DISPADDR2 (PVR_BASE+0x054) nkeynes@263: #define DISPSIZE (PVR_BASE+0x05C) nkeynes@263: #define HPOSEVENT (PVR_BASE+0x0C8) nkeynes@263: #define VPOSEVENT (PVR_BASE+0x0CC) nkeynes@263: #define DISPCFG2 (PVR_BASE+0x0D0) nkeynes@263: #define HBORDER (PVR_BASE+0x0D4) nkeynes@267: #define DISPTOTAL (PVR_BASE+0x0D8) nkeynes@263: #define VBORDER (PVR_BASE+0x0DC) nkeynes@267: #define SYNCTIME (PVR_BASE+0x0E0) nkeynes@263: #define DISPCFG3 (PVR_BASE+0x0E8) nkeynes@263: #define HPOS (PVR_BASE+0x0EC) nkeynes@263: #define VPOS (PVR_BASE+0x0F0) nkeynes@263: #define SYNCSTAT (PVR_BASE+0x10C) nkeynes@263: nkeynes@267: #define MAX_FRAME_WAIT 0x50000 nkeynes@267: nkeynes@267: #define EVENT_RETRACE 5 nkeynes@263: nkeynes@263: #define WAIT_LINE( a ) if( wait_line(a) != 0 ) { fprintf(stderr, "Timeout at %s:%d:%s() waiting for line %d\n", __FILE__, __LINE__, __func__, a ); return -1; } nkeynes@263: #define WAIT_LASTLINE( a ) if( wait_lastline(a) != 0 ) { fprintf(stderr, "Last line check failed at %s:%d:%s() waiting for line %d\n", __FILE__, __LINE__, __func__, a ); return -1; } nkeynes@263: nkeynes@263: void dump_display_regs( FILE *out ) nkeynes@263: { nkeynes@263: fprintf( out, "%08X DISPCFG1: %08X\n", DISPCFG1, long_read(DISPCFG1) ); nkeynes@263: fprintf( out, "%08X DISPCFG2: %08X\n", DISPCFG2, long_read(DISPCFG2) ); nkeynes@263: fprintf( out, "%08X DISPCFG3: %08X\n", DISPCFG3, long_read(DISPCFG3) ); nkeynes@263: fprintf( out, "%08X DISPSIZE: %08X\n", DISPSIZE, long_read(DISPSIZE) ); nkeynes@263: fprintf( out, "%08X HBORDER: %08X\n", HBORDER, long_read(HBORDER) ); nkeynes@263: fprintf( out, "%08X VBORDER: %08X\n", VBORDER, long_read(VBORDER) ); nkeynes@267: fprintf( out, "%08X SYNCTIME: %08X\n", SYNCTIME, long_read(SYNCTIME) ); nkeynes@267: fprintf( out, "%08X DISPTOTAL: %08X\n", DISPTOTAL, long_read(DISPTOTAL) ); nkeynes@263: fprintf( out, "%08X DISPADDR1: %08X\n", DISPADDR1, long_read(DISPADDR1) ); nkeynes@263: fprintf( out, "%08X DISPADDR2: %08X\n", DISPADDR2, long_read(DISPADDR2) ); nkeynes@263: fprintf( out, "%08X HPOSEVENT: %08X\n", HPOSEVENT, long_read(HPOSEVENT) ); nkeynes@263: fprintf( out, "%08X VPOSEVENT: %08X\n", VPOSEVENT, long_read(VPOSEVENT) ); nkeynes@263: fprintf( out, "%08X HPOS: %08X\n", HPOS, long_read(HPOS) ); nkeynes@263: fprintf( out, "%08X VPOS: %08X\n", VPOS, long_read(VPOS) ); nkeynes@263: fprintf( out, "%08X SYNCSTAT: %08X\n", SYNCSTAT, long_read(SYNCSTAT) ); nkeynes@263: } nkeynes@263: nkeynes@263: uint32_t pal_settings[] = { nkeynes@263: DISPCFG1, 0x00000001, nkeynes@263: DISPCFG2, 0x00000150, nkeynes@263: DISPCFG3, 0x00160000, nkeynes@263: DISPSIZE, 0x1413BD3F, nkeynes@263: HBORDER, 0x008D034B, nkeynes@263: VBORDER, 0x00120102, nkeynes@267: DISPTOTAL, 0x0270035F, nkeynes@267: SYNCTIME, 0x07D6A53F, nkeynes@263: HPOS, 0x000000A4, nkeynes@263: VPOS, 0x00120012, nkeynes@267: VPOSEVENT, 0x00150136, nkeynes@263: 0, 0 }; nkeynes@263: nkeynes@267: uint32_t ntsc_settings[] = { nkeynes@267: DISPCFG1, 0x00000001, nkeynes@267: DISPCFG2, 0x00000150, nkeynes@267: DISPCFG3, 0x00160000, nkeynes@267: DISPSIZE, 0x1413BD3F, nkeynes@267: HBORDER, 0x007e0345, nkeynes@267: VBORDER, 0x00120102, nkeynes@267: DISPTOTAL, 0x020C0359, nkeynes@267: SYNCTIME, 0x07d6c63f, nkeynes@267: HPOS, 0x000000A4, nkeynes@267: VPOS, 0x00120012, nkeynes@267: VPOSEVENT, 0x001501FE, nkeynes@267: 0, 0 }; nkeynes@267: nkeynes@267: nkeynes@267: struct timing { nkeynes@267: uint32_t interlaced; nkeynes@267: uint32_t total_lines; nkeynes@267: uint32_t vsync_lines; nkeynes@267: uint32_t line_time_us; nkeynes@267: uint32_t field_time_us; nkeynes@267: uint32_t hsync_width_us; nkeynes@267: uint32_t front_porch_us; nkeynes@267: uint32_t back_porch_us; nkeynes@267: }; nkeynes@267: nkeynes@267: struct timing ntsc_timing = { 1, 525, 6, 31, 16641, 4, 12, 4 }; nkeynes@267: struct timing pal_timing = { 1, 625, 5, 31, 19949, 4, 12, 4 }; nkeynes@267: nkeynes@263: void apply_display_settings( uint32_t *regs ) { nkeynes@263: int i; nkeynes@263: for( i=0; regs[i] != 0; i+=2 ) { nkeynes@263: long_write( regs[i], regs[i+1] ); nkeynes@263: } nkeynes@263: } nkeynes@263: nkeynes@263: /** nkeynes@263: * Wait until the given line is being displayed (ie is set in the syncstat nkeynes@263: * register). nkeynes@263: * @return 0 if the line is reached before timeout, otherwise -1. nkeynes@263: */ nkeynes@263: int wait_line( int line ) nkeynes@263: { nkeynes@263: int i; nkeynes@263: for( i=0; i< MAX_FRAME_WAIT; i++ ) { nkeynes@263: uint32_t sync = long_read(SYNCSTAT) & 0x03FF; nkeynes@263: if( sync == line ) { nkeynes@263: return 0; nkeynes@263: } nkeynes@263: } nkeynes@263: return -1; nkeynes@263: } nkeynes@263: nkeynes@263: /** nkeynes@263: * Wait until just after the last line of the frame is being displayed (according nkeynes@263: * to the syncstat register). After this function the current line will be 0. nkeynes@263: * @return 0 if the last line is the given line, otherwise -1. nkeynes@263: */ nkeynes@263: int wait_lastline( int line ) nkeynes@263: { nkeynes@267: int lastline = 0, i; nkeynes@263: for( i=0; i< MAX_FRAME_WAIT; i++ ) { nkeynes@263: uint32_t sync = long_read(SYNCSTAT) & 0x03FF; nkeynes@267: if( sync == 0 && lastline != 0 ) { nkeynes@263: CHECK_IEQUALS( line, lastline ); nkeynes@263: return 0; nkeynes@263: } nkeynes@263: lastline = sync; nkeynes@263: } nkeynes@263: fprintf( stderr, "Timeout waiting for line %d\n", line ); nkeynes@263: return -1; nkeynes@263: } nkeynes@263: nkeynes@267: int check_events_interlaced( ) nkeynes@267: { nkeynes@267: uint32_t status1, status2, status3; nkeynes@267: int i; nkeynes@267: for( i=0; i< MAX_FRAME_WAIT; i++ ) { nkeynes@267: status1 = long_read(SYNCSTAT) & 0x07FF; nkeynes@267: if( status1 == 0x04FF ) { nkeynes@267: break; nkeynes@267: } nkeynes@267: } nkeynes@267: asic_clear(); nkeynes@267: asic_wait(EVENT_RETRACE); nkeynes@267: status1 = long_read(SYNCSTAT); nkeynes@267: asic_clear(); nkeynes@267: asic_wait(EVENT_SCANLINE2); nkeynes@267: status2 = long_read(SYNCSTAT); nkeynes@267: asic_clear(); nkeynes@267: asic_wait(EVENT_SCANLINE1); nkeynes@267: status3 = long_read(SYNCSTAT); nkeynes@267: CHECK_IEQUALS( 0x0000, status1 ); nkeynes@267: CHECK_IEQUALS( 0x202A, status2 ); nkeynes@267: CHECK_IEQUALS( 0x226C, status3 ); nkeynes@267: nkeynes@267: for( i=0; i< MAX_FRAME_WAIT; i++ ) { nkeynes@267: status1 = long_read(SYNCSTAT) & 0x07FF; nkeynes@267: if( status1 == 0x00FF ) { nkeynes@267: break; nkeynes@267: } nkeynes@267: } nkeynes@267: asic_clear(); nkeynes@267: asic_wait(EVENT_RETRACE); nkeynes@267: status1 = long_read(SYNCSTAT); nkeynes@267: asic_clear(); nkeynes@267: asic_wait(EVENT_SCANLINE2); nkeynes@267: status2 = long_read(SYNCSTAT); nkeynes@267: asic_clear(); nkeynes@267: asic_wait(EVENT_SCANLINE1); nkeynes@267: status3 = long_read(SYNCSTAT); nkeynes@267: fprintf( stderr, "%08X, %08X, %08X\n", status1, status2, status3 ); nkeynes@267: CHECK_IEQUALS( 0x1400, status1 ); nkeynes@267: CHECK_IEQUALS( 0x242B, status2 ); nkeynes@267: CHECK_IEQUALS( 0x266D, status3 ); nkeynes@263: nkeynes@263: return 0; nkeynes@263: } nkeynes@263: nkeynes@267: int check_timing( struct timing *t ) { nkeynes@267: uint32_t line_time, field_time; nkeynes@267: uint32_t stat; nkeynes@267: uint32_t last_line = t->total_lines - 1; nkeynes@267: int i; nkeynes@267: nkeynes@267: WAIT_LINE( t->total_lines - 1 ); nkeynes@267: asic_clear(); nkeynes@267: for( i=0; i< MAX_FRAME_WAIT; i++ ) { nkeynes@267: stat = long_read(SYNCSTAT) & 0x07FF; nkeynes@267: if( stat == 0 ) { nkeynes@267: break; nkeynes@267: } else if( (stat & 0x03FF) != last_line ) { nkeynes@267: asic_clear(); nkeynes@267: last_line = stat & 0x03FF; nkeynes@267: } nkeynes@267: } nkeynes@267: if( stat != 0 ) { nkeynes@267: fprintf( stderr, "Timeout waiting for line 0 field 0\n" ); nkeynes@267: return -1; nkeynes@267: } nkeynes@267: timer_start(); nkeynes@267: asic_clear(); nkeynes@267: if( asic_check( EVENT_RETRACE ) != 0 ) { nkeynes@267: fprintf( stderr, "Failed to clear retrace event ?\n" ); nkeynes@267: return -1; nkeynes@267: } nkeynes@267: CHECK_IEQUALS( stat, 0 ); /* VSYNC, HSYNC, no display */ nkeynes@267: WAIT_LINE(1); nkeynes@267: line_time = timer_gettime_us(); nkeynes@267: WAIT_LASTLINE(t->total_lines-1); nkeynes@267: field_time = timer_gettime_us(); nkeynes@267: nkeynes@267: if( line_time != t->line_time_us || nkeynes@267: field_time != t->field_time_us ) { nkeynes@267: fprintf( stderr, "Assertion failed: Expected Timing %d,%d but was %d,%d\n", nkeynes@267: t->line_time_us, t->field_time_us, line_time, field_time ); nkeynes@267: return -1; nkeynes@267: } nkeynes@267: return 0; nkeynes@267: } nkeynes@267: nkeynes@267: int test_ntsc_timing() { nkeynes@267: apply_display_settings( ntsc_settings ); nkeynes@267: // check_events_interlaced(); nkeynes@267: asic_clear(); nkeynes@267: uint32_t result = check_timing( &ntsc_timing ); nkeynes@267: dump_display_regs( stdout ); nkeynes@267: return result; nkeynes@267: } nkeynes@267: nkeynes@263: nkeynes@263: int test_pal_timing() nkeynes@263: { nkeynes@263: uint32_t line_time, field_time; nkeynes@263: /* Set PAL display mode */ nkeynes@263: apply_display_settings( pal_settings ); nkeynes@263: nkeynes@267: check_events_interlaced(); nkeynes@263: asic_clear(); nkeynes@267: uint32_t result = check_timing( &pal_timing ); nkeynes@263: dump_display_regs( stdout ); nkeynes@267: return result; nkeynes@263: } nkeynes@263: nkeynes@263: nkeynes@263: /********************************* Main **************************************/ nkeynes@263: nkeynes@263: typedef int (*test_func_t)(); nkeynes@263: nkeynes@263: test_func_t test_fns[] = { test_ntsc_timing, test_pal_timing, nkeynes@263: NULL }; nkeynes@263: nkeynes@263: int main() nkeynes@263: { nkeynes@263: return run_tests( test_fns ); nkeynes@263: }