Skip to content

Commit bd2b012

Browse files
committed
Fix a few MCU-related bugs, gm9 should boot properly now
- 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
1 parent be6d642 commit bd2b012

File tree

16 files changed

+497
-62
lines changed

16 files changed

+497
-62
lines changed

arm11/source/main.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -123,8 +123,8 @@ static void initScreens(u32 brightnessLevel, struct fb *fbs)
123123
for(u32 i = 0; i < 256; i++)
124124
*(vu32 *)0x10400584 = 0x10101 * i;
125125

126-
*(vu32 *)0x10202204 = 0x00000000; //unset LCD fill
127-
*(vu32 *)0x10202A04 = 0x00000000;
126+
//*(vu32 *)0x10202204 = 0x00000000; //unset LCD fill
127+
//*(vu32 *)0x10202A04 = 0x00000000;
128128
}
129129

130130
static void setupFramebuffers(struct fb *fbs)

arm9/linker.ld

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,16 +45,19 @@ SECTIONS
4545

4646
chainloader.o(.text*)
4747
i2c.o(.text*)
48+
mcu.o(.text*)
4849
arm9_exception_handlers.o(.text*)
4950

5051
*(.arm9_exception_handlers.rodata*)
5152
chainloader.o(.rodata*)
5253
i2c.o(.rodata*)
54+
mcu.o(.rodata*)
5355
arm9_exception_handlers.o(.rodata*)
5456

5557
*(.arm9_exception_handlers.data*)
5658
chainloader.o(.data*)
5759
i2c.o(.data*)
60+
mcu.o(.data*)
5861
arm9_exception_handlers.o(.data*)
5962
. = ALIGN(32);
6063
} >itcm AT>main :itcm
@@ -67,6 +70,7 @@ SECTIONS
6770
*(.arm9_exception_handlers.bss*)
6871
chainloader.o(.bss* COMMON)
6972
i2c.o(.bss* COMMON)
73+
mcu.o(.bss* COMMON)
7074
arm9_exception_handlers.o(.bss* COMMON)
7175
. = ALIGN(32);
7276
PROVIDE (__itcm_end__ = ABSOLUTE(.));

arm9/source/arm9_exception_handlers.c

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -25,8 +25,7 @@
2525
*/
2626

2727
#include "arm9_exception_handlers.h"
28-
#include "i2c.h"
29-
#include "screen.h"
28+
#include "mcu.h"
3029

3130
#define FINAL_BUFFER 0x25000000
3231

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

106-
if(ARESCREENSINITIALIZED) I2C_writeReg(I2C_DEV_MCU, 0x22, 1 << 0); //Shutdown LCD
105+
mcuPowerBacklightsOff();
107106

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

110-
I2C_writeReg(I2C_DEV_MCU, 0x20, 1 << 2); //Reboot
111-
while(true);
109+
mcuReboot();
112110
}

arm9/source/exceptions.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -200,5 +200,5 @@ void detectAndProcessExceptionDumps(void)
200200

201201
exit:
202202
memset((void *)dumpHeader, 0, dumpHeader->totalSize);
203-
mcuPowerOff();
203+
powerOff();
204204
}

arm9/source/firm.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@
3737
#include "screen.h"
3838
#include "fmt.h"
3939
#include "chainloader.h"
40+
#include "mcu.h"
4041

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

@@ -561,6 +562,7 @@ u32 patch1x2xNativeAndSafeFirm(void)
561562

562563
void launchFirm(int argc, char **argv)
563564
{
565+
mcuFinalize();
564566
prepareArm11ForFirmlaunch();
565567
chainload(argc, argv, firm);
566568
}

arm9/source/gpio.h

Lines changed: 225 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,225 @@
1+
/*
2+
* This file is part of Luma3DS
3+
* Copyright (C) 2021 Aurora Wright, TuxSH
4+
*
5+
* This program is free software: you can redistribute it and/or modify
6+
* it under the terms of the GNU General Public License as published by
7+
* the Free Software Foundation, either version 3 of the License, or
8+
* (at your option) any later version.
9+
*
10+
* This program is distributed in the hope that it will be useful,
11+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
12+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13+
* GNU General Public License for more details.
14+
*
15+
* You should have received a copy of the GNU General Public License
16+
* along with this program. If not, see <http://www.gnu.org/licenses/>.
17+
*
18+
* Additional Terms 7.b and 7.c of GPLv3 apply to this file:
19+
* * Requiring preservation of specified reasonable legal notices or
20+
* author attributions in that material or in the Appropriate Legal
21+
* Notices displayed by works containing it.
22+
* * Prohibiting misrepresentation of the origin of that material,
23+
* or requiring that modified versions of such material be marked in
24+
* reasonable ways as different from the original version.
25+
*/
26+
27+
#pragma once
28+
29+
#include "types.h"
30+
31+
typedef struct GpioRegisters {
32+
u8 gpio1_data;
33+
u8 _0x001[0x010 - 0x001];
34+
35+
u8 gpio2_data;
36+
u8 gpio2_dir;
37+
u8 gpio2_intcfg;
38+
u8 gpio2_inten;
39+
u16 gpio2_data2;
40+
u8 _0x016[0x020 - 0x016];
41+
42+
u16 gpio3_data;
43+
u16 gpio3_dir;
44+
u16 gpio3_intcfg;
45+
u16 gpio3_inten;
46+
u16 gpio3_data2;
47+
u8 _0x02a[0x100 - 0x02A];
48+
} GpioRegisters;
49+
50+
typedef enum GpioDirection {
51+
GPIO_DIR_INPUT = 0,
52+
GPIO_DIR_OUTPUT = 1,
53+
} GpioDirection;
54+
55+
typedef enum GpioInterruptConfig {
56+
GPIO_INTCFG_FALLING_EDGE = 0,
57+
GPIO_INTCFG_RISING_EDGE = 1,
58+
} GpioInterruptConfig;
59+
60+
#define GPIO_PIN(bank, idx) (((bank) << 4) | ((idx) & 0xF))
61+
#define BANK_OF(pin) ((pin) >> 4)
62+
#define BIT_OF(pin) ((pin) & 0xF)
63+
64+
typedef enum GpioPin {
65+
// GPIO1
66+
GPIO_DEBUG_BUTTON = GPIO_PIN(1, 0), // active-low
67+
GPIO_TOUCH_SCREEN = GPIO_PIN(1, 1), // active-low, 0 when the touch screen is pressed
68+
GPIO_SHELL_CLOSED = GPIO_PIN(1, 2),
69+
70+
// GPIO2
71+
GPIO_HEADPHONES_INSERTED = GPIO_PIN(2, 0),
72+
GPIO_TWL_DEPOP = GPIO_PIN(2, 1), // active-low
73+
74+
// GPIO2 (DATA2)
75+
GPIO_WIFI_MODE = GPIO_PIN(4, 0), // 0 is CTR, 1 is MP (DS WiFi)
76+
77+
// GPIO3
78+
GPIO_CSTICK_INT = GPIO_PIN(3, 0),
79+
GPIO_IRDA_INT = GPIO_PIN(3, 1), // active-low
80+
GPIO_GYRO_INT = GPIO_PIN(3, 2),
81+
GPIO_CSTICK_STOP = GPIO_PIN(3, 3), // output
82+
GPIO_IRDA_TXRC = GPIO_PIN(3, 4), // output
83+
GPIO_IRDA_RXD = GPIO_PIN(3, 5), // active-low
84+
GPIO_NFC_OUT1 = GPIO_PIN(3, 6), // output
85+
GPIO_NFC_OUT2 = GPIO_PIN(3, 7), // output
86+
GPIO_HEADPHONES_BUTTON = GPIO_PIN(3, 8), // active-low ("half-inserted")
87+
GPIO_MCU_INT = GPIO_PIN(3, 9),
88+
GPIO_NFC_INT = GPIO_PIN(3, 10),
89+
GPIO_QTM_OUT = GPIO_PIN(3, 11), // output
90+
91+
// GPIO3 (DATA2)
92+
GPIO_WIFI_ENABLED = GPIO_PIN(5, 0),
93+
} GpioPin;
94+
95+
static volatile GpioRegisters *const GPIO = (volatile GpioRegisters *)0x10147000;
96+
97+
static inline bool gpioRead(GpioPin pin)
98+
{
99+
u32 bank = BANK_OF(pin);
100+
u32 bit = BIT_OF(pin);
101+
102+
switch (bank) {
103+
case 1:
104+
return (GPIO->gpio1_data & BIT(bit)) != 0;
105+
case 2:
106+
return (GPIO->gpio2_data & BIT(bit)) != 0;
107+
case 3:
108+
return (GPIO->gpio3_data & BIT(bit)) != 0;
109+
case 4:
110+
return (GPIO->gpio2_data2 & BIT(bit)) != 0;
111+
case 5:
112+
return (GPIO->gpio3_data2 & BIT(bit)) != 0;
113+
114+
default:
115+
return false;
116+
}
117+
}
118+
119+
static inline void gpioWrite(GpioPin pin, bool val)
120+
{
121+
u32 bank = BANK_OF(pin);
122+
u32 bit = BIT_OF(pin);
123+
124+
u32 valMask = (val ? 1 : 0) << bit;
125+
u32 tmp;
126+
127+
switch (bank) {
128+
case 1:
129+
tmp = GPIO->gpio1_data & ~BIT(bit);
130+
GPIO->gpio1_data = (u8)(tmp | valMask);
131+
break;
132+
case 2:
133+
tmp = GPIO->gpio2_data & ~BIT(bit);
134+
GPIO->gpio2_data = (u8)(tmp | valMask);
135+
break;
136+
case 3:
137+
tmp = GPIO->gpio3_data & ~BIT(bit);
138+
GPIO->gpio3_data = (u16)(tmp | valMask);
139+
break;
140+
case 4:
141+
tmp = GPIO->gpio2_data2 & ~BIT(bit);
142+
GPIO->gpio2_data2 = (u16)(tmp | valMask);
143+
break;
144+
case 5:
145+
tmp = GPIO->gpio3_data2 & ~BIT(bit);
146+
GPIO->gpio3_data2 = (u16)(tmp | valMask);
147+
break;
148+
149+
default:
150+
break;
151+
}
152+
}
153+
154+
static inline void gpioSetDirection(GpioPin pin, GpioDirection direction)
155+
{
156+
u32 bank = BANK_OF(pin);
157+
u32 bit = BIT_OF(pin);
158+
159+
u32 valMask = (direction == GPIO_DIR_OUTPUT ? 1 : 0) << bit;
160+
u32 tmp;
161+
162+
switch (bank) {
163+
case 2:
164+
tmp = GPIO->gpio2_dir & ~BIT(bit);
165+
GPIO->gpio2_dir = (u8)(tmp | valMask);
166+
break;
167+
case 3:
168+
tmp = GPIO->gpio3_dir & ~BIT(bit);
169+
GPIO->gpio3_dir = (u16)(tmp | valMask);
170+
break;
171+
172+
default:
173+
break;
174+
}
175+
}
176+
177+
static inline void gpioConfigureInterrupt(GpioPin pin, GpioInterruptConfig cfg)
178+
{
179+
u32 bank = BANK_OF(pin);
180+
u32 bit = BIT_OF(pin);
181+
182+
u32 valMask = (cfg == GPIO_INTCFG_RISING_EDGE ? 1 : 0) << bit;
183+
u32 tmp;
184+
185+
switch (bank) {
186+
case 2:
187+
tmp = GPIO->gpio2_intcfg & ~BIT(bit);
188+
GPIO->gpio2_intcfg = (u8)(tmp | valMask);
189+
break;
190+
case 3:
191+
tmp = GPIO->gpio3_data & ~BIT(bit);
192+
GPIO->gpio3_intcfg = (u16)(tmp | valMask);
193+
break;
194+
195+
default:
196+
break;
197+
}
198+
}
199+
200+
static inline void gpioSetInterruptEnabled(GpioPin pin, bool enabled)
201+
{
202+
u32 bank = BANK_OF(pin);
203+
u32 bit = BIT_OF(pin);
204+
205+
u32 valMask = (enabled ? 1 : 0) << bit;
206+
u32 tmp;
207+
208+
switch (bank) {
209+
case 2:
210+
tmp = GPIO->gpio2_inten & ~BIT(bit);
211+
GPIO->gpio2_inten = (u8)(tmp | valMask);
212+
break;
213+
case 3:
214+
tmp = GPIO->gpio3_inten & ~BIT(bit);
215+
GPIO->gpio3_inten = (u16)(tmp | valMask);
216+
break;
217+
218+
default:
219+
break;
220+
}
221+
}
222+
223+
#undef GPIO_PIN
224+
#undef BIT_OF
225+
#undef BANK_OF

arm9/source/i2c.c

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,10 @@
1616
* along with this program. If not, see <http://www.gnu.org/licenses/>.
1717
*/
1818

19+
// Modified 2021 TuxSH
20+
1921
#include <stdbool.h>
22+
#include <string.h>
2023
#include "types.h"
2124
#include "i2c.h"
2225
#include "utils.h"
@@ -158,39 +161,40 @@ static bool i2cStartTransfer(I2cDevice devId, u8 regAddr, bool read, I2cRegs *co
158161
else return false;
159162
}
160163

161-
bool I2C_readRegBuf(I2cDevice devId, u8 regAddr, u8 *out, u32 size)
164+
bool I2C_readRegBuf(I2cDevice devId, u8 regAddr, void *out, u32 size)
162165
{
163166
const u8 busId = i2cDevTable[devId].busId;
164167
I2cRegs *const regs = i2cGetBusRegsBase(busId);
165-
168+
u8 *out8 = (u8 *)out;
166169

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

169172
while(--size)
170173
{
171174
regs->REG_I2C_CNT = I2C_ENABLE | I2C_IRQ_ENABLE | I2C_DIRE_READ | I2C_ACK;
172175
i2cWaitBusy(regs);
173-
*out++ = regs->REG_I2C_DATA;
176+
*out8++ = regs->REG_I2C_DATA;
174177
}
175178

176179
regs->REG_I2C_CNT = I2C_ENABLE | I2C_IRQ_ENABLE | I2C_DIRE_READ | I2C_STOP;
177180
i2cWaitBusy(regs);
178-
*out = regs->REG_I2C_DATA; // Last byte
181+
*out8 = regs->REG_I2C_DATA; // Last byte
179182

180183
return true;
181184
}
182185

183-
bool I2C_writeRegBuf(I2cDevice devId, u8 regAddr, const u8 *in, u32 size)
186+
bool I2C_writeRegBuf(I2cDevice devId, u8 regAddr, const void *in, u32 size)
184187
{
185188
const u8 busId = i2cDevTable[devId].busId;
186189
I2cRegs *const regs = i2cGetBusRegsBase(busId);
190+
const u8 *in8 = (const u8 *)in;
187191

188192

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

191195
while(--size)
192196
{
193-
regs->REG_I2C_DATA = *in++;
197+
regs->REG_I2C_DATA = *in8++;
194198
regs->REG_I2C_CNT = I2C_ENABLE | I2C_IRQ_ENABLE | I2C_DIRE_WRITE;
195199
i2cWaitBusy(regs);
196200
if(!I2C_GET_ACK(regs->REG_I2C_CNT)) // If ack flag is 0 it failed.
@@ -200,7 +204,7 @@ bool I2C_writeRegBuf(I2cDevice devId, u8 regAddr, const u8 *in, u32 size)
200204
}
201205
}
202206

203-
regs->REG_I2C_DATA = *in;
207+
regs->REG_I2C_DATA = *in8;
204208
regs->REG_I2C_CNT = I2C_ENABLE | I2C_IRQ_ENABLE | I2C_DIRE_WRITE | I2C_STOP;
205209
i2cWaitBusy(regs);
206210
if(!I2C_GET_ACK(regs->REG_I2C_CNT)) // If ack flag is 0 it failed.

arm9/source/i2c.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,7 @@ void I2C_init(void);
6666
*
6767
* @return Returns true on success and false on failure.
6868
*/
69-
bool I2C_readRegBuf(I2cDevice devId, u8 regAddr, u8 *out, u32 size);
69+
bool I2C_readRegBuf(I2cDevice devId, u8 regAddr, void *out, u32 size);
7070

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

8383
/**
8484
* @brief Reads a byte from a I2C register.

0 commit comments

Comments
 (0)