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