Index: apps/filetree.c =================================================================== --- apps/filetree.c (revision 19788) +++ apps/filetree.c (working copy) @@ -557,6 +557,12 @@ display_cuesheet_content(buf); break; +#ifdef IPOD_VIDEO + case FILE_ATTR_BMP: + tvout_bmp(buf); + break; +#endif /* IPOD_VIDEO */ + default: { const char* plugin; Index: apps/debug_menu.c =================================================================== --- apps/debug_menu.c (revision 19788) +++ apps/debug_menu.c (working copy) @@ -2634,7 +2634,11 @@ } #endif - +bool tvout(unsigned char * fn); +bool dbg_tvout_off(void) { + tvout_enable(false); + return false; +} /****** The menu *********/ struct the_menu_item { unsigned char *desc; /* string or ID */ @@ -2682,7 +2686,10 @@ #if (CONFIG_STORAGE & STORAGE_ATA) { "Dump ATA identify info", dbg_identify_info}, #endif +#ifdef IPOD_VIDEO + { "Disable TV out", dbg_tvout_off }, #endif +#endif #ifdef HAVE_DIRCACHE { "View dircache info", dbg_dircache_info }, #endif Index: firmware/export/lcd.h =================================================================== --- firmware/export/lcd.h (revision 19788) +++ firmware/export/lcd.h (working copy) @@ -461,4 +461,9 @@ #endif /* HAVE_LCD_BITMAP */ +#ifdef IPOD_VIDEO +void tvout_enable(bool enable); +bool tvout_bmp(unsigned char * fn); +#endif + #endif /* __LCD_H__ */ Index: firmware/target/arm/ipod/video/lcd-video.c =================================================================== --- firmware/target/arm/ipod/video/lcd-video.c (revision 19788) +++ firmware/target/arm/ipod/video/lcd-video.c (working copy) @@ -30,6 +30,9 @@ #include "lcd.h" #include "kernel.h" #include "system.h" +/* Buffer is used for TV out functions */ +#include "audio.h" +#include "buffer.h" /* The BCM bus width is 16 bits. But since the low address bits aren't decoded * by the chip (the 3 BCM address bits are mapped to address bits 16..18 of the @@ -52,6 +55,21 @@ #define BCM_FB_BASE 0xE0020 /* Address of internal BCM framebuffer */ +/* Addresses within BCM */ +#define BCMA_COMMAND 0x1F8 +#define BCMA_STATUS 0x1FC +#define BCMA_TVBUF 0xC0200000 + +/* BCM commands */ +#define BCM_CMD(x) ((~(x) << 16) | (x)) +#define BCMCMD_LCD_UPDATE BCM_CMD(0) +/* BCM_CMD(1) unknown, involves 40 second wait */ +#define BCMCMD_TV_PALBMP BCM_CMD(2) +#define BCMCMD_TV_NTSCBMP BCM_CMD(3) +#define BCMCMD_LCD_UPDATERECT BCM_CMD(5) +/* BCM_CMD(8), BCM_CMD(12) involved in shutdown */ +#define BCMCMD_TV_MVOFF BCM_CMD(14) /* Turn off Macrovision */ + /* Time until the BCM is considered stalled and will be re-kicked. * Must be guaranteed to be >~ 20ms. */ #define BCM_UPDATE_TIMEOUT (HZ/20) @@ -341,3 +359,94 @@ lcd_unblock_and_update(); } + +void tvout_enable(bool enable) +{ + unsigned temp; + + /* Enable TV out? */ + temp = bcm_read32(0x10002804); + temp |= 0x40; + temp &= ~0x80; + bcm_write32(0x10002804, temp); + + if (enable) + bcm_write32(0x10002810, 0x80000); + else + bcm_write32(0x10002818, 0x80000); +} + +static void bcm_simplecmd(unsigned cmd) { + unsigned status; + + bcm_write32(BCMA_COMMAND, cmd); + + BCM_CONTROL = 0x31; + + do { + status = bcm_read32(BCMA_COMMAND); + } while (status == cmd || status == 0xFFFF); +} + +bool tvout_bmp(unsigned char * fn) +{ + int fd; + long length, gotbytes = 0; + unsigned cmd, status; + + fd = open(fn, O_RDONLY); + if (fd < 0) + return false; + + /* Buffer is needed to load bitmap */ + audio_stop(); + + length = filesize(fd); + if (length <= (audiobufend - audiobuf)) + gotbytes = read(fd, audiobuf, length); + + close(fd); + + if (gotbytes != length) + return false; + + while (lcd_state.state != LCD_IDLE) + yield(); + /* This requires that no other threads are updating the LCD */ + lcd_block_tick(); + + tvout_enable(true); + + if (((unsigned short *)audiobuf)[22/2] == 576) + cmd = BCMCMD_TV_PALBMP; + else + cmd = BCMCMD_TV_NTSCBMP; + + bcm_write32(BCMA_COMMAND, cmd); + + bcm_write_addr(BCMA_TVBUF); + /* lcd_write_data requires an even number of words */ + if (length & 3) + length += 4; + length = (length & ~3) >> 1; + lcd_write_data((unsigned short *)audiobuf, length); + + /* Execute command */ + BCM_CONTROL = 0x31; + + /* Wait for command to complete. Comparing with + bcm_read32(BCMA_STATUS) loops forever the 2nd time this + function is run. Comparing with cmd (like in LCD update + code) works. + */ + do { + status = bcm_read32(BCMA_COMMAND); + } while (status == cmd || status == 0xFFFF); + + /* For command status, sign-extend low 16 bits */ + /* bcm_read32(BCMA_STATUS); */ + + bcm_simplecmd(BCMCMD_TV_MVOFF); + + return true; +}