- implemented MCU stuff and its interrupts, thanks @profi200 for the info

- moved brightness control to the ARM11
- moved HID updating to the ARM11
- moved screen init from ARM9 to the ARM11, always performed unconditionally
- removed unnecessary SCREENINIT and SET_BRIGHTNESS pxi commands

and other stuff I probably forgot about
This commit is contained in:
Wolfvak 2019-04-17 11:58:54 -03:00 committed by d0k3
parent 5e56cd2f77
commit f5a877d00b
18 changed files with 321 additions and 140 deletions

View File

@ -3,7 +3,7 @@
#include <arm.h>
#define STACK_SZ (8192)
#define STACK_SZ (16384)
.global __boot
__boot:

34
arm11/source/hw/gpio.h Executable file
View File

@ -0,0 +1,34 @@
/*
* 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/>.
*/
// Modified to make all routines inlined, since they're so simple anyway...
#pragma once
#include <types.h>
#define REG_GPIO ((vu16*)(0x10100000 + 0x47000))
static inline void GPIO_setBit(u16 reg, u8 bitNum)
{
REG_GPIO[reg] |= 1u<<bitNum;
}
static inline void GPIO_clearBit(u16 reg, u8 bitNum)
{
REG_GPIO[reg] &= ~(1u<<bitNum);
}

View File

@ -1,16 +1,21 @@
#pragma once
#include <types.h>
#define VBLANK_INTERRUPT (0x2A)
void LCD_SetBrightness(u8 brightness);
void LCD_Deinitialize(void);
void GPU_PSCFill(u32 start, u32 end, u32 fv);
#define PDC_RGBA8 (0<<0)
#define PDC_RGB24 (1<<0)
#define PDC_RGB565 (2<<0)
#define PDC_RGB5A1 (3<<0)
#define PDC_RGBA4 (4<<0)
enum {
PDC_RGBA8 = 0,
PDC_RGB24 = 1,
PDC_RGB565 = 2,
PDC_RGB5A1 = 3,
PDC_RGBA4 = 4,
};
void GPU_SetFramebufferMode(u32 screen, u8 mode);
void GPU_SetFramebuffers(const u32 *framebuffers);
void GPU_Init(void);

View File

@ -0,0 +1,87 @@
#include <hid_map.h>
#include <types.h>
#include <arm.h>
#include "hw/gpio.h"
#include "hw/gpulcd.h"
#include "hw/i2c.h"
#include "hw/mcu.h"
enum {
PWR_BTN = 0,
PWR_HOLD = 1,
HOME_BTN = 2,
HOME_HOLD = 3,
WIFI_SWITCH = 4,
SHELL_CLOSE = 5,
SHELL_OPEN = 6,
VOL_SLIDER = 22,
};
static u8 cached_volume_slider = 0;
static u32 spec_hid = 0;
static void MCU_UpdateVolumeSlider(void)
{
cached_volume_slider = MCU_ReadReg(0x09);
}
void MCU_HandleInterrupts(u32 __attribute__((unused)) irqn)
{
u32 ints;
// Reading the pending mask automagically acknowledges
// all the interrupts, so we must be sure to process all
// of them in one go, possibly keep reading from the
// register until it returns all zeroes
MCU_ReadRegBuf(0x10, (u8*)&ints, sizeof(ints));
while(ints != 0) {
u32 mcu_int_id = 31 - __builtin_clz(ints);
switch(mcu_int_id) {
case PWR_BTN:
case PWR_HOLD:
spec_hid |= BUTTON_POWER;
break;
case HOME_BTN:
case HOME_HOLD:
spec_hid |= BUTTON_HOME;
break;
case WIFI_SWITCH:
spec_hid |= BUTTON_WIFI;
break;
case VOL_SLIDER:
MCU_UpdateVolumeSlider();
break;
default:
break;
}
ints &= ~BIT(mcu_int_id);
}
}
void MCU_Init(void)
{
u32 mask = 0xFFBF0000 | BIT(11);
I2C_writeRegBuf(3, 0x18, (const u8*)&mask, sizeof(mask));
MCU_UpdateVolumeSlider();
GPIO_setBit(19, 9); // enables MCU interrupts?
}
u8 MCU_GetVolumeSlider(void)
{
return cached_volume_slider;
}
u32 MCU_GetSpecialHID(void)
{
u32 ret = spec_hid;
spec_hid = 0;
return ret;
}

View File

@ -0,0 +1,36 @@
#pragma once
#include <types.h>
#include "hw/i2c.h"
#define MCU_INTERRUPT (0x71)
#define I2C_MCU_DEVICE (3)
void MCU_HandleInterrupts(u32 irqn);
void MCU_Init(void);
u8 MCU_GetVolumeSlider(void);
u32 MCU_GetSpecialHID(void);
static inline u8 MCU_ReadReg(u8 addr)
{
u8 val;
I2C_readRegBuf(I2C_MCU_DEVICE, addr, &val, 1);
return val;
}
static inline bool MCU_ReadRegBuf(u8 addr, u8 *buf, u8 size)
{
return I2C_readRegBuf(I2C_MCU_DEVICE, addr, buf, size);
}
static inline bool MCU_WriteReg(u8 addr, u8 val)
{
return I2C_writeRegBuf(I2C_MCU_DEVICE, addr, &val, 1);
}
static inline bool MCU_WriteRegBuf(u8 addr, const u8 *buf, u8 size)
{
return I2C_writeRegBuf(I2C_MCU_DEVICE, addr, buf, size);
}

View File

@ -1,9 +1,12 @@
#include <hid_map.h>
#include <common.h>
#include <types.h>
#include <vram.h>
#include <arm.h>
#include <pxi.h>
#include "arm/gic.h"
#include "hw/gpulcd.h"
#include "hw/i2c.h"
#include "hw/mcu.h"
@ -12,6 +15,34 @@
static bool legacy = false;
#define REG_HID (~(*(vu16*)(0x10146000)) & BUTTON_ANY)
static const u8 brightness_lvls[] = {
0x10, 0x17, 0x1E, 0x25,
0x2C, 0x34, 0x3C, 0x44,
0x4D, 0x56, 0x60, 0x6B,
0x79, 0x8C, 0xA7, 0xD2
};
static int prev_bright_lvl = -1;
static vu32 global_hid_state = 0;
void VBlank_Handler(u32 __attribute__((unused)) irqn)
{
int cur_bright_lvl = (MCU_GetVolumeSlider() >> 2);
cur_bright_lvl %= countof(brightness_lvls);
if (cur_bright_lvl != prev_bright_lvl) {
prev_bright_lvl = cur_bright_lvl;
LCD_SetBrightness(brightness_lvls[cur_bright_lvl]);
}
// the state should probably be stored on its own
// setion without caching enabled, since it must
// be readable by the ARM9 at all times anyway
global_hid_state = REG_HID | MCU_GetSpecialHID();
ARM_WbDC_Range((void*)&global_hid_state, 4);
ARM_DMB();
}
void PXI_RX_Handler(u32 __attribute__((unused)) irqn)
{
u32 ret, msg, cmd, argc, args[PXI_MAX_ARGS];
@ -38,29 +69,8 @@ void PXI_RX_Handler(u32 __attribute__((unused)) irqn)
case PXI_GET_SHMEM:
{
//ret = (u32)SHMEM_GetGlobalPointer();
ret = 0xFFFFFFFF;
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});
GPU_SetFramebufferMode(0, PDC_RGB24);
GPU_SetFramebufferMode(1, PDC_RGB24);
ret = 0;
break;
}
case PXI_BRIGHTNESS:
{
LCD_SetBrightness(args[0]);
ret = args[0];
ret = (u32)&global_hid_state;
//ret = 0xFFFFFFFF;
break;
}
@ -68,14 +78,14 @@ void PXI_RX_Handler(u32 __attribute__((unused)) irqn)
{
ret = I2C_readRegBuf(args[0], args[1], (u8*)args[2], args[3]);
ARM_WbDC_Range((void*)args[2], args[3]);
ARM_DSB();
ARM_DMB();
break;
}
case PXI_I2C_WRITE:
{
ARM_InvDC_Range((void*)args[2], args[3]);
ARM_DSB();
ARM_DMB();
ret = I2C_writeRegBuf(args[0], args[1], (u8*)args[2], args[3]);
break;
}
@ -96,12 +106,17 @@ void PXI_RX_Handler(u32 __attribute__((unused)) irqn)
}
PXI_Send(ret);
return;
}
void MainLoop(void)
void __attribute__((noreturn)) MainLoop(void)
{
GIC_Enable(IRQ_PXI_RX, BIT(0), GIC_HIGHEST_PRIO, PXI_RX_Handler);
// enable MCU interrupts
GIC_Enable(MCU_INTERRUPT, BIT(0), GIC_HIGHEST_PRIO, MCU_HandleInterrupts);
// enable PXI RX interrupt
GIC_Enable(PXI_RX_INTERRUPT, BIT(0), GIC_HIGHEST_PRIO, PXI_RX_Handler);
GIC_Enable(VBLANK_INTERRUPT, BIT(0), GIC_HIGHEST_PRIO + 1, VBlank_Handler);
// ARM9 won't try anything funny until this point
PXI_Barrier(ARM11_READY_BARRIER);

View File

@ -2,7 +2,7 @@
#include <types.h>
#define DEF_SECT_(n) extern u32 __##n##_pa, __##n##_va, __##n##_len; static const u32 n##_pa = (u32)&__##n##_pa, n##_va = (u32)&__##n##_va;
#define DEF_SECT_(n) extern u32 __##n##_pa, __##n##_va, __##n##_len;
DEF_SECT_(vector)
DEF_SECT_(text)
DEF_SECT_(data)
@ -10,8 +10,8 @@ DEF_SECT_(rodata)
DEF_SECT_(bss)
#undef DEF_SECT_
#define SECTION_VA(n) n##_va
#define SECTION_PA(n) n##_pa
#define SECTION_VA(n) ((u32)&__##n##_va)
#define SECTION_PA(n) ((u32)&__##n##_pa)
#define SECTION_LEN(n) ((u32)&__##n##_len)
#define SECTION_TRI(n) SECTION_VA(n), SECTION_PA(n), SECTION_LEN(n)

View File

@ -1,4 +1,5 @@
#include <types.h>
#include <vram.h>
#include <arm.h>
#include <pxi.h>
@ -6,7 +7,9 @@
#include "arm/scu.h"
#include "arm/mmu.h"
#include "hw/gpulcd.h"
#include "hw/i2c.h"
#include "hw/mcu.h"
#include "system/sections.h"
@ -80,7 +83,17 @@ void SYS_CoreZeroInit(void)
// Initialize peripherals
PXI_Reset();
I2C_init();
//MCU_init();
MCU_Init();
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);
MCU_WriteReg(0x22, 0x2A);
}
void SYS_CoreInit(void)
@ -109,7 +122,7 @@ void SYS_CoreZeroShutdown(void)
GIC_GlobalReset();
}
void SYS_CoreShutdown(void)
void __attribute__((noreturn)) SYS_CoreShutdown(void)
{
u32 core = ARM_CoreID();
@ -133,4 +146,5 @@ void SYS_CoreShutdown(void)
// (waits for IPI + branches to word @ 0x1FFFFFDC)
((void (*)(void))LEGACY_BOOT_ROUTINE_SMP)();
}
__builtin_unreachable();
}

View File

@ -17,4 +17,4 @@ void SYS_CoreZeroInit(void);
void SYS_CoreInit(void);
void SYS_CoreZeroShutdown(void);
void SYS_CoreShutdown(void);
void __attribute__((noreturn)) SYS_CoreShutdown(void);

View File

@ -1,60 +1,65 @@
#include "hid.h"
#include "i2c.h"
#include "timer.h"
#include "power.h" // for brightness slider
#include "screenshot.h" // for screenshots
#include "arm.h"
u32 HID_ReadState(void)
{ // this should probably be abstracted away in something like "SHMEM_GetHID"
return *(u32*)ARM_GetTID();
}
u32 InputWait(u32 timeout_sec) {
static u64 delay = 0;
u32 pad_state_old = HID_STATE;
u32 cart_state_old = CART_STATE;
u32 sd_state_old = SD_STATE;
u64 timer = timer_start();
u64 timer_mcu = timer;
delay = (delay) ? 72 : 128;
while (true) {
u32 pad_state = HID_STATE;
if (timeout_sec && (timer_sec(timer) >= timeout_sec))
return TIMEOUT_HID; // HID timeout
if (!(pad_state & BUTTON_ANY)) { // no buttons pressed
u32 cart_state = CART_STATE;
if (cart_state != cart_state_old)
return cart_state ? CART_INSERT : CART_EJECT;
u32 sd_state = SD_STATE;
if (sd_state != sd_state_old)
return sd_state ? SD_INSERT : SD_EJECT;
u8 special_key;
if ((timer_msec(timer_mcu) >= 64) && (I2C_readRegBuf(I2C_DEV_MCU, 0x10, &special_key, 1))) {
CheckBrightness();
if (special_key == 0x01)
return pad_state | BUTTON_POWER;
else if (special_key == 0x04)
return pad_state | BUTTON_HOME;
timer_mcu = timer_start();
}
pad_state_old = pad_state;
u32 oldpad = HID_ReadState();
u32 oldcart = CART_STATE;
u32 oldsd = SD_STATE;
delay = delay ? 72 : 128;
do {
u32 newpad = HID_ReadState();
if (!newpad) { // no buttons pressed, check for I/O changes instead
u32 state = CART_STATE;
if (state != oldcart)
return state ? CART_INSERT : CART_EJECT;
state = SD_STATE;
if (state != oldsd)
return state ? SD_INSERT : SD_EJECT;
oldpad = 0;
delay = 0;
continue;
}
if ((pad_state == pad_state_old) &&
(!(pad_state & BUTTON_ARROW) ||
// special case for dpad keys
// if any of those are held, don't wait for key changes
// but do insert a small latency to make
// sure any menus don't go flying off
if ((newpad == oldpad) &&
(!(newpad & BUTTON_ARROW) ||
(delay && (timer_msec(timer) < delay))))
continue;
// make sure the key is pressed
u32 t_pressed = 0;
for(; (t_pressed < 0x13000) && (pad_state == HID_STATE); t_pressed++);
while((t_pressed++ < 0x13000) && (newpad == HID_ReadState()));
if (t_pressed >= 0x13000) {
if ((pad_state & BUTTON_ANY) == (BUTTON_R1 | BUTTON_L1))
if ((newpad & BUTTON_ANY) == (BUTTON_R1 | BUTTON_L1))
CreateScreenshot(); // screenshot handling
return pad_state;
return newpad;
}
}
} while (!timeout_sec || (timeout_sec && (timer_sec(timer) < timeout_sec)));
return TIMEOUT_HID;
}
bool CheckButton(u32 button) {
u32 t_pressed = 0;
for(; (t_pressed < 0x13000) && ((HID_STATE & button) == button); t_pressed++);
return (t_pressed >= 0x13000);
return (HID_ReadState() & button) == button;
}
void ButtonToString(u32 button, char* str) {

View File

@ -2,36 +2,16 @@
#include "common.h"
#include "hid_map.h"
// see: http://3dbrew.org/wiki/CONFIG9_Registers
// see: http://3dbrew.org/wiki/EMMC_Registers
#define HID_STATE (~(*(volatile u32*)0x10146000) & BUTTON_ANY)
u32 HID_ReadState(void);
#define CART_STATE (~(*(volatile u8*)0x10000010) & 0x1)
#define SD_STATE ((*(volatile u16*)0x1000601C) & (0x1<<5))
#define BUTTON_A ((u32)1 << 0)
#define BUTTON_B ((u32)1 << 1)
#define BUTTON_SELECT ((u32)1 << 2)
#define BUTTON_START ((u32)1 << 3)
#define BUTTON_RIGHT ((u32)1 << 4)
#define BUTTON_LEFT ((u32)1 << 5)
#define BUTTON_UP ((u32)1 << 6)
#define BUTTON_DOWN ((u32)1 << 7)
#define BUTTON_R1 ((u32)1 << 8)
#define BUTTON_L1 ((u32)1 << 9)
#define BUTTON_X ((u32)1 << 10)
#define BUTTON_Y ((u32)1 << 11)
#define BUTTON_ANY 0x00000FFF
#define BUTTON_ARROW (BUTTON_RIGHT|BUTTON_LEFT|BUTTON_UP|BUTTON_DOWN)
// special buttons / cart / sd
#define BUTTON_POWER ((u32)1 << 12)
#define BUTTON_HOME ((u32)1 << 13)
#define CART_INSERT ((u32)1 << 14)
#define CART_EJECT ((u32)1 << 15)
#define SD_INSERT ((u32)1 << 16)
#define SD_EJECT ((u32)1 << 17)
#define TIMEOUT_HID ((u32)1 << 31)
// strings for button conversion
#define BUTTON_STRINGS "A", "B", "SELECT", "START", "RIGHT", "LEFT", "UP", "DOWN", "R", "L", "X", "Y"

View File

@ -3,24 +3,6 @@
#include "i2c.h"
#include "pxi.h"
static const u8 br_settings[] = {0x10, 0x17, 0x1E, 0x25, 0x2C, 0x34, 0x3C, 0x44, 0x4D, 0x56, 0x60, 0x6B, 0x79, 0x8C, 0xA7, 0xD2};
static int prev_brightness = -1;
void CheckBrightness() {
u8 curSlider;
#ifndef FIXED_BRIGHTNESS
I2C_readRegBuf(I2C_DEV_MCU, 0x09, &curSlider, 1);
// Volume Slider value is always between 0x00 and 0x3F
curSlider >>= 2;
#else
curSlider = FIXED_BRIGHTNESS % sizeof(br_settings);
#endif
if (curSlider != prev_brightness) {
PXI_DoCMD(PXI_BRIGHTNESS, (u32[]){br_settings[curSlider]}, 1);
prev_brightness = curSlider;
}
return;
}
u32 GetBatteryPercent() {
u8 battery = 0;
I2C_readRegBuf(I2C_DEV_MCU, 0x0B, &battery, 1);

View File

@ -2,7 +2,6 @@
#include "common.h"
void CheckBrightness();
u32 GetBatteryPercent();
bool IsCharging();
void Reboot();

View File

@ -1060,6 +1060,5 @@ bool ShowProgress(u64 current, u64 total, const char* opstr)
last_prog_width = prog_width;
CheckBrightness();
return !CheckButton(BUTTON_B);
}

View File

@ -2101,7 +2101,7 @@ u32 GodMode(int entrypoint) {
// bootmenu handler
if (bootmenu) {
bootloader = false;
while (HID_STATE); // wait until no buttons are pressed
while (HID_ReadState()); // wait until no buttons are pressed
while (!bootloader && !godmode9) {
const char* optionstr[6] = { "Resume GodMode9", "Resume bootloader", "Select payload...", "Select script...",
"Poweroff system", "Reboot system" };

View File

@ -4,7 +4,7 @@
#include "pxi.h"
#include "i2c.h"
#include "vram.h"
#include "arm.h"
void main(int argc, char** argv, int entrypoint)
{
@ -17,8 +17,9 @@ void main(int argc, char** argv, int entrypoint)
// ARM11 says it's ready
PXI_Barrier(ARM11_READY_BARRIER);
PXI_DoCMD(PXI_SCREENINIT, NULL, 0);
I2C_writeReg(I2C_DEV_MCU, 0x22, 0x2A);
// A pointer to the shared memory region is
// stored in the thread ID register in the ARM9
ARM_SetTID(PXI_DoCMD(PXI_GET_SHMEM, NULL, 0));
#ifdef SCRIPT_RUNNER
// Run the script runner

27
common/hid_map.h Executable file
View File

@ -0,0 +1,27 @@
#pragma once
#define BUTTON_A ((u32)1 << 0)
#define BUTTON_B ((u32)1 << 1)
#define BUTTON_SELECT ((u32)1 << 2)
#define BUTTON_START ((u32)1 << 3)
#define BUTTON_RIGHT ((u32)1 << 4)
#define BUTTON_LEFT ((u32)1 << 5)
#define BUTTON_UP ((u32)1 << 6)
#define BUTTON_DOWN ((u32)1 << 7)
#define BUTTON_R1 ((u32)1 << 8)
#define BUTTON_L1 ((u32)1 << 9)
#define BUTTON_X ((u32)1 << 10)
#define BUTTON_Y ((u32)1 << 11)
#define BUTTON_ANY 0x00000FFF
#define BUTTON_ARROW (BUTTON_RIGHT|BUTTON_LEFT|BUTTON_UP|BUTTON_DOWN)
// special buttons / cart / sd
#define BUTTON_POWER ((u32)1 << 12)
#define BUTTON_HOME ((u32)1 << 13)
#define BUTTON_WIFI ((u32)1 << 14)
#define CART_INSERT ((u32)1 << 15)
#define CART_EJECT ((u32)1 << 16)
#define SD_INSERT ((u32)1 << 17)
#define SD_EJECT ((u32)1 << 18)
#define TIMEOUT_HID ((u32)1 << 31)

View File

@ -7,27 +7,25 @@
#include <types.h>
#ifdef ARM9
#define PXI_BASE (0x10008000)
#define IRQ_PXI_RX (14)
#define PXI_BASE (0x10008000)
#define PXI_RX_INTERRUPT (14)
#else
#define PXI_BASE (0x10163000)
#define IRQ_PXI_RX (83)
#define PXI_BASE (0x10163000)
#define PXI_RX_INTERRUPT (83)
#endif
enum {
PXI_LEGACY_MODE = 0,
PXI_GET_SHMEM,
PXI_SCREENINIT,
PXI_BRIGHTNESS,
PXI_I2C_READ,
PXI_I2C_WRITE,
};
/*
* These should be pseudo-random numbers
* and shouldnt be similar to those
* used by any other software
* These should be somewhat "unusual"
* IDs and shouldnt be similar to
* those used by any other software
*/
enum {
ARM11_READY_BARRIER = 19,
@ -52,7 +50,6 @@ enum {
#define PXI_CNT_RECV_FIFO_EMPTY (BIT(8))
#define PXI_CNT_RECV_FIFO_FULL (BIT(9))
#define PXI_CNT_RECV_FIFO_AVAIL_IRQ (BIT(10))
#define PXI_CNT_ERROR_ACK (BIT(14))
#define PXI_CNT_ENABLE_FIFO (BIT(15))
static inline void PXI_SetRemote(u8 msg)
@ -83,10 +80,10 @@ static inline void PXI_Reset(void)
PXI_SetRemote(0xFF);
}
static inline void PXI_Barrier(u8 bar)
static inline void PXI_Barrier(u8 barrier_id)
{
PXI_SetRemote(bar);
PXI_WaitRemote(bar);
PXI_SetRemote(barrier_id);
PXI_WaitRemote(barrier_id);
}
static inline void PXI_Send(u32 w)