vidreset.c 2.99 KB

#include <bcp.h>
#include "vidreset.h"


extern void __osBbDelay(u32 usec);
extern u32 __osDisableInt(void);
extern void __osRestoreInt(u32 mask);
extern void __osBbVideoPllInit(s32 tvType);

/*
 * Helper routines for video reset
 */
#define SIGNATURE 0x43210123
static void
sig_put()
{
    u32 ctrl = IO_READ(VI_CONTROL_REG);

    IO_WRITE(VI_CONTROL_REG, 0x880);
    IO_WRITE(VI_SPANADDR_REG, 0);
    IO_WRITE(VI_SPANDATA_REG, SIGNATURE);

    IO_WRITE(VI_SPANADDR_REG, 1);
    IO_WRITE(VI_SPANDATA_REG, 0);
    IO_WRITE(VI_SPANADDR_REG, 2);
    IO_WRITE(VI_SPANDATA_REG, 0);
    IO_WRITE(VI_SPANADDR_REG, 3);
    IO_WRITE(VI_SPANDATA_REG, 0);

    IO_WRITE(VI_CONTROL_REG, ctrl);

}

static int
sig_check()
{
    u32 sig;

    u32 ctrl = IO_READ(VI_CONTROL_REG);
    IO_WRITE(VI_CONTROL_REG, 0x880);
    IO_WRITE(VI_SPANADDR_REG, 0);
    sig = IO_READ(VI_SPANDATA_REG);

    IO_WRITE(VI_CONTROL_REG, ctrl);

    if (sig == SIGNATURE) {
        return 1;
    } else {
        return 0;
    }

}

/*
 * Note this should return with the VI correctly out of reset and also
 * disabled. You can do video set up using libultra routines after this.
 * It needs some frame buffer area to work. Right now it should only use
 * the first 10 lines of the buffer.
 *
 * To keep things simple we use a 320 wide x 16 bits/pixel framebuffer
 *
 * Before this function is called the PLL should be set up.
 *
 * Interrupts are disabled. It may not matter, but just in case. This routine
 * should be called before osInitialize() anyway
 *
 */
int vidReset(u16 *cfb)
{
    u32 avctrl;
    int cnt = 0;
    u32 mask;

    mask = __osDisableInt();
    /*
     * Clear a few lines in the Framebuffer first
     */
    memset(cfb, 0, 320*10*2);
  
    do {
        IO_WRITE(VI_CONTROL_REG, 0x0);
        __osBbDelay(10);
        
        // Reset the video subsystem
        avctrl = IO_READ(MI_AVCTRL_REG);
        avctrl &= ~MI_AVCTRL_AV_RESET;
        IO_WRITE(MI_AVCTRL_REG, avctrl);
        __osBbDelay(1);
        IO_WRITE(MI_AVCTRL_REG, avctrl | MI_AVCTRL_AV_RESET);
        
        // Fill up the registers
        IO_WRITE(VI_ORIGIN_REG, cfb);
        IO_WRITE(VI_WIDTH_REG, 0x140);
        IO_WRITE(VI_INTR_REG, 0x208);
        IO_WRITE(VI_BURST_REG, 0x3e52239);
        IO_WRITE(VI_V_SYNC_REG, 0x20d);
        IO_WRITE(VI_H_SYNC_REG, 0xc15);
        IO_WRITE(VI_LEAP_REG, 0xc150c15);
        IO_WRITE(VI_H_START_REG, 0x6c02ec);
        IO_WRITE(VI_V_START_REG, 0x2501ff);
        IO_WRITE(VI_V_BURST_REG, 0xe0204);
        IO_WRITE(VI_X_SCALE_REG, 0x200);
        IO_WRITE(VI_Y_SCALE_REG, 0x400);
        
        sig_put();
        
        IO_WRITE(VI_CURRENT_REG, 0x0);
        IO_WRITE(VI_CONTROL_REG, 0x120e);
        
        /*
         * Wait until some active lines have gone by
         */
        while (IO_READ(VI_CURRENT_REG) < 0x30) ;

        cnt++;
    } while (sig_check());

    /*
     * This leaves things running, but makes the screen black
     */
    IO_WRITE(VI_H_START_REG, 0x0);
    
    __osRestoreInt(mask);


    return cnt-1;
        
}