From 9fb0ec8f60976fc8845a2e2854badfbb3db2ec4f Mon Sep 17 00:00:00 2001 From: Jeff Epler Date: Mon, 17 Mar 2025 20:14:56 -0500 Subject: [PATCH] Add psram support it seems to be a tad slower but what do you want....! --- CMakeLists.txt | 31 +++++--- src/main.c | 197 +++++++++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 208 insertions(+), 20 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 5671c05..fa79eb2 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -55,6 +55,9 @@ set(HSTX_D2P 18 CACHE STRING "HSTX D2+ PIN") 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)") +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 set(PIN_USB_HOST_DP 1 CACHE STRING "USB D+ PIN") set(PIN_USB_HOST_DM 2 CACHE STRING "USB D- PIN") @@ -112,19 +115,17 @@ if (USE_HSTX) add_compile_definitions(HSTX_CKP=${HSTX_CKP} HSTX_D0P=${HSTX_D0P} HSTX_D1P=${HSTX_D1P} HSTX_D2P=${HSTX_D2P}) set(VIDEO_SRC src/video_hstx.c) else() - if (USE_VGA_RES) - add_compile_definitions(USE_VGA_RES=1) - add_compile_definitions(DISP_WIDTH=640) - add_compile_definitions(DISP_HEIGHT=480) - else() - add_compile_definitions(DISP_WIDTH=512) - add_compile_definitions(DISP_HEIGHT=342) - endif() - - add_compile_definitions(GPIO_VID_BASE=${VIDEO_PIN}) - set(VIDEO_SRC src/video_vga.c) - + if (USE_VGA_RES) + add_compile_definitions(USE_VGA_RES=1) + add_compile_definitions(DISP_WIDTH=640) + add_compile_definitions(DISP_HEIGHT=480) + else() + add_compile_definitions(DISP_WIDTH=512) + add_compile_definitions(DISP_HEIGHT=342) + endif() + add_compile_definitions(GPIO_VID_BASE=${VIDEO_PIN}) + set(VIDEO_SRC src/video_vga.c) endif() 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_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) add_executable(firmware src/main.c diff --git a/src/main.c b/src/main.c index 3418a03..04fdf1c 100644 --- a/src/main.c +++ b/src/main.c @@ -53,6 +53,10 @@ #include "hw_config.h" #endif +#if USE_PSRAM +#include "hardware/structs/qmi.h" +#include "hardware/structs/xip.h" +#endif //////////////////////////////////////////////////////////////////////////////// // Imports and data @@ -69,7 +73,12 @@ static const uint8_t umac_rom[] = { #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]; +#endif //////////////////////////////////////////////////////////////////////////////// @@ -97,6 +106,27 @@ static int umac_cursor_x = 0; static int umac_cursor_y = 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 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_vsync = absolute_time_diff_us(last_vsync, now); if (p_vsync >= 16667) { +#if USE_PSRAM + copy_framebuffer(); +#endif /* FIXME: Trigger this off actual vsync */ umac_vsync_event(); last_vsync = now; @@ -251,11 +284,16 @@ static void core1_main() printf("Core 1 started\n"); 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); /* Video runs on core 1, i.e. IRQs/DMA are unaffected by * core 0's USB activity. */ video_init((uint32_t *)(umac_ram + umac_get_fb_offset())); +#endif 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() { // set_sys_clock_khz(250*1000, true); + setup_psram(); + stdio_init_all(); io_init(); @@ -278,17 +461,15 @@ int main() pio_usb_configuration_t pio_cfg = PIO_USB_DEFAULT_CONFIG; pio_cfg.tx_ch = 2; pio_cfg.pin_dp = PICO_DEFAULT_PIO_USB_DP_PIN; - -//#ifdef 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_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; + +#ifdef 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_put(PICO_DEFAULT_PIO_USB_VBUSEN_PIN, PICO_DEFAULT_PIO_USB_VBUSEN_STATE); #endif + tuh_configure(BOARD_TUH_RHPORT, TUH_CFGID_RPI_PIO_USB_CONFIGURATION, &pio_cfg); tuh_init(BOARD_TUH_RHPORT);