- 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
This commit is contained in:
Wolfvak 2019-04-22 16:24:45 -03:00 committed by d0k3
parent b52bf3b9a5
commit 70757e3385
15 changed files with 274 additions and 153 deletions

View File

@ -1,21 +1,18 @@
#include <arm.h> #include <arm.h>
.arm .arm
.align 2 .align 3
.section .vector, "ax" .section .vector, "ax"
vectors: vectors:
ldr pc, =XRQ_Reset b XRQ_Reset @ RESET
ldr pc, =XRQ_Reset b XRQ_Reset @ UNDEFINED
ldr pc, =XRQ_Reset b XRQ_Reset @ SVC
ldr pc, =XRQ_Reset b XRQ_Reset @ PREFETCH ABORT
ldr pc, =XRQ_Reset b XRQ_Reset @ DATA ABORT
b . @ RESERVED b XRQ_Reset @ RESERVED
ldr pc, =XRQ_IRQ b XRQ_IRQ @ IRQ
ldr pc, =XRQ_Reset b XRQ_Reset @ FIQ
.pool
.section .text.XRQS, "ax"
XRQ_Reset: XRQ_Reset:
mov r0, #0x18000000 mov r0, #0x18000000
@ -24,12 +21,9 @@ XRQ_Reset:
1: 1:
cmp r0, r1 cmp r0, r1
strne r2, [r0], #4 strne r2, [r0], #4
bne 1b moveq r0, #0x18000000
2: b 1b
wfi
b 2b
.global XRQ_IRQ
XRQ_IRQ: XRQ_IRQ:
sub lr, lr, #4 @ Fix return address sub lr, lr, #4 @ Fix return address
srsfd sp!, #SR_SVC_MODE @ Store IRQ mode LR and SPSR on the SVC stack 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 and r4, sp, #7 @ Fix SP to be 8byte aligned
sub sp, sp, r4 sub sp, sp, r4
bl GIC_MainHandler mov lr, pc
ldr pc, =GIC_MainHandler
add sp, sp, r4 add sp, sp, r4

View File

@ -18,11 +18,9 @@
#include "hw/codec.h" #include "hw/codec.h"
#include "hw/spi.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_THRESH (150)
#define CPAD_FACTOR (150)
/* SPI stuff */ /* SPI stuff */
static void CODEC_WriteRead(u32 *txb, u8 txl, u32 *rxb, u8 rxl) 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; cpad_y = ((raw_data[0x14] << 8 | raw_data[0x15]) & 0xFFF) - 2048;
// X axis is inverted // X axis is inverted
input->cpad_x = (abs(cpad_x) > CPAD_THRESH) ? -cpad_x / CPAD_FACTOR : 0; input->cpad_x = (abs(cpad_x) > CPAD_THRESH) ? -cpad_x : 0;
input->cpad_y = (abs(cpad_y) > CPAD_THRESH) ? cpad_y / CPAD_FACTOR : 0; input->cpad_y = (abs(cpad_y) > CPAD_THRESH) ? cpad_y : 0;
ts_pressed = !(raw_data[0] & BIT(4)); ts_pressed = !(raw_data[0] & BIT(4));
if (ts_pressed) { if (ts_pressed) {

77
arm11/source/hw/nvram.c Executable file
View File

@ -0,0 +1,77 @@
#include <types.h>
#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);
}

16
arm11/source/hw/nvram.h Executable file
View File

@ -0,0 +1,16 @@
#pragma once
#include <types.h>
#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);

View File

@ -42,12 +42,12 @@
static struct { static struct {
u32 bus; u32 bus;
u32 regcfg; u32 reg;
} SPI_Devices[] = { } SPI_Devices[] = {
{REG_SPI_BUS0, SPI_CONTROL_RATE(2) | SPI_CONTROL_CS(0)}, // device 0 {REG_SPI_BUS0, SPI_CONTROL_RATE(2) | SPI_CONTROL_CS(0)},
{REG_SPI_BUS0, SPI_CONTROL_RATE(0) | SPI_CONTROL_CS(1)}, {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_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 // 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 | REG_SPI(bus, REG_SPI_CONTROL) = reg |
(read ? SPI_DIRECTION_READ : SPI_DIRECTION_WRITE) | SPI_CONTROL_START; (read ? SPI_DIRECTION_READ : SPI_DIRECTION_WRITE) | SPI_CONTROL_START;
SPI_WaitFIFO(bus);
do { do {
if ((pos % SPI_FIFO_WIDTH) == 0) if ((pos % SPI_FIFO_WIDTH) == 0)
SPI_WaitFIFO(bus); SPI_WaitFIFO(bus);
@ -88,19 +90,21 @@ static void SPI_SingleXfer(u32 reg, u32 bus, u32 *buffer, u32 len, bool read)
} while(pos < len); } 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 bus, reg;
u32 dev_reg;
bus = SPI_Devices[dev].bus; bus = SPI_Devices[dev].bus;
dev_reg = SPI_Devices[dev].regcfg; reg = SPI_Devices[dev].reg;
for (u32 i = 0; i < xfer_cnt; i++) { 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_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); SPI_WaitBusy(bus);

View File

@ -4,10 +4,10 @@
typedef struct { typedef struct {
u32 *buf; u32 *buf;
u8 len; u32 len;
bool read; bool read;
} SPI_XferInfo; } 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); void SPI_Init(void);

View File

@ -10,6 +10,7 @@
#include "hw/gpulcd.h" #include "hw/gpulcd.h"
#include "hw/i2c.h" #include "hw/i2c.h"
#include "hw/mcu.h" #include "hw/mcu.h"
#include "hw/nvram.h"
#include "system/sys.h" #include "system/sys.h"
@ -50,7 +51,7 @@ void PXI_RX_Handler(u32 __attribute__((unused)) irqn)
cmd = msg & 0xFFFF; cmd = msg & 0xFFFF;
argc = msg >> 16; argc = msg >> 16;
if (argc > PXI_MAX_ARGS) { if (argc >= PXI_MAX_ARGS) {
PXI_Send(0xFFFFFFFF); PXI_Send(0xFFFFFFFF);
return; return;
} }
@ -74,6 +75,7 @@ void PXI_RX_Handler(u32 __attribute__((unused)) irqn)
case PXI_I2C_READ: case PXI_I2C_READ:
{ {
ARM_InvDC_Range((void*)args[2], args[3]);
ret = I2C_readRegBuf(args[0], args[1], (u8*)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_WbDC_Range((void*)args[2], args[3]);
ARM_DMB(); ARM_DMB();
@ -88,6 +90,16 @@ void PXI_RX_Handler(u32 __attribute__((unused)) irqn)
break; 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: /* New CMD template:
case CMD_ID: case CMD_ID:
{ {

View File

@ -85,8 +85,10 @@ void SYS_CoreZeroInit(void)
// Initialize peripherals // Initialize peripherals
PXI_Reset(); PXI_Reset();
I2C_init(); I2C_init();
MCU_Init(); MCU_Init();
SPI_Init(); SPI_Init();
CODEC_Init(); CODEC_Init();

View File

@ -23,8 +23,14 @@ u32 HID_ReadRawTouchState(void)
return ARM_GetSHMEM()->hid_state >> 32; return ARM_GetSHMEM()->hid_state >> 32;
} }
static u32 ts_x_org, ts_y_org; // ts_mult indicates a scalar for each axis
static fixp_t ts_x_mult, ts_y_mult; // 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) void HID_ReadTouchState(u16 *x, u16 *y)
{ {
u32 ts; u32 ts;
@ -34,20 +40,20 @@ void HID_ReadTouchState(u16 *x, u16 *y)
tx = INT_TO_FIXP(HID_RAW_TX(ts) - HID_TOUCH_MIDPOINT); tx = INT_TO_FIXP(HID_RAW_TX(ts) - HID_TOUCH_MIDPOINT);
ty = INT_TO_FIXP(HID_RAW_TY(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; *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_y_mult))) + ts_y_org; *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) 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; 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; return false;
x_mid = screen_w / 2; mid_x = screen_w / 2;
y_mid = screen_h / 2; mid_y = screen_h / 2;
avg_x = 0; avg_x = 0;
avg_y = 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 // translate the [0, screen_w] x [0, screen_h] system
// to [-screen_w/2, screen_w/2] x [-screen_h/2, screen_h/2] // 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_x = INT_TO_FIXP(data->screen_x - mid_x);
screen_y = INT_TO_FIXP(data->screen_y - y_mid); screen_y = INT_TO_FIXP(data->screen_y - mid_y);
// same thing for raw touchscreen data // same thing for raw touchscreen data
touch_x = INT_TO_FIXP(HID_RAW_TX(data->ts_raw) - HID_TOUCH_MIDPOINT); 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) if (!screen_x || !screen_y || !touch_x || !touch_y)
return false; return false;
avg_x += fixp_quotient(screen_x, touch_x); // prevent integer overflows by dividing in this step
avg_y += fixp_quotient(screen_y, touch_y); 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; // set state variables
ts_y_mult = avg_y / point_cnt; ts_mult[0] = avg_x;
ts_mult[1] = avg_y;
ts_x_org = x_mid; ts_org[0] = mid_x;
ts_y_org = y_mid; ts_org[1] = mid_y;
return true; return true;
} }

View File

@ -1062,3 +1062,83 @@ bool ShowProgress(u64 current, u64 total, const char* opstr)
return !CheckButton(BUTTON_B); 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;
}
}

View File

@ -82,3 +82,6 @@ u64 ShowNumberPrompt(u64 start_val, const char *format, ...);
bool ShowDataPrompt(u8* data, u32* size, const char *format, ...); bool ShowDataPrompt(u8* data, u32* size, const char *format, ...);
bool ShowRtcSetterPrompt(void* time, const char *format, ...); bool ShowRtcSetterPrompt(void* time, const char *format, ...);
bool ShowProgress(u64 current, u64 total, const char* opstr); bool ShowProgress(u64 current, u64 total, const char* opstr);
bool ShowCalibrationDialog(void);
void ShowTouchPlayground(void);

View File

@ -2506,11 +2506,15 @@ u32 GodMode(int entrypoint) {
const char* optionstr[8]; const char* optionstr[8];
const char* buttonstr = (pad_state & BUTTON_HOME) ? "HOME" : "POWER"; const char* buttonstr = (pad_state & BUTTON_HOME) ? "HOME" : "POWER";
u32 n_opt = 0; u32 n_opt = 0;
int calib = ++n_opt;
int playground = ++n_opt;
int poweroff = ++n_opt; int poweroff = ++n_opt;
int reboot = ++n_opt; int reboot = ++n_opt;
int scripts = ++n_opt; int scripts = ++n_opt;
int payloads = ++n_opt; int payloads = ++n_opt;
int more = ++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 (poweroff > 0) optionstr[poweroff - 1] = "Poweroff system";
if (reboot > 0) optionstr[reboot - 1] = "Reboot system"; if (reboot > 0) optionstr[reboot - 1] = "Reboot system";
if (scripts > 0) optionstr[scripts - 1] = "Scripts..."; if (scripts > 0) optionstr[scripts - 1] = "Scripts...";
@ -2531,6 +2535,10 @@ u32 GodMode(int entrypoint) {
ClearScreenF(true, true, COLOR_STD_BG); ClearScreenF(true, true, COLOR_STD_BG);
break; break;
} }
} else if (user_select == calib) {
ShowPrompt(true, "CALIB: %d", ShowCalibrationDialog());
} else if (user_select == playground) {
ShowTouchPlayground();
} else if (user_select == payloads) { } else if (user_select == payloads) {
if (!CheckSupportDir(PAYLOADS_DIR)) ShowPrompt(false, "Payloads directory not found.\n(default path: 0:/gm9/" PAYLOADS_DIR ")"); 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")) else if (FileSelectorSupport(loadpath, "HOME payloads... menu.\nSelect payload:", PAYLOADS_DIR, "*.firm"))

View File

@ -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 <http://www.gnu.org/licenses/>.
*/
#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<size; i++)
buf[i] = spi_receive_byte();
// end of read
spiflash_select(0);
spi_receive_byte();
}

View File

@ -1,5 +1,4 @@
#pragma once #pragma once
/* /*
* This file is part of fastboot 3DS * This file is part of fastboot 3DS
* Copyright (C) 2017 derrek, profi200 * Copyright (C) 2017 derrek, profi200
@ -20,13 +19,22 @@
#include "common.h" #include "common.h"
#include "arm.h"
#include "pxi.h"
#define NVRAM_SIZE 0x20000 // 1 Mbit (128kiB) #define NVRAM_SIZE 0x20000 // 1 Mbit (128kiB)
#define SPIFLASH_CMD_RDSR (0x05)
#define SPIFLASH_CMD_READ (0x03)
// true if spiflash is installed, false otherwise // true if spiflash is installed, false otherwise
bool spiflash_get_status(); static inline bool spiflash_get_status(void)
void spiflash_read(u32 offset, u32 size, u8 *buf); { // there should probably be a command for this...
return true;
}
static inline void spiflash_read(u32 offset, u32 size, u8 *buf)
{
u32 args[] = {offset, (u32)buf, size};
ARM_WbDC_Range(buf, size);
ARM_DSB();
PXI_DoCMD(PXI_NVRAM_READ, args, 3);
ARM_InvDC_Range(buf, size);
}

View File

@ -20,6 +20,8 @@ enum {
PXI_I2C_READ, PXI_I2C_READ,
PXI_I2C_WRITE, PXI_I2C_WRITE,
PXI_NVRAM_READ,
}; };
/* /*
@ -32,9 +34,7 @@ enum {
}; };
#define PXI_FIFO_LEN (16) #define PXI_FIFO_LEN (16)
#define PXI_MAX_ARGS (32) #define PXI_MAX_ARGS (64)
#define PXI_INIT_MAGIC (0xDD)
#define PXI_SYNC_RECV ((vu8*)(PXI_BASE + 0x00)) #define PXI_SYNC_RECV ((vu8*)(PXI_BASE + 0x00))
#define PXI_SYNC_SEND ((vu8*)(PXI_BASE + 0x01)) #define PXI_SYNC_SEND ((vu8*)(PXI_BASE + 0x01))