fixed screen init, hopefully the last commmit

- properly performs gpu/backlight reset

- nukes vram so the initrd had to be moved to arm9 memory, and have its size (at least temporarily) limited to 256k
This commit is contained in:
Wolfvak 2020-07-18 20:25:34 -03:00
parent f20d2657fa
commit 30f0b004c2
36 changed files with 2409 additions and 2181 deletions

View File

@ -83,14 +83,14 @@ vram0:
@$(MAKE) --no-print-directory -C $(@D) @$(MAKE) --no-print-directory -C $(@D)
firm: $(ELF) vram0 firm: $(ELF) vram0
@test `wc -c <$(VRAM_OUT)` -le 3145728 @test `wc -c <$(VRAM_OUT)` -le 262144
@mkdir -p $(call dirname,"$(FIRM)") $(call dirname,"$(FIRMD)") @mkdir -p $(call dirname,"$(FIRM)") $(call dirname,"$(FIRMD)")
@echo "[FLAVOR] $(FLAVOR)" @echo "[FLAVOR] $(FLAVOR)"
@echo "[VERSION] $(VERSION)" @echo "[VERSION] $(VERSION)"
@echo "[BUILD] $(DBUILTL)" @echo "[BUILD] $(DBUILTL)"
@echo "[FIRM] $(FIRM)" @echo "[FIRM] $(FIRM)"
@$(PY3) -m firmtool build $(FIRM) $(FTFLAGS) -g -A 0x18000000 -D $(ELF) $(VRAM_OUT) -C NDMA XDMA memcpy @$(PY3) -m firmtool build $(FIRM) $(FTFLAGS) -g -A 0x80C0000 -D $(ELF) $(VRAM_OUT) -C NDMA XDMA memcpy
@echo "[FIRM] $(FIRMD)" @echo "[FIRM] $(FIRMD)"
@$(PY3) -m firmtool build $(FIRMD) $(FTDFLAGS) -g -A 0x18000000 -D $(ELF) $(VRAM_OUT) -C NDMA XDMA memcpy @$(PY3) -m firmtool build $(FIRMD) $(FTDFLAGS) -g -A 0x80C0000 -D $(ELF) $(VRAM_OUT) -C NDMA XDMA memcpy
.FORCE: .FORCE:

View File

@ -30,3 +30,7 @@
#define CLK_MS_TO_TICKS(m) (((BASE_CLKRATE / 1000) * (m)) - 1) #define CLK_MS_TO_TICKS(m) (((BASE_CLKRATE / 1000) * (m)) - 1)
void TIMER_WaitTicks(u32 ticks); void TIMER_WaitTicks(u32 ticks);
static inline void TIMER_WaitMS(u32 ms) {
TIMER_WaitTicks(CLK_MS_TO_TICKS(ms));
}

View File

@ -16,212 +16,284 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#include <common.h>
#include <types.h> #include <types.h>
#include <vram.h> #include <vram.h>
#include "arm/timer.h" #include "arm/timer.h"
#include "hw/i2c.h"
#include "hw/mcu.h" #include "hw/mcu.h"
#include "hw/gpulcd.h" #include "hw/gpulcd.h"
/* LCD Configuration Registers */ static struct
#define REG_LCD(x) ((vu32*)(0x10202000 + (x)))
void LCD_SetBrightness(u8 brightness)
{ {
*REG_LCD(0x240) = brightness; u16 lcdIds; // Bits 0-7 top screen, 8-15 bottom screen.
*REG_LCD(0xA40) = brightness; bool lcdIdsRead;
u8 lcdPower; // 1 = on. Bit 4 top light, bit 2 bottom light, bit 0 LCDs.
u8 lcdLights[2]; // LCD backlight brightness. Top, bottom.
u32 framebufs[2]; // For each screen
u8 doubleBuf[2]; // Top, bottom, 1 = enable.
u16 strides[2]; // Top, bottom
u32 formats[2]; // Top, bottom
} g_gfxState = {0};
static void setupDisplayController(u8 lcd);
static void resetLcdsMaybe(void);
static void waitLcdsReady(void);
static u32 gxModeWidth(unsigned c) {
switch(c) {
case 0: return 4;
case 1: return 3;
default: return 2;
}
} }
u8 LCD_GetBrightness(void) unsigned GFX_init(GfxFbFmt mode)
{ {
return *REG_LCD(0x240); unsigned err = 0;
REG_CFG11_GPUPROT = 0;
// Reset
REG_PDN_GPU_CNT = PDN_GPU_CNT_CLK_E;
waitClks(12);
REG_PDN_GPU_CNT = PDN_GPU_CNT_CLK_E | PDN_GPU_CNT_RST_ALL;
REG_GX_GPU_CLK = 0x100;
REG_GX_PSC_VRAM = 0;
REG_GX_PSC_FILL0_CNT = 0;
REG_GX_PSC_FILL1_CNT = 0;
REG_GX_PPF_CNT = 0;
// LCD framebuffer setup.
g_gfxState.strides[0] = 240 * gxModeWidth(mode);
g_gfxState.strides[1] = 240 * gxModeWidth(mode);
g_gfxState.framebufs[0] = VRAM_TOP_LA;
g_gfxState.framebufs[1] = VRAM_BOT_A;
g_gfxState.formats[0] = mode | BIT(6) | BIT(9);
g_gfxState.formats[1] = mode | BIT(9);
setupDisplayController(0);
setupDisplayController(1);
REG_LCD_PDC0_SWAP = 0; // Select framebuf 0.
REG_LCD_PDC1_SWAP = 0;
REG_LCD_PDC0_CNT = PDC_CNT_OUT_E | PDC_CNT_I_MASK_ERR | PDC_CNT_I_MASK_H | PDC_CNT_E; // Start
REG_LCD_PDC1_CNT = PDC_CNT_OUT_E | PDC_CNT_I_MASK_ERR | PDC_CNT_I_MASK_H | PDC_CNT_E;
// LCD reg setup.
REG_LCD_ABL0_FILL = 1u<<24; // Force blackscreen
REG_LCD_ABL1_FILL = 1u<<24; // Force blackscreen
REG_LCD_PARALLAX_CNT = 0;
REG_LCD_PARALLAX_PWM = 0xA390A39;
REG_LCD_RST = 0;
REG_LCD_UNK00C = 0x10001;
// Clear used VRAM
REG_GX_PSC_FILL0_S_ADDR = VRAM_TOP_LA >> 3;
REG_GX_PSC_FILL0_E_ADDR = VRAM_END >> 3;
REG_GX_PSC_FILL0_VAL = 0;
REG_GX_PSC_FILL0_CNT = BIT(9) | BIT(0);
// Backlight and other stuff.
REG_LCD_ABL0_LIGHT = 0;
REG_LCD_ABL0_CNT = 0;
REG_LCD_ABL0_LIGHT_PWM = 0;
REG_LCD_ABL1_LIGHT = 0;
REG_LCD_ABL1_CNT = 0;
REG_LCD_ABL1_LIGHT_PWM = 0;
REG_LCD_RST = 1;
REG_LCD_UNK00C = 0;
TIMER_WaitMS(10);
resetLcdsMaybe();
MCU_controlLCDPower(2u); // Power on LCDs.
if(MCU_waitEvents(0x3Fu<<24) != 2u<<24) __builtin_trap();
waitLcdsReady();
REG_LCD_ABL0_LIGHT_PWM = 0x1023E;
REG_LCD_ABL1_LIGHT_PWM = 0x1023E;
MCU_controlLCDPower(0x28u); // Power on backlights.
if(MCU_waitEvents(0x3Fu<<24) != 0x28u<<24) __builtin_trap();
g_gfxState.lcdPower = 0x15; // All on.
// Make sure the fills finished.
REG_LCD_ABL0_FILL = 0;
REG_LCD_ABL1_FILL = 0;
// GPU stuff.
REG_GX_GPU_CLK = 0x70100;
*((vu32*)0x10400050) = 0x22221200;
*((vu32*)0x10400054) = 0xFF2;
GFX_setBrightness(0x80, 0x80);
return err;
} }
void LCD_Initialize(u8 brightness) static u16 getLcdIds(void)
{ {
*REG_LCD(0x014) = 1; u16 ids;
*REG_LCD(0x00C) = 0;
TIMER_WaitTicks(CLK_MS_TO_TICKS(10));
*REG_LCD(0x240) = brightness; if(!g_gfxState.lcdIdsRead)
*REG_LCD(0xA40) = brightness;
*REG_LCD(0x244) = 0x1023E;
*REG_LCD(0xA44) = 0x1023E;
}
void LCD_Deinitialize(void)
{ {
*REG_LCD(0x244) = 0; g_gfxState.lcdIdsRead = true;
*REG_LCD(0xA44) = 0;
*REG_LCD(0x00C) = 0x10001; u16 top, bot;
*REG_LCD(0x014) = 0; I2C_writeReg(I2C_DEV_LCD0, 0x40, 0xFF);
I2C_readRegBuf(I2C_DEV_LCD0, 0x40, (u8*)&top, 2);
I2C_writeReg(I2C_DEV_LCD1, 0x40, 0xFF);
I2C_readRegBuf(I2C_DEV_LCD1, 0x40, (u8*)&bot, 2);
ids = top>>8;
ids |= bot & 0xFF00u;
g_gfxState.lcdIds = ids;
}
else ids = g_gfxState.lcdIds;
return ids;
} }
/* GPU Control Registers */ static void resetLcdsMaybe(void)
#define REG_GPU_CNT ((vu32*)(0x10141200))
/* GPU DMA */
#define REG_GPU_PSC(n, x) ((vu32*)(0x10400010 + ((n) * 0x10) + (x)))
#define GPU_PSC_START (0x00)
#define GPU_PSC_END (0x04)
#define GPU_PSC_FILLVAL (0x08)
#define GPU_PSC_CNT (0x0C)
#define GPUDMA_ADDR(x) ((x) >> 3)
#define PSC_START (BIT(0))
#define PSC_DONE (BIT(1))
#define PSC_32BIT (2 << 8)
#define PSC_24BIT (1 << 8)
#define PSC_16BIT (0 << 8)
void GPU_PSCFill(u32 start, u32 end, u32 fv)
{ {
u32 mp; const u16 ids = getLcdIds();
if (start > end)
return;
start = GPUDMA_ADDR(start); // Top screen
end = GPUDMA_ADDR(end); if(ids & 0xFFu) I2C_writeReg(I2C_DEV_LCD0, 0xFE, 0xAA);
mp = (start + end) / 2; else
*REG_GPU_PSC(0, GPU_PSC_START) = start;
*REG_GPU_PSC(0, GPU_PSC_END) = mp;
*REG_GPU_PSC(0, GPU_PSC_FILLVAL) = fv;
*REG_GPU_PSC(0, GPU_PSC_CNT) = PSC_START | PSC_32BIT;
*REG_GPU_PSC(1, GPU_PSC_START) = mp;
*REG_GPU_PSC(1, GPU_PSC_END) = end;
*REG_GPU_PSC(1, GPU_PSC_FILLVAL) = fv;
*REG_GPU_PSC(1, GPU_PSC_CNT) = PSC_START | PSC_32BIT;
while(!((*REG_GPU_PSC(0, GPU_PSC_CNT) | *REG_GPU_PSC(1, GPU_PSC_CNT)) & PSC_DONE));
}
/* GPU Display Registers */
#define GPU_PDC(n, x) ((vu32*)(0x10400400 + ((n) * 0x100) + x))
#define PDC_PARALLAX (BIT(5))
#define PDC_MAINSCREEN (BIT(6))
#define PDC_FIXSTRIP (BIT(7))
void GPU_SetFramebuffers(const u32 *framebuffers)
{ {
*GPU_PDC(0, 0x68) = framebuffers[0]; I2C_writeReg(I2C_DEV_LCD0, 0x11, 0x10);
*GPU_PDC(0, 0x6C) = framebuffers[1]; I2C_writeReg(I2C_DEV_LCD0, 0x50, 1);
*GPU_PDC(0, 0x94) = framebuffers[2];
*GPU_PDC(0, 0x98) = framebuffers[3];
*GPU_PDC(1, 0x68) = framebuffers[4];
*GPU_PDC(1, 0x6C) = framebuffers[5];
*GPU_PDC(0, 0x78) = 0;
*GPU_PDC(1, 0x78) = 0;
} }
void GPU_SetFramebufferMode(u32 screen, u8 mode) // Bottom screen
if(ids>>8) I2C_writeReg(I2C_DEV_LCD1, 0xFE, 0xAA);
else I2C_writeReg(I2C_DEV_LCD1, 0x11, 0x10);
I2C_writeReg(I2C_DEV_LCD0, 0x60, 0);
I2C_writeReg(I2C_DEV_LCD1, 0x60, 0);
I2C_writeReg(I2C_DEV_LCD0, 1, 0x10);
I2C_writeReg(I2C_DEV_LCD1, 1, 0x10);
}
static void waitLcdsReady(void)
{ {
u32 stride, cfg; const u16 ids = getLcdIds();
vu32 *fbcfg_reg, *fbstr_reg;
mode &= 7; if((ids & 0xFFu) == 0 || (ids>>8) == 0) // Unknown LCD?
screen &= 1;
cfg = PDC_FIXSTRIP | mode;
if (screen) {
fbcfg_reg = GPU_PDC(1, 0x70);
fbstr_reg = GPU_PDC(1, 0x90);
} else {
fbcfg_reg = GPU_PDC(0, 0x70);
fbstr_reg = GPU_PDC(0, 0x90);
cfg |= PDC_MAINSCREEN;
}
stride = 240;
switch(mode) {
case PDC_RGBA8:
stride *= 4;
break;
case PDC_RGB24:
stride *= 3;
break;
default:
stride *= 2;
break;
}
*fbcfg_reg = cfg;
*fbstr_reg = stride;
}
void GPU_Init(void)
{ {
MCU_PushToLCD(true); TIMER_WaitMS(150);
}
LCD_Initialize(0x20); else
{
*REG_GPU_CNT = 0x1007F; u32 i = 0;
*GPU_PDC(0, 0x00) = 0x000001C2; do
*GPU_PDC(0, 0x04) = 0x000000D1; {
*GPU_PDC(0, 0x08) = 0x000001C1; u16 top, bot;
*GPU_PDC(0, 0x0C) = 0x000001C1; I2C_writeReg(I2C_DEV_LCD0, 0x40, 0x62);
*GPU_PDC(0, 0x10) = 0x00000000; I2C_readRegBuf(I2C_DEV_LCD0, 0x40, (u8*)&top, 2);
*GPU_PDC(0, 0x14) = 0x000000CF; I2C_writeReg(I2C_DEV_LCD1, 0x40, 0x62);
*GPU_PDC(0, 0x18) = 0x000000D1; I2C_readRegBuf(I2C_DEV_LCD1, 0x40, (u8*)&bot, 2);
*GPU_PDC(0, 0x1C) = 0x01C501C1;
*GPU_PDC(0, 0x20) = 0x00010000; if((top>>8) == 1 && (bot>>8) == 1) break;
*GPU_PDC(0, 0x24) = 0x0000019D;
*GPU_PDC(0, 0x28) = 0x00000002; TIMER_WaitMS(33);
*GPU_PDC(0, 0x2C) = 0x00000192; } while(i++ < 10);
*GPU_PDC(0, 0x30) = 0x00000192; }
*GPU_PDC(0, 0x34) = 0x00000192; }
*GPU_PDC(0, 0x38) = 0x00000001;
*GPU_PDC(0, 0x3C) = 0x00000002; void GFX_powerOnBacklights(GfxBlight mask)
*GPU_PDC(0, 0x40) = 0x01960192; {
*GPU_PDC(0, 0x44) = 0x00000000; g_gfxState.lcdPower |= mask;
*GPU_PDC(0, 0x48) = 0x00000000;
*GPU_PDC(0, 0x5C) = 0x00F00190; mask <<= 1;
*GPU_PDC(0, 0x60) = 0x01C100D1; MCU_controlLCDPower(mask); // Power on backlights.
*GPU_PDC(0, 0x64) = 0x01920002; if(MCU_waitEvents(0x3Fu<<24) != (u32)mask<<24)
*GPU_PDC(0, 0x68) = VRAM_START; __builtin_trap();
*GPU_PDC(0, 0x6C) = VRAM_START; }
*GPU_PDC(0, 0x70) = 0x00080340;
*GPU_PDC(0, 0x74) = 0x00010501; void GFX_powerOffBacklights(GfxBlight mask)
*GPU_PDC(0, 0x78) = 0x00000000; {
*GPU_PDC(0, 0x90) = 0x000003C0; g_gfxState.lcdPower &= ~mask;
*GPU_PDC(0, 0x94) = VRAM_START;
*GPU_PDC(0, 0x98) = VRAM_START; MCU_controlLCDPower(mask); // Power off backlights.
*GPU_PDC(0, 0x9C) = 0x00000000; if(MCU_waitEvents(0x3Fu<<24) != (u32)mask<<24)
__builtin_trap();
for (u32 i = 0; i < 256; i++) }
*GPU_PDC(0, 0x84) = 0x10101 * i;
u8 GFX_getBrightness(void)
*GPU_PDC(1, 0x00) = 0x000001C2; {
*GPU_PDC(1, 0x04) = 0x000000D1; return REG_LCD_ABL0_LIGHT;
*GPU_PDC(1, 0x08) = 0x000001C1; }
*GPU_PDC(1, 0x0C) = 0x000001C1;
*GPU_PDC(1, 0x10) = 0x000000CD; void GFX_setBrightness(u8 top, u8 bot)
*GPU_PDC(1, 0x14) = 0x000000CF; {
*GPU_PDC(1, 0x18) = 0x000000D1; g_gfxState.lcdLights[0] = top;
*GPU_PDC(1, 0x1C) = 0x01C501C1; g_gfxState.lcdLights[1] = bot;
*GPU_PDC(1, 0x20) = 0x00010000; REG_LCD_ABL0_LIGHT = top;
*GPU_PDC(1, 0x24) = 0x0000019D; REG_LCD_ABL1_LIGHT = bot;
*GPU_PDC(1, 0x28) = 0x00000052; }
*GPU_PDC(1, 0x2C) = 0x00000192;
*GPU_PDC(1, 0x30) = 0x00000192; void GFX_setForceBlack(bool top, bool bot)
*GPU_PDC(1, 0x34) = 0x0000004F; {
*GPU_PDC(1, 0x38) = 0x00000050; REG_LCD_ABL0_FILL = (u32)top<<24; // Force blackscreen
*GPU_PDC(1, 0x3C) = 0x00000052; REG_LCD_ABL1_FILL = (u32)bot<<24; // Force blackscreen
*GPU_PDC(1, 0x40) = 0x01980194; }
*GPU_PDC(1, 0x44) = 0x00000000;
*GPU_PDC(1, 0x48) = 0x00000011; static void setupDisplayController(u8 lcd)
*GPU_PDC(1, 0x5C) = 0x00F00140; {
*GPU_PDC(1, 0x60) = 0x01C100d1; if(lcd > 1) return;
*GPU_PDC(1, 0x64) = 0x01920052;
*GPU_PDC(1, 0x68) = VRAM_START; static const u32 displayCfgs[2][24] =
*GPU_PDC(1, 0x6C) = VRAM_START; {
*GPU_PDC(1, 0x70) = 0x00080300; {
*GPU_PDC(1, 0x74) = 0x00010501; // PDC0 regs 0-0x4C.
*GPU_PDC(1, 0x78) = 0x00000000; 450, 209, 449, 449, 0, 207, 209, 453<<16 | 449,
*GPU_PDC(1, 0x90) = 0x000003C0; 1<<16 | 0, 413, 2, 402, 402, 402, 1, 2,
*GPU_PDC(1, 0x9C) = 0x00000000; 406<<16 | 402, 0, 0<<4 | 0, 0<<16 | 0xFF<<8 | 0,
// PDC0 regs 0x5C-0x64.
for (u32 i = 0; i < 256; i++) 400<<16 | 240, // Width and height.
*GPU_PDC(1, 0x84) = 0x10101 * i; 449<<16 | 209,
402<<16 | 2,
// PDC0 reg 0x9C.
0<<16 | 0
},
{
// PDC1 regs 0-0x4C.
450, 209, 449, 449, 205, 207, 209, 453<<16 | 449,
1<<16 | 0, 413, 82, 402, 402, 79, 80, 82,
408<<16 | 404, 0, 1<<4 | 1, 0<<16 | 0<<8 | 0xFF,
// PDC1 regs 0x5C-0x64.
320<<16 | 240, // Width and height.
449<<16 | 209,
402<<16 | 82,
// PDC1 reg 0x9C.
0<<16 | 0
}
};
const u32 *const cfg = displayCfgs[lcd];
vu32 *const regs = (vu32*)(GX_REGS_BASE + 0x400 + (0x100u * lcd));
for (unsigned i = 0; i < 0x50/4; i++)
regs[i] = cfg[i];
for (unsigned i = 0; i < 0xC/4; i++)
regs[23 + i] = cfg[20 + i];
regs[36] = g_gfxState.strides[lcd]; // PDC reg 0x90 stride.
regs[39] = cfg[23]; // PDC reg 0x9C.
// PDC regs 0x68, 0x6C, 0x94, 0x98 and 0x70.
regs[26] = g_gfxState.framebufs[lcd]; // Framebuffer A first address.
regs[27] = g_gfxState.framebufs[lcd]; // Framebuffer A second address.
regs[37] = g_gfxState.framebufs[lcd]; // Framebuffer B first address.
regs[38] = g_gfxState.framebufs[lcd]; // Framebuffer B second address.
regs[28] = g_gfxState.formats[lcd]; // Format
regs[32] = 0; // Gamma table index 0.
for(u32 i = 0; i < 256; i++) regs[33] = 0x10101u * i;
} }

View File

@ -21,21 +21,166 @@
#define VBLANK_INTERRUPT (0x2A) #define VBLANK_INTERRUPT (0x2A)
void LCD_SetBrightness(u8 brightness); enum
u8 LCD_GetBrightness(void); {
PDN_GPU_CNT_RST_REGS = 1u, // And more?
PDN_GPU_CNT_RST_PSC = 1u<<1, // ?
PDN_GPU_CNT_RST_GEOSHADER = 1u<<2, // ?
PDN_GPU_CNT_RST_RASTERIZER = 1u<<3, // ?
PDN_GPU_CNT_RST_PPF = 1u<<4,
PDN_GPU_CNT_RST_PDC = 1u<<5, // ?
PDN_GPU_CNT_RST_PDC2 = 1u<<6, // Maybe pixel pipeline or so?
void LCD_Deinitialize(void); PDN_GPU_CNT_RST_ALL = (PDN_GPU_CNT_RST_PDC2<<1) - 1
void GPU_PSCFill(u32 start, u32 end, u32 fv);
enum {
PDC_RGBA8 = 0,
PDC_RGB24 = 1,
PDC_RGB565 = 2,
PDC_RGB5A1 = 3,
PDC_RGBA4 = 4,
}; };
void GPU_SetFramebufferMode(u32 screen, u8 mode); typedef enum
void GPU_SetFramebuffers(const u32 *framebuffers); {
void GPU_Init(void); GFX_RGBA8 = 0, ///< RGBA8. (4 bytes)
GFX_BGR8 = 1, ///< BGR8. (3 bytes)
GFX_RGB565 = 2, ///< RGB565. (2 bytes)
GFX_RGB5A1 = 3, ///< RGB5A1. (2 bytes)
GFX_RGBA4 = 4 ///< RGBA4. (2 bytes)
} GfxFbFmt;
typedef enum
{
GFX_EVENT_PSC0 = 0u,
GFX_EVENT_PSC1 = 1u,
GFX_EVENT_PDC0 = 2u,
GFX_EVENT_PDC1 = 3u,
GFX_EVENT_PPF = 4u,
GFX_EVENT_P3D = 5u
} GfxEvent;
typedef enum
{
GFX_BLIGHT_BOT = 1u<<2,
GFX_BLIGHT_TOP = 1u<<4,
GFX_BLIGHT_BOTH = GFX_BLIGHT_TOP | GFX_BLIGHT_BOT
} GfxBlight;
#define REG_CFG11_GPUPROT *((vu16*)(0x10140140))
#define REG_PDN_GPU_CNT *((vu32*)(0x10141200))
#define PDN_GPU_CNT_CLK_E (1u<<16)
#define PDN_VRAM_CNT_CLK_E (1u)
#define GX_REGS_BASE (0x10400000)
#define REG_GX_GPU_CLK *((vu32*)(GX_REGS_BASE + 0x0004)) // ?
// PSC (memory fill) regs.
#define REG_GX_PSC_FILL0_S_ADDR *((vu32*)(GX_REGS_BASE + 0x0010)) // Start address
#define REG_GX_PSC_FILL0_E_ADDR *((vu32*)(GX_REGS_BASE + 0x0014)) // End address
#define REG_GX_PSC_FILL0_VAL *((vu32*)(GX_REGS_BASE + 0x0018)) // Fill value
#define REG_GX_PSC_FILL0_CNT *((vu32*)(GX_REGS_BASE + 0x001C))
#define REG_GX_PSC_FILL1_S_ADDR *((vu32*)(GX_REGS_BASE + 0x0020))
#define REG_GX_PSC_FILL1_E_ADDR *((vu32*)(GX_REGS_BASE + 0x0024))
#define REG_GX_PSC_FILL1_VAL *((vu32*)(GX_REGS_BASE + 0x0028))
#define REG_GX_PSC_FILL1_CNT *((vu32*)(GX_REGS_BASE + 0x002C))
#define REG_GX_PSC_VRAM *((vu32*)(GX_REGS_BASE + 0x0030)) // gsp mudule only changes bit 8-11.
#define REG_GX_PSC_STAT *((vu32*)(GX_REGS_BASE + 0x0034))
// PDC0/1 regs see lcd.h.
// PPF (transfer engine) regs.
#define REG_GX_PPF_IN_ADDR *((vu32*)(GX_REGS_BASE + 0x0C00))
#define REG_GX_PPF_OUT_ADDR *((vu32*)(GX_REGS_BASE + 0x0C04))
#define REG_GX_PPF_DT_OUTDIM *((vu32*)(GX_REGS_BASE + 0x0C08)) // Display transfer output dimensions.
#define REG_GX_PPF_DT_INDIM *((vu32*)(GX_REGS_BASE + 0x0C0C)) // Display transfer input dimensions.
#define REG_GX_PPF_FlAGS *((vu32*)(GX_REGS_BASE + 0x0C10))
#define REG_GX_PPF_UNK14 *((vu32*)(GX_REGS_BASE + 0x0C14)) // Transfer interval?
#define REG_GX_PPF_CNT *((vu32*)(GX_REGS_BASE + 0x0C18))
#define REG_GX_PPF_IRQ_POS *((vu32*)(GX_REGS_BASE + 0x0C1C)) // ?
#define REG_GX_PPF_LEN *((vu32*)(GX_REGS_BASE + 0x0C20)) // Texture copy size in bytes.
#define REG_GX_PPF_TC_INDIM *((vu32*)(GX_REGS_BASE + 0x0C24)) // Texture copy input width and gap in 16 byte units.
#define REG_GX_PPF_TC_OUTDIM *((vu32*)(GX_REGS_BASE + 0x0C28)) // Texture copy output width and gap in 16 byte units.
// P3D (GPU internal) regs. See gpu_regs.h.
#define REG_GX_P3D(reg) *((vu32*)(GX_REGS_BASE + 0x1000 + ((reg) * 4)))
// LCD/ABL regs.
#define LCD_REGS_BASE (0x10202000)
#define REG_LCD_PARALLAX_CNT *((vu32*)(LCD_REGS_BASE + 0x000)) // Controls PWM for the parallax barrier?
#define REG_LCD_PARALLAX_PWM *((vu32*)(LCD_REGS_BASE + 0x004)) // Frequency/other PWM stuff maybe?
#define REG_LCD_UNK00C *((vu32*)(LCD_REGS_BASE + 0x00C)) // Wtf is "FIX"?
#define REG_LCD_RST *((vu32*)(LCD_REGS_BASE + 0x014)) // Reset active low.
#define REG_LCD_ABL0_CNT *((vu32*)(LCD_REGS_BASE + 0x200)) // Bit 0 enables ABL aka power saving mode.
#define REG_LCD_ABL0_FILL *((vu32*)(LCD_REGS_BASE + 0x204))
#define REG_LCD_ABL0_LIGHT *((vu32*)(LCD_REGS_BASE + 0x240))
#define REG_LCD_ABL0_LIGHT_PWM *((vu32*)(LCD_REGS_BASE + 0x244))
#define REG_LCD_ABL1_CNT *((vu32*)(LCD_REGS_BASE + 0xA00)) // Bit 0 enables ABL aka power saving mode.
#define REG_LCD_ABL1_FILL *((vu32*)(LCD_REGS_BASE + 0xA04))
#define REG_LCD_ABL1_LIGHT *((vu32*)(LCD_REGS_BASE + 0xA40))
#define REG_LCD_ABL1_LIGHT_PWM *((vu32*)(LCD_REGS_BASE + 0xA44))
// Technically these regs belong in gx.h but they are used for LCD configuration so...
// Pitfall warning: The 3DS LCDs are physically rotated 90° CCW.
// PDC0 (top screen display controller) regs.
#define REG_LCD_PDC0_HTOTAL *((vu32*)(GX_REGS_BASE + 0x400))
#define REG_LCD_PDC0_VTOTAL *((vu32*)(GX_REGS_BASE + 0x424))
#define REG_LCD_PDC0_HPOS *((const vu32*)(GX_REGS_BASE + 0x450))
#define REG_LCD_PDC0_VPOS *((const vu32*)(GX_REGS_BASE + 0x454))
#define REG_LCD_PDC0_FB_A1 *((vu32*)(GX_REGS_BASE + 0x468))
#define REG_LCD_PDC0_FB_A2 *((vu32*)(GX_REGS_BASE + 0x46C))
#define REG_LCD_PDC0_FMT *((vu32*)(GX_REGS_BASE + 0x470))
#define REG_LCD_PDC0_CNT *((vu32*)(GX_REGS_BASE + 0x474))
#define REG_LCD_PDC0_SWAP *((vu32*)(GX_REGS_BASE + 0x478))
#define REG_LCD_PDC0_STAT *((const vu32*)(GX_REGS_BASE + 0x47C))
#define REG_LCD_PDC0_GTBL_IDX *((vu32*)(GX_REGS_BASE + 0x480)) // Gamma table index.
#define REG_LCD_PDC0_GTBL_FIFO *((vu32*)(GX_REGS_BASE + 0x484)) // Gamma table FIFO.
#define REG_LCD_PDC0_STRIDE *((vu32*)(GX_REGS_BASE + 0x490))
#define REG_LCD_PDC0_FB_B1 *((vu32*)(GX_REGS_BASE + 0x494))
#define REG_LCD_PDC0_FB_B2 *((vu32*)(GX_REGS_BASE + 0x498))
// PDC1 (bottom screen display controller) regs.
#define REG_LCD_PDC1_HTOTAL *((vu32*)(GX_REGS_BASE + 0x500))
#define REG_LCD_PDC1_VTOTAL *((vu32*)(GX_REGS_BASE + 0x524))
#define REG_LCD_PDC1_HPOS *((const vu32*)(GX_REGS_BASE + 0x550))
#define REG_LCD_PDC1_VPOS *((const vu32*)(GX_REGS_BASE + 0x554))
#define REG_LCD_PDC1_FB_A1 *((vu32*)(GX_REGS_BASE + 0x568))
#define REG_LCD_PDC1_FB_A2 *((vu32*)(GX_REGS_BASE + 0x56C))
#define REG_LCD_PDC1_FMT *((vu32*)(GX_REGS_BASE + 0x570))
#define REG_LCD_PDC1_CNT *((vu32*)(GX_REGS_BASE + 0x574))
#define REG_LCD_PDC1_SWAP *((vu32*)(GX_REGS_BASE + 0x578))
#define REG_LCD_PDC1_STAT *((const vu32*)(GX_REGS_BASE + 0x57C))
#define REG_LCD_PDC1_GTBL_IDX *((vu32*)(GX_REGS_BASE + 0x580)) // Gamma table index.
#define REG_LCD_PDC1_GTBL_FIFO *((vu32*)(GX_REGS_BASE + 0x584)) // Gamma table FIFO.
#define REG_LCD_PDC1_STRIDE *((vu32*)(GX_REGS_BASE + 0x590))
#define REG_LCD_PDC1_FB_B1 *((vu32*)(GX_REGS_BASE + 0x594))
#define REG_LCD_PDC1_FB_B2 *((vu32*)(GX_REGS_BASE + 0x598))
// REG_LCD_PDC_CNT
#define PDC_CNT_E (1u)
#define PDC_CNT_I_MASK_H (1u<<8) // Disables H(Blank?) IRQs.
#define PDC_CNT_I_MASK_V (1u<<9) // Disables VBlank IRQs.
#define PDC_CNT_I_MASK_ERR (1u<<10) // Disables error IRQs. What kind of errors?
#define PDC_CNT_OUT_E (1u<<16) // Output enable?
// REG_LCD_PDC_SWAP
// Masks
#define PDC_SWAP_NEXT (1u) // Next framebuffer.
#define PDC_SWAP_CUR (1u<<4) // Currently displaying framebuffer?
// Bits
#define PDC_SWAP_RST_FIFO (1u<<8) // Which FIFO?
#define PDC_SWAP_I_H (1u<<16) // H(Blank?) IRQ bit.
#define PDC_SWAP_I_V (1u<<17) // VBlank IRQ bit.
#define PDC_SWAP_I_ERR (1u<<18) // Error IRQ bit?
#define PDC_SWAP_I_ALL (PDC_SWAP_I_ERR | PDC_SWAP_I_V | PDC_SWAP_I_H)
unsigned GFX_init(GfxFbFmt mode);
void GFX_setForceBlack(bool top, bool bot);
void GFX_powerOnBacklights(GfxBlight mask);
void GFX_powerOffBacklights(GfxBlight mask);
u8 GFX_getBrightness(void);
void GFX_setBrightness(u8 top, u8 bot);

View File

@ -31,6 +31,9 @@
#define I2C_IRQ_ENABLE (1u<<6) #define I2C_IRQ_ENABLE (1u<<6)
#define I2C_ENABLE (1u<<7) #define I2C_ENABLE (1u<<7)
#define I2C_DEV_LCD0 5
#define I2C_DEV_LCD1 6
#define I2C_GET_ACK(reg) ((bool)((reg)>>4 & 1u)) #define I2C_GET_ACK(reg) ((bool)((reg)>>4 & 1u))
@ -62,3 +65,13 @@ bool I2C_readRegBuf(int devId, u8 regAddr, u8 *out, u32 size);
* @return Returns true on success and false on failure. * @return Returns true on success and false on failure.
*/ */
bool I2C_writeRegBuf(int devId, u8 regAddr, const u8 *in, u32 size); bool I2C_writeRegBuf(int devId, u8 regAddr, const u8 *in, u32 size);
static inline u8 I2C_readReg(int devId, u8 regAddr) {
u8 v;
I2C_readRegBuf(devId, regAddr, &v, 1);
return v;
}
static inline void I2C_writeReg(int devId, u8 regAddr, u8 v) {
I2C_writeRegBuf(devId, regAddr, &v, 1);
}

View File

@ -135,12 +135,6 @@ void MCU_ResetLED(void)
MCU_SetNotificationLED(0, 0); MCU_SetNotificationLED(0, 0);
} }
void MCU_PushToLCD(bool enable)
{
MCU_WriteReg(REG_LCD_STATE, enable ? 0x2A : 0x01);
TIMER_WaitTicks(CLK_MS_TO_TICKS(160));
}
void MCU_HandleInterrupts(u32 __attribute__((unused)) irqn) void MCU_HandleInterrupts(u32 __attribute__((unused)) irqn)
{ {
u32 ints; u32 ints;
@ -171,13 +165,11 @@ void MCU_HandleInterrupts(u32 __attribute__((unused)) irqn)
break; break;
case MCU_SHELL_OPEN: case MCU_SHELL_OPEN:
MCU_PushToLCD(true);
MCU_UpdateShellState(true); MCU_UpdateShellState(true);
MCU_ResetLED(); MCU_ResetLED();
break; break;
case MCU_SHELL_CLOSE: case MCU_SHELL_CLOSE:
MCU_PushToLCD(false);
MCU_UpdateShellState(false); MCU_UpdateShellState(false);
break; break;
@ -195,7 +187,7 @@ void MCU_HandleInterrupts(u32 __attribute__((unused)) irqn)
void MCU_Init(void) void MCU_Init(void)
{ {
u32 clrpend, mask = 0xFFBF0800; u32 clrpend, mask = 0;
/* set register mask and clear any pending registers */ /* set register mask and clear any pending registers */
MCU_WriteRegBuf(REG_INT_EN, (const u8*)&mask, sizeof(mask)); MCU_WriteRegBuf(REG_INT_EN, (const u8*)&mask, sizeof(mask));

View File

@ -20,6 +20,7 @@
#include <types.h> #include <types.h>
#include "arm/timer.h"
#include "hw/i2c.h" #include "hw/i2c.h"
#define MCU_INTERRUPT (0x71) #define MCU_INTERRUPT (0x71)
@ -31,8 +32,6 @@ u32 MCU_GetSpecialHID(void);
void MCU_SetNotificationLED(u32 period_ms, u32 color); void MCU_SetNotificationLED(u32 period_ms, u32 color);
void MCU_ResetLED(void); void MCU_ResetLED(void);
void MCU_PushToLCD(bool enable);
void MCU_HandleInterrupts(u32 irqn); void MCU_HandleInterrupts(u32 irqn);
void MCU_Init(void); void MCU_Init(void);
@ -58,3 +57,20 @@ static inline bool MCU_WriteRegBuf(u8 addr, const u8 *buf, u32 size)
{ {
return I2C_writeRegBuf(I2C_MCU_DEVICE, addr, buf, size); return I2C_writeRegBuf(I2C_MCU_DEVICE, addr, buf, size);
} }
static inline u32 MCU_waitEvents(u32 mask) {
u32 v;
while(1) {
TIMER_WaitMS(10);
MCU_ReadRegBuf(0x10, (u8*)&v, 4);
v &= mask;
if (v)
break;
}
return v;
}
static inline void MCU_controlLCDPower(u8 bits)
{
MCU_WriteReg(0x22u, bits);
}

View File

@ -52,7 +52,8 @@ void VBlank_Handler(u32 __attribute__((unused)) irqn)
int cur_bright_lvl = (MCU_GetVolumeSlider() >> 2) % countof(brightness_lvls); int cur_bright_lvl = (MCU_GetVolumeSlider() >> 2) % countof(brightness_lvls);
if ((cur_bright_lvl != prev_bright_lvl) && auto_brightness) { if ((cur_bright_lvl != prev_bright_lvl) && auto_brightness) {
prev_bright_lvl = cur_bright_lvl; prev_bright_lvl = cur_bright_lvl;
LCD_SetBrightness(brightness_lvls[cur_bright_lvl]); u8 br = brightness_lvls[cur_bright_lvl];
GFX_setBrightness(br, br);
} }
#endif #endif
@ -98,9 +99,8 @@ void PXI_RX_Handler(u32 __attribute__((unused)) irqn)
case PXI_SET_VMODE: case PXI_SET_VMODE:
{ {
int mode = args[0] ? PDC_RGB24 : PDC_RGB565; int mode = args[0] ? GFX_BGR8 : GFX_RGB565;
GPU_SetFramebufferMode(0, mode); GFX_init(mode);
GPU_SetFramebufferMode(1, mode);
ret = 0; ret = 0;
break; break;
} }
@ -147,10 +147,11 @@ void PXI_RX_Handler(u32 __attribute__((unused)) irqn)
case PXI_BRIGHTNESS: case PXI_BRIGHTNESS:
{ {
ret = LCD_GetBrightness(); s32 newbrightness = (s32)args[0];
ret = GFX_getBrightness();
#ifndef FIXED_BRIGHTNESS #ifndef FIXED_BRIGHTNESS
if ((args[0] > 0) && (args[0] < 0x100)) { if ((newbrightness > 0) && (newbrightness < 0x100)) {
LCD_SetBrightness(args[0]); GFX_setBrightness(newbrightness, newbrightness);
auto_brightness = false; auto_brightness = false;
} else { } else {
prev_bright_lvl = -1; prev_bright_lvl = -1;
@ -184,6 +185,8 @@ void PXI_RX_Handler(u32 __attribute__((unused)) irqn)
PXI_Send(ret); PXI_Send(ret);
} }
extern u32 pdcerr;
void __attribute__((noreturn)) MainLoop(void) void __attribute__((noreturn)) MainLoop(void)
{ {
#ifdef FIXED_BRIGHTNESS #ifdef FIXED_BRIGHTNESS

View File

@ -108,16 +108,7 @@ void SYS_CoreZeroInit(void)
SPI_Init(); SPI_Init();
CODEC_Init(); CODEC_Init();
GPU_Init(); GFX_init(GFX_RGB565);
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_PushToLCD(true);
} }
void SYS_CoreInit(void) void SYS_CoreInit(void)

View File

@ -19,9 +19,6 @@ void main(int argc, char** argv, int entrypoint)
// ARM11 says it's ready // ARM11 says it's ready
PXI_Barrier(ARM11_READY_BARRIER); PXI_Barrier(ARM11_READY_BARRIER);
// Set screens to RGB16 mode
PXI_DoCMD(PXI_SET_VMODE, (u32[]){0}, 1);
// A pointer to the shared memory region is // A pointer to the shared memory region is
// stored in the thread ID register in the ARM9 // stored in the thread ID register in the ARM9
ARM_InitSHMEM(); ARM_InitSHMEM();

View File

@ -123,13 +123,9 @@ BootFirm:
@ Setup the framebuffer struct @ Setup the framebuffer struct
ldr r0, =FBPTR_LOC ldr r0, =FBPTR_LOC
ldr r1, =VRAM_TOP_LA ldr r1, =VRAM_TOP_LA
ldr r2, =VRAM_TOP_RA ldr r2, =VRAM_TOP_LA
ldr r3, =VRAM_BOT_A ldr r3, =VRAM_BOT_A
stmia r0!, {r1,r2,r3} stmia r0!, {r1,r2,r3}
ldr r1, =VRAM_TOP_LB
ldr r2, =VRAM_TOP_RB
ldr r3, =VRAM_BOT_B
stmia r0!, {r1,r2,r3} stmia r0!, {r1,r2,r3}
@ Copy the FIRM path somewhere safe @ Copy the FIRM path somewhere safe

View File

@ -18,8 +18,8 @@
#define VRAM0_EASTER_BIN "easter.bin" #define VRAM0_EASTER_BIN "easter.bin"
#define VRAM0_OFFSET 0x18000000 #define VRAM0_OFFSET 0x080C0000
#define VRAM0_LIMIT 0x00300000 #define VRAM0_LIMIT 0x00040000
#define TARDATA ((void*) VRAM0_OFFSET) #define TARDATA ((void*) VRAM0_OFFSET)
#define TARDATA_(off) ((void*) (u32) (VRAM0_OFFSET + (off))) #define TARDATA_(off) ((void*) (u32) (VRAM0_OFFSET + (off)))

View File

@ -1609,14 +1609,13 @@ u32 BuildCiaFromNcsdFile(const char* path_ncsd, const char* path_cia) {
// insert NCSD content // insert NCSD content
TmdContentChunk* chunk = cia->content_list; TmdContentChunk* chunk = cia->content_list;
for (u32 i = 0, idx = 0; i < 3; i++) { for (u32 i = 0; i < 3; i++) {
NcchPartition* partition = ncsd.partitions + i; NcchPartition* partition = ncsd.partitions + i;
u32 offset = partition->offset * NCSD_MEDIA_UNIT; u32 offset = partition->offset * NCSD_MEDIA_UNIT;
u32 size = partition->size * NCSD_MEDIA_UNIT; u32 size = partition->size * NCSD_MEDIA_UNIT;
if (!size) continue; if (!size) continue;
memset(chunk, 0, sizeof(TmdContentChunk)); memset(chunk, 0, sizeof(TmdContentChunk));
chunk->id[3] = i; chunk->id[3] = chunk->index[1] = i;
chunk->index[1] = idx++;
if (InsertCiaContent(path_cia, path_ncsd, offset, size, chunk++, NULL, false, (i == 0), false) != 0) { if (InsertCiaContent(path_cia, path_ncsd, offset, size, chunk++, NULL, false, (i == 0), false) != 0) {
free(cia); free(cia);
return 1; return 1;

View File

@ -61,11 +61,13 @@
#define assert(x) \ #define assert(x) \
(!!(x) ? (void)0 : __builtin_trap()) (!!(x) ? (void)0 : __builtin_trap())
static inline void waitClks(unsigned clk) {
asm_v("1: subs %0, %0, #2\n\tbne 1b\n\t":"=r"(clk)::"memory","cc");
}
#define STATIC_ASSERT(...) \ #define STATIC_ASSERT(...) \
_Static_assert((__VA_ARGS__), #__VA_ARGS__) _Static_assert((__VA_ARGS__), #__VA_ARGS__)
// standard output path (support file paths are in support.h) // standard output path (support file paths are in support.h)
#define OUTPUT_PATH "0:/gm9/out" #define OUTPUT_PATH "0:/gm9/out"

View File

@ -4,10 +4,8 @@
#define BOTTOM_VRAM (320*240*4) #define BOTTOM_VRAM (320*240*4)
#define VRAM_START (0x18300000) #define VRAM_START (0x18300000)
#define VRAM_TOP_LA (VRAM_START) #define VRAM_TOP_LA (VRAM_START)
#define VRAM_TOP_LB (VRAM_TOP_LA + TOP_VRAM) #define VRAM_BOT_A (VRAM_TOP_LA + TOP_VRAM)
#define VRAM_TOP_RA (VRAM_TOP_LB + TOP_VRAM)
#define VRAM_TOP_RB (VRAM_TOP_RA + TOP_VRAM) #define VRAM_END (VRAM_BOT_A + BOTTOM_VRAM)
#define VRAM_BOT_A (VRAM_TOP_RB + TOP_VRAM)
#define VRAM_BOT_B (VRAM_BOT_A + BOTTOM_VRAM)
#define VRAM_END (VRAM_BOT_B + BOTTOM_VRAM)