Skip to content

Commit

Permalink
Added dual emuNAND support, multi-payload loader with built-in screen…
Browse files Browse the repository at this point in the history
… init (inspired by arm9select, thanks Fix94)
  • Loading branch information
AuroraWright committed Mar 16, 2016
1 parent 8ce395c commit dcb09a9
Show file tree
Hide file tree
Showing 14 changed files with 400 additions and 33 deletions.
14 changes: 14 additions & 0 deletions loader/source/buttons.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
#pragma once

#include "types.h"

#define HID_PAD ((~*(vu16 *)0x10146000) & 0xFFF)
#define BUTTON_B (1 << 1)
#define BUTTON_X (1 << 10)
#define BUTTON_Y (1 << 11)
#define BUTTON_SELECT (1 << 2)
#define BUTTON_START (1 << 3)
#define BUTTON_RIGHT (1 << 4)
#define BUTTON_LEFT (1 << 5)
#define BUTTON_UP (1 << 6)
#define BUTTON_DOWN (1 << 7)
13 changes: 1 addition & 12 deletions loader/source/fatfs/sdmmc/common.h
Original file line number Diff line number Diff line change
@@ -1,15 +1,4 @@
#pragma once

#include <stdint.h>
#include <stddef.h>
#include <stdbool.h>

//Common data types
typedef uint8_t u8;
typedef uint16_t u16;
typedef uint32_t u32;
typedef uint64_t u64;
typedef volatile u8 vu8;
typedef volatile u16 vu16;
typedef volatile u32 vu32;
typedef volatile u64 vu64;
#include "../../types.h"
149 changes: 149 additions & 0 deletions loader/source/i2c.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,149 @@
#include "i2c.h"

//-----------------------------------------------------------------------------

static const struct { u8 bus_id, reg_addr; } dev_data[] = {
{0, 0x4A}, {0, 0x7A}, {0, 0x78},
{1, 0x4A}, {1, 0x78}, {1, 0x2C},
{1, 0x2E}, {1, 0x40}, {1, 0x44},
{2, 0xD6}, {2, 0xD0}, {2, 0xD2},
{2, 0xA4}, {2, 0x9A}, {2, 0xA0},
};

inline u8 i2cGetDeviceBusId(u8 device_id) {
return dev_data[device_id].bus_id;
}

inline u8 i2cGetDeviceRegAddr(u8 device_id) {
return dev_data[device_id].reg_addr;
}

//-----------------------------------------------------------------------------

static vu8* reg_data_addrs[] = {
(vu8*)(I2C1_REG_OFF + I2C_REG_DATA),
(vu8*)(I2C2_REG_OFF + I2C_REG_DATA),
(vu8*)(I2C3_REG_OFF + I2C_REG_DATA),
};

inline vu8* i2cGetDataReg(u8 bus_id) {
return reg_data_addrs[bus_id];
}

//-----------------------------------------------------------------------------

static vu8* reg_cnt_addrs[] = {
(vu8*)(I2C1_REG_OFF + I2C_REG_CNT),
(vu8*)(I2C2_REG_OFF + I2C_REG_CNT),
(vu8*)(I2C3_REG_OFF + I2C_REG_CNT),
};

inline vu8* i2cGetCntReg(u8 bus_id) {
return reg_cnt_addrs[bus_id];
}

//-----------------------------------------------------------------------------

inline void i2cWaitBusy(u8 bus_id) {
while (*i2cGetCntReg(bus_id) & 0x80);
}

inline bool i2cGetResult(u8 bus_id) {
i2cWaitBusy(bus_id);
return (*i2cGetCntReg(bus_id) >> 4) & 1;
}

void i2cStop(u8 bus_id, u8 arg0) {
*i2cGetCntReg(bus_id) = (arg0 << 5) | 0xC0;
i2cWaitBusy(bus_id);
*i2cGetCntReg(bus_id) = 0xC5;
}

//-----------------------------------------------------------------------------

bool i2cSelectDevice(u8 bus_id, u8 dev_reg) {
i2cWaitBusy(bus_id);
*i2cGetDataReg(bus_id) = dev_reg;
*i2cGetCntReg(bus_id) = 0xC2;
return i2cGetResult(bus_id);
}

bool i2cSelectRegister(u8 bus_id, u8 reg) {
i2cWaitBusy(bus_id);
*i2cGetDataReg(bus_id) = reg;
*i2cGetCntReg(bus_id) = 0xC0;
return i2cGetResult(bus_id);
}

//-----------------------------------------------------------------------------

u8 i2cReadRegister(u8 dev_id, u8 reg) {
u8 bus_id = i2cGetDeviceBusId(dev_id);
u8 dev_addr = i2cGetDeviceRegAddr(dev_id);

for (size_t i = 0; i < 8; i++) {
if (i2cSelectDevice(bus_id, dev_addr) && i2cSelectRegister(bus_id, reg)) {
if (i2cSelectDevice(bus_id, dev_addr | 1)) {
i2cWaitBusy(bus_id);
i2cStop(bus_id, 1);
i2cWaitBusy(bus_id);
return *i2cGetDataReg(bus_id);
}
}
*i2cGetCntReg(bus_id) = 0xC5;
i2cWaitBusy(bus_id);
}
return 0xff;
}

bool i2cReadRegisterBuffer(unsigned int dev_id, int reg, u8* buffer, size_t buf_size) {
u8 bus_id = i2cGetDeviceBusId(dev_id);
u8 dev_addr = i2cGetDeviceRegAddr(dev_id);

size_t j = 0;
while (!i2cSelectDevice(bus_id, dev_addr)
|| !i2cSelectRegister(bus_id, reg)
|| !i2cSelectDevice(bus_id, dev_addr | 1))
{
i2cWaitBusy(bus_id);
*i2cGetCntReg(bus_id) = 0xC5;
i2cWaitBusy(bus_id);
if (++j >= 8)
return false;
}

if (buf_size != 1) {
for (size_t i = 0; i < buf_size - 1; i++) {
i2cWaitBusy(bus_id);
*i2cGetCntReg(bus_id) = 0xF0;
i2cWaitBusy(bus_id);
buffer[i] = *i2cGetDataReg(bus_id);
}
}

i2cWaitBusy(bus_id);
*i2cGetCntReg(bus_id) = 0xE1;
i2cWaitBusy(bus_id);
*buffer = *i2cGetDataReg(bus_id);
return true;
}

bool i2cWriteRegister(u8 dev_id, u8 reg, u8 data) {
u8 bus_id = i2cGetDeviceBusId(dev_id);
u8 dev_addr = i2cGetDeviceRegAddr(dev_id);

for (int i = 0; i < 8; i++) {
if (i2cSelectDevice(bus_id, dev_addr) && i2cSelectRegister(bus_id, reg)) {
i2cWaitBusy(bus_id);
*i2cGetDataReg(bus_id) = data;
*i2cGetCntReg(bus_id) = 0xC1;
i2cStop(bus_id, 0);
if (i2cGetResult(bus_id))
return true;
}
*i2cGetCntReg(bus_id) = 0xC5;
i2cWaitBusy(bus_id);
}

return false;
}
35 changes: 35 additions & 0 deletions loader/source/i2c.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
#pragma once

#include "common.h"

#define I2C1_REG_OFF 0x10161000
#define I2C2_REG_OFF 0x10144000
#define I2C3_REG_OFF 0x10148000

#define I2C_REG_DATA 0
#define I2C_REG_CNT 1
#define I2C_REG_CNTEX 2
#define I2C_REG_SCL 4

#define I2C_DEV_MCU 3
#define I2C_DEV_GYRO 10
#define I2C_DEV_IR 13

u8 i2cGetDeviceBusId(u8 device_id);
u8 i2cGetDeviceRegAddr(u8 device_id);

vu8* i2cGetDataReg(u8 bus_id);
vu8* i2cGetCntReg(u8 bus_id);

void i2cWaitBusy(u8 bus_id);
bool i2cGetResult(u8 bus_id);
u8 i2cGetData(u8 bus_id);
void i2cStop(u8 bus_id, u8 arg0);

bool i2cSelectDevice(u8 bus_id, u8 dev_reg);
bool i2cSelectRegister(u8 bus_id, u8 reg);

u8 i2cReadRegister(u8 dev_id, u8 reg);
bool i2cWriteRegister(u8 dev_id, u8 reg, u8 data);

bool i2cReadRegisterBuffer(unsigned int dev_id, int reg, u8* buffer, size_t buf_size);
39 changes: 32 additions & 7 deletions loader/source/main.c
Original file line number Diff line number Diff line change
@@ -1,17 +1,42 @@
#include "types.h"
#include "buttons.h"
#include "screeninit.h"
#include "fatfs/ff.h"

#define PAYLOAD_ADDRESS 0x23F00000

void main()
{
FATFS fs;
u32 loadPayload(const char *path){
FIL payload;
unsigned int br;

f_mount(&fs, "0:", 1);
if(f_open(&payload, "rei/arm9payload.bin", FA_READ) == FR_OK)
if(f_open(&payload, path, FA_READ) == FR_OK)
{
f_read(&payload, (void *)PAYLOAD_ADDRESS, f_size(&payload), &br);
f_read(&payload, (void*)PAYLOAD_ADDRESS, f_size(&payload), &br);
f_close(&payload);

return 1;
}

return 0;
}

void main(){
FATFS fs;
f_mount(&fs, "0:", 1);

//Get pressed buttons
u16 pressed = HID_PAD;

if(((pressed & BUTTON_B) && loadPayload("/rei/payloads/b.bin")) ||
((pressed & BUTTON_X) && loadPayload("/rei/payloads/x.bin")) ||
((pressed & BUTTON_Y) && loadPayload("/rei/payloads/y.bin")) ||
((pressed & BUTTON_SELECT) && loadPayload("/rei/payloads/select.bin")) ||
((pressed & BUTTON_START) && loadPayload("/rei/payloads/start.bin")) ||
((pressed & BUTTON_RIGHT) && loadPayload("/rei/payloads/right.bin")) ||
((pressed & BUTTON_LEFT) && loadPayload("/rei/payloads/left.bin")) ||
((pressed & BUTTON_UP) && loadPayload("/rei/payloads/up.bin")) ||
((pressed & BUTTON_DOWN) && loadPayload("/rei/payloads/down.bin")) ||
loadPayload("/rei/payloads/default.bin")){
initLCD();
((void (*)())PAYLOAD_ADDRESS)();
}
}
118 changes: 118 additions & 0 deletions loader/source/screeninit.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
#include "screeninit.h"
#include "i2c.h"

void initLCD()
{
vu32 *const arm11 = (u32 *)0x1FFFFFF8;

void __attribute__((naked)) ARM11()
{
*(vu32 *)0x10141200 = 0x1007F;
*(vu32 *)0x10202014 = 0x00000001;
*(vu32 *)0x1020200C &= 0xFFFEFFFE;
*(vu32 *)0x10202240 = 0x39;
*(vu32 *)0x10202A40 = 0x39;
*(vu32 *)0x10202244 = 0x1023E;
*(vu32 *)0x10202A44 = 0x1023E;

// Top screen
*(vu32 *)0x10400400 = 0x000001c2;
*(vu32 *)0x10400404 = 0x000000d1;
*(vu32 *)0x10400408 = 0x000001c1;
*(vu32 *)0x1040040c = 0x000001c1;
*(vu32 *)0x10400410 = 0x00000000;
*(vu32 *)0x10400414 = 0x000000cf;
*(vu32 *)0x10400418 = 0x000000d1;
*(vu32 *)0x1040041c = 0x01c501c1;
*(vu32 *)0x10400420 = 0x00010000;
*(vu32 *)0x10400424 = 0x0000019d;
*(vu32 *)0x10400428 = 0x00000002;
*(vu32 *)0x1040042c = 0x00000192;
*(vu32 *)0x10400430 = 0x00000192;
*(vu32 *)0x10400434 = 0x00000192;
*(vu32 *)0x10400438 = 0x00000001;
*(vu32 *)0x1040043c = 0x00000002;
*(vu32 *)0x10400440 = 0x01960192;
*(vu32 *)0x10400444 = 0x00000000;
*(vu32 *)0x10400448 = 0x00000000;
*(vu32 *)0x1040045C = 0x00f00190;
*(vu32 *)0x10400460 = 0x01c100d1;
*(vu32 *)0x10400464 = 0x01920002;
*(vu32 *)0x10400468 = 0x18300000;
*(vu32 *)0x10400470 = 0x80341;
*(vu32 *)0x10400474 = 0x00010501;
*(vu32 *)0x10400478 = 0;
*(vu32 *)0x10400490 = 0x000002D0;
*(vu32 *)0x1040049C = 0x00000000;

// Disco register
for(vu32 i = 0; i < 256; i++)
*(vu32 *)0x10400484 = 0x10101 * i;

// Bottom screen
*(vu32 *)0x10400500 = 0x000001c2;
*(vu32 *)0x10400504 = 0x000000d1;
*(vu32 *)0x10400508 = 0x000001c1;
*(vu32 *)0x1040050c = 0x000001c1;
*(vu32 *)0x10400510 = 0x000000cd;
*(vu32 *)0x10400514 = 0x000000cf;
*(vu32 *)0x10400518 = 0x000000d1;
*(vu32 *)0x1040051c = 0x01c501c1;
*(vu32 *)0x10400520 = 0x00010000;
*(vu32 *)0x10400524 = 0x0000019d;
*(vu32 *)0x10400528 = 0x00000052;
*(vu32 *)0x1040052c = 0x00000192;
*(vu32 *)0x10400530 = 0x00000192;
*(vu32 *)0x10400534 = 0x0000004f;
*(vu32 *)0x10400538 = 0x00000050;
*(vu32 *)0x1040053c = 0x00000052;
*(vu32 *)0x10400540 = 0x01980194;
*(vu32 *)0x10400544 = 0x00000000;
*(vu32 *)0x10400548 = 0x00000011;
*(vu32 *)0x1040055C = 0x00f00140;
*(vu32 *)0x10400560 = 0x01c100d1;
*(vu32 *)0x10400564 = 0x01920052;
*(vu32 *)0x10400568 = 0x18300000 + 0x46500;
*(vu32 *)0x10400570 = 0x80301;
*(vu32 *)0x10400574 = 0x00010501;
*(vu32 *)0x10400578 = 0;
*(vu32 *)0x10400590 = 0x000002D0;
*(vu32 *)0x1040059C = 0x00000000;

// Disco register
for(vu32 i = 0; i < 256; i++)
*(vu32 *)0x10400584 = 0x10101 * i;

// Enable backlight
i2cWriteRegister(I2C_DEV_MCU, 0x22, 0x2A);

*(vu32 *)0x10400468 = 0x18300000;
*(vu32 *)0x1040046c = 0x18300000;
*(vu32 *)0x10400494 = 0x18300000;
*(vu32 *)0x10400498 = 0x18300000;
*(vu32 *)0x10400568 = 0x18346500;
*(vu32 *)0x1040056c = 0x18346500;

//Clear ARM11 entry offset
*arm11 = 0;

//Wait for the entry to be set
while(!*arm11);
//Jump to it
((void (*)())*arm11)();
}

//Determine if screen was already inited
if(*(vu8 *)0x10141200 != 0x1) return;

//Set CakeBrah framebuffers
*(vu32 *)0x23FFFE00 = 0x18300000;
*(vu32 *)0x23FFFE04 = 0x18300000;
*(vu32 *)0x23FFFE08 = 0x18346500;

*arm11 = (u32)ARM11;

//This delay is needed for some reason
for(vu32 i = 0; i < 0x2000; ++i);
while(*arm11);
}
5 changes: 5 additions & 0 deletions loader/source/screeninit.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
#pragma once

#include "types.h"

void initLCD();
Loading

0 comments on commit dcb09a9

Please sign in to comment.