diff --git a/configure.py b/configure.py index 1dd025db0..fe6cb93fa 100755 --- a/configure.py +++ b/configure.py @@ -1186,6 +1186,9 @@ config.libs = [ "vi", [ Object(Matching, "dolphin/vi/vi.c"), + Object(Matching, "dolphin/vi/i2c.c"), + Object(Matching, "dolphin/vi/initphilips.c"), + Object(Matching, "dolphin/vi/gpioexi.c"), ], ), DolphinLib( @@ -1928,6 +1931,9 @@ def link_order_callback(module_id: int, objects: List[str]) -> List[str]: # objects.insert(objects.index("d/actor/d_a_agb.cpp"), "d/d_debug_camera.cpp") # objects.insert(objects.index("d/actor/d_a_agb.cpp"), "d/d_event_debug.cpp") # objects.insert(objects.index("d/actor/d_a_agb.cpp"), "d/d_kankyo_debug.cpp") + objects.insert(objects.index("dolphin/pad/Padclamp.c"), "dolphin/vi/i2c.c") + objects.insert(objects.index("dolphin/pad/Padclamp.c"), "dolphin/vi/initphilips.c") + objects.insert(objects.index("dolphin/pad/Padclamp.c"), "dolphin/vi/gpioexi.c") objects.insert(objects.index("dolphin/gx/GXPixel.c"), "dolphin/gx/GXDraw.c") # Example of adding new files for modding: diff --git a/src/dolphin/vi/gpioexi.c b/src/dolphin/vi/gpioexi.c new file mode 100644 index 000000000..a93de1975 --- /dev/null +++ b/src/dolphin/vi/gpioexi.c @@ -0,0 +1,142 @@ +#include "dolphin/os/OS.h" + +static u8 shadowGPIOOE; +static u8 shadowGPIOData; + +// prototypes +static void initGpioExi(void); +static void setVideoReset(int value); +static void setI2CEnable(int value); +static int gpioOutput(u8 value); +static int gpioOE(u8 value); +static int gpioOut(u32 addr, u8 value); +static int gpioInput(u8* p); + +void __VIInitI2C(void) { + OSTime time; + + initGpioExi(); + setVideoReset(0); + time = OSGetTime(); + while (OSGetTime() - time < OSMicrosecondsToTicks(100)) {} + setVideoReset(1); + setI2CEnable(1); +} + +static void initGpioExi(void) { + shadowGPIOOE = 0; + shadowGPIOData = 0; + gpioOutput(shadowGPIOData); + gpioOE(shadowGPIOOE); +} + +void __VISetSCL(int value) { + shadowGPIOOE &= ~2; + if (value == 0) { + shadowGPIOOE |= 2; + } + gpioOE(shadowGPIOOE); +} + +int __VIGetSCL(void) { + u8 value; + + gpioInput(&value); + if (value & 2) { + return 1; + } else { + return 0; + } +} + +void __VISetSDA(int value) { + shadowGPIOOE &= ~1; + if (value == 0) { + shadowGPIOOE |= 1; + } + gpioOE(shadowGPIOOE); +} + +int __VIGetSDA(void) { + u8 value; + + gpioInput(&value); + if (value & 1) { + return 1; + } else { + return 0; + } +} + +static void setVideoReset(int value) { + if (value != 0) { + shadowGPIOData |= 4; + } else { + shadowGPIOData &= ~4; + } + shadowGPIOOE |= 4; + gpioOutput(shadowGPIOData); + gpioOE(shadowGPIOOE); +} + +static void setI2CEnable(int value) { + if (value != 0) { + shadowGPIOData &= ~0x10; + } else { + shadowGPIOData |= 0x10; + } + shadowGPIOOE |= 0x10; + gpioOutput(shadowGPIOData); + gpioOE(shadowGPIOOE); +} + +static int gpioOutput(u8 value) { + return gpioOut(0x800404U, value); +} + +static int gpioOE(u8 value) { + return gpioOut(0x800408U, value); +} + +static int gpioOut(u32 addr, u8 value) { + u32 cmd; + + cmd = (addr | 0x02000000) << 6; + if (EXILock(0, 1, 0) == 0) { + return 0; + } + if (EXISelect(0, 1, 4) == 0) { + EXIUnlock(0); + return 0; + } + + EXIImm(0, &cmd, 4, EXI_WRITE, 0); + EXISync(0); + cmd = value << 24; + EXIImm(0, &cmd, 1, EXI_WRITE, 0); + EXISync(0); + EXIDeselect(0); + EXIUnlock(0); + return 1; +} + +static int gpioInput(u8* p) { + u32 cmd; + + if (EXILock(0, 1, 0) == 0) { + return 0; + } + if (EXISelect(0, 1, 4) == 0) { + EXIUnlock(0); + return 0; + } + cmd = 0x20010100; + EXIImm(0, &cmd, 4, EXI_WRITE, 0); + EXISync(0); + EXIImm(0, &cmd, 1, EXI_READ, 0); + EXISync(0); + EXIDeselect(0); + EXIUnlock(0); + *p = cmd >> 24; + return 1; +} diff --git a/src/dolphin/vi/i2c.c b/src/dolphin/vi/i2c.c new file mode 100644 index 000000000..2c028b9b1 --- /dev/null +++ b/src/dolphin/vi/i2c.c @@ -0,0 +1,227 @@ +#include "dolphin/os/OS.h" + +static volatile u32 __i2c_ident_flag = 1; +static volatile u32 __i2c_ident_first = 0; + +#define busRd32(addr) (*(volatile u32 *)(addr)) +#define busWrt32(addr, val) (*(volatile u32 *)(addr)) = (val) + +void WaitMicroTime(s32 usec) { + OSTime t = __OSGetSystemTime(); + + while (((__OSGetSystemTime() - t) * 8) / 486 < usec); +} + +static void VICheckI2C(void) { + __i2c_ident_flag = 1; +} + +static BOOL __VISetSCL(u32 value) { + u32 reg; + value &= 1; + + reg = busRd32(0xCD8000C0); + reg &= ~(1 << 14); + reg = (u32)(reg | (value << 14)); + busWrt32(0xCD8000C0, reg); + return TRUE; +} + +static BOOL __VISetSDA(u32 value) { + u32 reg; + value &= 1; + reg = busRd32(0xCD8000C0); + reg &= ~(1 << 15); + reg = (u32)(reg | (value << 15)); + busWrt32(0xCD8000C0, reg); + return TRUE; +} + +static u32 __VIGetSDA(void) { + u32 reg = busRd32(0xCD8000C8); + return (u32)((reg >> 15) & 1); +} + +static void __VIOpenI2C(u32 dir) { + u32 reg = busRd32(0xCD8000C4); + reg = (u32)(reg & ~(1 << 15)); + reg = (u32)(reg | (1 << 14) | (dir << 15)); + busWrt32(0xCD8000C4, reg); +} + +static int wait4ClkHigh(void) { + WaitMicroTime(2); + return 1; +} + +static int sendSlaveAddr(u8 slaveAddr) { + int i; + + if (0 == __i2c_ident_flag) { + __VISetSDA(1); + } else { + __VISetSDA(0); + } + + WaitMicroTime(2); + __VISetSCL(0); + + for (i = 0; i < 8; i++) { + if (slaveAddr & 0x80) { + if (0 == __i2c_ident_flag) { + __VISetSDA(0); + } else { + __VISetSDA(1); + } + } else { + if (0 == __i2c_ident_flag) { + __VISetSDA(1); + } else { + __VISetSDA(0); + } + } + + WaitMicroTime(2); + __VISetSCL(1); + + if (wait4ClkHigh() == 0) { + return 0; + } + + __VISetSCL(0); + slaveAddr <<= 1; + } + + __VIOpenI2C(0); + WaitMicroTime(2); + __VISetSCL(1); + + if (wait4ClkHigh() == 0) { + return 0; + } + + if (1 == __i2c_ident_flag) { + if (__VIGetSDA() != 0) { + return 0; + } + } + + if (0 == __i2c_ident_flag) { + __VISetSDA(1); + } else { + __VISetSDA(0); + } + + __VIOpenI2C(1); + __VISetSCL(0); + return 1; +} + +int __VISendI2CData(u8 slaveAddr, u8* pData, int nBytes) { + s32 i; + u8 data; + BOOL enabled; + + if (__i2c_ident_first == 0) { + VICheckI2C(); + __i2c_ident_first = 1; + } + + enabled = OSDisableInterrupts(); + + __VIOpenI2C(1); + __VISetSCL(1); + + if (0 == __i2c_ident_flag) { + __VISetSDA(0); + } else { + __VISetSDA(1); + } + + WaitMicroTime(2); + WaitMicroTime(2); + + if (sendSlaveAddr(slaveAddr) == 0) { + OSRestoreInterrupts(enabled); + return 0; + } + + __VIOpenI2C(1); + + while (nBytes != 0) { + data = *pData++; + for (i = 0; i < 8; i++) { + if (data & 0x80) { + if (0 == __i2c_ident_flag) { + __VISetSDA(0); + } else { + __VISetSDA(1); + } + } else { + if (0 == __i2c_ident_flag) { + __VISetSDA(1); + } else { + __VISetSDA(0); + } + } + + WaitMicroTime(2); + __VISetSCL(1); + + if (wait4ClkHigh() == 0) { + OSRestoreInterrupts(enabled); + return 0; + } + + __VISetSCL(0); + data <<= 1; + } + + __VIOpenI2C(0); + WaitMicroTime(2); + __VISetSCL(1); + + if (wait4ClkHigh() == 0) { + OSRestoreInterrupts(enabled); + return 0; + } + + if (1 == __i2c_ident_flag) { + if (__VIGetSDA() != 0) { + OSRestoreInterrupts(enabled); + return 0; + } + } + + if (0 == __i2c_ident_flag) { + __VISetSDA(1); + } else { + __VISetSDA(0); + } + + __VIOpenI2C(1); + __VISetSCL(0); + nBytes--; + } + + __VIOpenI2C(1); + + if (0 == __i2c_ident_flag) { + __VISetSDA(1); + } else { + __VISetSDA(0); + } + + WaitMicroTime(2); + __VISetSCL(1); + WaitMicroTime(2); + + if (0 == __i2c_ident_flag) { + __VISetSDA(0); + } else { + __VISetSDA(1); + } + + OSRestoreInterrupts(enabled); + return 1; +} diff --git a/src/dolphin/vi/initphilips.c b/src/dolphin/vi/initphilips.c new file mode 100644 index 000000000..9b1cda44c --- /dev/null +++ b/src/dolphin/vi/initphilips.c @@ -0,0 +1,71 @@ +#include "dolphin/vi/vi.h" + +static u8 ntscRange0[4] = { 0x00, 0x00, 0x19, 0x1D }; + +static u8 ntscRange1[38] = { + 0x2D, 0x76, 0xA5, 0x2A, + 0x2E, 0x2E, 0x00, 0x15, + 0x3F, 0x1F, 0x7C, 0xF0, + 0x21, 0x55, 0x56, 0x67, + 0x58, 0x20, 0xF9, 0x00, + 0xB0, 0x14, 0x80, 0xE8, + 0x10, 0x42, 0x03, 0x03, + 0x05, 0x16, 0x04, 0x16, + 0x18, 0x38, 0x40, 0x00, + 0x00, 0x00 +}; + +static u8 palRange0[4] = { 0x00, 0x00, 0x21, 0x1D }; + +static u8 palRange1[38] = { + 0x0C, 0x7D, 0xAF, 0x23, + 0x35, 0x35, 0x00, 0x06, + 0x2F, 0xCB, 0x8A, 0x09, + 0x2A, 0x55, 0x56, 0x67, + 0x58, 0x20, 0x05, 0x20, + 0xA0, 0x14, 0x80, 0xE8, + 0x10, 0x42, 0x03, 0x03, + 0x05, 0x16, 0x04, 0x16, + 0x18, 0x38, 0x40, 0x00, + 0x00, 0x00 +}; + +static u8 value3a = 19; + +static void send7120Data(u8 *range0, u8 *range1) { + u8 i; + u8 buffer[2]; + + for (i = 0; i < 38; i++) { + buffer[0] = i; + buffer[1] = 0; + __VISendI2CData(0x88, buffer, 2); + } + + for (i = 38; i < 42; i++) { + buffer[0] = i; + buffer[1] = range0[i - 38]; + __VISendI2CData(0x88, buffer, 2); + } + + for (i = 42; i < 58; i++) { + buffer[0] = i; + buffer[1] = 0; + __VISendI2CData(0x88, buffer, 2); + } + + buffer[0] = 0x3A; + buffer[1] = value3a; + __VISendI2CData(0x88, buffer, 2); + + for (i = 90; i < 128; i++) { + buffer[0] = i; + buffer[1] = range1[i - 90]; + __VISendI2CData(0x88, buffer, 2); + } +} + +void __VIInitPhilips(void) { + __VIInitI2C(); + send7120Data(ntscRange0, ntscRange1); +}