diff --git a/arm11/link.ld b/arm11/link.ld index f2cdb5b..88f4af8 100644 --- a/arm11/link.ld +++ b/arm11/link.ld @@ -12,6 +12,4 @@ SECTIONS .bss : ALIGN(4) { __bss_start = .; *(.bss*); __bss_end = .; } . = ALIGN(4); - - __stack_top = 0x1FFFE000; } diff --git a/arm11/source/boot.s b/arm11/source/boot.s index 37dbf8f..cdbcf64 100644 --- a/arm11/source/boot.s +++ b/arm11/source/boot.s @@ -5,14 +5,14 @@ .global __boot __boot: - cpsid aif, #(SR_SVC_MODE) + cpsid aif, #SR_SVC_MODE mov r0, #0 mcr p15, 0, r0, c7, c7, 0 mcr p15, 0, r0, c7, c14, 0 mcr p15, 0, r0, c7, c10, 4 - ldr sp, =__stack_top + ldr sp, =_stack_top @ Reset values ldr r0, =0x00054078 @@ -33,3 +33,8 @@ __boot: bl main b __boot + +.section .bss.stack +.align 3 + .space (8192 * 4) +_stack_top: diff --git a/arm11/source/i2c.c b/arm11/source/i2c.c new file mode 100644 index 0000000..ac2147f --- /dev/null +++ b/arm11/source/i2c.c @@ -0,0 +1,213 @@ +/* + * This file is part of fastboot 3DS + * Copyright (C) 2017 derrek, profi200 + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include +#include "types.h" +#include "i2c.h" + + +#define I2C1_REGS_BASE (0x10161000) + +#define I2C2_REGS_BASE (0x10144000) + +#define I2C3_REGS_BASE (0x10148000) + + +typedef struct +{ + vu8 REG_I2C_DATA; + vu8 REG_I2C_CNT; + vu16 REG_I2C_CNTEX; + vu16 REG_I2C_SCL; +} I2cRegs; + +static const struct +{ + u8 busId; + u8 devAddr; +} i2cDevTable[] = +{ + {0, 0x4A}, + {0, 0x7A}, + {0, 0x78}, + {1, 0x4A}, + {1, 0x78}, + {1, 0x2C}, + {1, 0x2E}, + {1, 0x40}, + {1, 0x44}, + {2, 0xA6}, // TODO: Find out if 0xA6 or 0xD6 is correct + {2, 0xD0}, + {2, 0xD2}, + {2, 0xA4}, + {2, 0x9A}, + {2, 0xA0}, + {1, 0xEE}, + {0, 0x40}, + {2, 0x54} +}; + + + +static void i2cWaitBusy(I2cRegs *const regs) +{ + while(regs->REG_I2C_CNT & I2C_ENABLE); +} + +static I2cRegs* i2cGetBusRegsBase(u8 busId) +{ + I2cRegs *base; + switch(busId) + { + case 0: + base = (I2cRegs*)I2C1_REGS_BASE; + break; + case 1: + base = (I2cRegs*)I2C2_REGS_BASE; + break; + case 2: + base = (I2cRegs*)I2C3_REGS_BASE; + break; + default: + base = NULL; + } + + return base; +} + +void I2C_init(void) +{ + I2cRegs *regs = i2cGetBusRegsBase(0); // Bus 1 + i2cWaitBusy(regs); + regs->REG_I2C_CNTEX = 2; // ? + regs->REG_I2C_SCL = 1280; // ? + + regs = i2cGetBusRegsBase(1); // Bus 2 + i2cWaitBusy(regs); + regs->REG_I2C_CNTEX = 2; // ? + regs->REG_I2C_SCL = 1280; // ? + + regs = i2cGetBusRegsBase(2); // Bus 3 + i2cWaitBusy(regs); + regs->REG_I2C_CNTEX = 2; // ? + regs->REG_I2C_SCL = 1280; // ? +} + +static bool i2cStartTransfer(int devId, u8 regAddr, bool read, I2cRegs *const regs) +{ + const u8 devAddr = i2cDevTable[devId].devAddr; + + + u32 i = 0; + for(; i < 8; i++) + { + i2cWaitBusy(regs); + + // Select device and start. + regs->REG_I2C_DATA = devAddr; + regs->REG_I2C_CNT = I2C_ENABLE | I2C_IRQ_ENABLE | I2C_START; + i2cWaitBusy(regs); + if(!I2C_GET_ACK(regs->REG_I2C_CNT)) // If ack flag is 0 it failed. + { + regs->REG_I2C_CNT = I2C_ENABLE | I2C_IRQ_ENABLE | I2C_ERROR | I2C_STOP; + continue; + } + + // Select register and change direction to write. + regs->REG_I2C_DATA = regAddr; + regs->REG_I2C_CNT = I2C_ENABLE | I2C_IRQ_ENABLE | I2C_DIRE_WRITE; + i2cWaitBusy(regs); + if(!I2C_GET_ACK(regs->REG_I2C_CNT)) // If ack flag is 0 it failed. + { + regs->REG_I2C_CNT = I2C_ENABLE | I2C_IRQ_ENABLE | I2C_ERROR | I2C_STOP; + continue; + } + + // Select device in read mode for read transfer. + if(read) + { + regs->REG_I2C_DATA = devAddr | 1u; // Set bit 0 for read. + regs->REG_I2C_CNT = I2C_ENABLE | I2C_IRQ_ENABLE | I2C_START; + i2cWaitBusy(regs); + if(!I2C_GET_ACK(regs->REG_I2C_CNT)) // If ack flag is 0 it failed. + { + regs->REG_I2C_CNT = I2C_ENABLE | I2C_IRQ_ENABLE | I2C_ERROR | I2C_STOP; + continue; + } + } + + break; + } + + if(i < 8) return true; + else return false; +} + +bool I2C_readRegBuf(int devId, u8 regAddr, u8 *out, u32 size) +{ + const u8 busId = i2cDevTable[devId].busId; + I2cRegs *const regs = i2cGetBusRegsBase(busId); + + + if(!i2cStartTransfer(devId, regAddr, true, regs)) return false; + + while(--size) + { + regs->REG_I2C_CNT = I2C_ENABLE | I2C_IRQ_ENABLE | I2C_DIRE_READ | I2C_ACK; + i2cWaitBusy(regs); + *out++ = regs->REG_I2C_DATA; + } + + regs->REG_I2C_CNT = I2C_ENABLE | I2C_IRQ_ENABLE | I2C_DIRE_READ | I2C_STOP; + i2cWaitBusy(regs); + *out = regs->REG_I2C_DATA; // Last byte + + return true; +} + +bool I2C_writeRegBuf(int devId, u8 regAddr, const u8 *in, u32 size) +{ + const u8 busId = i2cDevTable[devId].busId; + I2cRegs *const regs = i2cGetBusRegsBase(busId); + + + if(!i2cStartTransfer(devId, regAddr, false, regs)) return false; + + while(--size) + { + regs->REG_I2C_DATA = *in++; + regs->REG_I2C_CNT = I2C_ENABLE | I2C_IRQ_ENABLE | I2C_DIRE_WRITE; + i2cWaitBusy(regs); + if(!I2C_GET_ACK(regs->REG_I2C_CNT)) // If ack flag is 0 it failed. + { + regs->REG_I2C_CNT = I2C_ENABLE | I2C_IRQ_ENABLE | I2C_ERROR | I2C_STOP; + return false; + } + } + + regs->REG_I2C_DATA = *in; + regs->REG_I2C_CNT = I2C_ENABLE | I2C_IRQ_ENABLE | I2C_DIRE_WRITE | I2C_STOP; + i2cWaitBusy(regs); + if(!I2C_GET_ACK(regs->REG_I2C_CNT)) // If ack flag is 0 it failed. + { + regs->REG_I2C_CNT = I2C_ENABLE | I2C_IRQ_ENABLE | I2C_ERROR | I2C_STOP; + return false; + } + + return true; +} diff --git a/arm11/source/i2c.h b/arm11/source/i2c.h new file mode 100644 index 0000000..a164526 --- /dev/null +++ b/arm11/source/i2c.h @@ -0,0 +1,64 @@ +#pragma once + +/* + * This file is part of fastboot 3DS + * Copyright (C) 2017 derrek, profi200 + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include +#include "types.h" + + +#define I2C_STOP (1u) +#define I2C_START (1u<<1) +#define I2C_ERROR (1u<<2) +#define I2C_ACK (1u<<4) +#define I2C_DIRE_WRITE (0u) +#define I2C_DIRE_READ (1u<<5) +#define I2C_IRQ_ENABLE (1u<<6) +#define I2C_ENABLE (1u<<7) + +#define I2C_GET_ACK(reg) ((bool)((reg)>>4 & 1u)) + + +/** + * @brief Initializes the I2C buses. Call this only once. + */ +void I2C_init(void); + +/** + * @brief Reads data from a I2C register to a buffer. + * + * @param[in] devId The device ID. Use the enum above. + * @param[in] regAddr The register address. + * @param out The output buffer pointer. + * @param[in] size The read size. + * + * @return Returns true on success and false on failure. + */ +bool I2C_readRegBuf(int devId, u8 regAddr, u8 *out, u32 size); + +/** + * @brief Writes a buffer to a I2C register. + * + * @param[in] devId The device ID. Use the enum above. + * @param[in] regAddr The register address. + * @param[in] in The input buffer pointer. + * @param[in] size The write size. + * + * @return Returns true on success and false on failure. + */ +bool I2C_writeRegBuf(int devId, u8 regAddr, const u8 *in, u32 size); diff --git a/arm11/source/main.c b/arm11/source/main.c index 43df690..2565e52 100644 --- a/arm11/source/main.c +++ b/arm11/source/main.c @@ -5,63 +5,79 @@ #include #include +#include + +#define CFG11_MPCORE_CLKCNT ((vu16*)(0x10141300)) +#define CFG11_SOCINFO ((vu16*)(0x10140FFC)) + vu32 *entrypoint = (vu32*)0x1FFFFFFC; -void PXI_IRQHandler(void) +void PXI_RX_Handler(void) { - // char pxi_buf[PXI_MAXBUFLEN] = {0}; - u32 pxi_args[PXI_FIFO_LEN] = {0}; - u8 pxi_cmd; + u32 pxi_cmd, ret; + u32 pxi_args[PXI_FIFO_LEN]; - pxi_cmd = PXI_GetRemote(); + pxi_cmd = PXI_Recv(); switch (pxi_cmd) { - default: - break; + case PXI_SCREENINIT: + { + GPU_Init(); + GPU_PSCFill(VRAM_START, VRAM_END, 0); + GPU_SetFramebuffers((u32[]){VRAM_TOP_LA, VRAM_TOP_LB, + VRAM_TOP_RA, VRAM_TOP_RB, + VRAM_BOT_A, VRAM_BOT_B}); - case PXI_SCREENINIT: - { - GPU_Init(); - GPU_PSCFill(VRAM_START, VRAM_END, 0); - GPU_SetFramebuffers((u32[]){VRAM_TOP_LA, VRAM_TOP_LB, - VRAM_TOP_RA, VRAM_TOP_RB, - VRAM_BOT_A, VRAM_BOT_B}); + GPU_SetFramebufferMode(0, PDC_RGB24); + GPU_SetFramebufferMode(1, PDC_RGB24); + ret = 0; + break; + } - GPU_SetFramebufferMode(0, PDC_RGB24); - GPU_SetFramebufferMode(1, PDC_RGB24); + case PXI_BRIGHTNESS: + { + PXI_RecvArray(pxi_args, 1); + LCD_SetBrightness(0, pxi_args[0]); + LCD_SetBrightness(1, pxi_args[0]); + ret = pxi_args[0]; + break; + } - PXI_SetRemote(PXI_BUSY); - break; + case PXI_I2C_READ: + { + PXI_RecvArray(pxi_args, 4); + ret = I2C_readRegBuf(pxi_args[0], pxi_args[1], + (u8*)pxi_args[2], pxi_args[3]); + break; + } + + case PXI_I2C_WRITE: + { + PXI_RecvArray(pxi_args, 4); + ret = I2C_writeRegBuf(pxi_args[0], pxi_args[1], + (const u8*)pxi_args[2], pxi_args[3]); + break; + } + + /* New CMD template: + case CMD_ID: + { + + + + + break; + } + */ + + default: + ret = 0xFFFFFFFF; + break; } - case PXI_BRIGHTNESS: - { - PXI_RecvArray(pxi_args, 1); - PXI_SetRemote(PXI_BUSY); - LCD_SetBrightness(0, pxi_args[0]); - LCD_SetBrightness(1, pxi_args[0]); - break; - } - - /* New CMD template: - case CMD_ID: - { - - - - PXI_SetRemote(PXI_BUSY); - - break; - } - */ - } - - PXI_SetRemote(PXI_READY); + PXI_Send(ret); return; } -vu16 *CFG11_MPCORE_CLKCNT = (vu16*)(0x10141300); -vu16 *CFG11_SOCINFO = (vu16*)(0x10140FFC); - void main(void) { u32 entry; @@ -77,20 +93,20 @@ void main(void) CPU_DisableIRQ(); } - PXI_Reset(); GIC_Reset(); - GIC_SetIRQ(IRQ_PXI_SYNC, PXI_IRQHandler); - PXI_EnableIRQ(); - CPU_EnableIRQ(); - PXI_SetRemote(PXI_READY); + PXI_Reset(); + I2C_init(); + //MCU_init(); + + GIC_SetIRQ(IRQ_PXI_RX, PXI_RX_Handler); + + CPU_EnableIRQ(); *entrypoint = 0; while((entry=*entrypoint) == 0); CPU_DisableIRQ(); - PXI_DisableIRQ(); - PXI_Reset(); GIC_Reset(); ((void (*)())(entry))(); diff --git a/arm11/source/mcu.c b/arm11/source/mcu.c new file mode 100755 index 0000000..e69de29 diff --git a/arm11/source/mcu.h b/arm11/source/mcu.h new file mode 100755 index 0000000..e69de29 diff --git a/arm9/source/common/power.c b/arm9/source/common/power.c index 65f661a..a376f29 100644 --- a/arm9/source/common/power.c +++ b/arm9/source/common/power.c @@ -12,7 +12,7 @@ void CheckBrightness() { // Volume Slider value is always between 0x00 and 0x3F curSlider >>= 2; #else - curSlider = FIXED_BRIGHTNESS; + curSlider = FIXED_BRIGHTNESS % sizeof(br_settings); #endif if (curSlider != prev_brightness) { PXI_DoCMD(PXI_BRIGHTNESS, (u32[]){br_settings[curSlider]}, 1); @@ -35,15 +35,17 @@ bool IsCharging() { void Reboot() { I2C_writeReg(I2C_DEV_MCU, 0x22, 1 << 0); // poweroff LCD to prevent MCU hangs - flushEntireDCache(); - if (I2C_writeReg(I2C_DEV_MCU, 0x20, 1 << 2)) - while(true); + cpu_writeback_dc(); + cpu_membarrier(); + I2C_writeReg(I2C_DEV_MCU, 0x20, 1 << 2); + while(true); } void PowerOff() { I2C_writeReg(I2C_DEV_MCU, 0x22, 1 << 0); // poweroff LCD to prevent MCU hangs - flushEntireDCache(); - if (I2C_writeReg(I2C_DEV_MCU, 0x20, 1 << 0)) - while (true); + cpu_writeback_dc(); + cpu_membarrier(); + I2C_writeReg(I2C_DEV_MCU, 0x20, 1 << 0); + while(true); } diff --git a/arm9/source/main.c b/arm9/source/main.c index 4f97473..e9a5d1b 100644 --- a/arm9/source/main.c +++ b/arm9/source/main.c @@ -1,18 +1,17 @@ #include "godmode.h" #include "power.h" +#include "timer.h" #include "pxi.h" #include "i2c.h" +#include "vram.h" + void main(int argc, char** argv, int entrypoint) { (void) argc; (void) argv; PXI_Reset(); - I2C_init(); - - // Wait for ARM11 - PXI_WaitRemote(PXI_READY); PXI_DoCMD(PXI_SCREENINIT, NULL, 0); I2C_writeReg(I2C_DEV_MCU, 0x22, 0x2A); diff --git a/arm9/source/system/cache.h b/arm9/source/system/cache.h index 92257a5..9978e94 100644 --- a/arm9/source/system/cache.h +++ b/arm9/source/system/cache.h @@ -1,43 +1,102 @@ -/* -* This file is part of Luma3DS -* Copyright (C) 2016-2017 Aurora Wright, TuxSH -* -* This program is free software: you can redistribute it and/or modify -* it under the terms of the GNU General Public License as published by -* the Free Software Foundation, either version 3 of the License, or -* (at your option) any later version. -* -* This program is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -* GNU General Public License for more details. -* -* You should have received a copy of the GNU General Public License -* along with this program. If not, see . -* -* Additional Terms 7.b and 7.c of GPLv3 apply to this file: -* * Requiring preservation of specified reasonable legal notices or -* author attributions in that material or in the Appropriate Legal -* Notices displayed by works containing it. -* * Prohibiting misrepresentation of the origin of that material, -* or requiring that modified versions of such material be marked in -* reasonable ways as different from the original version. -*/ - #pragma once -#include "common.h" +#include "types.h" -/*** - The following functions flush the data cache, then waits for all memory transfers to be finished. - The data cache and/or the instruction cache MUST be flushed before doing one of the following: - - rebooting - - powering down - - setting the ARM11 entrypoint to execute a function - - jumping to a payload -***/ +static inline void +cpu_membarrier(void) { + __asm__ __volatile__("mcr p15, 0, %0, c7, c10, 4\n\t" + :: "r"(0) : "memory"); +} -void flushEntireDCache(void); //actually: "clean and flush" -void flushDCacheRange(void *startAddress, u32 size); -void flushEntireICache(void); -void flushICacheRange(void *startAddress, u32 size); +static inline void +cpu_invalidate_ic(void) { + __asm__ __volatile__("mcr p15, 0, %0, c7, c5, 0\n\t" + :: "r"(0) : "memory"); +} + +static inline void +cpu_invalidate_ic_range(void *base, u32 len) { + u32 addr = (u32)base & ~0x1F; + len >>= 5; + + do { + __asm__ __volatile__("mcr p15, 0, %0, c7, c5, 1\n\t" + :: "r"(addr) : "memory"); + + addr += 0x20; + } while(len--); +} + +static inline void +cpu_invalidate_dc(void) { + __asm__ __volatile__("mcr p15, 0, %0, c7, c6, 0\n\t" + :: "r"(0) : "memory"); +} + +static inline void +cpu_invalidate_dc_range(void *base, u32 len) { + u32 addr = (u32)base & ~0x1F; + len >>= 5; + + do { + __asm__ __volatile__("mcr p15, 0, %0, c7, c6, 1" + :: "r"(addr) : "memory"); + addr += 0x20; + } while(len--); +} + +static inline void +cpu_writeback_dc(void) { + u32 seg = 0, ind; + do { + ind = 0; + do { + __asm__ __volatile__("mcr p15, 0, %0, c7, c10, 2\n\t" + :: "r"(seg | ind) : "memory"); + + ind += 0x20; + } while(ind < 0x400); + seg += 0x40000000; + } while(seg != 0); +} + +static inline +void cpu_writeback_dc_range(void *base, u32 len) { + u32 addr = (u32)base & ~0x1F; + len >>= 5; + + do { + __asm__ __volatile__("mcr p15, 0, %0, c7, c10, 1" + :: "r"(addr) : "memory"); + + addr += 0x20; + } while(len--); +} + +static inline +void cpu_writeback_invalidate_dc(void) { + u32 seg = 0, ind; + do { + ind = 0; + do { + __asm__ __volatile__("mcr p15, 0, %0, c7, c14, 2\n\t" + :: "r"(seg | ind) : "memory"); + + ind += 0x20; + } while(ind < 0x400); + seg += 0x40000000; + } while(seg != 0); +} + +static inline +void cpu_writeback_invalidate_dc_range(void *base, u32 len) { + u32 addr = (u32)base & ~0x1F; + len >>= 5; + + do { + __asm__ __volatile__("mcr p15, 0, %0, c7, c14, 1" + :: "r"(addr) : "memory"); + + addr += 0x20; + } while(len--); +} diff --git a/arm9/source/system/cache.s b/arm9/source/system/cache.s deleted file mode 100644 index fcc55dc..0000000 --- a/arm9/source/system/cache.s +++ /dev/null @@ -1,93 +0,0 @@ -@ This file is part of Luma3DS -@ Copyright (C) 2016-2017 Aurora Wright, TuxSH -@ -@ This program is free software: you can redistribute it and/or modify -@ it under the terms of the GNU General Public License as published by -@ the Free Software Foundation, either version 3 of the License, or -@ (at your option) any later version. -@ -@ This program is distributed in the hope that it will be useful, -@ but WITHOUT ANY WARRANTY; without even the implied warranty of -@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -@ GNU General Public License for more details. -@ -@ You should have received a copy of the GNU General Public License -@ along with this program. If not, see . -@ -@ Additional Terms 7.b and 7.c of GPLv3 apply to this file: -@ * Requiring preservation of specified reasonable legal notices or -@ author attributions in that material or in the Appropriate Legal -@ Notices displayed by works containing it. -@ * Prohibiting misrepresentation of the origin of that material, -@ or requiring that modified versions of such material be marked in -@ reasonable ways as different from the original version. - -.text -.arm -.align 4 - -.global flushEntireDCache -.type flushEntireDCache, %function -flushEntireDCache: - @ Adapted from http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.ddi0155a/ch03s03s05.html, - @ and https://github.com/gemarcano/libctr9_io/blob/master/src/ctr_system_ARM.c#L39 as well - @ Note: ARM's example is actually for a 8KB DCache (which is what the 3DS has) - - @ Implemented in bootROM at address 0xffff0830 - mov r1, #0 @ segment counter - outer_loop: - mov r0, #0 @ line counter - - inner_loop: - orr r2, r1, r0 @ generate segment and line address - mcr p15, 0, r2, c7, c14, 2 @ clean and flush the line - add r0, #0x20 @ increment to next line - cmp r0, #0x400 - bne inner_loop - - add r1, #0x40000000 - cmp r1, #0 - bne outer_loop - - mcr p15, 0, r1, c7, c10, 4 @ drain write buffer - bx lr - -.global flushDCacheRange -.type flushDCacheRange, %function -flushDCacheRange: - @ Implemented in bootROM at address 0xffff08a0 - add r1, r0, r1 @ end address - bic r0, #0x1f @ align source address to cache line size (32 bytes) - - flush_dcache_range_loop: - mcr p15, 0, r0, c7, c14, 1 @ clean and flush the line corresponding to the address r0 is holding - add r0, #0x20 - cmp r0, r1 - blo flush_dcache_range_loop - - mov r0, #0 - mcr p15, 0, r0, c7, c10, 4 @ drain write buffer - bx lr - -.global flushEntireICache -.type flushEntireICache, %function -flushEntireICache: - @ Implemented in bootROM at address 0xffff0ab4 - mov r0, #0 - mcr p15, 0, r0, c7, c5, 0 - bx lr - -.global flushICacheRange -.type flushICacheRange, %function -flushICacheRange: - @ Implemented in bootROM at address 0xffff0ac0 - add r1, r0, r1 @ end address - bic r0, #0x1f @ align source address to cache line size (32 bytes) - - flush_icache_range_loop: - mcr p15, 0, r0, c7, c5, 1 @ flush the line corresponding to the address r0 is holding - add r0, #0x20 - cmp r0, r1 - blo flush_icache_range_loop - - bx lr diff --git a/arm9/source/system/i2c.c b/arm9/source/system/i2c.c old mode 100644 new mode 100755 index 8495914..d7668e5 --- a/arm9/source/system/i2c.c +++ b/arm9/source/system/i2c.c @@ -1,224 +1,85 @@ -/* - * This file is part of fastboot 3DS - * Copyright (C) 2017 derrek, profi200 - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ +#include "common.h" -#include -#include "types.h" +#include "cache.h" #include "i2c.h" +#include "pxi.h" +/* + disgusting hack that deserves to die in hell + ideally all buffers would be able to be accessed + by the ARM11, but those in ARM9 RAM are inaccessible + (.data, .rodata & .bss) -#define I2C1_REGS_BASE (0x10161000) - -#define I2C2_REGS_BASE (0x10144000) - -#define I2C3_REGS_BASE (0x10148000) - - -typedef struct -{ - vu8 REG_I2C_DATA; - vu8 REG_I2C_CNT; - vu16 REG_I2C_CNTEX; - vu16 REG_I2C_SCL; -} I2cRegs; - -static const struct -{ - u8 busId; - u8 devAddr; -} i2cDevTable[] = -{ - {0, 0x4A}, - {0, 0x7A}, - {0, 0x78}, - {1, 0x4A}, - {1, 0x78}, - {1, 0x2C}, - {1, 0x2E}, - {1, 0x40}, - {1, 0x44}, - {2, 0xA6}, // TODO: Find out if 0xA6 or 0xD6 is correct - {2, 0xD0}, - {2, 0xD2}, - {2, 0xA4}, - {2, 0x9A}, - {2, 0xA0}, - {1, 0xEE}, - {0, 0x40}, - {2, 0x54} -}; - - - -static void i2cWaitBusy(I2cRegs *const regs) -{ - while(regs->REG_I2C_CNT & I2C_ENABLE); -} - -static I2cRegs* i2cGetBusRegsBase(u8 busId) -{ - I2cRegs *base; - switch(busId) - { - case 0: - base = (I2cRegs*)I2C1_REGS_BASE; - break; - case 1: - base = (I2cRegs*)I2C2_REGS_BASE; - break; - case 2: - base = (I2cRegs*)I2C3_REGS_BASE; - break; - default: - base = NULL; - } - - return base; -} - -void I2C_init(void) -{ - I2cRegs *regs = i2cGetBusRegsBase(0); // Bus 1 - i2cWaitBusy(regs); - regs->REG_I2C_CNTEX = 2; // ? - regs->REG_I2C_SCL = 1280; // ? - - regs = i2cGetBusRegsBase(1); // Bus 2 - i2cWaitBusy(regs); - regs->REG_I2C_CNTEX = 2; // ? - regs->REG_I2C_SCL = 1280; // ? - - regs = i2cGetBusRegsBase(2); // Bus 3 - i2cWaitBusy(regs); - regs->REG_I2C_CNTEX = 2; // ? - regs->REG_I2C_SCL = 1280; // ? -} - -static bool i2cStartTransfer(I2cDevice devId, u8 regAddr, bool read, I2cRegs *const regs) -{ - const u8 devAddr = i2cDevTable[devId].devAddr; - - - u32 i = 0; - for(; i < 8; i++) - { - i2cWaitBusy(regs); - - // Select device and start. - regs->REG_I2C_DATA = devAddr; - regs->REG_I2C_CNT = I2C_ENABLE | I2C_IRQ_ENABLE | I2C_START; - i2cWaitBusy(regs); - if(!I2C_GET_ACK(regs->REG_I2C_CNT)) // If ack flag is 0 it failed. - { - regs->REG_I2C_CNT = I2C_ENABLE | I2C_IRQ_ENABLE | I2C_ERROR | I2C_STOP; - continue; - } - - // Select register and change direction to write. - regs->REG_I2C_DATA = regAddr; - regs->REG_I2C_CNT = I2C_ENABLE | I2C_IRQ_ENABLE | I2C_DIRE_WRITE; - i2cWaitBusy(regs); - if(!I2C_GET_ACK(regs->REG_I2C_CNT)) // If ack flag is 0 it failed. - { - regs->REG_I2C_CNT = I2C_ENABLE | I2C_IRQ_ENABLE | I2C_ERROR | I2C_STOP; - continue; - } - - // Select device in read mode for read transfer. - if(read) - { - regs->REG_I2C_DATA = devAddr | 1u; // Set bit 0 for read. - regs->REG_I2C_CNT = I2C_ENABLE | I2C_IRQ_ENABLE | I2C_START; - i2cWaitBusy(regs); - if(!I2C_GET_ACK(regs->REG_I2C_CNT)) // If ack flag is 0 it failed. - { - regs->REG_I2C_CNT = I2C_ENABLE | I2C_IRQ_ENABLE | I2C_ERROR | I2C_STOP; - continue; - } - } - - break; - } - - if(i < 8) return true; - else return false; -} + the current hack assumes all buffers in the heap are + located in FCRAM, which is accessible to both processors + but it's horrendous, and hopefully temporary +*/ +static char *i2c_fcram_buf = NULL; bool I2C_readRegBuf(I2cDevice devId, u8 regAddr, u8 *out, u32 size) { - const u8 busId = i2cDevTable[devId].busId; - I2cRegs *const regs = i2cGetBusRegsBase(busId); + if (!i2c_fcram_buf) + i2c_fcram_buf = malloc(256); + int ret; + u32 args[] = {devId, regAddr, (u32)i2c_fcram_buf, size}; - if(!i2cStartTransfer(devId, regAddr, true, regs)) return false; + cpu_writeback_dc_range(i2c_fcram_buf, size); + cpu_membarrier(); - while(--size) - { - regs->REG_I2C_CNT = I2C_ENABLE | I2C_IRQ_ENABLE | I2C_DIRE_READ | I2C_ACK; - i2cWaitBusy(regs); - *out++ = regs->REG_I2C_DATA; - } + ret = PXI_DoCMD(PXI_I2C_READ, args, 4); - regs->REG_I2C_CNT = I2C_ENABLE | I2C_IRQ_ENABLE | I2C_DIRE_READ | I2C_STOP; - i2cWaitBusy(regs); - *out = regs->REG_I2C_DATA; // Last byte + cpu_invalidate_dc_range(i2c_fcram_buf, size); + memcpy(out, i2c_fcram_buf, size); - return true; + return ret; } bool I2C_writeRegBuf(I2cDevice devId, u8 regAddr, const u8 *in, u32 size) { - const u8 busId = i2cDevTable[devId].busId; - I2cRegs *const regs = i2cGetBusRegsBase(busId); + if (!i2c_fcram_buf) + i2c_fcram_buf = malloc(256); + int ret; + u32 args[] = {devId, regAddr, (u32)i2c_fcram_buf, size}; - if(!i2cStartTransfer(devId, regAddr, false, regs)) return false; + memcpy(i2c_fcram_buf, in, size); + cpu_writeback_dc_range(i2c_fcram_buf, size); + cpu_membarrier(); - while(--size) - { - regs->REG_I2C_DATA = *in++; - regs->REG_I2C_CNT = I2C_ENABLE | I2C_IRQ_ENABLE | I2C_DIRE_WRITE; - i2cWaitBusy(regs); - if(!I2C_GET_ACK(regs->REG_I2C_CNT)) // If ack flag is 0 it failed. - { - regs->REG_I2C_CNT = I2C_ENABLE | I2C_IRQ_ENABLE | I2C_ERROR | I2C_STOP; - return false; - } - } - - regs->REG_I2C_DATA = *in; - regs->REG_I2C_CNT = I2C_ENABLE | I2C_IRQ_ENABLE | I2C_DIRE_WRITE | I2C_STOP; - i2cWaitBusy(regs); - if(!I2C_GET_ACK(regs->REG_I2C_CNT)) // If ack flag is 0 it failed. - { - regs->REG_I2C_CNT = I2C_ENABLE | I2C_IRQ_ENABLE | I2C_ERROR | I2C_STOP; - return false; - } - - return true; + ret = PXI_DoCMD(PXI_I2C_WRITE, args, 4); + return ret; } +/*bool I2C_readRegBuf(I2cDevice devId, u8 regAddr, u8 *out, u32 size) +{ + int ret; + u32 args[] = {devId, regAddr, (u32)out, size}; + cpu_writeback_invalidate_dc_range(out, size); + cpu_membarrier(); + ret = PXI_DoCMD(PXI_I2C_READ, args, 4); + cpu_invalidate_dc_range(out, size); + return ret; +}*/ + u8 I2C_readReg(I2cDevice devId, u8 regAddr) { u8 data; - if(!I2C_readRegBuf(devId, regAddr, &data, 1)) return 0xFF; + if (!I2C_readRegBuf(devId, regAddr, &data, 1)) + data = 0xFF; return data; } +/*bool I2C_writeRegBuf(I2cDevice devId, u8 regAddr, const u8 *in, u32 size) +{ + int ret; + u32 args[] = {devId, regAddr, (u32)in, size}; + cpu_writeback_dc_range(in, size); + cpu_membarrier(); + ret = PXI_DoCMD(PXI_I2C_WRITE, args, 4); + return ret; +}*/ + bool I2C_writeReg(I2cDevice devId, u8 regAddr, u8 data) { return I2C_writeRegBuf(devId, regAddr, &data, 1); diff --git a/arm9/source/system/i2c.h b/arm9/source/system/i2c.h old mode 100644 new mode 100755 index ee08dd7..fae0899 --- a/arm9/source/system/i2c.h +++ b/arm9/source/system/i2c.h @@ -18,22 +18,8 @@ * along with this program. If not, see . */ -#include #include "types.h" - -#define I2C_STOP (1u) -#define I2C_START (1u<<1) -#define I2C_ERROR (1u<<2) -#define I2C_ACK (1u<<4) -#define I2C_DIRE_WRITE (0u) -#define I2C_DIRE_READ (1u<<5) -#define I2C_IRQ_ENABLE (1u<<6) -#define I2C_ENABLE (1u<<7) - -#define I2C_GET_ACK(reg) ((bool)((reg)>>4 & 1u)) - - typedef enum { I2C_DEV_POWER = 0, // Unconfirmed @@ -49,13 +35,6 @@ typedef enum I2C_DEV_N3DS_HID = 17 } I2cDevice; - - -/** - * @brief Initializes the I2C buses. Call this only once. - */ -void I2C_init(void); - /** * @brief Reads data from a I2C register to a buffer. * diff --git a/common/arm.h b/common/arm.h index a12e61a..65122ac 100644 --- a/common/arm.h +++ b/common/arm.h @@ -13,6 +13,7 @@ #define SR_THUMB (1<<5) #define SR_FIQ (1<<6) #define SR_IRQ (1<<7) +#define SR_NOINT (SR_FIQ | SR_IRQ) #ifdef ARM9 #define CR_ENABLE_MPU (1<<0) diff --git a/common/pxi.h b/common/pxi.h index ca4746d..17cb81a 100644 --- a/common/pxi.h +++ b/common/pxi.h @@ -8,27 +8,27 @@ #ifdef ARM9 #define PXI_BASE (0x10008000) -#define IRQ_PXI_SYNC (12) +#define PXI_INIT_SYNC_SET (33) +#define PXI_INIT_SYNC_WAIT (66) #else #define PXI_BASE (0x10163000) -#define IRQ_PXI_SYNC (80) +#define IRQ_PXI_RX (83) +#define PXI_INIT_SYNC_SET (66) +#define PXI_INIT_SYNC_WAIT (33) #endif enum { - PXI_NONE = 0, - PXI_READY, - PXI_BUSY, - PXI_SCREENINIT, - PXI_BRIGHTNESS + PXI_SCREENINIT = 0, + PXI_BRIGHTNESS, + PXI_I2C_READ, + PXI_I2C_WRITE, }; -#define PXI_MAXBUFLEN (2048) -#define PXI_FIFO_LEN (16) +#define PXI_FIFO_LEN (16) #define PXI_SYNC_RECV ((vu8*)(PXI_BASE + 0x00)) #define PXI_SYNC_SEND ((vu8*)(PXI_BASE + 0x01)) #define PXI_SYNC_IRQ ((vu8*)(PXI_BASE + 0x03)) -#define PXI_SYNC ((vu32*)(PXI_BASE + 0x00)) #define PXI_CNT ((vu16*)(PXI_BASE + 0x04)) #define PXI_SEND ((vu32*)(PXI_BASE + 0x08)) #define PXI_RECV ((vu32*)(PXI_BASE + 0x0C)) @@ -39,7 +39,7 @@ enum { #define PXI_CNT_SEND_FIFO_FLUSH (BIT(3)) #define PXI_CNT_RECV_FIFO_EMPTY (BIT(8)) #define PXI_CNT_RECV_FIFO_FULL (BIT(9)) -#define PXI_CNT_RECV_FIFO_NEMPTY_IRQ (BIT(10)) +#define PXI_CNT_RECV_FIFO_AVAIL_IRQ (BIT(10)) #define PXI_CNT_ERROR_ACK (BIT(14)) #define PXI_CNT_ENABLE_FIFO (BIT(15)) @@ -59,83 +59,45 @@ static inline u8 PXI_GetRemote(void) static inline void PXI_WaitRemote(u8 msg) { - while(*PXI_SYNC_RECV != msg); -} - -static inline void PXI_EnableIRQ(void) -{ - *PXI_SYNC_IRQ = PXI_SYNC_ENABLE_IRQ; -} - -static inline void PXI_DisableIRQ(void) -{ - *PXI_SYNC_IRQ = 0; -} - -static inline void PXI_Sync(void) -{ - #ifdef ARM9 - *PXI_SYNC_IRQ |= PXI_SYNC_TRIGGER_MPCORE; - #else - *PXI_SYNC_IRQ |= PXI_SYNC_TRIGGER_OLDARM; - #endif + while(PXI_GetRemote() != msg); } static void PXI_Reset(void) { - *PXI_SYNC = 0; - *PXI_CNT = PXI_CNT_SEND_FIFO_FLUSH; - for (int i=0; i<16; i++) { + *PXI_SYNC_IRQ = 0; + *PXI_CNT = PXI_CNT_SEND_FIFO_FLUSH | PXI_CNT_ENABLE_FIFO; + for (int i = 0; i < PXI_FIFO_LEN; i++) *PXI_RECV; - } + *PXI_CNT = 0; - *PXI_CNT = PXI_CNT_ENABLE_FIFO; - return; + *PXI_CNT = PXI_CNT_RECV_FIFO_AVAIL_IRQ | PXI_CNT_ENABLE_FIFO; } static void PXI_Send(u32 w) { while(*PXI_CNT & PXI_CNT_SEND_FIFO_FULL); - do { - *PXI_SEND = w; - } while(*PXI_CNT & PXI_CNT_ERROR_ACK); - return; + *PXI_SEND = w; } static u32 PXI_Recv(void) { - u32 ret; while(*PXI_CNT & PXI_CNT_RECV_FIFO_EMPTY); - do { - ret = *PXI_RECV; - } while(*PXI_CNT & PXI_CNT_ERROR_ACK); - return ret; + return *PXI_RECV; } static void PXI_SendArray(const u32 *w, u32 c) { - if (c>PXI_FIFO_LEN) c=PXI_FIFO_LEN; - for (u32 i=0; iPXI_FIFO_LEN) c=PXI_FIFO_LEN; - for (u32 i=0; i