Add psram support

it seems to be a tad slower but what do you want....!
This commit is contained in:
Jeff Epler 2025-03-17 20:14:56 -05:00
parent bcb13e295a
commit 9fb0ec8f60
2 changed files with 208 additions and 20 deletions

View file

@ -55,6 +55,9 @@ set(HSTX_D2P 18 CACHE STRING "HSTX D2+ PIN")
option(USE_VGA_RES "Video uses VGA (640x480) resolution" OFF) option(USE_VGA_RES "Video uses VGA (640x480) resolution" OFF)
set(VIDEO_PIN 18 CACHE STRING "VGA Video GPIO base pin (followed by VS, CLK, HS)") set(VIDEO_PIN 18 CACHE STRING "VGA Video GPIO base pin (followed by VS, CLK, HS)")
option(USE_PSRAM "Locate main Mac ram in PSRAM (only for rp2350 / pico 2)" OFF)
set(PSRAM_CS 47 CACHE STRING "PSRAM Chip select pin")
# Pins for PIO-based USB host # Pins for PIO-based USB host
set(PIN_USB_HOST_DP 1 CACHE STRING "USB D+ PIN") set(PIN_USB_HOST_DP 1 CACHE STRING "USB D+ PIN")
set(PIN_USB_HOST_DM 2 CACHE STRING "USB D- PIN") set(PIN_USB_HOST_DM 2 CACHE STRING "USB D- PIN")
@ -123,8 +126,6 @@ else()
add_compile_definitions(GPIO_VID_BASE=${VIDEO_PIN}) add_compile_definitions(GPIO_VID_BASE=${VIDEO_PIN})
set(VIDEO_SRC src/video_vga.c) set(VIDEO_SRC src/video_vga.c)
endif() endif()
add_compile_definitions(PIN_USB_HOST_DP=${PIN_USB_HOST_DP}) add_compile_definitions(PIN_USB_HOST_DP=${PIN_USB_HOST_DP})
@ -132,6 +133,12 @@ add_compile_definitions(PIN_USB_HOST_DM=${PIN_USB_HOST_DM})
add_compile_definitions(PICO_DEFAULT_PIO_USB_DP_PIN=${PIN_USB_HOST_DP}) add_compile_definitions(PICO_DEFAULT_PIO_USB_DP_PIN=${PIN_USB_HOST_DP})
add_compile_definitions(PICO_DEFAULT_PIO_USB_DM_PIN=${PIN_USB_HOST_DM}) add_compile_definitions(PICO_DEFAULT_PIO_USB_DM_PIN=${PIN_USB_HOST_DM})
if (USE_PSRAM)
add_compile_definitions(PIN_PSRAM_CS=${PSRAM_CS} USE_PSRAM=1)
else()
add_compile_definitions(USE_PSRAM=0)
endif()
if (TARGET tinyusb_device) if (TARGET tinyusb_device)
add_executable(firmware add_executable(firmware
src/main.c src/main.c

View file

@ -53,6 +53,10 @@
#include "hw_config.h" #include "hw_config.h"
#endif #endif
#if USE_PSRAM
#include "hardware/structs/qmi.h"
#include "hardware/structs/xip.h"
#endif
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
// Imports and data // Imports and data
@ -69,7 +73,12 @@ static const uint8_t umac_rom[] = {
#include "umac-rom.h" #include "umac-rom.h"
}; };
#if USE_PSRAM
static uint32_t umac_framebuffer_mirror[640*480/32];
#define umac_ram ((uint8_t*)0x15000000)
#else
static uint8_t umac_ram[RAM_SIZE]; static uint8_t umac_ram[RAM_SIZE];
#endif
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
@ -97,6 +106,27 @@ static int umac_cursor_x = 0;
static int umac_cursor_y = 0; static int umac_cursor_y = 0;
static int umac_cursor_button = 0; static int umac_cursor_button = 0;
#if USE_PSRAM
static void copy_framebuffer() {
#if DISP_WIDTH==640 && DISP_HEIGHT==480
uint32_t *src = (uint32_t*)(umac_ram + umac_get_fb_offset()), *dest = umac_framebuffer_mirror;
for(int i=0; i<640*480/32; i++) {
*dest++ = *src++ ^ 0xfffffffful;
}
#elif DISP_WIDTH==512 && DISP_HEIGHT==384
uint32_t *src = umac_ram + umac_get_fb_offset();
for(i=0; i<384; i++) {
uint32_t *dest = umac_framebuffer_mirror + 962 + 20 * i;
for(j=0; j<16; i++) {
*dest++ = *src++ ^ 0xfffffffful;
}
}
#else
#error Unsupported display geometry
#endif
}
#endif
static void poll_umac() static void poll_umac()
{ {
static absolute_time_t last_1hz = 0; static absolute_time_t last_1hz = 0;
@ -108,6 +138,9 @@ static void poll_umac()
int64_t p_1hz = absolute_time_diff_us(last_1hz, now); int64_t p_1hz = absolute_time_diff_us(last_1hz, now);
int64_t p_vsync = absolute_time_diff_us(last_vsync, now); int64_t p_vsync = absolute_time_diff_us(last_vsync, now);
if (p_vsync >= 16667) { if (p_vsync >= 16667) {
#if USE_PSRAM
copy_framebuffer();
#endif
/* FIXME: Trigger this off actual vsync */ /* FIXME: Trigger this off actual vsync */
umac_vsync_event(); umac_vsync_event();
last_vsync = now; last_vsync = now;
@ -251,11 +284,16 @@ static void core1_main()
printf("Core 1 started\n"); printf("Core 1 started\n");
disc_setup(discs); disc_setup(discs);
#if USE_PSRAM
umac_init(umac_ram, (void *)umac_rom, discs);
video_init((uint32_t *)(umac_framebuffer_mirror));
#else
umac_init(umac_ram, (void *)umac_rom, discs); umac_init(umac_ram, (void *)umac_rom, discs);
/* Video runs on core 1, i.e. IRQs/DMA are unaffected by /* Video runs on core 1, i.e. IRQs/DMA are unaffected by
* core 0's USB activity. * core 0's USB activity.
*/ */
video_init((uint32_t *)(umac_ram + umac_get_fb_offset())); video_init((uint32_t *)(umac_ram + umac_get_fb_offset()));
#endif
printf("Enjoyable Mac times now begin:\n\n"); printf("Enjoyable Mac times now begin:\n\n");
@ -264,10 +302,155 @@ static void core1_main()
} }
} }
size_t psram_size;
size_t _psram_size;
static void __no_inline_not_in_flash_func(setup_psram)(void) {
_psram_size = 0;
#if USE_PSRAM
gpio_set_function(PIN_PSRAM_CS, GPIO_FUNC_XIP_CS1);
uint32_t save = save_and_disable_interrupts();
// Try and read the PSRAM ID via direct_csr.
qmi_hw->direct_csr = 30 << QMI_DIRECT_CSR_CLKDIV_LSB |
QMI_DIRECT_CSR_EN_BITS;
// Need to poll for the cooldown on the last XIP transfer to expire
// (via direct-mode BUSY flag) before it is safe to perform the first
// direct-mode operation
while ((qmi_hw->direct_csr & QMI_DIRECT_CSR_BUSY_BITS) != 0) {
}
// Exit out of QMI in case we've inited already
qmi_hw->direct_csr |= QMI_DIRECT_CSR_ASSERT_CS1N_BITS;
// Transmit as quad.
qmi_hw->direct_tx = QMI_DIRECT_TX_OE_BITS |
QMI_DIRECT_TX_IWIDTH_VALUE_Q << QMI_DIRECT_TX_IWIDTH_LSB |
0xf5;
while ((qmi_hw->direct_csr & QMI_DIRECT_CSR_BUSY_BITS) != 0) {
}
(void)qmi_hw->direct_rx;
qmi_hw->direct_csr &= ~(QMI_DIRECT_CSR_ASSERT_CS1N_BITS);
// Read the id
qmi_hw->direct_csr |= QMI_DIRECT_CSR_ASSERT_CS1N_BITS;
uint8_t kgd = 0;
uint8_t eid = 0;
for (size_t i = 0; i < 7; i++) {
if (i == 0) {
qmi_hw->direct_tx = 0x9f;
} else {
qmi_hw->direct_tx = 0xff;
}
while ((qmi_hw->direct_csr & QMI_DIRECT_CSR_TXEMPTY_BITS) == 0) {
}
while ((qmi_hw->direct_csr & QMI_DIRECT_CSR_BUSY_BITS) != 0) {
}
if (i == 5) {
kgd = qmi_hw->direct_rx;
} else if (i == 6) {
eid = qmi_hw->direct_rx;
} else {
(void)qmi_hw->direct_rx;
}
}
// Disable direct csr.
qmi_hw->direct_csr &= ~(QMI_DIRECT_CSR_ASSERT_CS1N_BITS | QMI_DIRECT_CSR_EN_BITS);
if (kgd != 0x5D) {
restore_interrupts(save);
return;
}
// Enable quad mode.
qmi_hw->direct_csr = 30 << QMI_DIRECT_CSR_CLKDIV_LSB |
QMI_DIRECT_CSR_EN_BITS;
// Need to poll for the cooldown on the last XIP transfer to expire
// (via direct-mode BUSY flag) before it is safe to perform the first
// direct-mode operation
while ((qmi_hw->direct_csr & QMI_DIRECT_CSR_BUSY_BITS) != 0) {
}
// RESETEN, RESET and quad enable
for (uint8_t i = 0; i < 3; i++) {
qmi_hw->direct_csr |= QMI_DIRECT_CSR_ASSERT_CS1N_BITS;
if (i == 0) {
qmi_hw->direct_tx = 0x66;
} else if (i == 1) {
qmi_hw->direct_tx = 0x99;
} else {
qmi_hw->direct_tx = 0x35;
}
while ((qmi_hw->direct_csr & QMI_DIRECT_CSR_BUSY_BITS) != 0) {
}
qmi_hw->direct_csr &= ~(QMI_DIRECT_CSR_ASSERT_CS1N_BITS);
for (size_t j = 0; j < 20; j++) {
asm ("nop");
}
(void)qmi_hw->direct_rx;
}
// Disable direct csr.
qmi_hw->direct_csr &= ~(QMI_DIRECT_CSR_ASSERT_CS1N_BITS | QMI_DIRECT_CSR_EN_BITS);
qmi_hw->m[1].timing =
QMI_M0_TIMING_PAGEBREAK_VALUE_1024 << QMI_M0_TIMING_PAGEBREAK_LSB | // Break between pages.
3 << QMI_M0_TIMING_SELECT_HOLD_LSB | // Delay releasing CS for 3 extra system cycles.
1 << QMI_M0_TIMING_COOLDOWN_LSB |
1 << QMI_M0_TIMING_RXDELAY_LSB |
16 << QMI_M0_TIMING_MAX_SELECT_LSB | // In units of 64 system clock cycles. PSRAM says 8us max. 8 / 0.00752 / 64 = 16.62
7 << QMI_M0_TIMING_MIN_DESELECT_LSB | // In units of system clock cycles. PSRAM says 50ns.50 / 7.52 = 6.64
2 << QMI_M0_TIMING_CLKDIV_LSB;
qmi_hw->m[1].rfmt = (QMI_M0_RFMT_PREFIX_WIDTH_VALUE_Q << QMI_M0_RFMT_PREFIX_WIDTH_LSB |
QMI_M0_RFMT_ADDR_WIDTH_VALUE_Q << QMI_M0_RFMT_ADDR_WIDTH_LSB |
QMI_M0_RFMT_SUFFIX_WIDTH_VALUE_Q << QMI_M0_RFMT_SUFFIX_WIDTH_LSB |
QMI_M0_RFMT_DUMMY_WIDTH_VALUE_Q << QMI_M0_RFMT_DUMMY_WIDTH_LSB |
QMI_M0_RFMT_DUMMY_LEN_VALUE_24 << QMI_M0_RFMT_DUMMY_LEN_LSB |
QMI_M0_RFMT_DATA_WIDTH_VALUE_Q << QMI_M0_RFMT_DATA_WIDTH_LSB |
QMI_M0_RFMT_PREFIX_LEN_VALUE_8 << QMI_M0_RFMT_PREFIX_LEN_LSB |
QMI_M0_RFMT_SUFFIX_LEN_VALUE_NONE << QMI_M0_RFMT_SUFFIX_LEN_LSB);
qmi_hw->m[1].rcmd = 0xeb << QMI_M0_RCMD_PREFIX_LSB |
0 << QMI_M0_RCMD_SUFFIX_LSB;
qmi_hw->m[1].wfmt = (QMI_M0_WFMT_PREFIX_WIDTH_VALUE_Q << QMI_M0_WFMT_PREFIX_WIDTH_LSB |
QMI_M0_WFMT_ADDR_WIDTH_VALUE_Q << QMI_M0_WFMT_ADDR_WIDTH_LSB |
QMI_M0_WFMT_SUFFIX_WIDTH_VALUE_Q << QMI_M0_WFMT_SUFFIX_WIDTH_LSB |
QMI_M0_WFMT_DUMMY_WIDTH_VALUE_Q << QMI_M0_WFMT_DUMMY_WIDTH_LSB |
QMI_M0_WFMT_DUMMY_LEN_VALUE_NONE << QMI_M0_WFMT_DUMMY_LEN_LSB |
QMI_M0_WFMT_DATA_WIDTH_VALUE_Q << QMI_M0_WFMT_DATA_WIDTH_LSB |
QMI_M0_WFMT_PREFIX_LEN_VALUE_8 << QMI_M0_WFMT_PREFIX_LEN_LSB |
QMI_M0_WFMT_SUFFIX_LEN_VALUE_NONE << QMI_M0_WFMT_SUFFIX_LEN_LSB);
qmi_hw->m[1].wcmd = 0x38 << QMI_M0_WCMD_PREFIX_LSB |
0 << QMI_M0_WCMD_SUFFIX_LSB;
restore_interrupts(save);
_psram_size = 1024 * 1024; // 1 MiB
uint8_t size_id = eid >> 5;
if (eid == 0x26 || size_id == 2) {
_psram_size *= 8;
} else if (size_id == 0) {
_psram_size *= 2;
} else if (size_id == 1) {
_psram_size *= 4;
}
// Mark that we can write to PSRAM.
xip_ctrl_hw->ctrl |= XIP_CTRL_WRITABLE_M1_BITS;
// Test write to the PSRAM.
volatile uint32_t *psram_nocache = (volatile uint32_t *)0x15000000;
psram_nocache[0] = 0x12345678;
volatile uint32_t readback = psram_nocache[0];
if (readback != 0x12345678) {
_psram_size = 0;
return;
}
#endif
}
int main() int main()
{ {
// set_sys_clock_khz(250*1000, true); // set_sys_clock_khz(250*1000, true);
setup_psram();
stdio_init_all(); stdio_init_all();
io_init(); io_init();
@ -278,17 +461,15 @@ int main()
pio_usb_configuration_t pio_cfg = PIO_USB_DEFAULT_CONFIG; pio_usb_configuration_t pio_cfg = PIO_USB_DEFAULT_CONFIG;
pio_cfg.tx_ch = 2; pio_cfg.tx_ch = 2;
pio_cfg.pin_dp = PICO_DEFAULT_PIO_USB_DP_PIN; pio_cfg.pin_dp = PICO_DEFAULT_PIO_USB_DP_PIN;
_Static_assert(PIN_USB_HOST_DP + 1 == PIN_USB_HOST_DM || PIN_USB_HOST_DP - 1 == PIN_USB_HOST_DM, "Permitted USB D+/D- configuration");
pio_cfg.pinout = PIN_USB_HOST_DP + 1 == PIN_USB_HOST_DM ? PIO_USB_PINOUT_DPDM : PIO_USB_PINOUT_DMDP;
//#ifdef PICO_DEFAULT_PIO_USB_VBUSEN_PIN #ifdef PICO_DEFAULT_PIO_USB_VBUSEN_PIN
gpio_init(PICO_DEFAULT_PIO_USB_VBUSEN_PIN); gpio_init(PICO_DEFAULT_PIO_USB_VBUSEN_PIN);
gpio_set_dir(PICO_DEFAULT_PIO_USB_VBUSEN_PIN, GPIO_OUT); gpio_set_dir(PICO_DEFAULT_PIO_USB_VBUSEN_PIN, GPIO_OUT);
gpio_put(PICO_DEFAULT_PIO_USB_VBUSEN_PIN, PICO_DEFAULT_PIO_USB_VBUSEN_STATE); gpio_put(PICO_DEFAULT_PIO_USB_VBUSEN_PIN, PICO_DEFAULT_PIO_USB_VBUSEN_STATE);
//#endif
#if 0
_Static_assert(PIN_USB_HOST_DP + 1 == PIN_USB_HOST_DM || PIN_USB_HOST_DP - 1 == PIN_USB_HOST_DM, "Permitted USB D+/D- configuration");
pio_cfg.pinout = PIN_USB_HOST_DP + 1 == PIN_USB_HOST_DM ? PIO_USB_PINOUT_DPDM : PIO_USB_PINOUT_DMDP;
#endif #endif
tuh_configure(BOARD_TUH_RHPORT, TUH_CFGID_RPI_PIO_USB_CONFIGURATION, &pio_cfg); tuh_configure(BOARD_TUH_RHPORT, TUH_CFGID_RPI_PIO_USB_CONFIGURATION, &pio_cfg);
tuh_init(BOARD_TUH_RHPORT); tuh_init(BOARD_TUH_RHPORT);