Added brightness adjustment through the volume slider, made the ARM11 finally do something rather than sit and wait for the entrypoint

This commit is contained in:
Wolfvak 2017-08-08 09:40:09 -03:00
parent ed257e9216
commit b56ca0e8b8
16 changed files with 416 additions and 55 deletions

View File

@ -23,7 +23,7 @@ endif
BUILD := build
SOURCES := source source/common source/filesys source/crypto source/fatfs source/nand source/virtual source/game source/gamecart source/quicklz
DATA := data
INCLUDES := source source/common source/font source/filesys source/crypto source/fatfs source/nand source/virtual source/game source/gamecart source/quicklz
INCLUDES := common source source/common source/font source/filesys source/crypto source/fatfs source/nand source/virtual source/game source/gamecart source/quicklz
#---------------------------------------------------------------------------------
# options for code generation

68
common/cpu.h Normal file
View File

@ -0,0 +1,68 @@
/*
Written by Wolfvak, specially sublicensed under the GPLv2
Read LICENSE for more details
*/
#pragma once
#include <types.h>
#define asm __asm volatile
static inline u32 CPU_ReadCPSR(void)
{
u32 cpsr;
asm("mrs %0, cpsr\n\t":"=r"(cpsr));
return cpsr;
}
static inline void CPU_WriteCPSR_c(u32 cpsr)
{
asm("msr cpsr_c, %0\n\t"::"r"(cpsr));
return;
}
static inline u32 CPU_ReadCR(void)
{
u32 cr;
asm("mrc p15, 0, %0, c1, c0, 0\n\t":"=r"(cr));
return cr;
}
static inline void CPU_WriteCR(u32 cr)
{
asm("mcr p15, 0, %0, c1, c0, 0\n\t"::"r"(cr));
return;
}
static inline void CPU_DisableIRQ(void)
{
#ifdef ARM9
CPU_WriteCPSR_c(CPU_ReadCPSR() | (0xC0));
#else
asm("cpsid if\n\t");
#endif
return;
}
static inline void CPU_EnableIRQ(void)
{
#ifdef ARM9
CPU_WriteCPSR_c(CPU_ReadCPSR() & ~(0xC0));
#else
asm("cpsie if\n\t");
#endif
return;
}
static inline void CPU_EnterCritical(u32 *ss)
{
*ss = CPU_ReadCPSR();
CPU_DisableIRQ();
return;
}
static inline void CPU_LeaveCritical(u32 *ss)
{
CPU_WriteCPSR_c(*ss);
return;
}

101
common/pxi.h Normal file
View File

@ -0,0 +1,101 @@
/*
Written by Wolfvak, specially sublicensed under the GPLv2
Read LICENSE for more details
*/
#pragma once
#include <types.h>
#ifdef ARM9
#define PXI_BASE (0x10008000)
#define IRQ_PXI_SYNC (12)
#else
#define PXI_BASE (0x10163000)
#define IRQ_PXI_SYNC (80)
#endif
enum {
PXI_NOCMD = 0,
PXI_SETBRIGHTNESS = 1
};
#define PXI_SYNC_RECV ((volatile uint8_t*)(PXI_BASE + 0x00))
#define PXI_SYNC_SEND ((volatile uint8_t*)(PXI_BASE + 0x01))
#define PXI_SYNC_IRQ ((volatile uint8_t*)(PXI_BASE + 0x03))
#define PXI_CNT ((volatile uint16_t*)(PXI_BASE + 0x04))
#define PXI_SEND ((volatile uint32_t*)(PXI_BASE + 0x08))
#define PXI_RECV ((volatile uint32_t*)(PXI_BASE + 0x0C))
#define PXI_CNT_SEND_FIFO_EMPTY (1<<0)
#define PXI_CNT_SEND_FIFO_FULL (1<<1)
#define PXI_CNT_SEND_FIFO_EMPTY_IRQ (1<<2)
#define PXI_CNT_SEND_FIFO_FLUSH (1<<3)
#define PXI_CNT_RECV_FIFO_EMPTY (1<<8)
#define PXI_CNT_RECV_FIFO_FULL (1<<9)
#define PXI_CNT_RECV_FIFO_NEMPTY_IRQ (1<<10)
#define PXI_CNT_ERROR_ACK (1<<14)
#define PXI_CNT_ENABLE_FIFO (1<<15)
#define PXI_SYNC_TRIGGER_MPCORE (1<<5)
#define PXI_SYNC_TRIGGER_OLDARM (1<<6)
#define PXI_SYNC_ENABLE_IRQ (1<<7)
static inline void PXI_SetRemote(u8 msg)
{
*PXI_SYNC_SEND = msg;
}
static inline u8 PXI_GetRemote(void)
{
return *PXI_SYNC_RECV;
}
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_Wait(void)
{
while(PXI_GetRemote() != PXI_NOCMD);
}
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 inline void PXI_Reset(void)
{
*PXI_SYNC_SEND = 0;
*PXI_SYNC_IRQ = 0;
*PXI_CNT = PXI_CNT_SEND_FIFO_FLUSH | PXI_CNT_ENABLE_FIFO;
}
static inline void PXI_Send(u32 w)
{
while(*PXI_CNT & PXI_CNT_SEND_FIFO_FULL);
do {
*PXI_SEND = w;
} while(*PXI_CNT & PXI_CNT_ERROR_ACK);
return;
}
static inline u32 PXI_Recv(void)
{
u32 ret;
while(*PXI_CNT & PXI_CNT_RECV_FIFO_EMPTY);
do {
ret = *PXI_RECV;
} while(*PXI_CNT & PXI_CNT_ERROR_ACK);
return ret;
}

31
common/types.h Normal file
View File

@ -0,0 +1,31 @@
#pragma once
#ifndef ARM9
#ifndef ARM11
#error "Unknown processor"
#endif
#endif
#include <stdint.h>
#define BIT(x) (1<<(x))
typedef uint8_t u8;
typedef uint16_t u16;
typedef uint32_t u32;
typedef uint64_t u64;
typedef int64_t s8;
typedef int64_t s16;
typedef int64_t s32;
typedef int64_t s64;
typedef volatile u8 vu8;
typedef volatile u16 vu16;
typedef volatile u32 vu32;
typedef volatile u64 vu64;
typedef volatile s8 vs8;
typedef volatile s16 vs16;
typedef volatile s32 vs32;
typedef volatile s64 vs64;

View File

@ -12,9 +12,11 @@ dir_source := source
dir_build := build
dir_out := ../$(dir_build)
ASFLAGS := -mcpu=mpcore -mfloat-abi=hard
CFLAGS := -Wall -Wextra -MMD -MP -mthumb -mthumb-interwork $(ASFLAGS) -fno-builtin -std=c11 -Wno-main -O2 -flto -ffast-math
LDFLAGS := -nostdlib
ASFLAGS := -mcpu=mpcore -mfloat-abi=soft
CFLAGS := -DARM11 -Wall -Wextra -MMD -MP -marm -mno-thumb-interwork \
$(ASFLAGS) -fno-builtin -std=c11 -Wno-main -O2 -flto -ffast-math \
-I$(dir_source) -I../common
LDFLAGS := -nostdlib -nostartfiles
objects = $(patsubst $(dir_source)/%.s, $(dir_build)/%.o, \
$(patsubst $(dir_source)/%.c, $(dir_build)/%.o, \

View File

@ -9,8 +9,10 @@ SECTIONS
.text : ALIGN(4) { *(.text.start) *(.text*); . = ALIGN(4); }
.rodata : ALIGN(4) { *(.rodata*); . = ALIGN(4); }
.data : ALIGN(4) { *(.data*); . = ALIGN(8); *(.bss* COMMON); . = ALIGN(8); }
.bss : ALIGN(4) { __bss_start = .; *(.bss*); __bss_end = .; }
. = ALIGN(4);
__stack_top = 0x1FFFF800;
__irq_stack = 0x1FFFF800;
__prg_stack = 0x1FFFF400;
}

View File

@ -5,8 +5,8 @@
.global __boot
__boot:
@ Disable interrupts and switch to Supervisor
cpsid aif, #0x13
@ Disable interrupts and switch to IRQ
cpsid aif, #0x12
@ Writeback and invalidate caches
mov r0, #0
@ -14,7 +14,11 @@ __boot:
mcr p15, 0, r0, c7, c14, 0
mcr p15, 0, r0, c7, c10, 4
ldr sp, =__stack_top
ldr sp, =__irq_stack
@ Switch to SVC
cpsid aif, #0x13
ldr sp, =__prg_stack
@ Reset values
ldr r0, =0x00054078
@ -26,6 +30,14 @@ __boot:
mcr p15, 0, r1, c1, c0, 1
mcr p15, 0, r2, c1, c0, 2
ldr r0, =__bss_start
ldr r1, =__bss_end
mov r2, #0
.Lclearbss:
str r2, [r0], #4
cmp r0, r1
blt .Lclearbss
bl main
b __boot

57
screeninit/source/gic.c Normal file
View File

@ -0,0 +1,57 @@
/*
Written by Wolfvak, specially sublicensed under the GPLv2
Read LICENSE for more details
*/
#include <types.h>
#include <cpu.h>
#include <gic.h>
#define IRQ_BASE ((vu32*)0x1FFFFFA0)
irq_handler handler_table[MAX_IRQ];
void __attribute__((interrupt("IRQ"))) gic_irq_handler(void)
{
u32 xrq, ss;
CPU_EnterCritical(&ss);
xrq = *GIC_IRQACK;
if (xrq < MAX_IRQ && handler_table[xrq]) {
(handler_table[xrq])(xrq);
}
*GIC_IRQEND = xrq;
CPU_LeaveCritical(&ss);
return;
}
void GIC_Configure(u32 irq_id, irq_handler hndl)
{
handler_table[irq_id] = hndl;
DIC_CLRENABLE[irq_id/32] |= BIT(irq_id & 0x1F);
DIC_SETENABLE[irq_id/32] |= BIT(irq_id & 0x1F);
DIC_PROCTGT[irq_id] = 1;
return;
}
void GIC_Reset(void)
{
*GIC_CONTROL = 0;
*GIC_PRIOMASK = ~0;
for (int i = 0; i < (BIT(9)-1); i++) {
*GIC_IRQEND |= i;
}
*DIC_CONTROL = 0;
for (int i = 0; i < (0x20/4); i++) {
DIC_CLRENABLE[i] = ~0;
DIC_PRIORITY[i] = 0;
}
*DIC_CONTROL = 1;
*GIC_CONTROL = 1;
IRQ_BASE[1] = (u32)gic_irq_handler;
IRQ_BASE[0] = 0xE51FF004;
return;
}

56
screeninit/source/gic.h Normal file
View File

@ -0,0 +1,56 @@
/*
Written by Wolfvak, specially sublicensed under the GPLv2
Read LICENSE for more details
*/
#pragma once
#include <types.h>
typedef void (*irq_handler)(u32);
#define MAX_IRQ (0x80)
#define GIC_BASE (0x17E00100)
#define DIC_BASE (0x17E01000)
/* Setting bit 0 enables the GIC */
#define GIC_CONTROL ((vu32*)(GIC_BASE + 0x00))
/* Bits [7:0] control the min priority accepted */
#define GIC_PRIOMASK ((vu32*)(GIC_BASE + 0x04))
/* When an IRQ occurrs, this register holds the IRQ ID */
#define GIC_IRQACK ((vu32*)(GIC_BASE + 0x0C))
/* Write the IRQ ID here to acknowledge it */
#define GIC_IRQEND ((vu32*)(GIC_BASE + 0x10))
/* Setting bit 0 enables the DIC */
#define DIC_CONTROL ((vu32*)(DIC_BASE + 0x000))
/*
Write here to enable an IRQ ID
The register address is DIC_SETENABLE + (N/32)*4 and its
corresponding bit index is (N%32)
*/
#define DIC_SETENABLE ((vu32*)(DIC_BASE + 0x100))
/* same as above but disables the IRQ */
#define DIC_CLRENABLE ((vu32*)(DIC_BASE + 0x180))
/* sets the IRQ priority */
#define DIC_PRIORITY ((vu32*)(DIC_BASE + 0x400))
/* specifies which CPUs are allowed to be forwarded the IRQ */
#define DIC_PROCTGT ((vu8*)(DIC_BASE + 0x800))
/*
each irq has 2 bits assigned
bit 0 = 0: uses 1-N model
1: uses N-N model
bit 1 = 0: level high active
1: rising edge sensitive
*/
#define DIC_CFGREG ((vu32*)(DIC_BASE + 0xC00))
void gic_irq_handler(void);
void GIC_Configure(u32 irq_id, irq_handler hndl);
void GIC_Reset(void);

View File

@ -1,26 +1,33 @@
// screeninit source taken over from https://github.com/AuroraWright/arm9loaderhax/tree/master/payload_stage2/arm11
// check there for license info
// thanks go to AuroraWright
#include "types.h"
#include <types.h>
#include <cpu.h>
#include <gic.h>
#include <pxi.h>
// see: https://github.com/AuroraWright/Luma3DS/blob/53209b9be0c264af00fb81b32146d27f0d9498ac/source/screen.h#L32-L34
#define PDN_GPU_CNT (*(vu8 *)0x10141200)
#define ARESCREENSINITIALIZED (PDN_GPU_CNT != 1)
#define BRIGHTNESS (0xBF)
#define BASE_BRIGHTNESS (0x1F)
void main(void)
static volatile struct fb {
u8 *top_left;
u8 *top_right;
u8 *bottom;
} *const fb = (volatile struct fb *)0x23FFFE00;
void screen_init(void)
{
char do_disco = !ARESCREENSINITIALIZED;
vu32 *arm11Entry = (vu32 *)0x1FFFFFFC;
u32 entry;
*(vu32 *)0x10141200 = 0x1007F;
*(vu32 *)0x10202014 = 0x00000001;
*(vu32 *)0x1020200C &= 0xFFFEFFFE;
*(vu32 *)0x10202240 = BRIGHTNESS;
*(vu32 *)0x10202A40 = BRIGHTNESS;
*(vu32 *)0x10202240 = BASE_BRIGHTNESS;
*(vu32 *)0x10202A40 = BASE_BRIGHTNESS;
*(vu32 *)0x10202244 = 0x1023E;
*(vu32 *)0x10202A44 = 0x1023E;
@ -107,21 +114,59 @@ void main(void)
*REGs_PSC1 = (vu32 *)0x10400020;
REGs_PSC0[0] = (u32)fb->top_left >> 3; //Start address
REGs_PSC0[1] = (u32)(fb->top_left + SCREEN_TOP_FBSIZE) >> 3; //End address
REGs_PSC0[1] = (u32)(fb->top_left + 0x46500) >> 3; //End address
REGs_PSC0[2] = 0; //Fill value
REGs_PSC0[3] = (2 << 8) | 1; //32-bit pattern; start
REGs_PSC1[0] = (u32)fb->bottom >> 3; //Start address
REGs_PSC1[1] = (u32)(fb->bottom + SCREEN_BOTTOM_FBSIZE) >> 3; //End address
REGs_PSC1[1] = (u32)(fb->bottom + 0x38400) >> 3; //End address
REGs_PSC1[2] = 0; //Fill value
REGs_PSC1[3] = (2 << 8) | 1; //32-bit pattern; start
while(!((REGs_PSC0[3] & 2) && (REGs_PSC1[3] & 2)));
return;
}
void set_brightness(u8 brightness)
{
*(vu32 *)0x10202240 = brightness;
*(vu32 *)0x10202A40 = brightness;
}
void pxi_interrupt_handler(__attribute__((unused)) u32 xrq_n)
{
u8 msg = PXI_GetRemote();
switch(msg) {
case PXI_NOCMD:
break;
case PXI_SETBRIGHTNESS:
set_brightness(PXI_Recv());
break;
}
PXI_SetRemote(PXI_NOCMD);
return;
}
void main(void)
{
vu32 *arm11Entry = (vu32 *)0x1FFFFFFC;
u32 entry;
PXI_Reset();
GIC_Reset();
screen_init();
// Clear ARM11 entrypoint
*arm11Entry = 0;
GIC_Configure(IRQ_PXI_SYNC, pxi_interrupt_handler);
PXI_EnableIRQ();
CPU_EnableIRQ();
//Wait for the entrypoint to be set, then branch to it
while((entry=*arm11Entry) == 0);
CPU_DisableIRQ();
PXI_DisableIRQ();
((void (*)())(entry))();
}

View File

@ -1,25 +0,0 @@
#pragma once
#include <stdint.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;
#define SCREEN_TOP_WIDTH 400
#define SCREEN_BOTTOM_WIDTH 320
#define SCREEN_HEIGHT 240
#define SCREEN_TOP_FBSIZE (3 * SCREEN_TOP_WIDTH * SCREEN_HEIGHT)
#define SCREEN_BOTTOM_FBSIZE (3 * SCREEN_BOTTOM_WIDTH * SCREEN_HEIGHT)
static volatile struct fb {
u8 *top_left;
u8 *top_right;
u8 *bottom;
} *const fb = (volatile struct fb *)0x23FFFE00;

View File

@ -7,16 +7,7 @@
#include <ctype.h>
#include <stdlib.h>
#include <stdio.h>
#define u8 uint8_t
#define u16 uint16_t
#define u32 uint32_t
#define u64 uint64_t
#define vu8 volatile u8
#define vu16 volatile u16
#define vu32 volatile u32
#define vu64 volatile u64
#include <types.h>
#define max(a,b) \
(((a) > (b)) ? (a) : (b))

View File

@ -1,6 +1,7 @@
#include "hid.h"
#include "i2c.h"
#include "timer.h"
#include "power.h"
u32 InputWait(u32 timeout_sec) {
static u64 delay = 0;
@ -23,6 +24,7 @@ u32 InputWait(u32 timeout_sec) {
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)

View File

@ -2,6 +2,23 @@
#include "i2c.h"
#include "cache.h"
#include "timer.h"
#include "pxi.h"
static const u8 br_settings[] = {0x1F, 0x3F, 0x7F, 0xBF};
static int prev_brightness = -1;
void CheckBrightness() {
u8 curSlider;
I2C_readRegBuf(I2C_DEV_MCU, 0x09, &curSlider, 1);
curSlider >>= 4;
if (curSlider != prev_brightness) {
PXI_Wait();
PXI_Send(br_settings[curSlider]);
PXI_SetRemote(PXI_SETBRIGHTNESS);
PXI_Sync();
prev_brightness = curSlider;
}
return;
}
void ScreenOn() {
wait_msec(3); // wait 3ms (cause profi200 said so)

View File

@ -2,6 +2,7 @@
#include "common.h"
void CheckBrightness();
void ScreenOn();
void Reboot();
void PowerOff();

View File

@ -1,14 +1,15 @@
#include "godmode.h"
#include "power.h"
#include "pxi.h"
void main(int argc, char** argv)
{
(void) argc; // unused for now
(void) argv; // unused for now
// Screen on
ScreenOn();
// Run the main program
if (GodMode() == GODMODE_EXIT_REBOOT) Reboot();
else PowerOff();