Skip to content

Commit

Permalink
Fix a few MCU-related bugs, gm9 should boot properly now
Browse files Browse the repository at this point in the history
- Stop spamming mcu reads... use the GPIO pin to know if there's a MCU interrupt, instead
- Wait for the MCU interrupts to be raised when powering up LCD+backlights
- Also turn off LCD+backlight when needed
  • Loading branch information
TuxSH committed Jan 26, 2021
1 parent be6d642 commit bd2b012
Show file tree
Hide file tree
Showing 16 changed files with 497 additions and 62 deletions.
4 changes: 2 additions & 2 deletions arm11/source/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -123,8 +123,8 @@ static void initScreens(u32 brightnessLevel, struct fb *fbs)
for(u32 i = 0; i < 256; i++)
*(vu32 *)0x10400584 = 0x10101 * i;

*(vu32 *)0x10202204 = 0x00000000; //unset LCD fill
*(vu32 *)0x10202A04 = 0x00000000;
//*(vu32 *)0x10202204 = 0x00000000; //unset LCD fill
//*(vu32 *)0x10202A04 = 0x00000000;
}

static void setupFramebuffers(struct fb *fbs)
Expand Down
4 changes: 4 additions & 0 deletions arm9/linker.ld
Original file line number Diff line number Diff line change
Expand Up @@ -45,16 +45,19 @@ SECTIONS

chainloader.o(.text*)
i2c.o(.text*)
mcu.o(.text*)
arm9_exception_handlers.o(.text*)

*(.arm9_exception_handlers.rodata*)
chainloader.o(.rodata*)
i2c.o(.rodata*)
mcu.o(.rodata*)
arm9_exception_handlers.o(.rodata*)

*(.arm9_exception_handlers.data*)
chainloader.o(.data*)
i2c.o(.data*)
mcu.o(.data*)
arm9_exception_handlers.o(.data*)
. = ALIGN(32);
} >itcm AT>main :itcm
Expand All @@ -67,6 +70,7 @@ SECTIONS
*(.arm9_exception_handlers.bss*)
chainloader.o(.bss* COMMON)
i2c.o(.bss* COMMON)
mcu.o(.bss* COMMON)
arm9_exception_handlers.o(.bss* COMMON)
. = ALIGN(32);
PROVIDE (__itcm_end__ = ABSOLUTE(.));
Expand Down
8 changes: 3 additions & 5 deletions arm9/source/arm9_exception_handlers.c
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,7 @@
*/

#include "arm9_exception_handlers.h"
#include "i2c.h"
#include "screen.h"
#include "mcu.h"

#define FINAL_BUFFER 0x25000000

Expand Down Expand Up @@ -103,10 +102,9 @@ void __attribute__((noreturn)) arm9ExceptionHandlerMain(u32 *registerDump, u32 t
//Copy header (actually optimized by the compiler)
*(ExceptionDumpHeader *)FINAL_BUFFER = dumpHeader;

if(ARESCREENSINITIALIZED) I2C_writeReg(I2C_DEV_MCU, 0x22, 1 << 0); //Shutdown LCD
mcuPowerBacklightsOff();

((void (*)())0xFFFF0830)(); //Ensure that all memory transfers have completed and that the data cache has been flushed

I2C_writeReg(I2C_DEV_MCU, 0x20, 1 << 2); //Reboot
while(true);
mcuReboot();
}
2 changes: 1 addition & 1 deletion arm9/source/exceptions.c
Original file line number Diff line number Diff line change
Expand Up @@ -200,5 +200,5 @@ void detectAndProcessExceptionDumps(void)

exit:
memset((void *)dumpHeader, 0, dumpHeader->totalSize);
mcuPowerOff();
powerOff();
}
2 changes: 2 additions & 0 deletions arm9/source/firm.c
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@
#include "screen.h"
#include "fmt.h"
#include "chainloader.h"
#include "mcu.h"

static Firm *firm = (Firm *)0x20001000;

Expand Down Expand Up @@ -561,6 +562,7 @@ u32 patch1x2xNativeAndSafeFirm(void)

void launchFirm(int argc, char **argv)
{
mcuFinalize();
prepareArm11ForFirmlaunch();
chainload(argc, argv, firm);
}
225 changes: 225 additions & 0 deletions arm9/source/gpio.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,225 @@
/*
* This file is part of Luma3DS
* Copyright (C) 2021 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

#include "types.h"

typedef struct GpioRegisters {
u8 gpio1_data;
u8 _0x001[0x010 - 0x001];

u8 gpio2_data;
u8 gpio2_dir;
u8 gpio2_intcfg;
u8 gpio2_inten;
u16 gpio2_data2;
u8 _0x016[0x020 - 0x016];

u16 gpio3_data;
u16 gpio3_dir;
u16 gpio3_intcfg;
u16 gpio3_inten;
u16 gpio3_data2;
u8 _0x02a[0x100 - 0x02A];
} GpioRegisters;

typedef enum GpioDirection {
GPIO_DIR_INPUT = 0,
GPIO_DIR_OUTPUT = 1,
} GpioDirection;

typedef enum GpioInterruptConfig {
GPIO_INTCFG_FALLING_EDGE = 0,
GPIO_INTCFG_RISING_EDGE = 1,
} GpioInterruptConfig;

#define GPIO_PIN(bank, idx) (((bank) << 4) | ((idx) & 0xF))
#define BANK_OF(pin) ((pin) >> 4)
#define BIT_OF(pin) ((pin) & 0xF)

typedef enum GpioPin {
// GPIO1
GPIO_DEBUG_BUTTON = GPIO_PIN(1, 0), // active-low
GPIO_TOUCH_SCREEN = GPIO_PIN(1, 1), // active-low, 0 when the touch screen is pressed
GPIO_SHELL_CLOSED = GPIO_PIN(1, 2),

// GPIO2
GPIO_HEADPHONES_INSERTED = GPIO_PIN(2, 0),
GPIO_TWL_DEPOP = GPIO_PIN(2, 1), // active-low

// GPIO2 (DATA2)
GPIO_WIFI_MODE = GPIO_PIN(4, 0), // 0 is CTR, 1 is MP (DS WiFi)

// GPIO3
GPIO_CSTICK_INT = GPIO_PIN(3, 0),
GPIO_IRDA_INT = GPIO_PIN(3, 1), // active-low
GPIO_GYRO_INT = GPIO_PIN(3, 2),
GPIO_CSTICK_STOP = GPIO_PIN(3, 3), // output
GPIO_IRDA_TXRC = GPIO_PIN(3, 4), // output
GPIO_IRDA_RXD = GPIO_PIN(3, 5), // active-low
GPIO_NFC_OUT1 = GPIO_PIN(3, 6), // output
GPIO_NFC_OUT2 = GPIO_PIN(3, 7), // output
GPIO_HEADPHONES_BUTTON = GPIO_PIN(3, 8), // active-low ("half-inserted")
GPIO_MCU_INT = GPIO_PIN(3, 9),
GPIO_NFC_INT = GPIO_PIN(3, 10),
GPIO_QTM_OUT = GPIO_PIN(3, 11), // output

// GPIO3 (DATA2)
GPIO_WIFI_ENABLED = GPIO_PIN(5, 0),
} GpioPin;

static volatile GpioRegisters *const GPIO = (volatile GpioRegisters *)0x10147000;

static inline bool gpioRead(GpioPin pin)
{
u32 bank = BANK_OF(pin);
u32 bit = BIT_OF(pin);

switch (bank) {
case 1:
return (GPIO->gpio1_data & BIT(bit)) != 0;
case 2:
return (GPIO->gpio2_data & BIT(bit)) != 0;
case 3:
return (GPIO->gpio3_data & BIT(bit)) != 0;
case 4:
return (GPIO->gpio2_data2 & BIT(bit)) != 0;
case 5:
return (GPIO->gpio3_data2 & BIT(bit)) != 0;

default:
return false;
}
}

static inline void gpioWrite(GpioPin pin, bool val)
{
u32 bank = BANK_OF(pin);
u32 bit = BIT_OF(pin);

u32 valMask = (val ? 1 : 0) << bit;
u32 tmp;

switch (bank) {
case 1:
tmp = GPIO->gpio1_data & ~BIT(bit);
GPIO->gpio1_data = (u8)(tmp | valMask);
break;
case 2:
tmp = GPIO->gpio2_data & ~BIT(bit);
GPIO->gpio2_data = (u8)(tmp | valMask);
break;
case 3:
tmp = GPIO->gpio3_data & ~BIT(bit);
GPIO->gpio3_data = (u16)(tmp | valMask);
break;
case 4:
tmp = GPIO->gpio2_data2 & ~BIT(bit);
GPIO->gpio2_data2 = (u16)(tmp | valMask);
break;
case 5:
tmp = GPIO->gpio3_data2 & ~BIT(bit);
GPIO->gpio3_data2 = (u16)(tmp | valMask);
break;

default:
break;
}
}

static inline void gpioSetDirection(GpioPin pin, GpioDirection direction)
{
u32 bank = BANK_OF(pin);
u32 bit = BIT_OF(pin);

u32 valMask = (direction == GPIO_DIR_OUTPUT ? 1 : 0) << bit;
u32 tmp;

switch (bank) {
case 2:
tmp = GPIO->gpio2_dir & ~BIT(bit);
GPIO->gpio2_dir = (u8)(tmp | valMask);
break;
case 3:
tmp = GPIO->gpio3_dir & ~BIT(bit);
GPIO->gpio3_dir = (u16)(tmp | valMask);
break;

default:
break;
}
}

static inline void gpioConfigureInterrupt(GpioPin pin, GpioInterruptConfig cfg)
{
u32 bank = BANK_OF(pin);
u32 bit = BIT_OF(pin);

u32 valMask = (cfg == GPIO_INTCFG_RISING_EDGE ? 1 : 0) << bit;
u32 tmp;

switch (bank) {
case 2:
tmp = GPIO->gpio2_intcfg & ~BIT(bit);
GPIO->gpio2_intcfg = (u8)(tmp | valMask);
break;
case 3:
tmp = GPIO->gpio3_data & ~BIT(bit);
GPIO->gpio3_intcfg = (u16)(tmp | valMask);
break;

default:
break;
}
}

static inline void gpioSetInterruptEnabled(GpioPin pin, bool enabled)
{
u32 bank = BANK_OF(pin);
u32 bit = BIT_OF(pin);

u32 valMask = (enabled ? 1 : 0) << bit;
u32 tmp;

switch (bank) {
case 2:
tmp = GPIO->gpio2_inten & ~BIT(bit);
GPIO->gpio2_inten = (u8)(tmp | valMask);
break;
case 3:
tmp = GPIO->gpio3_inten & ~BIT(bit);
GPIO->gpio3_inten = (u16)(tmp | valMask);
break;

default:
break;
}
}

#undef GPIO_PIN
#undef BIT_OF
#undef BANK_OF
18 changes: 11 additions & 7 deletions arm9/source/i2c.c
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,10 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/

// Modified 2021 TuxSH

#include <stdbool.h>
#include <string.h>
#include "types.h"
#include "i2c.h"
#include "utils.h"
Expand Down Expand Up @@ -158,39 +161,40 @@ static bool i2cStartTransfer(I2cDevice devId, u8 regAddr, bool read, I2cRegs *co
else return false;
}

bool I2C_readRegBuf(I2cDevice devId, u8 regAddr, u8 *out, u32 size)
bool I2C_readRegBuf(I2cDevice devId, u8 regAddr, void *out, u32 size)
{
const u8 busId = i2cDevTable[devId].busId;
I2cRegs *const regs = i2cGetBusRegsBase(busId);

u8 *out8 = (u8 *)out;

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;
*out8++ = 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
*out8 = regs->REG_I2C_DATA; // Last byte

return true;
}

bool I2C_writeRegBuf(I2cDevice devId, u8 regAddr, const u8 *in, u32 size)
bool I2C_writeRegBuf(I2cDevice devId, u8 regAddr, const void *in, u32 size)
{
const u8 busId = i2cDevTable[devId].busId;
I2cRegs *const regs = i2cGetBusRegsBase(busId);
const u8 *in8 = (const u8 *)in;


if(!i2cStartTransfer(devId, regAddr, false, regs)) return false;

while(--size)
{
regs->REG_I2C_DATA = *in++;
regs->REG_I2C_DATA = *in8++;
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.
Expand All @@ -200,7 +204,7 @@ bool I2C_writeRegBuf(I2cDevice devId, u8 regAddr, const u8 *in, u32 size)
}
}

regs->REG_I2C_DATA = *in;
regs->REG_I2C_DATA = *in8;
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.
Expand Down
4 changes: 2 additions & 2 deletions arm9/source/i2c.h
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ void I2C_init(void);
*
* @return Returns true on success and false on failure.
*/
bool I2C_readRegBuf(I2cDevice devId, u8 regAddr, u8 *out, u32 size);
bool I2C_readRegBuf(I2cDevice devId, u8 regAddr, void *out, u32 size);

/**
* @brief Writes a buffer to a I2C register.
Expand All @@ -78,7 +78,7 @@ bool I2C_readRegBuf(I2cDevice devId, u8 regAddr, u8 *out, u32 size);
*
* @return Returns true on success and false on failure.
*/
bool I2C_writeRegBuf(I2cDevice devId, u8 regAddr, const u8 *in, u32 size);
bool I2C_writeRegBuf(I2cDevice devId, u8 regAddr, const void *in, u32 size);

/**
* @brief Reads a byte from a I2C register.
Expand Down
Loading

0 comments on commit bd2b012

Please sign in to comment.