forked from Mirror/GodMode9
beginning of better ARM11:
- moved I2C code to the ARM11 (with an ugly hack that MUST be fixed) - reworked the PXI protocol to have lower latencies and remove any potential async support
This commit is contained in:
parent
9ab9c01aae
commit
987b820c4a
@ -12,6 +12,4 @@ SECTIONS
|
|||||||
.bss : ALIGN(4) { __bss_start = .; *(.bss*); __bss_end = .; }
|
.bss : ALIGN(4) { __bss_start = .; *(.bss*); __bss_end = .; }
|
||||||
|
|
||||||
. = ALIGN(4);
|
. = ALIGN(4);
|
||||||
|
|
||||||
__stack_top = 0x1FFFE000;
|
|
||||||
}
|
}
|
||||||
|
@ -5,14 +5,14 @@
|
|||||||
|
|
||||||
.global __boot
|
.global __boot
|
||||||
__boot:
|
__boot:
|
||||||
cpsid aif, #(SR_SVC_MODE)
|
cpsid aif, #SR_SVC_MODE
|
||||||
|
|
||||||
mov r0, #0
|
mov r0, #0
|
||||||
mcr p15, 0, r0, c7, c7, 0
|
mcr p15, 0, r0, c7, c7, 0
|
||||||
mcr p15, 0, r0, c7, c14, 0
|
mcr p15, 0, r0, c7, c14, 0
|
||||||
mcr p15, 0, r0, c7, c10, 4
|
mcr p15, 0, r0, c7, c10, 4
|
||||||
|
|
||||||
ldr sp, =__stack_top
|
ldr sp, =_stack_top
|
||||||
|
|
||||||
@ Reset values
|
@ Reset values
|
||||||
ldr r0, =0x00054078
|
ldr r0, =0x00054078
|
||||||
@ -33,3 +33,8 @@ __boot:
|
|||||||
|
|
||||||
bl main
|
bl main
|
||||||
b __boot
|
b __boot
|
||||||
|
|
||||||
|
.section .bss.stack
|
||||||
|
.align 3
|
||||||
|
.space (8192 * 4)
|
||||||
|
_stack_top:
|
||||||
|
213
arm11/source/i2c.c
Normal file
213
arm11/source/i2c.c
Normal file
@ -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 <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdbool.h>
|
||||||
|
#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;
|
||||||
|
}
|
64
arm11/source/i2c.h
Normal file
64
arm11/source/i2c.h
Normal file
@ -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 <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdbool.h>
|
||||||
|
#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);
|
@ -5,63 +5,79 @@
|
|||||||
#include <vram.h>
|
#include <vram.h>
|
||||||
#include <types.h>
|
#include <types.h>
|
||||||
|
|
||||||
|
#include <i2c.h>
|
||||||
|
|
||||||
|
#define CFG11_MPCORE_CLKCNT ((vu16*)(0x10141300))
|
||||||
|
#define CFG11_SOCINFO ((vu16*)(0x10140FFC))
|
||||||
|
|
||||||
vu32 *entrypoint = (vu32*)0x1FFFFFFC;
|
vu32 *entrypoint = (vu32*)0x1FFFFFFC;
|
||||||
|
|
||||||
void PXI_IRQHandler(void)
|
void PXI_RX_Handler(void)
|
||||||
{
|
{
|
||||||
// char pxi_buf[PXI_MAXBUFLEN] = {0};
|
u32 pxi_cmd, ret;
|
||||||
u32 pxi_args[PXI_FIFO_LEN] = {0};
|
u32 pxi_args[PXI_FIFO_LEN];
|
||||||
u8 pxi_cmd;
|
|
||||||
|
|
||||||
pxi_cmd = PXI_GetRemote();
|
pxi_cmd = PXI_Recv();
|
||||||
switch (pxi_cmd) {
|
switch (pxi_cmd) {
|
||||||
default:
|
case PXI_SCREENINIT:
|
||||||
break;
|
{
|
||||||
|
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_SetFramebufferMode(0, PDC_RGB24);
|
||||||
{
|
GPU_SetFramebufferMode(1, PDC_RGB24);
|
||||||
GPU_Init();
|
ret = 0;
|
||||||
GPU_PSCFill(VRAM_START, VRAM_END, 0);
|
break;
|
||||||
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);
|
case PXI_BRIGHTNESS:
|
||||||
GPU_SetFramebufferMode(1, PDC_RGB24);
|
{
|
||||||
|
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);
|
case PXI_I2C_READ:
|
||||||
break;
|
{
|
||||||
|
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:
|
||||||
|
{
|
||||||
|
<var declarations/assignments>
|
||||||
|
<receive args from PXI FIFO>
|
||||||
|
<execute the command>
|
||||||
|
<set the return value>
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
default:
|
||||||
|
ret = 0xFFFFFFFF;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case PXI_BRIGHTNESS:
|
PXI_Send(ret);
|
||||||
{
|
|
||||||
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:
|
|
||||||
{
|
|
||||||
<var declarations/assignments>
|
|
||||||
<receive args from PXI FIFO>
|
|
||||||
<if necessary, copy stuff to pxi_buf>
|
|
||||||
PXI_SetRemote(PXI_BUSY);
|
|
||||||
<execute the command>
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
}
|
|
||||||
|
|
||||||
PXI_SetRemote(PXI_READY);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
vu16 *CFG11_MPCORE_CLKCNT = (vu16*)(0x10141300);
|
|
||||||
vu16 *CFG11_SOCINFO = (vu16*)(0x10140FFC);
|
|
||||||
|
|
||||||
void main(void)
|
void main(void)
|
||||||
{
|
{
|
||||||
u32 entry;
|
u32 entry;
|
||||||
@ -77,20 +93,20 @@ void main(void)
|
|||||||
CPU_DisableIRQ();
|
CPU_DisableIRQ();
|
||||||
}
|
}
|
||||||
|
|
||||||
PXI_Reset();
|
|
||||||
GIC_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;
|
*entrypoint = 0;
|
||||||
while((entry=*entrypoint) == 0);
|
while((entry=*entrypoint) == 0);
|
||||||
|
|
||||||
CPU_DisableIRQ();
|
CPU_DisableIRQ();
|
||||||
PXI_DisableIRQ();
|
|
||||||
PXI_Reset();
|
|
||||||
GIC_Reset();
|
GIC_Reset();
|
||||||
|
|
||||||
((void (*)())(entry))();
|
((void (*)())(entry))();
|
||||||
|
0
arm11/source/mcu.c
Executable file
0
arm11/source/mcu.c
Executable file
0
arm11/source/mcu.h
Executable file
0
arm11/source/mcu.h
Executable file
@ -12,7 +12,7 @@ void CheckBrightness() {
|
|||||||
// Volume Slider value is always between 0x00 and 0x3F
|
// Volume Slider value is always between 0x00 and 0x3F
|
||||||
curSlider >>= 2;
|
curSlider >>= 2;
|
||||||
#else
|
#else
|
||||||
curSlider = FIXED_BRIGHTNESS;
|
curSlider = FIXED_BRIGHTNESS % sizeof(br_settings);
|
||||||
#endif
|
#endif
|
||||||
if (curSlider != prev_brightness) {
|
if (curSlider != prev_brightness) {
|
||||||
PXI_DoCMD(PXI_BRIGHTNESS, (u32[]){br_settings[curSlider]}, 1);
|
PXI_DoCMD(PXI_BRIGHTNESS, (u32[]){br_settings[curSlider]}, 1);
|
||||||
@ -35,15 +35,17 @@ bool IsCharging() {
|
|||||||
|
|
||||||
void Reboot() {
|
void Reboot() {
|
||||||
I2C_writeReg(I2C_DEV_MCU, 0x22, 1 << 0); // poweroff LCD to prevent MCU hangs
|
I2C_writeReg(I2C_DEV_MCU, 0x22, 1 << 0); // poweroff LCD to prevent MCU hangs
|
||||||
flushEntireDCache();
|
cpu_writeback_dc();
|
||||||
if (I2C_writeReg(I2C_DEV_MCU, 0x20, 1 << 2))
|
cpu_membarrier();
|
||||||
while(true);
|
I2C_writeReg(I2C_DEV_MCU, 0x20, 1 << 2);
|
||||||
|
while(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
void PowerOff()
|
void PowerOff()
|
||||||
{
|
{
|
||||||
I2C_writeReg(I2C_DEV_MCU, 0x22, 1 << 0); // poweroff LCD to prevent MCU hangs
|
I2C_writeReg(I2C_DEV_MCU, 0x22, 1 << 0); // poweroff LCD to prevent MCU hangs
|
||||||
flushEntireDCache();
|
cpu_writeback_dc();
|
||||||
if (I2C_writeReg(I2C_DEV_MCU, 0x20, 1 << 0))
|
cpu_membarrier();
|
||||||
while (true);
|
I2C_writeReg(I2C_DEV_MCU, 0x20, 1 << 0);
|
||||||
|
while(true);
|
||||||
}
|
}
|
||||||
|
@ -1,18 +1,17 @@
|
|||||||
#include "godmode.h"
|
#include "godmode.h"
|
||||||
#include "power.h"
|
#include "power.h"
|
||||||
|
#include "timer.h"
|
||||||
#include "pxi.h"
|
#include "pxi.h"
|
||||||
#include "i2c.h"
|
#include "i2c.h"
|
||||||
|
|
||||||
|
#include "vram.h"
|
||||||
|
|
||||||
void main(int argc, char** argv, int entrypoint)
|
void main(int argc, char** argv, int entrypoint)
|
||||||
{
|
{
|
||||||
(void) argc;
|
(void) argc;
|
||||||
(void) argv;
|
(void) argv;
|
||||||
|
|
||||||
PXI_Reset();
|
PXI_Reset();
|
||||||
I2C_init();
|
|
||||||
|
|
||||||
// Wait for ARM11
|
|
||||||
PXI_WaitRemote(PXI_READY);
|
|
||||||
|
|
||||||
PXI_DoCMD(PXI_SCREENINIT, NULL, 0);
|
PXI_DoCMD(PXI_SCREENINIT, NULL, 0);
|
||||||
I2C_writeReg(I2C_DEV_MCU, 0x22, 0x2A);
|
I2C_writeReg(I2C_DEV_MCU, 0x22, 0x2A);
|
||||||
|
@ -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 <http://www.gnu.org/licenses/>.
|
|
||||||
*
|
|
||||||
* 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
|
#pragma once
|
||||||
|
|
||||||
#include "common.h"
|
#include "types.h"
|
||||||
|
|
||||||
/***
|
static inline void
|
||||||
The following functions flush the data cache, then waits for all memory transfers to be finished.
|
cpu_membarrier(void) {
|
||||||
The data cache and/or the instruction cache MUST be flushed before doing one of the following:
|
__asm__ __volatile__("mcr p15, 0, %0, c7, c10, 4\n\t"
|
||||||
- rebooting
|
:: "r"(0) : "memory");
|
||||||
- powering down
|
}
|
||||||
- setting the ARM11 entrypoint to execute a function
|
|
||||||
- jumping to a payload
|
|
||||||
***/
|
|
||||||
|
|
||||||
void flushEntireDCache(void); //actually: "clean and flush"
|
static inline void
|
||||||
void flushDCacheRange(void *startAddress, u32 size);
|
cpu_invalidate_ic(void) {
|
||||||
void flushEntireICache(void);
|
__asm__ __volatile__("mcr p15, 0, %0, c7, c5, 0\n\t"
|
||||||
void flushICacheRange(void *startAddress, u32 size);
|
:: "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--);
|
||||||
|
}
|
||||||
|
@ -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 <http://www.gnu.org/licenses/>.
|
|
||||||
@
|
|
||||||
@ 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
|
|
249
arm9/source/system/i2c.c
Normal file → Executable file
249
arm9/source/system/i2c.c
Normal file → Executable file
@ -1,224 +1,85 @@
|
|||||||
/*
|
#include "common.h"
|
||||||
* 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 <http://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <stdbool.h>
|
#include "cache.h"
|
||||||
#include "types.h"
|
|
||||||
#include "i2c.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)
|
the current hack assumes all buffers in the heap are
|
||||||
|
located in FCRAM, which is accessible to both processors
|
||||||
#define I2C2_REGS_BASE (0x10144000)
|
but it's horrendous, and hopefully temporary
|
||||||
|
*/
|
||||||
#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;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
static char *i2c_fcram_buf = NULL;
|
||||||
bool I2C_readRegBuf(I2cDevice devId, u8 regAddr, u8 *out, u32 size)
|
bool I2C_readRegBuf(I2cDevice devId, u8 regAddr, u8 *out, u32 size)
|
||||||
{
|
{
|
||||||
const u8 busId = i2cDevTable[devId].busId;
|
if (!i2c_fcram_buf)
|
||||||
I2cRegs *const regs = i2cGetBusRegsBase(busId);
|
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)
|
ret = PXI_DoCMD(PXI_I2C_READ, args, 4);
|
||||||
{
|
|
||||||
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;
|
cpu_invalidate_dc_range(i2c_fcram_buf, size);
|
||||||
i2cWaitBusy(regs);
|
memcpy(out, i2c_fcram_buf, size);
|
||||||
*out = regs->REG_I2C_DATA; // Last byte
|
|
||||||
|
|
||||||
return true;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool I2C_writeRegBuf(I2cDevice devId, u8 regAddr, const u8 *in, u32 size)
|
bool I2C_writeRegBuf(I2cDevice devId, u8 regAddr, const u8 *in, u32 size)
|
||||||
{
|
{
|
||||||
const u8 busId = i2cDevTable[devId].busId;
|
if (!i2c_fcram_buf)
|
||||||
I2cRegs *const regs = i2cGetBusRegsBase(busId);
|
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)
|
ret = PXI_DoCMD(PXI_I2C_WRITE, args, 4);
|
||||||
{
|
return ret;
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*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 I2C_readReg(I2cDevice devId, u8 regAddr)
|
||||||
{
|
{
|
||||||
u8 data;
|
u8 data;
|
||||||
if(!I2C_readRegBuf(devId, regAddr, &data, 1)) return 0xFF;
|
if (!I2C_readRegBuf(devId, regAddr, &data, 1))
|
||||||
|
data = 0xFF;
|
||||||
return data;
|
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)
|
bool I2C_writeReg(I2cDevice devId, u8 regAddr, u8 data)
|
||||||
{
|
{
|
||||||
return I2C_writeRegBuf(devId, regAddr, &data, 1);
|
return I2C_writeRegBuf(devId, regAddr, &data, 1);
|
||||||
|
21
arm9/source/system/i2c.h
Normal file → Executable file
21
arm9/source/system/i2c.h
Normal file → Executable file
@ -18,22 +18,8 @@
|
|||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <stdbool.h>
|
|
||||||
#include "types.h"
|
#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
|
typedef enum
|
||||||
{
|
{
|
||||||
I2C_DEV_POWER = 0, // Unconfirmed
|
I2C_DEV_POWER = 0, // Unconfirmed
|
||||||
@ -49,13 +35,6 @@ typedef enum
|
|||||||
I2C_DEV_N3DS_HID = 17
|
I2C_DEV_N3DS_HID = 17
|
||||||
} I2cDevice;
|
} I2cDevice;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Initializes the I2C buses. Call this only once.
|
|
||||||
*/
|
|
||||||
void I2C_init(void);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Reads data from a I2C register to a buffer.
|
* @brief Reads data from a I2C register to a buffer.
|
||||||
*
|
*
|
||||||
|
@ -13,6 +13,7 @@
|
|||||||
#define SR_THUMB (1<<5)
|
#define SR_THUMB (1<<5)
|
||||||
#define SR_FIQ (1<<6)
|
#define SR_FIQ (1<<6)
|
||||||
#define SR_IRQ (1<<7)
|
#define SR_IRQ (1<<7)
|
||||||
|
#define SR_NOINT (SR_FIQ | SR_IRQ)
|
||||||
|
|
||||||
#ifdef ARM9
|
#ifdef ARM9
|
||||||
#define CR_ENABLE_MPU (1<<0)
|
#define CR_ENABLE_MPU (1<<0)
|
||||||
|
86
common/pxi.h
86
common/pxi.h
@ -8,27 +8,27 @@
|
|||||||
|
|
||||||
#ifdef ARM9
|
#ifdef ARM9
|
||||||
#define PXI_BASE (0x10008000)
|
#define PXI_BASE (0x10008000)
|
||||||
#define IRQ_PXI_SYNC (12)
|
#define PXI_INIT_SYNC_SET (33)
|
||||||
|
#define PXI_INIT_SYNC_WAIT (66)
|
||||||
#else
|
#else
|
||||||
#define PXI_BASE (0x10163000)
|
#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
|
#endif
|
||||||
|
|
||||||
enum {
|
enum {
|
||||||
PXI_NONE = 0,
|
PXI_SCREENINIT = 0,
|
||||||
PXI_READY,
|
PXI_BRIGHTNESS,
|
||||||
PXI_BUSY,
|
PXI_I2C_READ,
|
||||||
PXI_SCREENINIT,
|
PXI_I2C_WRITE,
|
||||||
PXI_BRIGHTNESS
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#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_RECV ((vu8*)(PXI_BASE + 0x00))
|
||||||
#define PXI_SYNC_SEND ((vu8*)(PXI_BASE + 0x01))
|
#define PXI_SYNC_SEND ((vu8*)(PXI_BASE + 0x01))
|
||||||
#define PXI_SYNC_IRQ ((vu8*)(PXI_BASE + 0x03))
|
#define PXI_SYNC_IRQ ((vu8*)(PXI_BASE + 0x03))
|
||||||
#define PXI_SYNC ((vu32*)(PXI_BASE + 0x00))
|
|
||||||
#define PXI_CNT ((vu16*)(PXI_BASE + 0x04))
|
#define PXI_CNT ((vu16*)(PXI_BASE + 0x04))
|
||||||
#define PXI_SEND ((vu32*)(PXI_BASE + 0x08))
|
#define PXI_SEND ((vu32*)(PXI_BASE + 0x08))
|
||||||
#define PXI_RECV ((vu32*)(PXI_BASE + 0x0C))
|
#define PXI_RECV ((vu32*)(PXI_BASE + 0x0C))
|
||||||
@ -39,7 +39,7 @@ enum {
|
|||||||
#define PXI_CNT_SEND_FIFO_FLUSH (BIT(3))
|
#define PXI_CNT_SEND_FIFO_FLUSH (BIT(3))
|
||||||
#define PXI_CNT_RECV_FIFO_EMPTY (BIT(8))
|
#define PXI_CNT_RECV_FIFO_EMPTY (BIT(8))
|
||||||
#define PXI_CNT_RECV_FIFO_FULL (BIT(9))
|
#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_ERROR_ACK (BIT(14))
|
||||||
#define PXI_CNT_ENABLE_FIFO (BIT(15))
|
#define PXI_CNT_ENABLE_FIFO (BIT(15))
|
||||||
|
|
||||||
@ -59,83 +59,45 @@ static inline u8 PXI_GetRemote(void)
|
|||||||
|
|
||||||
static inline void PXI_WaitRemote(u8 msg)
|
static inline void PXI_WaitRemote(u8 msg)
|
||||||
{
|
{
|
||||||
while(*PXI_SYNC_RECV != msg);
|
while(PXI_GetRemote() != 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
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void PXI_Reset(void)
|
static void PXI_Reset(void)
|
||||||
{
|
{
|
||||||
*PXI_SYNC = 0;
|
*PXI_SYNC_IRQ = 0;
|
||||||
*PXI_CNT = PXI_CNT_SEND_FIFO_FLUSH;
|
*PXI_CNT = PXI_CNT_SEND_FIFO_FLUSH | PXI_CNT_ENABLE_FIFO;
|
||||||
for (int i=0; i<16; i++) {
|
for (int i = 0; i < PXI_FIFO_LEN; i++)
|
||||||
*PXI_RECV;
|
*PXI_RECV;
|
||||||
}
|
|
||||||
*PXI_CNT = 0;
|
*PXI_CNT = 0;
|
||||||
*PXI_CNT = PXI_CNT_ENABLE_FIFO;
|
*PXI_CNT = PXI_CNT_RECV_FIFO_AVAIL_IRQ | PXI_CNT_ENABLE_FIFO;
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void PXI_Send(u32 w)
|
static void PXI_Send(u32 w)
|
||||||
{
|
{
|
||||||
while(*PXI_CNT & PXI_CNT_SEND_FIFO_FULL);
|
while(*PXI_CNT & PXI_CNT_SEND_FIFO_FULL);
|
||||||
do {
|
*PXI_SEND = w;
|
||||||
*PXI_SEND = w;
|
|
||||||
} while(*PXI_CNT & PXI_CNT_ERROR_ACK);
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static u32 PXI_Recv(void)
|
static u32 PXI_Recv(void)
|
||||||
{
|
{
|
||||||
u32 ret;
|
|
||||||
while(*PXI_CNT & PXI_CNT_RECV_FIFO_EMPTY);
|
while(*PXI_CNT & PXI_CNT_RECV_FIFO_EMPTY);
|
||||||
do {
|
return *PXI_RECV;
|
||||||
ret = *PXI_RECV;
|
|
||||||
} while(*PXI_CNT & PXI_CNT_ERROR_ACK);
|
|
||||||
return ret;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void PXI_SendArray(const u32 *w, u32 c)
|
static void PXI_SendArray(const u32 *w, u32 c)
|
||||||
{
|
{
|
||||||
if (c>PXI_FIFO_LEN) c=PXI_FIFO_LEN;
|
while(c--) PXI_Send(*(w++));
|
||||||
for (u32 i=0; i<c; i++) {
|
|
||||||
PXI_Send(w[i]);
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void PXI_RecvArray(u32 *w, u32 c)
|
static void PXI_RecvArray(u32 *w, u32 c)
|
||||||
{
|
{
|
||||||
if (c>PXI_FIFO_LEN) c=PXI_FIFO_LEN;
|
while(c--) *(w++) = PXI_Recv();
|
||||||
for (u32 i=0; i<c; i++) {
|
|
||||||
w[i] = PXI_Recv();
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void PXI_DoCMD(u8 cmd, u32 *args, u32 argc)
|
static u32 PXI_DoCMD(u32 cmd, const u32 *args, u32 argc)
|
||||||
{
|
{
|
||||||
PXI_WaitRemote(PXI_READY);
|
PXI_Send(cmd);
|
||||||
PXI_SendArray(args, argc);
|
PXI_SendArray(args, argc);
|
||||||
PXI_SetRemote(cmd);
|
return PXI_Recv();
|
||||||
PXI_Sync();
|
|
||||||
PXI_WaitRemote(PXI_BUSY);
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user