mirror of
https://github.com/d0k3/GodMode9.git
synced 2026-02-25 08:24:39 +00:00
126 lines
2.8 KiB
C
Executable File
126 lines
2.8 KiB
C
Executable File
#include "common.h"
|
|
#include "arm.h"
|
|
#include "pxi.h"
|
|
#include "shmem.h"
|
|
|
|
#include "ui.h"
|
|
|
|
typedef struct {
|
|
u32 id;
|
|
u32 size;
|
|
const char *name;
|
|
} spiflash_chip_t;
|
|
|
|
/**
|
|
* List of known SPI flash chips available in the NDS/3DS family of systems.
|
|
* If it doesn't match any of these, it should be safe to assume we have a 128k flash chip.
|
|
* Obtained from gbatek (https://problemkaputt.de/gbatek-ds-firmware-serial-flash-memory.htm) as of 1/21/26.
|
|
*/
|
|
static const spiflash_chip_t spiflash_known_chips[] = {
|
|
{ 0x124020, 256u << 10, "ST M45PE20" },
|
|
{ 0x125020, 256u << 10, "ST M35PE20" },
|
|
{ 0x138020, 512u << 10, "ST M25PE40" },
|
|
{ 0x114020, 128u << 10, "ST 45PE10V6" },
|
|
{ 0x0C5820, 128u << 10, "5A32 (4k)" },
|
|
{ 0x0C6262, 128u << 10, "32B/3XH (4k)" },
|
|
};
|
|
|
|
static const spiflash_chip_t *spiflash_initialize(void) {
|
|
static spiflash_chip_t spiflash_chip = {
|
|
.id = 0xFFFFFFFF, /* filled at runtime */
|
|
.size = 128u << 10,
|
|
.name = "Unknown"
|
|
};
|
|
if (spiflash_chip.id != 0xFFFFFFFF)
|
|
return &spiflash_chip;
|
|
|
|
u32 id = PXI_DoCMD(PXICMD_NVRAM_ID, NULL, 0);
|
|
|
|
spiflash_chip.id = id;
|
|
|
|
for (unsigned i = 0; i < countof(spiflash_known_chips); i++) {
|
|
if (id == spiflash_known_chips[i].id) {
|
|
spiflash_chip = spiflash_known_chips[i];
|
|
break;
|
|
}
|
|
}
|
|
|
|
return &spiflash_chip;
|
|
}
|
|
|
|
u32 spiflash_size(void)
|
|
{
|
|
return spiflash_initialize()->size;
|
|
}
|
|
|
|
bool spiflash_read(u32 offset, u32 size, u8 *buf)
|
|
{
|
|
u32 total_size = spiflash_size();
|
|
if ((offset >= total_size) ||
|
|
(size > total_size) ||
|
|
(offset + size > total_size))
|
|
return false;
|
|
|
|
u32 *const dataBuffer = ARM_GetSHMEM()->dataBuffer.w;
|
|
u32 args[2];
|
|
|
|
while(size > 0) {
|
|
u32 blksz = min(size, SHMEM_BUFFER_SIZE);
|
|
|
|
args[0] = offset;
|
|
args[1] = blksz;
|
|
|
|
int result = PXI_DoCMD(PXICMD_NVRAM_READ, args, 2);
|
|
if (result != 0) {
|
|
ShowPrompt(false, "SPI flash read failed at offset\n0x%08lx size 0x%08lx (%d)", offset, blksz, result);
|
|
return false;
|
|
}
|
|
|
|
ARM_InvDC_Range(dataBuffer, blksz);
|
|
ARM_DSB();
|
|
|
|
memcpy(buf, dataBuffer, blksz);
|
|
|
|
buf += blksz;
|
|
size -= blksz;
|
|
offset += blksz;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
bool spiflash_write(u32 offset, u32 size, const u8 *buf)
|
|
{
|
|
u32 total_size = spiflash_size();
|
|
if ((offset >= total_size) ||
|
|
(size > total_size) ||
|
|
(offset + size > total_size))
|
|
return false;
|
|
|
|
u32 *const dataBuffer = ARM_GetSHMEM()->dataBuffer.w;
|
|
u32 args[2];
|
|
|
|
while(size > 0) {
|
|
u32 blksz = min(size, SHMEM_BUFFER_SIZE);
|
|
|
|
args[0] = offset;
|
|
args[1] = blksz;
|
|
|
|
memcpy(dataBuffer, buf, blksz);
|
|
ARM_WbInvDC_Range(dataBuffer, blksz);
|
|
ARM_DSB();
|
|
|
|
int result = PXI_DoCMD(PXICMD_NVRAM_WRITE, args, 2);
|
|
if (result != 0) {
|
|
ShowPrompt(false, "SPI flash write failed at offset\n0x%08lx size 0x%08lx (%d)", offset, blksz, result);
|
|
return false;
|
|
}
|
|
|
|
buf += blksz;
|
|
size -= blksz;
|
|
offset += blksz;
|
|
}
|
|
|
|
return true;
|
|
}
|