From 70757e33855bba9f9ce7351b0111fedc69a70c54 Mon Sep 17 00:00:00 2001 From: Wolfvak Date: Mon, 22 Apr 2019 16:24:45 -0300 Subject: [PATCH] - added extremely simple calibration dialog, to be replaced by something prettier/saner/safer at a later point in time - moved all SPI code to the ARM11 - reimplemented NVRAM reading for the new SPI interface --- arm11/source/arm/vectors.s | 31 +++++------- arm11/source/hw/codec.c | 8 ++-- arm11/source/hw/nvram.c | 77 ++++++++++++++++++++++++++++++ arm11/source/hw/nvram.h | 16 +++++++ arm11/source/hw/spi.c | 24 ++++++---- arm11/source/hw/spi.h | 4 +- arm11/source/main.c | 14 +++++- arm11/source/system/sys.c | 2 + arm9/source/common/hid.c | 41 +++++++++------- arm9/source/common/ui.c | 80 +++++++++++++++++++++++++++++++ arm9/source/common/ui.h | 3 ++ arm9/source/godmode.c | 8 ++++ arm9/source/system/spiflash.c | 89 ----------------------------------- arm9/source/system/spiflash.h | 24 ++++++---- common/pxi.h | 6 +-- 15 files changed, 274 insertions(+), 153 deletions(-) create mode 100755 arm11/source/hw/nvram.c create mode 100755 arm11/source/hw/nvram.h delete mode 100644 arm9/source/system/spiflash.c diff --git a/arm11/source/arm/vectors.s b/arm11/source/arm/vectors.s index d667a1f..ec968f1 100644 --- a/arm11/source/arm/vectors.s +++ b/arm11/source/arm/vectors.s @@ -1,21 +1,18 @@ #include .arm -.align 2 +.align 3 .section .vector, "ax" vectors: - ldr pc, =XRQ_Reset - ldr pc, =XRQ_Reset - ldr pc, =XRQ_Reset - ldr pc, =XRQ_Reset - ldr pc, =XRQ_Reset - b . @ RESERVED - ldr pc, =XRQ_IRQ - ldr pc, =XRQ_Reset -.pool - -.section .text.XRQS, "ax" + b XRQ_Reset @ RESET + b XRQ_Reset @ UNDEFINED + b XRQ_Reset @ SVC + b XRQ_Reset @ PREFETCH ABORT + b XRQ_Reset @ DATA ABORT + b XRQ_Reset @ RESERVED + b XRQ_IRQ @ IRQ + b XRQ_Reset @ FIQ XRQ_Reset: mov r0, #0x18000000 @@ -24,12 +21,9 @@ XRQ_Reset: 1: cmp r0, r1 strne r2, [r0], #4 - bne 1b - 2: - wfi - b 2b + moveq r0, #0x18000000 + b 1b -.global XRQ_IRQ XRQ_IRQ: sub lr, lr, #4 @ Fix return address srsfd sp!, #SR_SVC_MODE @ Store IRQ mode LR and SPSR on the SVC stack @@ -39,7 +33,8 @@ XRQ_IRQ: and r4, sp, #7 @ Fix SP to be 8byte aligned sub sp, sp, r4 - bl GIC_MainHandler + mov lr, pc + ldr pc, =GIC_MainHandler add sp, sp, r4 diff --git a/arm11/source/hw/codec.c b/arm11/source/hw/codec.c index f3eb5fe..9e69304 100755 --- a/arm11/source/hw/codec.c +++ b/arm11/source/hw/codec.c @@ -18,11 +18,9 @@ #include "hw/codec.h" #include "hw/spi.h" -#define CODEC_SPI_DEV (3) +#define CODEC_SPI_DEV 3 -#define MAX_12BIT (BIT(12) - 1) #define CPAD_THRESH (150) -#define CPAD_FACTOR (150) /* SPI stuff */ static void CODEC_WriteRead(u32 *txb, u8 txl, u32 *rxb, u8 rxl) @@ -141,8 +139,8 @@ void CODEC_Get(CODEC_Input *input) cpad_y = ((raw_data[0x14] << 8 | raw_data[0x15]) & 0xFFF) - 2048; // X axis is inverted - input->cpad_x = (abs(cpad_x) > CPAD_THRESH) ? -cpad_x / CPAD_FACTOR : 0; - input->cpad_y = (abs(cpad_y) > CPAD_THRESH) ? cpad_y / CPAD_FACTOR : 0; + input->cpad_x = (abs(cpad_x) > CPAD_THRESH) ? -cpad_x : 0; + input->cpad_y = (abs(cpad_y) > CPAD_THRESH) ? cpad_y : 0; ts_pressed = !(raw_data[0] & BIT(4)); if (ts_pressed) { diff --git a/arm11/source/hw/nvram.c b/arm11/source/hw/nvram.c new file mode 100755 index 0000000..ca5664b --- /dev/null +++ b/arm11/source/hw/nvram.c @@ -0,0 +1,77 @@ +#include + +#include "hw/spi.h" +#include "hw/nvram.h" + +#define NVRAM_SPI_DEV 1 + +// returns manuf id, memory type and size +// size = (1 << id[2]) ? +// apparently unreliable on some Sanyo chips? +#define CMD_RDID 0x9F + +#define CMD_READ 0x03 +#define CMD_WREN 0x06 +#define CMD_WRDI 0x04 + +#define CMD_RDSR 0x05 + +#define CMD_DPD 0xB9 // deep power down +#define CMD_RDP 0xAB // release from deep power down + +static u32 NVRAM_SendStatusCommand(u32 cmd, u32 width) +{ + u32 ret; + SPI_XferInfo xfer[2]; + + xfer[0].buf = &cmd; + xfer[0].len = 1; + xfer[0].read = false; + + xfer[1].buf = &ret; + xfer[1].len = width; + xfer[1].read = true; + + ret = 0; + SPI_DoXfer(NVRAM_SPI_DEV, xfer, 2); + return ret; +} + +u32 NVRAM_Status(void) +{ + return NVRAM_SendStatusCommand(CMD_RDSR, 1); +} + +u32 NVRAM_ReadID(void) +{ + return NVRAM_SendStatusCommand(CMD_RDID, 3); +} + +void NVRAM_DeepStandby(void) +{ + NVRAM_SendStatusCommand(CMD_DPD, 0); +} + +void NVRAM_Wakeup(void) +{ + NVRAM_SendStatusCommand(CMD_RDP, 0); +} + +void NVRAM_Read(u32 address, u32 *buffer, u32 len) +{ + SPI_XferInfo xfer[2]; + u32 cmd; + + address &= BIT(24) - 1; + cmd = __builtin_bswap32(address) | CMD_READ; + + xfer[0].buf = &cmd; + xfer[0].len = 4; + xfer[0].read = false; + + xfer[1].buf = buffer; + xfer[1].len = len; + xfer[1].read = true; + + SPI_DoXfer(NVRAM_SPI_DEV, xfer, 2); +} diff --git a/arm11/source/hw/nvram.h b/arm11/source/hw/nvram.h new file mode 100755 index 0000000..a4de573 --- /dev/null +++ b/arm11/source/hw/nvram.h @@ -0,0 +1,16 @@ +#pragma once + +#include + +#include "hw/spi.h" + +#define NVRAM_SR_WIP BIT(0) // work in progress / busy +#define NVRAM_SR_WEL BIT(1) // write enable latch + +u32 NVRAM_Status(void); +u32 NVRAM_ReadID(void); + +void NVRAM_Read(u32 offset, u32 *buffer, u32 len); + +void NVRAM_DeepStandby(void); +void NVRAM_Wakeup(void); diff --git a/arm11/source/hw/spi.c b/arm11/source/hw/spi.c index ed064dd..0eef334 100755 --- a/arm11/source/hw/spi.c +++ b/arm11/source/hw/spi.c @@ -42,12 +42,12 @@ static struct { u32 bus; - u32 regcfg; + u32 reg; } SPI_Devices[] = { - {REG_SPI_BUS0, SPI_CONTROL_RATE(2) | SPI_CONTROL_CS(0)}, // device 0 - {REG_SPI_BUS0, SPI_CONTROL_RATE(0) | SPI_CONTROL_CS(1)}, + {REG_SPI_BUS0, SPI_CONTROL_RATE(2) | SPI_CONTROL_CS(0)}, + {REG_SPI_BUS0, SPI_CONTROL_RATE(0) | SPI_CONTROL_CS(1)}, // NVRAM {REG_SPI_BUS0, SPI_CONTROL_RATE(0) | SPI_CONTROL_CS(2)}, - {REG_SPI_BUS1, SPI_CONTROL_RATE(5) | SPI_CONTROL_CS(0)}, + {REG_SPI_BUS1, SPI_CONTROL_RATE(5) | SPI_CONTROL_CS(0)}, // CODEC // TODO: complete this table }; @@ -74,6 +74,8 @@ static void SPI_SingleXfer(u32 reg, u32 bus, u32 *buffer, u32 len, bool read) REG_SPI(bus, REG_SPI_CONTROL) = reg | (read ? SPI_DIRECTION_READ : SPI_DIRECTION_WRITE) | SPI_CONTROL_START; + SPI_WaitFIFO(bus); + do { if ((pos % SPI_FIFO_WIDTH) == 0) SPI_WaitFIFO(bus); @@ -88,19 +90,21 @@ static void SPI_SingleXfer(u32 reg, u32 bus, u32 *buffer, u32 len, bool read) } while(pos < len); } -int SPI_DoXfer(u32 dev, SPI_XferInfo *xfers, u32 xfer_cnt) +int SPI_DoXfer(u32 dev, const SPI_XferInfo *xfers, u32 xfer_cnt) { - u32 bus; - u32 dev_reg; + u32 bus, reg; bus = SPI_Devices[dev].bus; - dev_reg = SPI_Devices[dev].regcfg; + reg = SPI_Devices[dev].reg; for (u32 i = 0; i < xfer_cnt; i++) { - SPI_XferInfo *xfer = &xfers[i]; + const SPI_XferInfo *xfer = &xfers[i]; + + if (!xfer->buf || !xfer->len) + continue; SPI_WaitBusy(bus); - SPI_SingleXfer(dev_reg, bus, xfer->buf, xfer->len, xfer->read); + SPI_SingleXfer(reg, bus, xfer->buf, xfer->len, xfer->read); } SPI_WaitBusy(bus); diff --git a/arm11/source/hw/spi.h b/arm11/source/hw/spi.h index b2dc6fb..ee80a8f 100755 --- a/arm11/source/hw/spi.h +++ b/arm11/source/hw/spi.h @@ -4,10 +4,10 @@ typedef struct { u32 *buf; - u8 len; + u32 len; bool read; } SPI_XferInfo; -int SPI_DoXfer(u32 dev, SPI_XferInfo *xfer, u32 xfer_cnt); +int SPI_DoXfer(u32 dev, const SPI_XferInfo *xfer, u32 xfer_cnt); void SPI_Init(void); diff --git a/arm11/source/main.c b/arm11/source/main.c index 47dbf7c..a4d30fb 100644 --- a/arm11/source/main.c +++ b/arm11/source/main.c @@ -10,6 +10,7 @@ #include "hw/gpulcd.h" #include "hw/i2c.h" #include "hw/mcu.h" +#include "hw/nvram.h" #include "system/sys.h" @@ -50,7 +51,7 @@ void PXI_RX_Handler(u32 __attribute__((unused)) irqn) cmd = msg & 0xFFFF; argc = msg >> 16; - if (argc > PXI_MAX_ARGS) { + if (argc >= PXI_MAX_ARGS) { PXI_Send(0xFFFFFFFF); return; } @@ -74,6 +75,7 @@ void PXI_RX_Handler(u32 __attribute__((unused)) irqn) case PXI_I2C_READ: { + ARM_InvDC_Range((void*)args[2], args[3]); ret = I2C_readRegBuf(args[0], args[1], (u8*)args[2], args[3]); ARM_WbDC_Range((void*)args[2], args[3]); ARM_DMB(); @@ -88,6 +90,16 @@ void PXI_RX_Handler(u32 __attribute__((unused)) irqn) break; } + case PXI_NVRAM_READ: + { + ARM_InvDC_Range((void*)args[1], args[2]); + NVRAM_Read(args[0], (u32*)args[1], args[2]); + ARM_WbDC_Range((void*)args[1], args[2]); + ARM_DMB(); + ret = 0; + break; + } + /* New CMD template: case CMD_ID: { diff --git a/arm11/source/system/sys.c b/arm11/source/system/sys.c index e75e2c4..49141c5 100755 --- a/arm11/source/system/sys.c +++ b/arm11/source/system/sys.c @@ -85,8 +85,10 @@ void SYS_CoreZeroInit(void) // Initialize peripherals PXI_Reset(); + I2C_init(); MCU_Init(); + SPI_Init(); CODEC_Init(); diff --git a/arm9/source/common/hid.c b/arm9/source/common/hid.c index 1bb6516..0eecaa4 100644 --- a/arm9/source/common/hid.c +++ b/arm9/source/common/hid.c @@ -23,8 +23,14 @@ u32 HID_ReadRawTouchState(void) return ARM_GetSHMEM()->hid_state >> 32; } -static u32 ts_x_org, ts_y_org; -static fixp_t ts_x_mult, ts_y_mult; +// ts_mult indicates a scalar for each axis +// if |ts_mult| > 1 => point must be "scaled out" +// if |ts_mult| < 1 => point must be "scaled in" +// if ts_mult < 0 => axis is inverted +static fixp_t ts_mult[2]; + +// ts_org indicates the coordinate system origin +static u32 ts_org[2]; void HID_ReadTouchState(u16 *x, u16 *y) { u32 ts; @@ -34,20 +40,20 @@ void HID_ReadTouchState(u16 *x, u16 *y) tx = INT_TO_FIXP(HID_RAW_TX(ts) - HID_TOUCH_MIDPOINT); ty = INT_TO_FIXP(HID_RAW_TY(ts) - HID_TOUCH_MIDPOINT); - *x = FIXP_TO_INT(fixp_round(fixp_product(tx, ts_x_mult))) + ts_x_org; - *y = FIXP_TO_INT(fixp_round(fixp_product(ty, ts_y_mult))) + ts_y_org; + *x = FIXP_TO_INT(fixp_round(fixp_product(tx, ts_mult[0]))) + ts_org[0]; + *y = FIXP_TO_INT(fixp_round(fixp_product(ty, ts_mult[1]))) + ts_org[1]; } bool HID_SetCalibrationData(const HID_CalibrationData *calibs, int point_cnt, u32 screen_w, u32 screen_h) { - int x_mid, y_mid; + int mid_x, mid_y; fixp_t avg_x, avg_y; - if (!screen_w || !screen_h || point_cnt <= 0) + if (!screen_w || !screen_h || point_cnt <= 0 || point_cnt > 7) return false; - x_mid = screen_w / 2; - y_mid = screen_h / 2; + mid_x = screen_w / 2; + mid_y = screen_h / 2; avg_x = 0; avg_y = 0; @@ -58,8 +64,8 @@ bool HID_SetCalibrationData(const HID_CalibrationData *calibs, int point_cnt, u3 // translate the [0, screen_w] x [0, screen_h] system // to [-screen_w/2, screen_w/2] x [-screen_h/2, screen_h/2] - screen_x = INT_TO_FIXP(data->screen_x - x_mid); - screen_y = INT_TO_FIXP(data->screen_y - y_mid); + screen_x = INT_TO_FIXP(data->screen_x - mid_x); + screen_y = INT_TO_FIXP(data->screen_y - mid_y); // same thing for raw touchscreen data touch_x = INT_TO_FIXP(HID_RAW_TX(data->ts_raw) - HID_TOUCH_MIDPOINT); @@ -69,15 +75,16 @@ bool HID_SetCalibrationData(const HID_CalibrationData *calibs, int point_cnt, u3 if (!screen_x || !screen_y || !touch_x || !touch_y) return false; - avg_x += fixp_quotient(screen_x, touch_x); - avg_y += fixp_quotient(screen_y, touch_y); + // prevent integer overflows by dividing in this step + avg_x += fixp_quotient(screen_x, touch_x * point_cnt); + avg_y += fixp_quotient(screen_y, touch_y * point_cnt); } - ts_x_mult = avg_x / point_cnt; - ts_y_mult = avg_y / point_cnt; - - ts_x_org = x_mid; - ts_y_org = y_mid; + // set state variables + ts_mult[0] = avg_x; + ts_mult[1] = avg_y; + ts_org[0] = mid_x; + ts_org[1] = mid_y; return true; } diff --git a/arm9/source/common/ui.c b/arm9/source/common/ui.c index 5d75fe1..3e3284f 100644 --- a/arm9/source/common/ui.c +++ b/arm9/source/common/ui.c @@ -1062,3 +1062,83 @@ bool ShowProgress(u64 current, u64 total, const char* opstr) return !CheckButton(BUTTON_B); } + +static void DrawSimpleCircle(unsigned char *screen, int x, int y, int color, int bgcolor) +{ + x -= GetFontWidth() / 2; + y -= GetFontHeight() / 2; + DrawCharacter(screen, 'O', x, y, color, bgcolor); +} + +bool ShowCalibrationDialog(void) +{ + int current_dot; + static const u32 dot_positions[][2] = { + {16, 16}, + {320 - 16, 240 - 16}, + {16, 240 - 16}, + {320 - 16, 16}, + }; + HID_CalibrationData calibrations[countof(dot_positions)]; + + ClearScreenF(true, true, COLOR_BLACK); + for (u32 i = 0; i < countof(dot_positions); i++) { + calibrations[i].screen_x = dot_positions[i][0]; + calibrations[i].screen_y = dot_positions[i][1]; + } + + current_dot = 0; + while(current_dot < countof(dot_positions)) { + for (int i = 0; i < current_dot; i++) + DrawSimpleCircle(BOT_SCREEN, dot_positions[i][0], dot_positions[i][1], COLOR_BRIGHTGREEN, COLOR_BLACK); + DrawSimpleCircle(BOT_SCREEN, dot_positions[current_dot][0], dot_positions[current_dot][1], COLOR_RED, COLOR_BLACK); + for (u32 i = current_dot+1; i < countof(dot_positions); i++) + DrawSimpleCircle(BOT_SCREEN, dot_positions[i][0], dot_positions[i][1], COLOR_WHITE, COLOR_BLACK); + + while(HID_ReadState()); + + while(1) { + u32 pressed = HID_ReadState(); + if (pressed & BUTTON_B) { + if (current_dot == 0) + return false; + current_dot--; + break; + } + + if (pressed & BUTTON_TOUCH) { + calibrations[current_dot].ts_raw = HID_ReadRawTouchState(); + current_dot++; + if (current_dot == countof(dot_positions)) { + return HID_SetCalibrationData(calibrations, countof(dot_positions), 320, 240); + } + break; + } + } + } + + return true; +} + +void ShowTouchPlayground(void) +{ + ClearScreenF(true, true, COLOR_BLACK); + + while(1) { + u16 tx, ty; + u32 pressed = HID_ReadState(); + + if (pressed & BUTTON_TOUCH) { + HID_ReadTouchState(&tx, &ty); + if (tx < 320 && ty < 240) + DrawRectangle(BOT_SCREEN, tx, ty, 1, 1, COLOR_BRIGHTYELLOW); + } else { + tx = ty = 0; + } + + DrawStringF(TOP_SCREEN, 16, 16, COLOR_WHITE, COLOR_BLACK, "Current touchscreen coordinates: %d, %d", tx, ty); + if (pressed & BUTTON_B) + return; + } + +} diff --git a/arm9/source/common/ui.h b/arm9/source/common/ui.h index 6cc36e8..5ca8bc6 100644 --- a/arm9/source/common/ui.h +++ b/arm9/source/common/ui.h @@ -82,3 +82,6 @@ u64 ShowNumberPrompt(u64 start_val, const char *format, ...); bool ShowDataPrompt(u8* data, u32* size, const char *format, ...); bool ShowRtcSetterPrompt(void* time, const char *format, ...); bool ShowProgress(u64 current, u64 total, const char* opstr); + +bool ShowCalibrationDialog(void); +void ShowTouchPlayground(void); diff --git a/arm9/source/godmode.c b/arm9/source/godmode.c index 5367f46..a65c61b 100644 --- a/arm9/source/godmode.c +++ b/arm9/source/godmode.c @@ -2506,11 +2506,15 @@ u32 GodMode(int entrypoint) { const char* optionstr[8]; const char* buttonstr = (pad_state & BUTTON_HOME) ? "HOME" : "POWER"; u32 n_opt = 0; + int calib = ++n_opt; + int playground = ++n_opt; int poweroff = ++n_opt; int reboot = ++n_opt; int scripts = ++n_opt; int payloads = ++n_opt; int more = ++n_opt; + if (calib > 0) optionstr[calib - 1] = "Calibrate touchscreen"; + if (playground > 0) optionstr[playground - 1] = "Test touchscreen"; if (poweroff > 0) optionstr[poweroff - 1] = "Poweroff system"; if (reboot > 0) optionstr[reboot - 1] = "Reboot system"; if (scripts > 0) optionstr[scripts - 1] = "Scripts..."; @@ -2531,6 +2535,10 @@ u32 GodMode(int entrypoint) { ClearScreenF(true, true, COLOR_STD_BG); break; } + } else if (user_select == calib) { + ShowPrompt(true, "CALIB: %d", ShowCalibrationDialog()); + } else if (user_select == playground) { + ShowTouchPlayground(); } else if (user_select == payloads) { if (!CheckSupportDir(PAYLOADS_DIR)) ShowPrompt(false, "Payloads directory not found.\n(default path: 0:/gm9/" PAYLOADS_DIR ")"); else if (FileSelectorSupport(loadpath, "HOME payloads... menu.\nSelect payload:", PAYLOADS_DIR, "*.firm")) diff --git a/arm9/source/system/spiflash.c b/arm9/source/system/spiflash.c deleted file mode 100644 index 3c51f92..0000000 --- a/arm9/source/system/spiflash.c +++ /dev/null @@ -1,89 +0,0 @@ -/* - * 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 . - */ - -#include "common.h" -#include "spiflash.h" - - -#define SPI_REGS_BUS2_BASE (0x10000000 + 0x100000 + 0x60000) -#define REG_SPI_BUS2_CNT *((vu16*)(SPI_REGS_BUS2_BASE + 0x00)) -#define REG_SPI_BUS2_DATA *((vu8* )(SPI_REGS_BUS2_BASE + 0x02)) - - - -static void spi_busy_wait() -{ - while(REG_SPI_BUS2_CNT & 0x80); -} - -static void spi_put_byte(u8 data) -{ - REG_SPI_BUS2_DATA = data; - spi_busy_wait(); -} - -static u8 spi_receive_byte() -{ - // clock out a dummy byte - REG_SPI_BUS2_DATA = 0x00; - spi_busy_wait(); - return REG_SPI_BUS2_DATA; -} - -// select spiflash if select=true, deselect otherwise -static void spiflash_select(bool select) -{ - // select device 1, enable SPI bus - REG_SPI_BUS2_CNT = 0x8100 | (select << 11); -} - -bool spiflash_get_status() -{ - u8 resp; - - spi_busy_wait(); - spiflash_select(1); - spi_put_byte(SPIFLASH_CMD_RDSR); - spiflash_select(0); - resp = spi_receive_byte(); - - if(resp & 1) return false; - return true; -} - -void spiflash_read(u32 offset, u32 size, u8 *buf) -{ - spi_busy_wait(); - spiflash_select(1); - spi_put_byte(SPIFLASH_CMD_READ); - - // write addr (24-bit, msb first) - for(int i=0; i<3; i++) - { - offset <<= 8; - spi_put_byte((offset >> 24) & 0xFF); - } - - // read bytes - for(u32 i=0; i