-
Notifications
You must be signed in to change notification settings - Fork 5
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #88 from imaandrew/sc64
Add SC64 support
- Loading branch information
Showing
8 changed files
with
261 additions
and
4 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,191 @@ | ||
#include "sc64.h" | ||
#include "io/iodev.h" | ||
#include "pi.h" | ||
#include "util/util.h" | ||
#include <stddef.h> | ||
|
||
static s32 cartIrqf; | ||
static u32 cartLat; | ||
static u32 cartPwd; | ||
|
||
_Alignas(16) static u64 cartBuf[512 / 8]; | ||
|
||
static void cartBufRd(const void *addr) { | ||
const uu64 *ptr = addr; | ||
for (s32 i = 0; i < 512 / 8; i += 2) { | ||
u64 a = ptr[i + 0]; | ||
u64 b = ptr[i + 1]; | ||
cartBuf[i + 0] = a; | ||
cartBuf[i + 1] = b; | ||
} | ||
} | ||
|
||
static void cartBufWr(void *addr) { | ||
uu64 *ptr = addr; | ||
for (s32 i = 0; i < 512 / 8; i += 2) { | ||
u64 a = cartBuf[i + 0]; | ||
u64 b = cartBuf[i + 1]; | ||
ptr[i + 0] = a; | ||
ptr[i + 1] = b; | ||
} | ||
} | ||
|
||
static void cartLock(void) { | ||
__osPiGetAccess(); | ||
|
||
cartIrqf = setIrqf(0); | ||
|
||
cartLat = pi_regs.dom1_lat; | ||
cartPwd = pi_regs.dom1_pwd; | ||
} | ||
|
||
static void cartUnlock(void) { | ||
pi_regs.dom1_lat = cartLat; | ||
pi_regs.dom1_pwd = cartPwd; | ||
|
||
__osPiRelAccess(); | ||
|
||
setIrqf(cartIrqf); | ||
} | ||
|
||
static inline u32 regRd(s32 reg) { | ||
return __piReadRaw((u32)®S_PTR[reg]); | ||
} | ||
|
||
static inline void regWr(s32 reg, u32 dat) { | ||
return __piWriteRaw((u32)®S_PTR[reg], dat); | ||
} | ||
|
||
static s32 scSync(void) { | ||
while (regRd(SC_STATUS_REG) & SC_CMD_BUSY) { | ||
; | ||
} | ||
if (regRd(SC_STATUS_REG) & SC_CMD_ERROR) { | ||
return -1; | ||
} | ||
return 0; | ||
} | ||
|
||
static s32 probe(void) { | ||
cartLock(); | ||
|
||
/* open registers */ | ||
regWr(SC_KEY_REG, SC_KEY_RESET); | ||
regWr(SC_KEY_REG, SC_KEY_UNL); | ||
regWr(SC_KEY_REG, SC_KEY_OCK); | ||
|
||
/* check magic number */ | ||
if ((regRd(SC_IDENTIFIER_REG)) != SC_IDENTIFIER) { | ||
regWr(SC_KEY_REG, 0); | ||
CART_ABORT(); | ||
} | ||
|
||
scSync(); | ||
cartUnlock(); | ||
return 0; | ||
} | ||
|
||
static s32 diskInit(void) { | ||
cartLock(); | ||
scSync(); | ||
|
||
regWr(SC_DATA1_REG, SC_SD_INIT); | ||
regWr(SC_COMMAND_REG, SC_SD_OP); | ||
|
||
if (scSync()) { | ||
regWr(SC_KEY_REG, 0); | ||
CART_ABORT(); | ||
} | ||
|
||
cartUnlock(); | ||
return 0; | ||
} | ||
|
||
static s32 diskRead(size_t lba, size_t nBlocks, void *dst) { | ||
char *addr = dst; | ||
s32 n; | ||
cartLock(); | ||
scSync(); | ||
|
||
while (nBlocks > 0) { | ||
n = nBlocks < 16 ? nBlocks : 16; | ||
|
||
regWr(SC_DATA0_REG, lba); | ||
regWr(SC_COMMAND_REG, SC_SD_SECTOR_SET); | ||
|
||
if (scSync()) { | ||
CART_ABORT(); | ||
} | ||
|
||
regWr(SC_DATA0_REG, SC_BUFFER_REG); | ||
regWr(SC_DATA1_REG, n); | ||
regWr(SC_COMMAND_REG, SC_SD_READ); | ||
|
||
if (scSync()) { | ||
CART_ABORT(); | ||
} | ||
|
||
if ((u32)addr & 7) { | ||
for (s32 i = 0; i < n; i++) { | ||
piReadLocked(SC_BUFFER_REG + 512 * i, cartBuf, 512); | ||
cartBufWr(addr); | ||
addr += 512; | ||
} | ||
} else { | ||
piReadLocked(SC_BUFFER_REG, addr, 512 * n); | ||
addr += 512 * n; | ||
} | ||
|
||
lba += n; | ||
nBlocks -= n; | ||
} | ||
|
||
cartUnlock(); | ||
return 0; | ||
} | ||
|
||
static s32 diskWrite(size_t lba, size_t nBlocks, const void *src) { | ||
const char *addr = src; | ||
s32 n; | ||
cartLock(); | ||
scSync(); | ||
|
||
while (nBlocks > 0) { | ||
n = nBlocks < 16 ? nBlocks : 16; | ||
|
||
if ((u32)addr & 7) { | ||
for (s32 i = 0; i < n; i++) { | ||
cartBufRd(addr); | ||
piWriteLocked(SC_BUFFER_REG + 512 * i, cartBuf, 512); | ||
addr += 512; | ||
} | ||
} else { | ||
piWriteLocked(SC_BUFFER_REG, addr, 512 * n); | ||
addr += 512 * n; | ||
} | ||
|
||
scSync(); | ||
regWr(SC_DATA0_REG, lba); | ||
regWr(SC_COMMAND_REG, SC_SD_SECTOR_SET); | ||
|
||
if (scSync()) { | ||
CART_ABORT(); | ||
} | ||
|
||
regWr(SC_DATA0_REG, SC_BUFFER_REG); | ||
regWr(SC_DATA1_REG, n); | ||
regWr(SC_COMMAND_REG, SC_SD_WRITE); | ||
|
||
if (scSync()) { | ||
CART_ABORT(); | ||
} | ||
|
||
lba += n; | ||
nBlocks -= n; | ||
} | ||
|
||
cartUnlock(); | ||
return 0; | ||
} | ||
|
||
struct Iodev sc64 = {.probe = probe, .diskInit = diskInit, .diskRead = diskRead, .diskWrite = diskWrite}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,56 @@ | ||
#ifndef SC64_H | ||
#define SC64_H | ||
|
||
#include "types.h" | ||
|
||
#define SC_BASE_REG 0xBFFF0000 | ||
#define SC_BUFFER_REG 0xBFFE0000 | ||
#define REGS_PTR ((volatile u32 *)SC_BASE_REG) | ||
|
||
#define SC_STATUS_REG 0 | ||
#define SC_COMMAND_REG 0 | ||
#define SC_DATA0_REG 1 | ||
#define SC_DATA1_REG 2 | ||
#define SC_IDENTIFIER_REG 3 | ||
#define SC_KEY_REG 4 | ||
|
||
#define SC_CMD_BUSY 0x80000000 | ||
#define SC_CMD_ERROR 0x40000000 | ||
#define SC_IRQ_PENDING 0x20000000 | ||
|
||
#define SC_CONFIG_GET 'c' | ||
#define SC_CONFIG_SET 'C' | ||
#define SC_SD_OP 'i' | ||
#define SC_SD_SECTOR_SET 'I' | ||
#define SC_SD_READ 's' | ||
#define SC_SD_WRITE 'S' | ||
|
||
#define SC_CFG_ROM_WRITE 1 | ||
#define SC_CFG_DD_MODE 3 | ||
#define SC_CFG_SAVE_TYPE 6 | ||
|
||
#define SC_SD_DEINIT 0 | ||
#define SC_SD_INIT 1 | ||
#define SC_SD_GET_STATUS 2 | ||
#define SC_SD_GET_INFO 3 | ||
#define SC_SD_BYTESWAP_ON 4 | ||
#define SC_SD_BYTESWAP_OFF 5 | ||
|
||
#define SC_DD_MODE_REGS 1 | ||
#define SC_DD_MODE_IPL 2 | ||
|
||
#define SC_IDENTIFIER 0x53437632 /* SCv2 */ | ||
|
||
#define SC_KEY_RESET 0x00000000 | ||
#define SC_KEY_LOCK 0xFFFFFFFF | ||
#define SC_KEY_UNL 0x5F554E4C /* _UNL */ | ||
#define SC_KEY_OCK 0x4F434B5F /* OCK_ */ | ||
|
||
typedef u64 uu64 __attribute__((aligned(1))); // NOLINT | ||
#define CART_ABORT() \ | ||
{ \ | ||
cartUnlock(); \ | ||
return -1; \ | ||
} | ||
|
||
#endif |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
#ifndef SC64_IO_H | ||
#define SC64_IO_H | ||
|
||
struct Iodev; | ||
|
||
extern struct Iodev sc64; | ||
|
||
#endif |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters