mirror of
https://github.com/Polprzewodnikowy/SummerCart64.git
synced 2024-11-21 21:49:15 +01:00
[SC64][SW] Disable writeback prior to jumping to menu code, … (#44)
…added SDRAM tests, SC64 reference implementation rewrite
This commit is contained in:
parent
a4a52fd15a
commit
664092036f
@ -20,8 +20,8 @@ docker run \
|
|||||||
--rm \
|
--rm \
|
||||||
--user $(id -u):$(id -g) \
|
--user $(id -u):$(id -g) \
|
||||||
--mac-address ${MAC_ADDRESS:-F8:12:34:56:78:90} \
|
--mac-address ${MAC_ADDRESS:-F8:12:34:56:78:90} \
|
||||||
--mount type=bind,src="$(pwd)/fw/project/lcmxo2/license.dat",target="/flexlm/license.dat" \
|
-v "$(pwd)"/fw/project/lcmxo2/license.dat:/flexlm/license.dat \
|
||||||
--mount type=bind,src="$(pwd)",target="/workdir" \
|
-v "$(pwd)":/workdir \
|
||||||
-h=`hostname` \
|
-h=`hostname` \
|
||||||
-e GIT_BRANCH="$GIT_BRANCH" \
|
-e GIT_BRANCH="$GIT_BRANCH" \
|
||||||
-e GIT_TAG="$GIT_TAG" \
|
-e GIT_TAG="$GIT_TAG" \
|
||||||
|
@ -23,12 +23,13 @@ SECTIONS {
|
|||||||
*(.framebuffer .framebuffer.*)
|
*(.framebuffer .framebuffer.*)
|
||||||
} > framebuffer
|
} > framebuffer
|
||||||
|
|
||||||
.text : SUBALIGN(4) {
|
.text : SUBALIGN(8) {
|
||||||
*(.text.entry_handler)
|
*(.text.entry_handler)
|
||||||
*(.text .text.* .gnu.linkonce.t.*)
|
*(.text .text.* .gnu.linkonce.t.*)
|
||||||
*(.assets .assets.*)
|
*(.assets .assets.*)
|
||||||
*(.rodata .rodata.* .gnu.linkonce.r.*)
|
*(.rodata .rodata.* .gnu.linkonce.r.*)
|
||||||
*(.data .data.* .gnu.linkonce.d.*)
|
*(.data .data.* .gnu.linkonce.d.*)
|
||||||
|
. = ALIGN(8);
|
||||||
_gp = . + 0x8000;
|
_gp = . + 0x8000;
|
||||||
*(.sdata .sdata.* .gnu.linkonce.s.*)
|
*(.sdata .sdata.* .gnu.linkonce.s.*)
|
||||||
*(.lit8 .lit4)
|
*(.lit8 .lit4)
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
#include <stdbool.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include "display.h"
|
#include "display.h"
|
||||||
#include "font.h"
|
#include "font.h"
|
||||||
@ -19,6 +20,7 @@
|
|||||||
static io32_t display_framebuffer[SCREEN_WIDTH * SCREEN_HEIGHT] __attribute__((section(".framebuffer, \"aw\", %nobits#")));
|
static io32_t display_framebuffer[SCREEN_WIDTH * SCREEN_HEIGHT] __attribute__((section(".framebuffer, \"aw\", %nobits#")));
|
||||||
static int char_x;
|
static int char_x;
|
||||||
static int char_y;
|
static int char_y;
|
||||||
|
static bool vi_configured = false;
|
||||||
static const vi_regs_t vi_config[] = {{
|
static const vi_regs_t vi_config[] = {{
|
||||||
.CR = VI_CR,
|
.CR = VI_CR,
|
||||||
.H_WIDTH = SCREEN_WIDTH,
|
.H_WIDTH = SCREEN_WIDTH,
|
||||||
@ -99,6 +101,22 @@ static void display_draw_character (char c) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (c == '\b') {
|
||||||
|
char_x -= FONT_WIDTH;
|
||||||
|
for (int i = 0; i < (FONT_WIDTH * FONT_HEIGHT); i++) {
|
||||||
|
int c_x = char_x + (i % FONT_WIDTH);
|
||||||
|
int c_y = char_y + (i / FONT_WIDTH);
|
||||||
|
|
||||||
|
if ((c_x >= (SCREEN_WIDTH - BORDER_WIDTH)) || (c_y >= (SCREEN_HEIGHT - BORDER_HEIGHT))) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
int screen_offset = c_x + (c_y * SCREEN_WIDTH);
|
||||||
|
cpu_io_write(&display_framebuffer[screen_offset], BACKGROUND_COLOR);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if ((char_x + FONT_WIDTH) > (SCREEN_WIDTH - BORDER_WIDTH)) {
|
if ((char_x + FONT_WIDTH) > (SCREEN_WIDTH - BORDER_WIDTH)) {
|
||||||
char_x = BORDER_WIDTH;
|
char_x = BORDER_WIDTH;
|
||||||
char_y += FONT_HEIGHT + LINE_SPACING;
|
char_y += FONT_HEIGHT + LINE_SPACING;
|
||||||
@ -113,7 +131,7 @@ static void display_draw_character (char c) {
|
|||||||
int c_y = char_y + (i / FONT_WIDTH);
|
int c_y = char_y + (i / FONT_WIDTH);
|
||||||
|
|
||||||
if ((c_x >= (SCREEN_WIDTH - BORDER_WIDTH)) || (c_y >= (SCREEN_HEIGHT - BORDER_HEIGHT))) {
|
if ((c_x >= (SCREEN_WIDTH - BORDER_WIDTH)) || (c_y >= (SCREEN_HEIGHT - BORDER_HEIGHT))) {
|
||||||
break;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (font_data[c - ' '][i / 8] & (1 << (i % 8))) {
|
if (font_data[c - ' '][i / 8] & (1 << (i % 8))) {
|
||||||
@ -133,8 +151,6 @@ static void display_draw_string (const char *s) {
|
|||||||
|
|
||||||
|
|
||||||
void display_init (uint32_t *background) {
|
void display_init (uint32_t *background) {
|
||||||
const vi_regs_t *cfg = &vi_config[OS_INFO->tv_type];
|
|
||||||
|
|
||||||
char_x = BORDER_WIDTH;
|
char_x = BORDER_WIDTH;
|
||||||
char_y = BORDER_HEIGHT;
|
char_y = BORDER_HEIGHT;
|
||||||
|
|
||||||
@ -144,20 +160,26 @@ void display_init (uint32_t *background) {
|
|||||||
display_clear_background();
|
display_clear_background();
|
||||||
}
|
}
|
||||||
|
|
||||||
cpu_io_write(&VI->MADDR, (uint32_t) (display_framebuffer));
|
if (!vi_configured) {
|
||||||
cpu_io_write(&VI->H_WIDTH, cfg->H_WIDTH);
|
vi_configured = true;
|
||||||
cpu_io_write(&VI->V_INTR, cfg->V_INTR);
|
|
||||||
cpu_io_write(&VI->CURR_LINE, cfg->CURR_LINE);
|
const vi_regs_t *cfg = &vi_config[OS_INFO->tv_type];
|
||||||
cpu_io_write(&VI->TIMING, cfg->TIMING);
|
|
||||||
cpu_io_write(&VI->V_SYNC, cfg->V_SYNC);
|
cpu_io_write(&VI->MADDR, (uint32_t) (display_framebuffer));
|
||||||
cpu_io_write(&VI->H_SYNC, cfg->H_SYNC);
|
cpu_io_write(&VI->H_WIDTH, cfg->H_WIDTH);
|
||||||
cpu_io_write(&VI->H_SYNC_LEAP, cfg->H_SYNC_LEAP);
|
cpu_io_write(&VI->V_INTR, cfg->V_INTR);
|
||||||
cpu_io_write(&VI->H_LIMITS, cfg->H_LIMITS);
|
cpu_io_write(&VI->CURR_LINE, cfg->CURR_LINE);
|
||||||
cpu_io_write(&VI->V_LIMITS, cfg->V_LIMITS);
|
cpu_io_write(&VI->TIMING, cfg->TIMING);
|
||||||
cpu_io_write(&VI->COLOR_BURST, cfg->COLOR_BURST);
|
cpu_io_write(&VI->V_SYNC, cfg->V_SYNC);
|
||||||
cpu_io_write(&VI->H_SCALE, cfg->H_SCALE);
|
cpu_io_write(&VI->H_SYNC, cfg->H_SYNC);
|
||||||
cpu_io_write(&VI->V_SCALE, cfg->V_SCALE);
|
cpu_io_write(&VI->H_SYNC_LEAP, cfg->H_SYNC_LEAP);
|
||||||
cpu_io_write(&VI->CR, cfg->CR);
|
cpu_io_write(&VI->H_LIMITS, cfg->H_LIMITS);
|
||||||
|
cpu_io_write(&VI->V_LIMITS, cfg->V_LIMITS);
|
||||||
|
cpu_io_write(&VI->COLOR_BURST, cfg->COLOR_BURST);
|
||||||
|
cpu_io_write(&VI->H_SCALE, cfg->H_SCALE);
|
||||||
|
cpu_io_write(&VI->V_SCALE, cfg->V_SCALE);
|
||||||
|
cpu_io_write(&VI->CR, cfg->CR);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void display_vprintf (const char *fmt, va_list args) {
|
void display_vprintf (const char *fmt, va_list args) {
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include "ff.h"
|
#include "ff.h"
|
||||||
#include "diskio.h"
|
#include "diskio.h"
|
||||||
|
#include "../error.h"
|
||||||
#include "../io.h"
|
#include "../io.h"
|
||||||
#include "../sc64.h"
|
#include "../sc64.h"
|
||||||
|
|
||||||
@ -15,7 +16,12 @@ DSTATUS disk_status (BYTE pdrv) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
DSTATUS status = 0;
|
DSTATUS status = 0;
|
||||||
sc64_sd_card_status_t sd_card_status = sc64_sd_card_get_status();
|
sc64_error_t error;
|
||||||
|
sc64_sd_card_status_t sd_card_status;
|
||||||
|
|
||||||
|
if ((error = sc64_sd_card_get_status(&sd_card_status)) != SC64_OK) {
|
||||||
|
error_display("Could not get SD card status: %d", error);
|
||||||
|
}
|
||||||
|
|
||||||
if (!(sd_card_status & SD_CARD_STATUS_INSERTED)) {
|
if (!(sd_card_status & SD_CARD_STATUS_INSERTED)) {
|
||||||
status |= STA_NODISK;
|
status |= STA_NODISK;
|
||||||
@ -47,7 +53,7 @@ DRESULT disk_read (BYTE pdrv, BYTE *buff, LBA_t sector, UINT count) {
|
|||||||
while (count > 0) {
|
while (count > 0) {
|
||||||
uint32_t blocks = ((count > BUFFER_BLOCKS_MAX) ? BUFFER_BLOCKS_MAX : count);
|
uint32_t blocks = ((count > BUFFER_BLOCKS_MAX) ? BUFFER_BLOCKS_MAX : count);
|
||||||
size_t length = (blocks * SD_SECTOR_SIZE);
|
size_t length = (blocks * SD_SECTOR_SIZE);
|
||||||
if (sc64_sd_read_sectors((uint32_t *) (SC64_BUFFERS->BUFFER), sector, blocks)) {
|
if (sc64_sd_read_sectors((uint32_t *) (SC64_BUFFERS->BUFFER), sector, blocks) != SC64_OK) {
|
||||||
return RES_ERROR;
|
return RES_ERROR;
|
||||||
}
|
}
|
||||||
if (((uint32_t) (buff) % 8) == 0) {
|
if (((uint32_t) (buff) % 8) == 0) {
|
||||||
@ -61,7 +67,7 @@ DRESULT disk_read (BYTE pdrv, BYTE *buff, LBA_t sector, UINT count) {
|
|||||||
count -= blocks;
|
count -= blocks;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (sc64_sd_read_sectors(physical_address, sector, count)) {
|
if (sc64_sd_read_sectors(physical_address, sector, count) != SC64_OK) {
|
||||||
return RES_ERROR;
|
return RES_ERROR;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -85,7 +91,7 @@ DRESULT disk_write (BYTE pdrv, const BYTE* buff, LBA_t sector, UINT count) {
|
|||||||
memcpy(aligned_buffer, buff, length);
|
memcpy(aligned_buffer, buff, length);
|
||||||
pi_dma_write((io32_t *) (SC64_BUFFERS->BUFFER), aligned_buffer, length);
|
pi_dma_write((io32_t *) (SC64_BUFFERS->BUFFER), aligned_buffer, length);
|
||||||
}
|
}
|
||||||
if (sc64_sd_write_sectors((uint32_t *) (SC64_BUFFERS->BUFFER), sector, blocks)) {
|
if (sc64_sd_write_sectors((uint32_t *) (SC64_BUFFERS->BUFFER), sector, blocks) != SC64_OK) {
|
||||||
return RES_ERROR;
|
return RES_ERROR;
|
||||||
}
|
}
|
||||||
buff += length;
|
buff += length;
|
||||||
@ -93,7 +99,7 @@ DRESULT disk_write (BYTE pdrv, const BYTE* buff, LBA_t sector, UINT count) {
|
|||||||
count -= blocks;
|
count -= blocks;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (sc64_sd_write_sectors(physical_address, sector, count)) {
|
if (sc64_sd_write_sectors(physical_address, sector, count) != SC64_OK) {
|
||||||
return RES_ERROR;
|
return RES_ERROR;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -112,8 +118,13 @@ DRESULT disk_ioctl (BYTE pdrv, BYTE cmd, void *buff) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
DWORD get_fattime(void) {
|
DWORD get_fattime(void) {
|
||||||
|
sc64_error_t error;
|
||||||
sc64_rtc_time_t t;
|
sc64_rtc_time_t t;
|
||||||
sc64_get_time(&t);
|
|
||||||
|
if ((error = sc64_get_time(&t)) != SC64_OK) {
|
||||||
|
error_display("Command TIME_GET failed: %d", error);
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
((FROM_BCD(t.year) + 20) << 25) |
|
((FROM_BCD(t.year) + 20) << 25) |
|
||||||
(FROM_BCD(t.month) << 21) |
|
(FROM_BCD(t.month) << 21) |
|
||||||
|
@ -6,6 +6,8 @@
|
|||||||
|
|
||||||
|
|
||||||
void init (void) {
|
void init (void) {
|
||||||
|
sc64_error_t error;
|
||||||
|
|
||||||
uint32_t pifram = si_io_read((io32_t *) (PIFRAM_STATUS));
|
uint32_t pifram = si_io_read((io32_t *) (PIFRAM_STATUS));
|
||||||
si_io_write((io32_t *) (PIFRAM_STATUS), pifram | PIFRAM_TERMINATE_BOOT);
|
si_io_write((io32_t *) (PIFRAM_STATUS), pifram | PIFRAM_TERMINATE_BOOT);
|
||||||
|
|
||||||
@ -20,12 +22,14 @@ void init (void) {
|
|||||||
exception_enable_watchdog();
|
exception_enable_watchdog();
|
||||||
exception_enable_interrupts();
|
exception_enable_interrupts();
|
||||||
|
|
||||||
|
if ((error = sc64_set_config(CFG_ID_BOOTLOADER_SWITCH, false)) != SC64_OK) {
|
||||||
|
error_display("Command SET_CONFIG [BOOTLOADER_SWITCH] failed: %d", error);
|
||||||
|
}
|
||||||
|
|
||||||
if (test_check()) {
|
if (test_check()) {
|
||||||
exception_disable_watchdog();
|
exception_disable_watchdog();
|
||||||
test_execute();
|
test_execute();
|
||||||
}
|
}
|
||||||
|
|
||||||
sc64_set_config(CFG_ID_BOOTLOADER_SWITCH, false);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void deinit (void) {
|
void deinit (void) {
|
||||||
|
@ -26,6 +26,27 @@ void cache_inst_hit_invalidate (void *address, size_t length) {
|
|||||||
cache_operation(HIT_INVALIDATE_I, CACHE_LINE_SIZE_I, address, length);
|
cache_operation(HIT_INVALIDATE_I, CACHE_LINE_SIZE_I, address, length);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uint32_t c0_count (void) {
|
||||||
|
uint32_t value;
|
||||||
|
asm volatile (
|
||||||
|
"mfc0 %[value], $9 \n" :
|
||||||
|
[value] "=r" (value)
|
||||||
|
);
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
void delay_ms (int ms) {
|
||||||
|
uint64_t start = c0_count();
|
||||||
|
uint64_t end = start + (ms * ((93750000 / 2) / 1000));
|
||||||
|
uint64_t current;
|
||||||
|
do {
|
||||||
|
current = c0_count();
|
||||||
|
if (current < start) {
|
||||||
|
current += 0x100000000ULL;
|
||||||
|
}
|
||||||
|
} while (current < end);
|
||||||
|
}
|
||||||
|
|
||||||
uint32_t cpu_io_read (io32_t *address) {
|
uint32_t cpu_io_read (io32_t *address) {
|
||||||
io32_t *uncached = UNCACHED(address);
|
io32_t *uncached = UNCACHED(address);
|
||||||
uint32_t value = *uncached;
|
uint32_t value = *uncached;
|
||||||
@ -37,6 +58,15 @@ void cpu_io_write (io32_t *address, uint32_t value) {
|
|||||||
*uncached = value;
|
*uncached = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void pi_io_config (uint8_t page_size, uint8_t latency, uint8_t pulse_width, uint8_t release) {
|
||||||
|
for (int domain = 0; domain < 2; domain += 1) {
|
||||||
|
cpu_io_write(&PI->DOM[domain].PGS, page_size);
|
||||||
|
cpu_io_write(&PI->DOM[domain].LAT, latency);
|
||||||
|
cpu_io_write(&PI->DOM[domain].PWD, pulse_width);
|
||||||
|
cpu_io_write(&PI->DOM[domain].RLS, release);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
uint32_t pi_busy (void) {
|
uint32_t pi_busy (void) {
|
||||||
return (cpu_io_read(&PI->SR) & (PI_SR_IO_BUSY | PI_SR_DMA_BUSY));
|
return (cpu_io_read(&PI->SR) & (PI_SR_IO_BUSY | PI_SR_DMA_BUSY));
|
||||||
}
|
}
|
||||||
|
@ -254,8 +254,11 @@ typedef struct {
|
|||||||
#define OS_INFO_RESET_TYPE_NMI (1)
|
#define OS_INFO_RESET_TYPE_NMI (1)
|
||||||
|
|
||||||
|
|
||||||
|
uint32_t c0_count (void);
|
||||||
|
void delay_ms (int ms);
|
||||||
uint32_t cpu_io_read (io32_t *address);
|
uint32_t cpu_io_read (io32_t *address);
|
||||||
void cpu_io_write (io32_t *address, uint32_t value);
|
void cpu_io_write (io32_t *address, uint32_t value);
|
||||||
|
void pi_io_config (uint8_t page_size, uint8_t latency, uint8_t pulse_width, uint8_t release);
|
||||||
uint32_t pi_busy (void);
|
uint32_t pi_busy (void);
|
||||||
uint32_t pi_io_read (io32_t *address);
|
uint32_t pi_io_read (io32_t *address);
|
||||||
void pi_io_write (io32_t *address, uint32_t value);
|
void pi_io_write (io32_t *address, uint32_t value);
|
||||||
|
@ -7,10 +7,13 @@
|
|||||||
|
|
||||||
|
|
||||||
void main (void) {
|
void main (void) {
|
||||||
|
sc64_error_t error;
|
||||||
boot_info_t boot_info;
|
boot_info_t boot_info;
|
||||||
sc64_boot_info_t sc64_boot_info;
|
sc64_boot_info_t sc64_boot_info;
|
||||||
|
|
||||||
sc64_get_boot_info(&sc64_boot_info);
|
if ((error = sc64_get_boot_info(&sc64_boot_info)) != SC64_OK) {
|
||||||
|
error_display("Could not obtain boot info: %d", error);
|
||||||
|
}
|
||||||
|
|
||||||
switch (sc64_boot_info.boot_mode) {
|
switch (sc64_boot_info.boot_mode) {
|
||||||
case BOOT_MODE_MENU:
|
case BOOT_MODE_MENU:
|
||||||
|
@ -3,6 +3,7 @@
|
|||||||
#include "init.h"
|
#include "init.h"
|
||||||
#include "io.h"
|
#include "io.h"
|
||||||
#include "menu.h"
|
#include "menu.h"
|
||||||
|
#include "sc64.h"
|
||||||
|
|
||||||
|
|
||||||
extern const void __bootloader_start __attribute__((section(".data")));
|
extern const void __bootloader_start __attribute__((section(".data")));
|
||||||
@ -65,6 +66,19 @@ static void menu_check_load_address (void *address, size_t size) {
|
|||||||
|
|
||||||
|
|
||||||
void menu_load_and_run (void) {
|
void menu_load_and_run (void) {
|
||||||
|
sc64_error_t error;
|
||||||
|
bool writeback_pending;
|
||||||
|
|
||||||
|
do {
|
||||||
|
if ((error = sc64_writeback_pending(&writeback_pending)) != SC64_OK) {
|
||||||
|
error_display("Command WRITEBACK_PENDING failed: %d", error);
|
||||||
|
}
|
||||||
|
} while (writeback_pending);
|
||||||
|
|
||||||
|
if ((error = sc64_writeback_disable()) != SC64_OK) {
|
||||||
|
error_display("Could not disable writeback: %d", error);
|
||||||
|
}
|
||||||
|
|
||||||
void (* menu)(void);
|
void (* menu)(void);
|
||||||
FRESULT fresult;
|
FRESULT fresult;
|
||||||
FATFS fs;
|
FATFS fs;
|
||||||
|
@ -12,6 +12,7 @@ typedef struct {
|
|||||||
#define SC64_REGS_BASE (0x1FFF0000UL)
|
#define SC64_REGS_BASE (0x1FFF0000UL)
|
||||||
#define SC64_REGS ((sc64_regs_t *) SC64_REGS_BASE)
|
#define SC64_REGS ((sc64_regs_t *) SC64_REGS_BASE)
|
||||||
|
|
||||||
|
|
||||||
#define SC64_SR_IRQ_PENDING (1 << 29)
|
#define SC64_SR_IRQ_PENDING (1 << 29)
|
||||||
#define SC64_SR_CMD_ERROR (1 << 30)
|
#define SC64_SR_CMD_ERROR (1 << 30)
|
||||||
#define SC64_SR_CPU_BUSY (1 << 31)
|
#define SC64_SR_CPU_BUSY (1 << 31)
|
||||||
@ -23,29 +24,31 @@ typedef struct {
|
|||||||
#define SC64_KEY_UNLOCK_2 (0x4F434B5FUL)
|
#define SC64_KEY_UNLOCK_2 (0x4F434B5FUL)
|
||||||
#define SC64_KEY_LOCK (0xFFFFFFFFUL)
|
#define SC64_KEY_LOCK (0xFFFFFFFFUL)
|
||||||
|
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
SC64_CMD_IDENTIFIER_GET = 'v',
|
CMD_ID_IDENTIFIER_GET = 'v',
|
||||||
SC64_CMD_VERSION_GET = 'V',
|
CMD_ID_VERSION_GET = 'V',
|
||||||
SC64_CMD_CONFIG_GET = 'c',
|
CMD_ID_CONFIG_GET = 'c',
|
||||||
SC64_CMD_CONFIG_SET = 'C',
|
CMD_ID_CONFIG_SET = 'C',
|
||||||
SC64_CMD_SETTING_GET = 'a',
|
CMD_ID_SETTING_GET = 'a',
|
||||||
SC64_CMD_SETTING_SET = 'A',
|
CMD_ID_SETTING_SET = 'A',
|
||||||
SC64_CMD_TIME_GET = 't',
|
CMD_ID_TIME_GET = 't',
|
||||||
SC64_CMD_TIME_SET = 'T',
|
CMD_ID_TIME_SET = 'T',
|
||||||
SC64_CMD_USB_READ = 'm',
|
CMD_ID_USB_READ = 'm',
|
||||||
SC64_CMD_USB_WRITE = 'M',
|
CMD_ID_USB_WRITE = 'M',
|
||||||
SC64_CMD_USB_READ_STATUS = 'u',
|
CMD_ID_USB_READ_STATUS = 'u',
|
||||||
SC64_CMD_USB_WRITE_STATUS = 'U',
|
CMD_ID_USB_WRITE_STATUS = 'U',
|
||||||
SC64_CMD_SD_CARD_OP = 'i',
|
CMD_ID_SD_CARD_OP = 'i',
|
||||||
SC64_CMD_SD_SECTOR_SET = 'I',
|
CMD_ID_SD_SECTOR_SET = 'I',
|
||||||
SC64_CMD_SD_READ = 's',
|
CMD_ID_SD_READ = 's',
|
||||||
SC64_CMD_SD_WRITE = 'S',
|
CMD_ID_SD_WRITE = 'S',
|
||||||
SC64_CMD_DD_SD_INFO = 'D',
|
CMD_ID_DD_SD_INFO = 'D',
|
||||||
SC64_CMD_WRITEBACK_SD_INFO = 'W',
|
CMD_ID_WRITEBACK_PENDING = 'w',
|
||||||
SC64_CMD_FLASH_PROGRAM = 'K',
|
CMD_ID_WRITEBACK_SD_INFO = 'W',
|
||||||
SC64_CMD_FLASH_WAIT_BUSY = 'p',
|
CMD_ID_FLASH_PROGRAM = 'K',
|
||||||
SC64_CMD_FLASH_ERASE_BLOCK = 'P',
|
CMD_ID_FLASH_WAIT_BUSY = 'p',
|
||||||
} cmd_id_t;
|
CMD_ID_FLASH_ERASE_BLOCK = 'P',
|
||||||
|
} sc64_cmd_id_t;
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
SD_CARD_OP_DEINIT = 0,
|
SD_CARD_OP_DEINIT = 0,
|
||||||
@ -56,37 +59,35 @@ typedef enum {
|
|||||||
SD_CARD_OP_BYTE_SWAP_OFF = 5,
|
SD_CARD_OP_BYTE_SWAP_OFF = 5,
|
||||||
} sd_card_op_t;
|
} sd_card_op_t;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
sc64_cmd_id_t id;
|
||||||
|
uint32_t arg[2];
|
||||||
|
uint32_t rsp[2];
|
||||||
|
} sc64_cmd_t;
|
||||||
|
|
||||||
|
|
||||||
|
static sc64_error_t sc64_execute_cmd (sc64_cmd_t *cmd) {
|
||||||
|
pi_io_write(&SC64_REGS->DATA[0], cmd->arg[0]);
|
||||||
|
pi_io_write(&SC64_REGS->DATA[1], cmd->arg[1]);
|
||||||
|
|
||||||
|
pi_io_write(&SC64_REGS->SR_CMD, (cmd->id & 0xFF));
|
||||||
|
|
||||||
static bool sc64_wait_cpu_busy (void) {
|
|
||||||
uint32_t sr;
|
uint32_t sr;
|
||||||
do {
|
do {
|
||||||
sr = pi_io_read(&SC64_REGS->SR_CMD);
|
sr = pi_io_read(&SC64_REGS->SR_CMD);
|
||||||
} while (sr & SC64_SR_CPU_BUSY);
|
} while (sr & SC64_SR_CPU_BUSY);
|
||||||
return (sr & SC64_SR_CMD_ERROR);
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool sc64_execute_cmd (uint8_t cmd, uint32_t *args, uint32_t *result) {
|
if (sr & SC64_SR_CMD_ERROR) {
|
||||||
if (args != NULL) {
|
|
||||||
pi_io_write(&SC64_REGS->DATA[0], args[0]);
|
|
||||||
pi_io_write(&SC64_REGS->DATA[1], args[1]);
|
|
||||||
}
|
|
||||||
pi_io_write(&SC64_REGS->SR_CMD, ((uint32_t) (cmd)) & 0xFF);
|
|
||||||
bool error = sc64_wait_cpu_busy();
|
|
||||||
if (result != NULL) {
|
|
||||||
result[0] = pi_io_read(&SC64_REGS->DATA[0]);
|
|
||||||
result[1] = pi_io_read(&SC64_REGS->DATA[1]);
|
|
||||||
}
|
|
||||||
return error;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
sc64_error_t sc64_get_error (void) {
|
|
||||||
if (pi_io_read(&SC64_REGS->SR_CMD) & SC64_SR_CMD_ERROR) {
|
|
||||||
return (sc64_error_t) (pi_io_read(&SC64_REGS->DATA[0]));
|
return (sc64_error_t) (pi_io_read(&SC64_REGS->DATA[0]));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
cmd->rsp[0] = pi_io_read(&SC64_REGS->DATA[0]);
|
||||||
|
cmd->rsp[1] = pi_io_read(&SC64_REGS->DATA[1]);
|
||||||
|
|
||||||
return SC64_OK;
|
return SC64_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void sc64_unlock (void) {
|
void sc64_unlock (void) {
|
||||||
pi_io_write(&SC64_REGS->KEY, SC64_KEY_RESET);
|
pi_io_write(&SC64_REGS->KEY, SC64_KEY_RESET);
|
||||||
pi_io_write(&SC64_REGS->KEY, SC64_KEY_UNLOCK_1);
|
pi_io_write(&SC64_REGS->KEY, SC64_KEY_UNLOCK_1);
|
||||||
@ -99,204 +100,334 @@ void sc64_lock (void) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool sc64_check_presence (void) {
|
bool sc64_check_presence (void) {
|
||||||
uint32_t identifier = pi_io_read(&SC64_REGS->IDENTIFIER);
|
bool detected = (pi_io_read(&SC64_REGS->IDENTIFIER) == SC64_V2_IDENTIFIER);
|
||||||
if (identifier == SC64_V2_IDENTIFIER) {
|
if (detected) {
|
||||||
sc64_wait_cpu_busy();
|
while (pi_io_read(&SC64_REGS->SR_CMD) & SC64_SR_CPU_BUSY);
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
return false;
|
return detected;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool sc64_irq_pending (void) {
|
bool sc64_irq_pending (void) {
|
||||||
if (pi_io_read(&SC64_REGS->SR_CMD) & SC64_SR_IRQ_PENDING) {
|
return (pi_io_read(&SC64_REGS->SR_CMD) & SC64_SR_IRQ_PENDING);
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void sc64_irq_clear (void) {
|
void sc64_irq_clear (void) {
|
||||||
pi_io_write(&SC64_REGS->IDENTIFIER, 0);
|
pi_io_write(&SC64_REGS->IDENTIFIER, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t sc64_get_config (sc64_cfg_id_t id) {
|
|
||||||
uint32_t args[2] = { id, 0 };
|
|
||||||
uint32_t result[2];
|
|
||||||
sc64_execute_cmd(SC64_CMD_CONFIG_GET, args, result);
|
|
||||||
return result[1];
|
|
||||||
}
|
|
||||||
|
|
||||||
void sc64_set_config (sc64_cfg_id_t id, uint32_t value) {
|
sc64_error_t sc64_get_identifier (uint32_t *identifier) {
|
||||||
uint32_t args[2] = { id, value };
|
sc64_cmd_t cmd = {
|
||||||
sc64_execute_cmd(SC64_CMD_CONFIG_SET, args, NULL);
|
.id = CMD_ID_IDENTIFIER_GET
|
||||||
}
|
|
||||||
|
|
||||||
uint32_t sc64_get_setting (sc64_setting_id_t id) {
|
|
||||||
uint32_t args[2] = { id, 0 };
|
|
||||||
uint32_t result[2];
|
|
||||||
sc64_execute_cmd(SC64_CMD_SETTING_GET, args, result);
|
|
||||||
return result[1];
|
|
||||||
}
|
|
||||||
|
|
||||||
void sc64_set_setting (sc64_setting_id_t id, uint32_t value) {
|
|
||||||
uint32_t args[2] = { id, value };
|
|
||||||
sc64_execute_cmd(SC64_CMD_SETTING_SET, args, NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
void sc64_get_boot_info (sc64_boot_info_t *info) {
|
|
||||||
info->boot_mode = (sc64_boot_mode_t) sc64_get_config(CFG_ID_BOOT_MODE);
|
|
||||||
info->cic_seed = (sc64_cic_seed_t) sc64_get_config(CFG_ID_CIC_SEED);
|
|
||||||
info->tv_type = (sc64_tv_type_t) sc64_get_config(CFG_ID_TV_TYPE);
|
|
||||||
}
|
|
||||||
|
|
||||||
void sc64_get_time (sc64_rtc_time_t *t) {
|
|
||||||
uint32_t result[2];
|
|
||||||
sc64_execute_cmd(SC64_CMD_TIME_GET, NULL, result);
|
|
||||||
t->second = (result[0] & 0xFF);
|
|
||||||
t->minute = ((result[0] >> 8) & 0xFF);
|
|
||||||
t->hour = ((result[0] >> 16) & 0xFF);
|
|
||||||
t->weekday = ((result[1] >> 24) & 0xFF);
|
|
||||||
t->day = (result[1] & 0xFF);
|
|
||||||
t->month = ((result[1] >> 8) & 0xFF);
|
|
||||||
t->year = ((result[1] >> 16) & 0xFF);
|
|
||||||
}
|
|
||||||
|
|
||||||
void sc64_set_time (sc64_rtc_time_t *t) {
|
|
||||||
uint32_t args[2] = {
|
|
||||||
((t->hour << 16) | (t->minute << 8) | t->second),
|
|
||||||
((t->weekday << 24) | (t->year << 16) | (t->month << 8) | t->day),
|
|
||||||
};
|
};
|
||||||
sc64_execute_cmd(SC64_CMD_TIME_SET, args, NULL);
|
sc64_error_t error = sc64_execute_cmd(&cmd);
|
||||||
|
*identifier = cmd.rsp[0];
|
||||||
|
return error;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool sc64_usb_read_ready (uint8_t *type, uint32_t *length) {
|
sc64_error_t sc64_get_version (uint16_t *major, uint16_t *minor, uint32_t *revision) {
|
||||||
uint32_t result[2];
|
sc64_cmd_t cmd = {
|
||||||
sc64_execute_cmd(SC64_CMD_USB_READ_STATUS, NULL, result);
|
.id = CMD_ID_VERSION_GET
|
||||||
if (type != NULL) {
|
};
|
||||||
*type = result[0] & 0xFF;
|
sc64_error_t error = sc64_execute_cmd(&cmd);
|
||||||
|
*major = ((cmd.rsp[0] >> 16) & 0xFFFF);
|
||||||
|
*minor = (cmd.rsp[0] & 0xFFFF);
|
||||||
|
*revision = cmd.rsp[1];
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
sc64_error_t sc64_get_config (sc64_cfg_id_t id, uint32_t *value) {
|
||||||
|
sc64_cmd_t cmd = {
|
||||||
|
.id = CMD_ID_CONFIG_GET,
|
||||||
|
.arg = { id }
|
||||||
|
};
|
||||||
|
sc64_error_t error = sc64_execute_cmd(&cmd);
|
||||||
|
*value = cmd.rsp[1];
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
|
||||||
|
sc64_error_t sc64_set_config (sc64_cfg_id_t id, uint32_t value) {
|
||||||
|
sc64_cmd_t cmd = {
|
||||||
|
.id = CMD_ID_CONFIG_SET,
|
||||||
|
.arg = { id, value }
|
||||||
|
};
|
||||||
|
return sc64_execute_cmd(&cmd);
|
||||||
|
}
|
||||||
|
|
||||||
|
sc64_error_t sc64_get_setting (sc64_setting_id_t id, uint32_t *value) {
|
||||||
|
sc64_cmd_t cmd = {
|
||||||
|
.id = CMD_ID_SETTING_GET,
|
||||||
|
.arg = { id }
|
||||||
|
};
|
||||||
|
sc64_error_t error = sc64_execute_cmd(&cmd);
|
||||||
|
*value = cmd.rsp[1];
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
|
||||||
|
sc64_error_t sc64_set_setting (sc64_setting_id_t id, uint32_t value) {
|
||||||
|
sc64_cmd_t cmd = {
|
||||||
|
.id = CMD_ID_SETTING_SET,
|
||||||
|
.arg = { id, value }
|
||||||
|
};
|
||||||
|
return sc64_execute_cmd(&cmd);
|
||||||
|
}
|
||||||
|
|
||||||
|
sc64_error_t sc64_get_boot_info (sc64_boot_info_t *info) {
|
||||||
|
sc64_error_t error;
|
||||||
|
uint32_t value;
|
||||||
|
|
||||||
|
if ((error = sc64_get_config(CFG_ID_BOOT_MODE, &value)) != SC64_OK) {
|
||||||
|
return error;
|
||||||
}
|
}
|
||||||
if (length != NULL) {
|
info->boot_mode = value;
|
||||||
*length = result[1];
|
|
||||||
|
if ((error = sc64_get_config(CFG_ID_CIC_SEED, &value)) != SC64_OK) {
|
||||||
|
return error;
|
||||||
}
|
}
|
||||||
return (result[1] > 0);
|
info->cic_seed = value;
|
||||||
}
|
|
||||||
|
|
||||||
bool sc64_usb_read (void *address, uint32_t length) {
|
if ((error = sc64_get_config(CFG_ID_TV_TYPE, &value)) != SC64_OK) {
|
||||||
uint32_t args[2] = { (uint32_t) (address), length };
|
return error;
|
||||||
uint32_t result[2];
|
|
||||||
if (sc64_execute_cmd(SC64_CMD_USB_READ, args, NULL)) {
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
do {
|
info->tv_type = value;
|
||||||
sc64_execute_cmd(SC64_CMD_USB_READ_STATUS, NULL, result);
|
|
||||||
} while(result[0] & (1 << 31));
|
return SC64_OK;
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool sc64_usb_write_ready (void) {
|
|
||||||
uint32_t result[2];
|
sc64_error_t sc64_get_time (sc64_rtc_time_t *t) {
|
||||||
sc64_execute_cmd(SC64_CMD_USB_WRITE_STATUS, NULL, result);
|
sc64_cmd_t cmd = {
|
||||||
return (!(result[0] & (1 << 31)));
|
.id = CMD_ID_TIME_GET
|
||||||
|
};
|
||||||
|
sc64_error_t error = sc64_execute_cmd(&cmd);
|
||||||
|
t->hour = ((cmd.rsp[0] >> 16) & 0xFF);
|
||||||
|
t->minute = ((cmd.rsp[0] >> 8) & 0xFF);
|
||||||
|
t->second = (cmd.rsp[0] & 0xFF);
|
||||||
|
t->weekday = ((cmd.rsp[1] >> 24) & 0xFF);
|
||||||
|
t->year = ((cmd.rsp[1] >> 16) & 0xFF);
|
||||||
|
t->month = ((cmd.rsp[1] >> 8) & 0xFF);
|
||||||
|
t->day = (cmd.rsp[1] & 0xFF);
|
||||||
|
return error;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool sc64_usb_write (void *address, uint8_t type, uint32_t length) {
|
sc64_error_t sc64_set_time (sc64_rtc_time_t *t) {
|
||||||
while (!sc64_usb_write_ready());
|
uint32_t time[2] = {(
|
||||||
uint32_t args[2] = { (uint32_t) (address), ((type << 24) | (length & 0xFFFFFF)) };
|
((t->hour << 16) & 0xFF) |
|
||||||
return sc64_execute_cmd(SC64_CMD_USB_WRITE, args, NULL);
|
((t->minute << 8) & 0xFF) |
|
||||||
|
(t->second & 0xFF)
|
||||||
|
), (
|
||||||
|
((t->weekday << 24) & 0xFF) |
|
||||||
|
((t->year << 16) & 0xFF) |
|
||||||
|
((t->month << 8) & 0xFF) |
|
||||||
|
(t->day & 0xFF)
|
||||||
|
)};
|
||||||
|
sc64_cmd_t cmd = {
|
||||||
|
.id = CMD_ID_TIME_SET,
|
||||||
|
.arg = { time[0], time[1] }
|
||||||
|
};
|
||||||
|
return sc64_execute_cmd(&cmd);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool sc64_sd_card_init (void) {
|
|
||||||
uint32_t args[2] = { (uint32_t) (NULL), SD_CARD_OP_INIT };
|
sc64_error_t sc64_usb_get_status (bool *reset_state, bool *cable_unplugged) {
|
||||||
if (sc64_execute_cmd(SC64_CMD_SD_CARD_OP, args, NULL)) {
|
sc64_cmd_t cmd = {
|
||||||
return true;
|
.id = CMD_ID_USB_READ_STATUS,
|
||||||
|
};
|
||||||
|
sc64_error_t error = sc64_execute_cmd(&cmd);
|
||||||
|
*reset_state = (bool) (cmd.rsp[0] & (1 << 30));
|
||||||
|
*cable_unplugged = (bool) (cmd.rsp[0] & (1 << 29));
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
|
||||||
|
sc64_error_t sc64_usb_read_info (uint8_t *type, uint32_t *length) {
|
||||||
|
sc64_cmd_t cmd = {
|
||||||
|
.id = CMD_ID_USB_READ_STATUS,
|
||||||
|
};
|
||||||
|
sc64_error_t error = sc64_execute_cmd(&cmd);
|
||||||
|
*type = (cmd.rsp[0] & 0xFF);
|
||||||
|
*length = cmd.rsp[1];
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
|
||||||
|
sc64_error_t sc64_usb_read_busy (bool *read_busy) {
|
||||||
|
sc64_cmd_t cmd = {
|
||||||
|
.id = CMD_ID_USB_READ_STATUS,
|
||||||
|
};
|
||||||
|
sc64_error_t error = sc64_execute_cmd(&cmd);
|
||||||
|
*read_busy = (bool) (cmd.rsp[0] & (1 << 31));
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
|
||||||
|
sc64_error_t sc64_usb_write_busy (bool *write_busy) {
|
||||||
|
sc64_cmd_t cmd = {
|
||||||
|
.id = CMD_ID_USB_WRITE_STATUS,
|
||||||
|
};
|
||||||
|
sc64_error_t error = sc64_execute_cmd(&cmd);
|
||||||
|
*write_busy = (bool) (cmd.rsp[0] & (1 << 31));
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
|
||||||
|
sc64_error_t sc64_usb_read (void *address, uint32_t length) {
|
||||||
|
sc64_cmd_t cmd = {
|
||||||
|
.id = CMD_ID_USB_READ,
|
||||||
|
.arg = { (uint32_t) (address), length }
|
||||||
|
};
|
||||||
|
return sc64_execute_cmd(&cmd);
|
||||||
|
}
|
||||||
|
|
||||||
|
sc64_error_t sc64_usb_write (void *address, uint8_t type, uint32_t length) {
|
||||||
|
sc64_cmd_t cmd = {
|
||||||
|
.id = CMD_ID_USB_WRITE,
|
||||||
|
.arg = { (uint32_t) (address), ((type << 24) | (length & 0xFFFFFF)) }
|
||||||
|
};
|
||||||
|
return sc64_execute_cmd(&cmd);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
sc64_error_t sc64_sd_card_init (void) {
|
||||||
|
sc64_cmd_t cmd = {
|
||||||
|
.id = CMD_ID_SD_CARD_OP,
|
||||||
|
.arg = { (uint32_t) (NULL), SD_CARD_OP_INIT }
|
||||||
|
};
|
||||||
|
return sc64_execute_cmd(&cmd);
|
||||||
|
}
|
||||||
|
|
||||||
|
sc64_error_t sc64_sd_card_deinit (void) {
|
||||||
|
sc64_cmd_t cmd = {
|
||||||
|
.id = CMD_ID_SD_CARD_OP,
|
||||||
|
.arg = { (uint32_t) (NULL), SD_CARD_OP_DEINIT }
|
||||||
|
};
|
||||||
|
return sc64_execute_cmd(&cmd);
|
||||||
|
}
|
||||||
|
|
||||||
|
sc64_error_t sc64_sd_card_get_status (sc64_sd_card_status_t *sd_card_status) {
|
||||||
|
sc64_cmd_t cmd = {
|
||||||
|
.id = CMD_ID_SD_CARD_OP,
|
||||||
|
.arg = { (uint32_t) (NULL), SD_CARD_OP_GET_STATUS }
|
||||||
|
};
|
||||||
|
sc64_error_t error = sc64_execute_cmd(&cmd);
|
||||||
|
*sd_card_status = (sc64_sd_card_status_t) (cmd.rsp[1]);
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
|
||||||
|
sc64_error_t sc64_sd_card_get_info (void *address) {
|
||||||
|
sc64_cmd_t cmd = {
|
||||||
|
.id = CMD_ID_SD_CARD_OP,
|
||||||
|
.arg = { (uint32_t) (address), SD_CARD_OP_GET_INFO }
|
||||||
|
};
|
||||||
|
return sc64_execute_cmd(&cmd);
|
||||||
|
}
|
||||||
|
|
||||||
|
sc64_error_t sc64_sd_set_byte_swap (bool enabled) {
|
||||||
|
sc64_cmd_t cmd = {
|
||||||
|
.id = CMD_ID_SD_CARD_OP,
|
||||||
|
.arg = { (uint32_t) (NULL), enabled ? SD_CARD_OP_BYTE_SWAP_ON : SD_CARD_OP_BYTE_SWAP_OFF }
|
||||||
|
};
|
||||||
|
return sc64_execute_cmd(&cmd);
|
||||||
|
}
|
||||||
|
|
||||||
|
static sc64_error_t sc64_sd_sector_set (uint32_t sector) {
|
||||||
|
sc64_cmd_t cmd = {
|
||||||
|
.id = CMD_ID_SD_SECTOR_SET,
|
||||||
|
.arg = { sector }
|
||||||
|
};
|
||||||
|
return sc64_execute_cmd(&cmd);
|
||||||
|
}
|
||||||
|
|
||||||
|
sc64_error_t sc64_sd_read_sectors (void *address, uint32_t sector, uint32_t count) {
|
||||||
|
sc64_error_t error;
|
||||||
|
if ((error = sc64_sd_sector_set(sector)) != SC64_OK) {
|
||||||
|
return error;
|
||||||
}
|
}
|
||||||
return false;
|
sc64_cmd_t cmd = {
|
||||||
|
.id = CMD_ID_SD_READ,
|
||||||
|
.arg = { (uint32_t) (address), count }
|
||||||
|
};
|
||||||
|
return sc64_execute_cmd(&cmd);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool sc64_sd_card_deinit (void) {
|
sc64_error_t sc64_sd_write_sectors (void *address, uint32_t sector, uint32_t count) {
|
||||||
uint32_t args[2] = { (uint32_t) (NULL), SD_CARD_OP_DEINIT };
|
sc64_error_t error;
|
||||||
if (sc64_execute_cmd(SC64_CMD_SD_CARD_OP, args, NULL)) {
|
if ((error = sc64_sd_sector_set(sector)) != SC64_OK) {
|
||||||
return true;
|
return error;
|
||||||
}
|
}
|
||||||
return false;
|
sc64_cmd_t cmd = {
|
||||||
|
.id = CMD_ID_SD_WRITE,
|
||||||
|
.arg = { (uint32_t) (address), count }
|
||||||
|
};
|
||||||
|
return sc64_execute_cmd(&cmd);
|
||||||
}
|
}
|
||||||
|
|
||||||
sc64_sd_card_status_t sc64_sd_card_get_status (void) {
|
|
||||||
uint32_t args[2] = { (uint32_t) (NULL), SD_CARD_OP_GET_STATUS };
|
sc64_error_t sc64_dd_set_sd_info (void *address, uint32_t length) {
|
||||||
uint32_t result[2];
|
sc64_cmd_t cmd = {
|
||||||
if (sc64_execute_cmd(SC64_CMD_SD_CARD_OP, args, result)) {
|
.id = CMD_ID_DD_SD_INFO,
|
||||||
return false;
|
.arg = { (uint32_t) (address), length }
|
||||||
|
};
|
||||||
|
return sc64_execute_cmd(&cmd);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
sc64_error_t sc64_writeback_pending (bool *pending) {
|
||||||
|
sc64_cmd_t cmd = {
|
||||||
|
.id = CMD_ID_WRITEBACK_PENDING
|
||||||
|
};
|
||||||
|
sc64_error_t error = sc64_execute_cmd(&cmd);
|
||||||
|
*pending = (cmd.rsp[0] != 0);
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
|
||||||
|
sc64_error_t sc64_writeback_enable (void *address) {
|
||||||
|
sc64_cmd_t cmd = {
|
||||||
|
.id = CMD_ID_WRITEBACK_SD_INFO,
|
||||||
|
.arg = { (uint32_t) (address) }
|
||||||
|
};
|
||||||
|
return sc64_execute_cmd(&cmd);
|
||||||
|
}
|
||||||
|
|
||||||
|
sc64_error_t sc64_writeback_disable (void) {
|
||||||
|
sc64_error_t error;
|
||||||
|
uint32_t save_type;
|
||||||
|
error = sc64_get_config(CFG_ID_SAVE_TYPE, &save_type);
|
||||||
|
if (error != SC64_OK) {
|
||||||
|
return error;
|
||||||
}
|
}
|
||||||
return (sc64_sd_card_status_t) (result[1]);
|
return sc64_set_config(CFG_ID_SAVE_TYPE, save_type);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool sc64_sd_card_get_info (void *address) {
|
|
||||||
uint32_t args[2] = { (uint32_t) (address), SD_CARD_OP_GET_INFO };
|
sc64_error_t sc64_flash_program (void *address, uint32_t length) {
|
||||||
if (sc64_execute_cmd(SC64_CMD_SD_CARD_OP, args, NULL)) {
|
sc64_cmd_t cmd = {
|
||||||
return true;
|
.id = CMD_ID_FLASH_PROGRAM,
|
||||||
}
|
.arg = { (uint32_t) (address), length }
|
||||||
return false;
|
};
|
||||||
|
return sc64_execute_cmd(&cmd);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool sc64_sd_set_byte_swap (bool enabled) {
|
sc64_error_t sc64_flash_wait_busy (void) {
|
||||||
uint32_t args[2] = { (uint32_t) (NULL), enabled ? SD_CARD_OP_BYTE_SWAP_ON : SD_CARD_OP_BYTE_SWAP_OFF };
|
sc64_cmd_t cmd = {
|
||||||
if (sc64_execute_cmd(SC64_CMD_SD_CARD_OP, args, NULL)) {
|
.id = CMD_ID_FLASH_WAIT_BUSY,
|
||||||
return true;
|
.arg = { true }
|
||||||
}
|
};
|
||||||
return false;
|
return sc64_execute_cmd(&cmd);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool sc64_sd_read_sectors (void *address, uint32_t sector, uint32_t count) {
|
sc64_error_t sc64_flash_get_erase_block_size (size_t *erase_block_size) {
|
||||||
uint32_t sector_set_args[2] = { sector, 0 };
|
sc64_cmd_t cmd = {
|
||||||
uint32_t read_args[2] = { (uint32_t) (address), count };
|
.id = CMD_ID_FLASH_WAIT_BUSY,
|
||||||
if (sc64_execute_cmd(SC64_CMD_SD_SECTOR_SET, sector_set_args, NULL)) {
|
.arg = { false }
|
||||||
return true;
|
};
|
||||||
}
|
sc64_error_t error = sc64_execute_cmd(&cmd);
|
||||||
return sc64_execute_cmd(SC64_CMD_SD_READ, read_args, NULL);
|
*erase_block_size = (size_t) (cmd.rsp[0]);
|
||||||
|
return error;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool sc64_sd_write_sectors (void *address, uint32_t sector, uint32_t count) {
|
sc64_error_t sc64_flash_erase_block (void *address) {
|
||||||
uint32_t sector_set_args[2] = { sector, 0 };
|
sc64_cmd_t cmd = {
|
||||||
uint32_t write_args[2] = { (uint32_t) (address), count };
|
.id = CMD_ID_FLASH_ERASE_BLOCK,
|
||||||
if (sc64_execute_cmd(SC64_CMD_SD_SECTOR_SET, sector_set_args, NULL)) {
|
.arg = { (uint32_t) (address) }
|
||||||
return true;
|
};
|
||||||
}
|
return sc64_execute_cmd(&cmd);
|
||||||
return sc64_execute_cmd(SC64_CMD_SD_WRITE, write_args, NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool sc64_dd_set_sd_info (void *address, uint32_t length) {
|
|
||||||
uint32_t args[2] = { (uint32_t) (address), length };
|
|
||||||
if (sc64_execute_cmd(SC64_CMD_DD_SD_INFO, args, NULL)) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool sc64_writeback_enable (void *address) {
|
|
||||||
uint32_t args[2] = { (uint32_t) (address), 0 };
|
|
||||||
if (sc64_execute_cmd(SC64_CMD_WRITEBACK_SD_INFO, args, NULL)) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool sc64_flash_program (void *address, uint32_t length) {
|
|
||||||
uint32_t args[2] = { (uint32_t) (address), length };
|
|
||||||
return sc64_execute_cmd(SC64_CMD_FLASH_PROGRAM, args, NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
void sc64_flash_wait_busy (void) {
|
|
||||||
uint32_t args[2] = { true, 0 };
|
|
||||||
sc64_execute_cmd(SC64_CMD_FLASH_WAIT_BUSY, args, NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
uint32_t sc64_flash_get_erase_block_size (void) {
|
|
||||||
uint32_t args[2] = { false, 0 };
|
|
||||||
uint32_t result[2];
|
|
||||||
sc64_execute_cmd(SC64_CMD_FLASH_WAIT_BUSY, args, result);
|
|
||||||
return result[0];
|
|
||||||
}
|
|
||||||
|
|
||||||
bool sc64_flash_erase_block (void *address) {
|
|
||||||
uint32_t args[2] = { (uint32_t) (address), 0 };
|
|
||||||
return sc64_execute_cmd(SC64_CMD_FLASH_ERASE_BLOCK, args, NULL);
|
|
||||||
}
|
}
|
||||||
|
@ -21,7 +21,7 @@ typedef enum {
|
|||||||
CFG_ID_ROM_WRITE_ENABLE,
|
CFG_ID_ROM_WRITE_ENABLE,
|
||||||
CFG_ID_ROM_SHADOW_ENABLE,
|
CFG_ID_ROM_SHADOW_ENABLE,
|
||||||
CFG_ID_DD_MODE,
|
CFG_ID_DD_MODE,
|
||||||
CFG_ID_ISV_ENABLE,
|
CFG_ID_ISV_ADDRESS,
|
||||||
CFG_ID_BOOT_MODE,
|
CFG_ID_BOOT_MODE,
|
||||||
CFG_ID_SAVE_TYPE,
|
CFG_ID_SAVE_TYPE,
|
||||||
CFG_ID_CIC_SEED,
|
CFG_ID_CIC_SEED,
|
||||||
@ -74,6 +74,17 @@ typedef enum {
|
|||||||
TV_TYPE_PASSTHROUGH = 3
|
TV_TYPE_PASSTHROUGH = 3
|
||||||
} sc64_tv_type_t;
|
} sc64_tv_type_t;
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
DRIVE_TYPE_RETAIL,
|
||||||
|
DRIVE_TYPE_DEVELOPMENT,
|
||||||
|
} sc64_drive_type_t;
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
DISK_STATE_EJECTED,
|
||||||
|
DISK_STATE_INSERTED,
|
||||||
|
DISK_STATE_CHANGED,
|
||||||
|
} sc64_disk_state_t;
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
BUTTON_MODE_NONE,
|
BUTTON_MODE_NONE,
|
||||||
BUTTON_MODE_N64_IRQ,
|
BUTTON_MODE_N64_IRQ,
|
||||||
@ -81,14 +92,6 @@ typedef enum {
|
|||||||
BUTTON_MODE_DD_DISK_SWAP,
|
BUTTON_MODE_DD_DISK_SWAP,
|
||||||
} sc64_button_mode_t;
|
} sc64_button_mode_t;
|
||||||
|
|
||||||
typedef enum {
|
|
||||||
SD_CARD_STATUS_INSERTED = (1 << 0),
|
|
||||||
SD_CARD_STATUS_INITIALIZED = (1 << 1),
|
|
||||||
SD_CARD_STATUS_TYPE_BLOCK = (1 << 2),
|
|
||||||
SD_CARD_STATUS_50MHZ_MODE = (1 << 3),
|
|
||||||
SD_CARD_STATUS_BYTE_SWAP = (1 << 4),
|
|
||||||
} sc64_sd_card_status_t;
|
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
sc64_boot_mode_t boot_mode;
|
sc64_boot_mode_t boot_mode;
|
||||||
sc64_cic_seed_t cic_seed;
|
sc64_cic_seed_t cic_seed;
|
||||||
@ -105,6 +108,14 @@ typedef struct {
|
|||||||
uint8_t year;
|
uint8_t year;
|
||||||
} sc64_rtc_time_t;
|
} sc64_rtc_time_t;
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
SD_CARD_STATUS_INSERTED = (1 << 0),
|
||||||
|
SD_CARD_STATUS_INITIALIZED = (1 << 1),
|
||||||
|
SD_CARD_STATUS_TYPE_BLOCK = (1 << 2),
|
||||||
|
SD_CARD_STATUS_50MHZ_MODE = (1 << 3),
|
||||||
|
SD_CARD_STATUS_BYTE_SWAP = (1 << 4),
|
||||||
|
} sc64_sd_card_status_t;
|
||||||
|
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
volatile uint8_t BUFFER[8192];
|
volatile uint8_t BUFFER[8192];
|
||||||
@ -117,8 +128,6 @@ typedef struct {
|
|||||||
#define SC64_BUFFERS ((sc64_buffers_t *) SC64_BUFFERS_BASE)
|
#define SC64_BUFFERS ((sc64_buffers_t *) SC64_BUFFERS_BASE)
|
||||||
|
|
||||||
|
|
||||||
sc64_error_t sc64_get_error (void);
|
|
||||||
|
|
||||||
void sc64_unlock (void);
|
void sc64_unlock (void);
|
||||||
void sc64_lock (void);
|
void sc64_lock (void);
|
||||||
bool sc64_check_presence (void);
|
bool sc64_check_presence (void);
|
||||||
@ -126,34 +135,43 @@ bool sc64_check_presence (void);
|
|||||||
bool sc64_irq_pending (void);
|
bool sc64_irq_pending (void);
|
||||||
void sc64_irq_clear (void);
|
void sc64_irq_clear (void);
|
||||||
|
|
||||||
uint32_t sc64_get_config (sc64_cfg_id_t id);
|
sc64_error_t sc64_get_identifier (uint32_t *identifier);
|
||||||
void sc64_set_config (sc64_cfg_id_t id, uint32_t value);
|
sc64_error_t sc64_get_version (uint16_t *major, uint16_t *minor, uint32_t *revision);
|
||||||
uint32_t sc64_get_setting (sc64_setting_id_t id);
|
|
||||||
void sc64_set_setting (sc64_setting_id_t id, uint32_t value);
|
|
||||||
void sc64_get_boot_info (sc64_boot_info_t *info);
|
|
||||||
|
|
||||||
void sc64_get_time (sc64_rtc_time_t *t);
|
sc64_error_t sc64_get_config (sc64_cfg_id_t id, uint32_t *value);
|
||||||
void sc64_set_time (sc64_rtc_time_t *t);
|
sc64_error_t sc64_set_config (sc64_cfg_id_t id, uint32_t value);
|
||||||
|
sc64_error_t sc64_get_setting (sc64_setting_id_t id, uint32_t *value);
|
||||||
|
sc64_error_t sc64_set_setting (sc64_setting_id_t id, uint32_t value);
|
||||||
|
sc64_error_t sc64_get_boot_info (sc64_boot_info_t *info);
|
||||||
|
|
||||||
bool sc64_usb_read_ready (uint8_t *type, uint32_t *length);
|
sc64_error_t sc64_get_time (sc64_rtc_time_t *t);
|
||||||
bool sc64_usb_read (void *address, uint32_t length);
|
sc64_error_t sc64_set_time (sc64_rtc_time_t *t);
|
||||||
bool sc64_usb_write_ready (void);
|
|
||||||
bool sc64_usb_write (void *address, uint8_t type, uint32_t length);
|
|
||||||
|
|
||||||
bool sc64_sd_card_init (void);
|
sc64_error_t sc64_usb_get_status (bool *reset_state, bool *cable_unplugged);
|
||||||
bool sc64_sd_card_deinit (void);
|
sc64_error_t sc64_usb_read_info (uint8_t *type, uint32_t *length);
|
||||||
sc64_sd_card_status_t sc64_sd_card_get_status (void);
|
sc64_error_t sc64_usb_read_busy (bool *read_busy);
|
||||||
bool sc64_sd_card_get_info (void *address);
|
sc64_error_t sc64_usb_write_busy (bool *write_busy);
|
||||||
bool sc64_sd_set_byte_swap (bool enabled);
|
sc64_error_t sc64_usb_read (void *address, uint32_t length);
|
||||||
bool sc64_sd_write_sectors (void *address, uint32_t sector, uint32_t count);
|
sc64_error_t sc64_usb_write (void *address, uint8_t type, uint32_t length);
|
||||||
bool sc64_sd_read_sectors (void *address, uint32_t sector, uint32_t count);
|
|
||||||
bool sc64_dd_set_sd_disk_info (void *address, uint32_t length);
|
|
||||||
bool sc64_writeback_enable (void *address);
|
|
||||||
|
|
||||||
bool sc64_flash_program (void *address, uint32_t length);
|
sc64_error_t sc64_sd_card_init (void);
|
||||||
void sc64_flash_wait_busy (void);
|
sc64_error_t sc64_sd_card_deinit (void);
|
||||||
uint32_t sc64_flash_get_erase_block_size (void);
|
sc64_error_t sc64_sd_card_get_status (sc64_sd_card_status_t *sd_card_status);
|
||||||
bool sc64_flash_erase_block (void *address);
|
sc64_error_t sc64_sd_card_get_info (void *address);
|
||||||
|
sc64_error_t sc64_sd_set_byte_swap (bool enabled);
|
||||||
|
sc64_error_t sc64_sd_read_sectors (void *address, uint32_t sector, uint32_t count);
|
||||||
|
sc64_error_t sc64_sd_write_sectors (void *address, uint32_t sector, uint32_t count);
|
||||||
|
|
||||||
|
sc64_error_t sc64_dd_set_sd_info (void *address, uint32_t length);
|
||||||
|
|
||||||
|
sc64_error_t sc64_writeback_pending (bool *pending);
|
||||||
|
sc64_error_t sc64_writeback_enable (void *address);
|
||||||
|
sc64_error_t sc64_writeback_disable (void);
|
||||||
|
|
||||||
|
sc64_error_t sc64_flash_program (void *address, uint32_t length);
|
||||||
|
sc64_error_t sc64_flash_wait_busy (void);
|
||||||
|
sc64_error_t sc64_flash_get_erase_block_size (size_t *erase_block_size);
|
||||||
|
sc64_error_t sc64_flash_erase_block (void *address);
|
||||||
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -1,12 +1,38 @@
|
|||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
|
#include <stdlib.h>
|
||||||
#include "display.h"
|
#include "display.h"
|
||||||
|
#include "error.h"
|
||||||
#include "io.h"
|
#include "io.h"
|
||||||
#include "sc64.h"
|
#include "sc64.h"
|
||||||
#include "test.h"
|
#include "test.h"
|
||||||
|
|
||||||
|
|
||||||
|
static void test_sc64_cfg (void) {
|
||||||
|
sc64_error_t error;
|
||||||
|
uint32_t identifier;
|
||||||
|
uint16_t major;
|
||||||
|
uint16_t minor;
|
||||||
|
uint32_t revision;
|
||||||
|
|
||||||
|
if ((error = sc64_get_identifier(&identifier)) != SC64_OK) {
|
||||||
|
error_display("Command IDENTIFIER_GET failed: %d", error);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((error = sc64_get_version(&major, &minor, &revision)) != SC64_OK) {
|
||||||
|
error_display("Command VERSION_GET failed: %d", error);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
display_printf("Identifier: 0x%08X\n\n", identifier);
|
||||||
|
|
||||||
|
display_printf("SC64 firmware version: %d.%d.%d\n", major, minor, revision);
|
||||||
|
}
|
||||||
|
|
||||||
static void test_rtc (void) {
|
static void test_rtc (void) {
|
||||||
|
sc64_error_t error;
|
||||||
sc64_rtc_time_t t;
|
sc64_rtc_time_t t;
|
||||||
|
|
||||||
const char *weekdays[8] = {
|
const char *weekdays[8] = {
|
||||||
"",
|
"",
|
||||||
"Monday",
|
"Monday",
|
||||||
@ -18,7 +44,9 @@ static void test_rtc (void) {
|
|||||||
"Sunday",
|
"Sunday",
|
||||||
};
|
};
|
||||||
|
|
||||||
sc64_get_time(&t);
|
if ((error = sc64_get_time(&t)) != SC64_OK) {
|
||||||
|
error_display("Command TIME_GET failed: %d", error);
|
||||||
|
}
|
||||||
|
|
||||||
display_printf("RTC current time:\n ");
|
display_printf("RTC current time:\n ");
|
||||||
display_printf("%04d-%02d-%02d", 2000 + FROM_BCD(t.year), FROM_BCD(t.month), FROM_BCD(t.day));
|
display_printf("%04d-%02d-%02d", 2000 + FROM_BCD(t.year), FROM_BCD(t.month), FROM_BCD(t.day));
|
||||||
@ -29,11 +57,14 @@ static void test_rtc (void) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void test_sd_card (void) {
|
static void test_sd_card (void) {
|
||||||
|
sc64_error_t error;
|
||||||
sc64_sd_card_status_t card_status;
|
sc64_sd_card_status_t card_status;
|
||||||
uint8_t card_info[32] __attribute__((aligned(8)));
|
uint8_t card_info[32] __attribute__((aligned(8)));
|
||||||
uint8_t sector[512] __attribute__((aligned(8)));
|
uint8_t sector[512] __attribute__((aligned(8)));
|
||||||
|
|
||||||
card_status = sc64_sd_card_get_status();
|
if ((error = sc64_sd_card_get_status(&card_status)) != SC64_OK) {
|
||||||
|
error_display("Could not get SD card info: %d", error);
|
||||||
|
}
|
||||||
|
|
||||||
if (card_status & SD_CARD_STATUS_INSERTED) {
|
if (card_status & SD_CARD_STATUS_INSERTED) {
|
||||||
display_printf("SD card is inserted\n");
|
display_printf("SD card is inserted\n");
|
||||||
@ -41,12 +72,14 @@ static void test_sd_card (void) {
|
|||||||
display_printf("SD card is not inserted\n");
|
display_printf("SD card is not inserted\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (sc64_sd_card_init()) {
|
if ((error = sc64_sd_card_init()) != SC64_OK) {
|
||||||
display_printf("SD card init error!\n");
|
display_printf("SD card init error: %d\n", error);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
card_status = sc64_sd_card_get_status();
|
if ((error = sc64_sd_card_get_status(&card_status)) != SC64_OK) {
|
||||||
|
error_display("Could not get SD card info: %d", error);
|
||||||
|
}
|
||||||
|
|
||||||
if (card_status & SD_CARD_STATUS_INITIALIZED) {
|
if (card_status & SD_CARD_STATUS_INITIALIZED) {
|
||||||
display_printf("SD card is initialized\n");
|
display_printf("SD card is initialized\n");
|
||||||
@ -61,8 +94,8 @@ static void test_sd_card (void) {
|
|||||||
display_printf("SD card read byte swap is enabled\n");
|
display_printf("SD card read byte swap is enabled\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (sc64_sd_card_get_info((uint32_t *) (SC64_BUFFERS->BUFFER))) {
|
if ((error = sc64_sd_card_get_info((uint32_t *) (SC64_BUFFERS->BUFFER))) != SC64_OK) {
|
||||||
display_printf("SD card get info error!\n");
|
display_printf("SD card get info error: %d\n", error);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -82,8 +115,8 @@ static void test_sd_card (void) {
|
|||||||
}
|
}
|
||||||
display_printf("\n");
|
display_printf("\n");
|
||||||
|
|
||||||
if (sc64_sd_read_sectors((void *) (SC64_BUFFERS->BUFFER), 0, 1)) {
|
if ((error = sc64_sd_read_sectors((void *) (SC64_BUFFERS->BUFFER), 0, 1)) != SC64_OK) {
|
||||||
display_printf("SD card read sector 0 error!\n");
|
display_printf("SD card read sector 0 error: %d\n", error);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -101,25 +134,138 @@ static void test_sd_card (void) {
|
|||||||
display_printf(" Boot signature: 0x%02X%02X\n", sector[510], sector[511]);
|
display_printf(" Boot signature: 0x%02X%02X\n", sector[510], sector[511]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#define SDRAM_ADDRESS (0x10000000)
|
||||||
|
#define SDRAM_SIZE (64 * 1024 * 1024)
|
||||||
|
#define BUFFER_SIZE (128 * 1024)
|
||||||
|
|
||||||
|
static uint32_t w_buffer[BUFFER_SIZE / sizeof(uint32_t)] __attribute__((aligned(8)));
|
||||||
|
static uint32_t r_buffer[BUFFER_SIZE / sizeof(uint32_t)] __attribute__((aligned(8)));
|
||||||
|
|
||||||
|
static void test_sdram (void) {
|
||||||
|
sc64_error_t error;
|
||||||
|
|
||||||
|
if ((error = sc64_set_config(CFG_ID_ROM_WRITE_ENABLE, true))) {
|
||||||
|
error_display("Command CONFIG_SET [ROM_WRITE_ENABLE] failed: %d", error);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((error = sc64_set_config(CFG_ID_ROM_SHADOW_ENABLE, false))) {
|
||||||
|
error_display("Command CONFIG_SET [ROM_SHADOW_ENABLE] failed: %d", error);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
pi_io_config(0x0B, 0x05, 0x0C, 0x02);
|
||||||
|
display_printf("PI config - PGS: 0x0B, LAT: 0x05, PWD: 0x0C, RLS: 0x02\n");
|
||||||
|
|
||||||
|
const struct patterns_s {
|
||||||
|
bool constant;
|
||||||
|
uint32_t value;
|
||||||
|
} patterns[] = {
|
||||||
|
{ .constant = true, .value = 0x00000000 },
|
||||||
|
{ .constant = true, .value = 0xFFFFFFFF },
|
||||||
|
{ .constant = true, .value = 0xFFFF0000 },
|
||||||
|
{ .constant = true, .value = 0x0000FFFF },
|
||||||
|
{ .constant = true, .value = 0xF0F0F0F0 },
|
||||||
|
{ .constant = true, .value = 0x0F0F0F0F },
|
||||||
|
{ .constant = true, .value = 0xAAAAAAAA },
|
||||||
|
{ .constant = true, .value = 0x55555555 },
|
||||||
|
{ .constant = true, .value = 0xA5A5A5A5 },
|
||||||
|
{ .constant = true, .value = 0x5A5A5A5A },
|
||||||
|
{ .constant = false },
|
||||||
|
{ .constant = false },
|
||||||
|
};
|
||||||
|
|
||||||
|
srand(c0_count());
|
||||||
|
|
||||||
|
for (int pattern = 0; pattern < sizeof(patterns) / sizeof(patterns[0]); pattern++) {
|
||||||
|
if (patterns[pattern].constant) {
|
||||||
|
display_printf("Pattern: 0x%08X ", patterns[pattern].value);
|
||||||
|
for (int i = 0; i < BUFFER_SIZE / sizeof(uint32_t); i++) {
|
||||||
|
w_buffer[i] = patterns[pattern].value;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
display_printf("Pattern: random ");
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int offset = 0; offset < SDRAM_SIZE; offset += BUFFER_SIZE) {
|
||||||
|
if (!patterns[pattern].constant) {
|
||||||
|
for (int i = 0; i < BUFFER_SIZE / sizeof(uint32_t); i++) {
|
||||||
|
*UNCACHED(&w_buffer[i]) = (rand() << 31) | rand();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pi_dma_write((io32_t *) (SDRAM_ADDRESS + offset), w_buffer, BUFFER_SIZE);
|
||||||
|
|
||||||
|
pi_dma_read((io32_t *) (SDRAM_ADDRESS + offset), r_buffer, BUFFER_SIZE);
|
||||||
|
|
||||||
|
for (int i = 0; i < BUFFER_SIZE / sizeof(uint32_t); i++) {
|
||||||
|
if (*UNCACHED(&w_buffer[i]) != *UNCACHED(&r_buffer[i])) {
|
||||||
|
display_printf(
|
||||||
|
"\nMISMATCH: [0x%08X]: 0x%08X (R) != 0x%08X (W)\n",
|
||||||
|
SDRAM_ADDRESS + offset,
|
||||||
|
*UNCACHED(&r_buffer[i]),
|
||||||
|
*UNCACHED(&w_buffer[i])
|
||||||
|
);
|
||||||
|
while (true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((offset % (SDRAM_SIZE / 32)) == 0) {
|
||||||
|
display_printf(".");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
display_printf(" OK\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
bool test_check (void) {
|
bool test_check (void) {
|
||||||
|
sc64_error_t error;
|
||||||
|
uint32_t button_state;
|
||||||
|
|
||||||
if (OS_INFO->reset_type != OS_INFO_RESET_TYPE_COLD) {
|
if (OS_INFO->reset_type != OS_INFO_RESET_TYPE_COLD) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return sc64_get_config(CFG_ID_BUTTON_STATE);
|
|
||||||
|
if ((error = sc64_get_config(CFG_ID_BUTTON_STATE, &button_state)) != SC64_OK) {
|
||||||
|
error_display("Command CONFIG_GET [BUTTON_STATE] failed: %d", error);
|
||||||
|
}
|
||||||
|
|
||||||
|
return button_state != 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static struct {
|
||||||
|
const char *title;
|
||||||
|
void (*fn) (void);
|
||||||
|
} tests[] = {
|
||||||
|
{ "SC64 CFG", test_sc64_cfg },
|
||||||
|
{ "RTC", test_rtc },
|
||||||
|
{ "SD card", test_sd_card },
|
||||||
|
{ "SDRAM", test_sdram },
|
||||||
|
};
|
||||||
|
|
||||||
void test_execute (void) {
|
void test_execute (void) {
|
||||||
display_init(NULL);
|
const int test_count = sizeof(tests) / sizeof(tests[0]);
|
||||||
display_printf("SC64 Test suite\n\n");
|
int current = 0;
|
||||||
|
|
||||||
display_printf("[ RTC tests ]\n");
|
while (true) {
|
||||||
test_rtc();
|
display_init(NULL);
|
||||||
display_printf("\n");
|
display_printf("SC64 Test suite (%d / %d)\n\n", current + 1, test_count);
|
||||||
|
|
||||||
display_printf("[ SD card tests ]\n");
|
display_printf("[ %s tests ]\n\n", tests[current].title);
|
||||||
test_sd_card();
|
tests[current].fn();
|
||||||
display_printf("\n");
|
display_printf("\n");
|
||||||
|
|
||||||
while (1);
|
current += 1;
|
||||||
|
if (current == test_count) {
|
||||||
|
current = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
display_printf("Next test [ %s ] starts in: ", tests[current].title);
|
||||||
|
for (int delay = 5; delay > 0; delay--) {
|
||||||
|
display_printf("\b%d", delay);
|
||||||
|
delay_ms(1000);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user