194 lines
4.3 KiB
C
194 lines
4.3 KiB
C
|
#include "gba/gba.h"
|
||
|
#include "gba/flash_internal.h"
|
||
|
|
||
|
const u16 mxMaxTime[] =
|
||
|
{
|
||
|
10, 65469, TIMER_ENABLE | TIMER_INTR_ENABLE | TIMER_256CLK,
|
||
|
10, 65469, TIMER_ENABLE | TIMER_INTR_ENABLE | TIMER_256CLK,
|
||
|
2000, 65469, TIMER_ENABLE | TIMER_INTR_ENABLE | TIMER_256CLK,
|
||
|
2000, 65469, TIMER_ENABLE | TIMER_INTR_ENABLE | TIMER_256CLK,
|
||
|
};
|
||
|
|
||
|
const struct FlashSetupInfo MX29L010 =
|
||
|
{
|
||
|
ProgramFlashByte_MX,
|
||
|
ProgramFlashSector_MX,
|
||
|
EraseFlashChip_MX,
|
||
|
EraseFlashSector_MX,
|
||
|
WaitForFlashWrite_Common,
|
||
|
mxMaxTime,
|
||
|
{
|
||
|
131072, // ROM size
|
||
|
{
|
||
|
4096, // sector size
|
||
|
12, // bit shift to multiply by sector size (4096 == 1 << 12)
|
||
|
32, // number of sectors
|
||
|
0 // appears to be unused
|
||
|
},
|
||
|
{ 3, 1 }, // wait state setup data
|
||
|
{ { 0xC2, 0x09 } } // ID
|
||
|
}
|
||
|
};
|
||
|
|
||
|
const struct FlashSetupInfo DefaultFlash =
|
||
|
{
|
||
|
ProgramFlashByte_MX,
|
||
|
ProgramFlashSector_MX,
|
||
|
EraseFlashChip_MX,
|
||
|
EraseFlashSector_MX,
|
||
|
WaitForFlashWrite_Common,
|
||
|
mxMaxTime,
|
||
|
{
|
||
|
131072, // ROM size
|
||
|
{
|
||
|
4096, // sector size
|
||
|
12, // bit shift to multiply by sector size (4096 == 1 << 12)
|
||
|
32, // number of sectors
|
||
|
0 // appears to be unused
|
||
|
},
|
||
|
{ 3, 1 }, // wait state setup data
|
||
|
{ { 0x00, 0x00 } } // ID of 0
|
||
|
}
|
||
|
};
|
||
|
|
||
|
u16 EraseFlashChip_MX(void)
|
||
|
{
|
||
|
u16 result;
|
||
|
u16 readFlash1Buffer[0x20];
|
||
|
|
||
|
REG_WAITCNT = (REG_WAITCNT & ~WAITCNT_SRAM_MASK) | gFlash->wait[0];
|
||
|
|
||
|
FLASH_WRITE(0x5555, 0xAA);
|
||
|
FLASH_WRITE(0x2AAA, 0x55);
|
||
|
FLASH_WRITE(0x5555, 0x80);
|
||
|
FLASH_WRITE(0x5555, 0xAA);
|
||
|
FLASH_WRITE(0x2AAA, 0x55);
|
||
|
FLASH_WRITE(0x5555, 0x10);
|
||
|
|
||
|
SetReadFlash1(readFlash1Buffer);
|
||
|
|
||
|
result = WaitForFlashWrite(3, FLASH_BASE, 0xFF);
|
||
|
|
||
|
REG_WAITCNT = (REG_WAITCNT & ~WAITCNT_SRAM_MASK) | WAITCNT_SRAM_8;
|
||
|
|
||
|
return result;
|
||
|
}
|
||
|
|
||
|
u16 EraseFlashSector_MX(u16 sectorNum)
|
||
|
{
|
||
|
u16 numTries;
|
||
|
u16 result;
|
||
|
u8 *addr;
|
||
|
u16 readFlash1Buffer[0x20];
|
||
|
|
||
|
if (sectorNum >= gFlash->sector.count)
|
||
|
return 0x80FF;
|
||
|
|
||
|
SwitchFlashBank(sectorNum / SECTORS_PER_BANK);
|
||
|
sectorNum %= SECTORS_PER_BANK;
|
||
|
|
||
|
numTries = 0;
|
||
|
|
||
|
try_erase:
|
||
|
REG_WAITCNT = (REG_WAITCNT & ~WAITCNT_SRAM_MASK) | gFlash->wait[0];
|
||
|
|
||
|
addr = FLASH_BASE + (sectorNum << gFlash->sector.shift);
|
||
|
|
||
|
FLASH_WRITE(0x5555, 0xAA);
|
||
|
FLASH_WRITE(0x2AAA, 0x55);
|
||
|
FLASH_WRITE(0x5555, 0x80);
|
||
|
FLASH_WRITE(0x5555, 0xAA);
|
||
|
FLASH_WRITE(0x2AAA, 0x55);
|
||
|
*addr = 0x30;
|
||
|
|
||
|
SetReadFlash1(readFlash1Buffer);
|
||
|
|
||
|
result = WaitForFlashWrite(2, addr, 0xFF);
|
||
|
|
||
|
if (!(result & 0xA000) || numTries > 3)
|
||
|
goto done;
|
||
|
|
||
|
numTries++;
|
||
|
|
||
|
goto try_erase;
|
||
|
|
||
|
done:
|
||
|
REG_WAITCNT = (REG_WAITCNT & ~WAITCNT_SRAM_MASK) | WAITCNT_SRAM_8;
|
||
|
|
||
|
return result;
|
||
|
}
|
||
|
|
||
|
u16 ProgramFlashByte_MX(u16 sectorNum, u32 offset, u8 data)
|
||
|
{
|
||
|
u8 *addr;
|
||
|
u16 readFlash1Buffer[0x20];
|
||
|
|
||
|
if (offset >= gFlash->sector.size)
|
||
|
return 0x8000;
|
||
|
|
||
|
SwitchFlashBank(sectorNum / SECTORS_PER_BANK);
|
||
|
sectorNum %= SECTORS_PER_BANK;
|
||
|
|
||
|
addr = FLASH_BASE + (sectorNum << gFlash->sector.shift) + offset;
|
||
|
|
||
|
SetReadFlash1(readFlash1Buffer);
|
||
|
|
||
|
REG_WAITCNT = (REG_WAITCNT & ~WAITCNT_SRAM_MASK) | gFlash->wait[0];
|
||
|
|
||
|
FLASH_WRITE(0x5555, 0xAA);
|
||
|
FLASH_WRITE(0x2AAA, 0x55);
|
||
|
FLASH_WRITE(0x5555, 0xA0);
|
||
|
*addr = data;
|
||
|
|
||
|
return WaitForFlashWrite(1, addr, data);
|
||
|
}
|
||
|
|
||
|
static u16 ProgramByte(u8 *src, u8 *dest)
|
||
|
{
|
||
|
FLASH_WRITE(0x5555, 0xAA);
|
||
|
FLASH_WRITE(0x2AAA, 0x55);
|
||
|
FLASH_WRITE(0x5555, 0xA0);
|
||
|
*dest = *src;
|
||
|
|
||
|
return WaitForFlashWrite(1, dest, *src);
|
||
|
}
|
||
|
|
||
|
u16 ProgramFlashSector_MX(u16 sectorNum, u8 *src)
|
||
|
{
|
||
|
u16 result;
|
||
|
u8 *dest;
|
||
|
u16 readFlash1Buffer[0x20];
|
||
|
|
||
|
if (sectorNum >= gFlash->sector.count)
|
||
|
return 0x80FF;
|
||
|
|
||
|
result = EraseFlashSector_MX(sectorNum);
|
||
|
|
||
|
if (result != 0)
|
||
|
return result;
|
||
|
|
||
|
SwitchFlashBank(sectorNum / SECTORS_PER_BANK);
|
||
|
sectorNum %= SECTORS_PER_BANK;
|
||
|
|
||
|
SetReadFlash1(readFlash1Buffer);
|
||
|
|
||
|
REG_WAITCNT = (REG_WAITCNT & ~WAITCNT_SRAM_MASK) | gFlash->wait[0];
|
||
|
|
||
|
gFlashNumRemainingBytes = gFlash->sector.size;
|
||
|
dest = FLASH_BASE + (sectorNum << gFlash->sector.shift);
|
||
|
|
||
|
while (gFlashNumRemainingBytes > 0)
|
||
|
{
|
||
|
result = ProgramByte(src, dest);
|
||
|
|
||
|
if (result != 0)
|
||
|
break;
|
||
|
|
||
|
gFlashNumRemainingBytes--;
|
||
|
src++;
|
||
|
dest++;
|
||
|
}
|
||
|
|
||
|
return result;
|
||
|
}
|