You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 

596 lines
12 KiB

#include "types.h"
#include "everdrive.h"
#include <libdragon.h>
#include <stdio.h>
#include "sys.h"
#include "errors.h"
//#include "rom.h"
#include "disk.h"
#define CMD0 0x40 // software reset
#define CMD1 0x41 // brings card out of idle state
#define CMD2 0x42 // not used in SPI mode
#define CMD3 0x43 // not used in SPI mode
#define CMD4 0x44 // not used in SPI mode
#define CMD5 0x45 // Reserved
#define CMD6 0x46 // Reserved
#define CMD7 0x47 // not used in SPI mode
#define CMD8 0x48 // Reserved
#define CMD9 0x49 // ask card to send card speficic data (CSD)
#define CMD10 0x4A // ask card to send card identification (CID)
#define CMD11 0x4B // not used in SPI mode
#define CMD12 0x4C // stop transmission on multiple block read
#define CMD13 0x4D // ask the card to send it's status register
#define CMD14 0x4E // Reserved
#define CMD15 0x4F // not used in SPI mode
#define CMD16 0x50 // sets the block length used by the memory card
#define CMD17 0x51 // read single block
#define CMD18 0x52 // read multiple block
#define CMD19 0x53 // Reserved
#define CMD20 0x54 // not used in SPI mode
#define CMD21 0x55 // Reserved
#define CMD22 0x56 // Reserved
#define CMD23 0x57 // Reserved
#define CMD24 0x58 // writes a single block
#define CMD25 0x59 // writes multiple blocks
#define CMD26 0x5A // not used in SPI mode
#define CMD27 0x5B // change the bits in CSD
#define CMD28 0x5C // sets the write protection bit
#define CMD29 0x5D // clears the write protection bit
#define CMD30 0x5E // checks the write protection bit
#define CMD31 0x5F // Reserved
#define CMD32 0x60 // Sets the address of the first sector of the erase group
#define CMD33 0x61 // Sets the address of the last sector of the erase group
#define CMD34 0x62 // removes a sector from the selected group
#define CMD35 0x63 // Sets the address of the first group
#define CMD36 0x64 // Sets the address of the last erase group
#define CMD37 0x65 // removes a group from the selected section
#define CMD38 0x66 // erase all selected groups
#define CMD39 0x67 // not used in SPI mode
#define CMD40 0x68 // not used in SPI mode
#define CMD41 0x69 // Reserved
#define CMD42 0x6A // locks a block
// CMD43 ... CMD57 are Reserved
#define CMD58 0x7A // reads the OCR register
#define CMD59 0x7B // turns CRC off
// CMD60 ... CMD63 are not used in SPI mode
#define ED_STATE_DMA_BUSY 0
#define ED_STATE_DMA_TOUT 1
#define ED_STATE_TXE 2
#define ED_STATE_RXF 3
#define ED_STATE_SPI 4
#define SPI_CFG_SPD0 0
#define SPI_CFG_SPD1 1
#define SPI_CFG_SS 2
#define SPI_CFG_RD 3
#define SPI_CFG_DAT 4
#define SPI_CFG_1BIT 5
#define SAV_EEP_ON 0
#define SAV_SRM_ON 1
#define SAV_EEP_SIZE 2
#define SAV_SRM_SIZE 3
//was missing
//#define BI_SPI_SPD_LO 0
#define BI_SPI_SPD_LO 2 // around 200khz (only for sd initialization)
#define BI_SPI_SPD_25 1
#define BI_SPI_SPD_50 0
void evd_setSpiSpeed(u8 speed);
u8 evd_mmcCmd(u8 cmd, u32 arg);
u8 sd_mode;
volatile u8 spi_cfg;
volatile u8 evd_cfg;
u8 sd_type;
volatile u32 *regs_ptr = (u32 *) 0xA8040000;
/*
result[2] <= ad[15:8] == {ad[6], ad[1], ad[0], ad[7], ad[5], ad[4], ad[3], ad[2]} ^ 8'h37 ^ prv[7:0];
prv[7:0] <= ad[15:8];
*/
void (*dma_busy_callback)();
void evd_setDmaAddr(u32 addr) {
}
inline u32 bi_reg_rd(u32 reg) {
*(vu32 *) (REGS_BASE);
return *(vu32 *) (REGS_BASE + reg * 4);
}
inline void bi_reg_wr(u32 reg, u32 data) {
*(vu32 *) (REGS_BASE);
*(vu32 *) (REGS_BASE + reg * 4) = data;
}
void bi_init() {
evd_cfg = ED_CFG_SDRAM_ON;
spi_cfg = 0 | BI_SPI_SPD_LO;
bi_reg_wr(REG_KEY, 0x1234);
bi_reg_wr(REG_CFG, evd_cfg);
bi_reg_wr(REG_SPI_CFG, spi_cfg);
}
void bi_speed50() {
spi_cfg = 0 | BI_SPI_SPD_50;
bi_reg_wr(REG_KEY, 0x1234);
bi_reg_wr(REG_SPI_CFG, spi_cfg);
}
void bi_speed25() {
spi_cfg = 0 | BI_SPI_SPD_25;
bi_reg_wr(REG_KEY, 0x1234);
bi_reg_wr(REG_SPI_CFG, spi_cfg);
}
void bi_load_firmware(u8 *firm) {
u32 i;
u16 f_ctr = 0;
evd_cfg &= ~ED_CFG_SDRAM_ON;
bi_reg_wr(REG_CFG, evd_cfg);
bi_reg_wr(REG_CFG_CNT, 0);
sleep(10);
bi_reg_wr(REG_CFG_CNT, 1);
sleep(10);
i = 0;
for (;;) {
bi_reg_wr(REG_CFG_DAT, *(u16 *) & firm[i]);
while ((bi_reg_rd(REG_CFG_CNT) & 8) != 0);
f_ctr = firm[i++] == 0xff ? f_ctr + 1 : 0;
if (f_ctr >= 47)break;
f_ctr = firm[i++] == 0xff ? f_ctr + 1 : 0;
if (f_ctr >= 47)break;
}
while ((bi_reg_rd(REG_CFG_CNT) & 4) == 0) {
bi_reg_wr(REG_CFG_DAT, 0xffff);
while ((bi_reg_rd(REG_CFG_CNT) & 8) != 0);
}
sleep(20);
bi_init();
}
void evd_init() {
volatile u8 val;
sd_mode = 0;
dma_busy_callback = 0;
sleep(1);
val = regs_ptr[0];
spi_cfg = (0 << SPI_CFG_SPD0) | (1 << SPI_CFG_SPD1) | (1 << SPI_CFG_SS);
evd_cfg = (1 << ED_CFG_SDRAM_ON);
val = regs_ptr[0];
regs_ptr[REG_KEY] = 0x1234;
val = regs_ptr[0];
regs_ptr[REG_CFG] = evd_cfg;
val = regs_ptr[0];
regs_ptr[REG_SPI_CFG] = spi_cfg;
evd_fifoRxf();
if (!evd_fifoRxf()) {
val = regs_ptr[0];
regs_ptr[REG_DMA_LEN] = 7; //clean 16k
val = regs_ptr[0];
regs_ptr[REG_DMA_RAM_ADDR] = (ROM_LEN - 0x200000) / 2048;
val = regs_ptr[0];
regs_ptr[REG_DMA_CFG] = DCFG_FIFO_TO_RAM;
while (evd_isDmaBusy());
}
}
void evd_ulockRegs(){
volatile u8 val;
val = regs_ptr[0];
regs_ptr[REG_KEY] = 0x1234;
}
void evd_lockRegs() {
volatile u8 val;
val = regs_ptr[0];
regs_ptr[REG_KEY] = 0;
}
u8 evd_fifoRxf() {
u16 val;
//regs_ptr[REG_STATE]++;
val = regs_ptr[REG_STATUS];
return (val >> ED_STATE_RXF) & 1;
}
u8 evd_fifoTxe() {
u16 val;
//regs_ptr[REG_STATE]++;
val = regs_ptr[REG_STATUS];
return (val >> ED_STATE_TXE) & 1;
}
u8 evd_isDmaBusy() {
u16 val;
//volatile u32 i;
sleep(1);
if(dma_busy_callback != 0)dma_busy_callback();
//regs_ptr[REG_STATE]++;
val = regs_ptr[REG_STATUS];
return (val >> ED_STATE_DMA_BUSY) & 1;
}
u8 evd_isDmaTimeout() {
u16 val;
//regs_ptr[REG_STATE]++;
val = regs_ptr[REG_STATUS];
return (val >> ED_STATE_DMA_TOUT) & 1;
}
u8 evd_fifoRdToCart(u32 cart_addr, u16 blocks) {
volatile u8 val;
cart_addr /= 2048;
val = regs_ptr[0];
regs_ptr[REG_DMA_LEN] = (blocks - 1);
val = regs_ptr[0];
regs_ptr[REG_DMA_RAM_ADDR] = cart_addr;
val = regs_ptr[0];
regs_ptr[REG_DMA_CFG] = DCFG_FIFO_TO_RAM;
while (evd_isDmaBusy());
if (evd_isDmaTimeout())return EVD_ERROR_FIFO_TIMEOUT;
return 0;
}
u8 evd_fifoWrFromCart(u32 cart_addr, u16 blocks) {
volatile u8 val;
cart_addr /= 2048;
val = regs_ptr[0];
regs_ptr[REG_DMA_LEN] = (blocks - 1);
val = regs_ptr[0];
regs_ptr[REG_DMA_RAM_ADDR] = cart_addr;
val = regs_ptr[0];
regs_ptr[REG_DMA_CFG] = DCFG_RAM_TO_FIFO;
while (evd_isDmaBusy());
if (evd_isDmaTimeout())return EVD_ERROR_FIFO_TIMEOUT;
return 0;
}
u8 evd_fifoRd(void *buff, u16 blocks) {
volatile u8 val;
u32 len = blocks == 0 ? 65536 * 512 : blocks * 512;
u32 ram_buff_addr = DMA_BUFF_ADDR / 2048; //(ROM_LEN - len - 65536 * 4) / 2048;
val = regs_ptr[0];
regs_ptr[REG_DMA_LEN] = (blocks - 1);
val = regs_ptr[0];
regs_ptr[REG_DMA_RAM_ADDR] = ram_buff_addr;
val = regs_ptr[0];
regs_ptr[REG_DMA_CFG] = DCFG_FIFO_TO_RAM;
while (evd_isDmaBusy());
dma_read_s(buff, (0xb0000000 + ram_buff_addr * 2048), len);
if (evd_isDmaTimeout())return EVD_ERROR_FIFO_TIMEOUT;
return 0;
}
u8 evd_fifoWr(void *buff, u16 blocks) {
volatile u8 val;
u32 len = blocks == 0 ? 65536 * 512 : blocks * 512;
u32 ram_buff_addr = DMA_BUFF_ADDR / 2048; //(ROM_LEN - len - 65536 * 4) / 2048;
dma_write_s(buff, (0xb0000000 + ram_buff_addr * 1024 * 2), len);
val = regs_ptr[0];
regs_ptr[REG_DMA_LEN] = (blocks - 1);
val = regs_ptr[0];
regs_ptr[REG_DMA_RAM_ADDR] = ram_buff_addr;
val = regs_ptr[0];
regs_ptr[REG_DMA_CFG] = DCFG_RAM_TO_FIFO;
while (evd_isDmaBusy());
if (evd_isDmaTimeout())return EVD_ERROR_FIFO_TIMEOUT;
return 0;
}
u8 evd_isSpiBusy() {
volatile u16 val;
regs_ptr[REG_STATUS];
val = regs_ptr[REG_STATUS];
return (val >> ED_STATE_SPI) & 1;
}
u8 evd_SPI(u8 dat) {
volatile u8 val;
val = regs_ptr[0];
regs_ptr[REG_SPI] = dat;
while (evd_isSpiBusy());
//osInvalICache((u32*) & regs_ptr[REG_SPI], 1);
val = regs_ptr[REG_SPI];
return val;
}
void evd_spiSSOn() {
volatile u8 val;
if (sd_mode)return;
spi_cfg &= ~(1 << SPI_CFG_SS);
val = regs_ptr[0];
regs_ptr[REG_SPI_CFG] = spi_cfg;
}
void evd_spiSSOff() {
volatile u8 val;
spi_cfg |= (1 << SPI_CFG_SS);
val = regs_ptr[0];
regs_ptr[REG_SPI_CFG] = spi_cfg;
}
void evd_enableSDMode() {
sd_mode = 1;
}
void evd_enableSPIMode() {
sd_mode = 0;
}
u8 evd_isSDMode() {
return sd_mode;
}
void evd_SDcmdWriteMode(u8 bit1_mode) {
volatile u8 val;
if (!sd_mode)return;
spi_cfg &= ~((1 << SPI_CFG_RD) | (1 << SPI_CFG_DAT));
if (bit1_mode) {
spi_cfg |= (1 << SPI_CFG_1BIT);
} else {
spi_cfg &= ~(1 << SPI_CFG_1BIT);
}
val = regs_ptr[0];
regs_ptr[REG_SPI_CFG] = spi_cfg;
}
void evd_SDcmdReadMode(u8 bit1_mode) {
volatile u8 val;
if (!sd_mode)return;
spi_cfg |= (1 << SPI_CFG_RD);
spi_cfg &= ~(1 << SPI_CFG_DAT);
if (bit1_mode) {
spi_cfg |= (1 << SPI_CFG_1BIT);
} else {
spi_cfg &= ~(1 << SPI_CFG_1BIT);
}
val = regs_ptr[0];
regs_ptr[REG_SPI_CFG] = spi_cfg;
}
void evd_SDdatWriteMode(u8 bit4_mode) {
volatile u8 val;
if (!sd_mode)return;
spi_cfg &= ~(1 << SPI_CFG_RD);
spi_cfg |= (1 << SPI_CFG_DAT);
if (bit4_mode) {
spi_cfg |= (1 << SPI_CFG_1BIT);
} else {
spi_cfg &= ~(1 << SPI_CFG_1BIT);
}
val = regs_ptr[0];
regs_ptr[REG_SPI_CFG] = spi_cfg;
}
void evd_SDdatReadMode(u8 bit4_mode) {
volatile u8 val;
if (!sd_mode)return;
spi_cfg |= (1 << SPI_CFG_RD) | (1 << SPI_CFG_DAT);
if (bit4_mode) {
spi_cfg |= (1 << SPI_CFG_1BIT);
} else {
spi_cfg &= ~(1 << SPI_CFG_1BIT);
}
val = regs_ptr[0];
regs_ptr[REG_SPI_CFG] = spi_cfg;
}
void evd_setSpiSpeed(u8 speed) {
volatile u8 val;
spi_cfg &= ~3; //((1 << SPI_CFG_SPD0) | (1 << SPI_CFG_SPD1));
spi_cfg |= speed & 3;
val = regs_ptr[0];
regs_ptr[REG_SPI_CFG] = spi_cfg;
}
u8 evd_mmcReadToCart(u32 cart_addr, u32 len) {
volatile u8 val;
cart_addr /= 2048;
val = regs_ptr[0];
regs_ptr[REG_DMA_LEN] = (len - 1);
val = regs_ptr[0];
regs_ptr[REG_DMA_RAM_ADDR] = cart_addr;
val = regs_ptr[0];
regs_ptr[REG_DMA_CFG] = DCFG_SD_TO_RAM;
while (evd_isDmaBusy());
if (evd_isDmaTimeout())return EVD_ERROR_MMC_TIMEOUT;
return 0;
}
void evd_setCfgBit(u8 option, u8 state) {
volatile u8 val;
if (state)evd_cfg |= (1 << option);
else
evd_cfg &= ~(1 << option);
val = regs_ptr[0];
regs_ptr[REG_CFG] = evd_cfg;
val = regs_ptr[0];
}
u16 evd_readReg(u8 reg) {
volatile u32 tmp;
tmp = regs_ptr[0];
return regs_ptr[reg];
}
void evd_setSaveType(u8 type) {
u8 eeprom_on, sram_on, eeprom_size, sram_size;
eeprom_on = 0;
sram_on = 0;
eeprom_size = 0;
sram_size = 0;
switch (type) {
case SAVE_TYPE_EEP16k:
eeprom_on = 1;
eeprom_size = 1;
break;
case SAVE_TYPE_EEP4k:
eeprom_on = 1;
break;
case SAVE_TYPE_SRAM:
sram_on = 1;
break;
case SAVE_TYPE_SRAM128:
sram_on = 1;
sram_size = 1;
break;
case SAVE_TYPE_FLASH:
sram_on = 0;
sram_size = 1;
break;
default:
sram_on = 0;
sram_size = 0;
break;
}
volatile u8 val;
val = regs_ptr[0];
regs_ptr[REG_SAV_CFG] = (eeprom_on << SAV_EEP_ON | sram_on << SAV_SRM_ON | eeprom_size << SAV_EEP_SIZE | sram_size << SAV_SRM_SIZE);
}
void evd_writeReg(u8 reg, u16 val) {
volatile u8 tmp;
tmp = regs_ptr[0];
regs_ptr[reg] = val;
}
void evd_mmcSetDmaSwap(u8 state) {
evd_setCfgBit(ED_CFG_SWAP, state);
}
void evd_writeMsg(u8 dat) {
evd_writeReg(REG_MSG, dat);
}
u8 evd_readMsg() {
return evd_readReg(REG_MSG);
}
u16 evd_getFirmVersion() {
return evd_readReg(REG_VER);
}
void evd_setDmaCallback(void (*callback)()) {
dma_busy_callback = callback;
}