diff --git a/components/esp32/Kconfig b/components/esp32/Kconfig index eb898326d3..910266a37a 100644 --- a/components/esp32/Kconfig +++ b/components/esp32/Kconfig @@ -131,7 +131,7 @@ menu "ESP32-specific" config SPIRAM_BANKSWITCH_ENABLE bool "Enable bank switching for >4MiB external RAM" - default y + default n depends on SPIRAM_USE_MEMMAP || SPIRAM_USE_CAPS_ALLOC || SPIRAM_USE_MALLOC help The ESP32 only supports 4MiB of external RAM in its address space. The hardware does support larger @@ -141,6 +141,9 @@ menu "ESP32-specific" #Note that this is limited to 62 banks, as esp_spiram_writeback_cache needs some kind of mapping of #some banks below that mark to work. We cannot at this moment guarantee this to exist when himem is #enabled. + + If spiram 2T mode is enabled, the size of 64Mbit psram will be changed as 32Mbit, so himem will be + unusable. config SPIRAM_BANKSWITCH_RESERVE int "Amount of 32K pages to reserve for bank switching" depends on SPIRAM_BANKSWITCH_ENABLE @@ -260,6 +263,24 @@ menu "ESP32-specific" For ESP32-PICO chip, the default value of this config should be 7. + config SPIRAM_2T_MODE + bool "Enable SPI PSRAM 2T mode" + depends on ESP32_SPIRAM_SUPPORT + default "y" + help + Enable this option to fix single bit errors inside 64Mbit PSRAM. + + Some 64Mbit PSRAM chips have a hardware issue in the RAM which causes bit errors at multiple + fixed bit positions. + + This option only applies to 64Mbit PSRAM chips which have this issue, detected at startup by + reading the PSRAM ID. It has no effect on other PSRAM sizes, or 64Mbit PSRAM chips which do not + have this issue. + + Note: If this option is enabled, the 64Mbit PSRAM chip will appear to be 32Mbit in size. + Applications will not be affected unless the use the esp_himem APIs, which are not supported + in 2T mode. + endmenu # "SPI RAM config" config ESP32_MEMMAP_TRACEMEM diff --git a/components/esp32/spiram_psram.c b/components/esp32/spiram_psram.c index 7673548ee2..b6ec52ce25 100644 --- a/components/esp32/spiram_psram.c +++ b/components/esp32/spiram_psram.c @@ -172,7 +172,8 @@ typedef enum { static psram_cache_mode_t s_psram_mode = PSRAM_CACHE_MAX; static psram_clk_mode_t s_clk_mode = PSRAM_CLK_MODE_DCLK; -static uint32_t s_psram_id = 0; +static uint64_t s_psram_id = 0; +static bool s_2t_mode_enabled = false; /* dummy_len_plus values defined in ROM for SPI flash configuration */ extern uint8_t g_rom_spiflash_dummy_len_plus[]; @@ -397,11 +398,12 @@ static void psram_disable_qio_mode(psram_spi_num_t spi_num) } //read psram id -static void psram_read_id(uint32_t* dev_id) +static void psram_read_id(uint64_t* dev_id) { psram_spi_num_t spi_num = PSRAM_SPI_1; psram_disable_qio_mode(spi_num); uint32_t dummy_bits = 0 + extra_dummy; + uint32_t psram_id[2] = {0}; psram_cmd_t ps_cmd; uint32_t addr = 0; @@ -425,14 +427,15 @@ static void psram_read_id(uint32_t* dev_id) ps_cmd.addr = &addr; ps_cmd.txDataBitLen = 0; ps_cmd.txData = NULL; - ps_cmd.rxDataBitLen = 4 * 8; - ps_cmd.rxData = dev_id; + ps_cmd.rxDataBitLen = 8 * 8; + ps_cmd.rxData = psram_id; ps_cmd.dummyBitLen = dummy_bits; psram_cmd_config(spi_num, &ps_cmd); psram_clear_spi_fifo(spi_num); psram_cmd_recv_start(spi_num, ps_cmd.rxData, ps_cmd.rxDataBitLen / 8, PSRAM_CMD_SPI); psram_cmd_end(spi_num); + *dev_id = (uint64_t)(((uint64_t)psram_id[1] << 32) | psram_id[0]); } //enter QPI mode @@ -467,6 +470,275 @@ static esp_err_t IRAM_ATTR psram_enable_qio_mode(psram_spi_num_t spi_num) return ESP_OK; } +#define PSRAM_2T_EID_M 0xf0ffffff +#define PSRAM_2T_EID_S 16 +#define PSRAM_2T_CHECK_ID(id) (((id) >> PSRAM_2T_EID_S) & PSRAM_2T_EID_M) + +/* + * If the psram id is included in below list, 2T mode need to be enabled + * Note:In order to save RAM memory, DRAM_ATTR is omitted intentionally + */ +static const uint32_t psram_check_id[] = { +// need check bits // original ID // + 0x0053B24A, // xxxx0x53B24A5D0D + 0x0064A246, // xxxx0x64A2465D0D + 0x00B9A046, // xxxx0xB9A0465D0D + 0x00BAA046, // xxxx0xBAA0465D0D + 0x00C0A046, // xxxx0xC0A0465D0D + 0x1053B24A, // xxxx1x53B24A5D0D + 0x1064A246, // xxxx1x64A2465D0D + 0x10B9A046, // xxxx1xB9A0465D0D + 0x10BAA046, // xxxx1xBAA0465D0D + 0x10C0A046, // xxxx1xC0A0465D0D + 0x2022A146, // xxxx2x22A1465D0D + 0x20A8A146, // xxxx2xA8A1465D0D + 0x20C0A046, // xxxx2xC0A0465D0D + 0x20C0B158, // xxxx2xC0B1585D0D + 0x3022A146, // xxxx3x22A1465D0D + 0x30A8A146, // xxxx3xA8A1465D0D + 0x30C0A046, // xxxx3xC0A0465D0D + 0x30C0B158, // xxxx3xC0B1585D0D + 0x4026A158, // xxxx4x26A1585D0D + 0x402AA046, // xxxx4x2AA0465D0D + 0x402FA046, // xxxx4x2FA0465D0D + 0x402FA048, // xxxx4x2FA0485D0D + 0x4064A246, // xxxx4x64A2465D0D + 0x40A8A15A, // xxxx4xA8A15A5D0D + 0x40B9D14A, // xxxx4xB9D14A5D0D + 0x5026A158, // xxxx5x26A1585D0D + 0x502AA046, // xxxx5x2AA0465D0D + 0x502FA046, // xxxx5x2FA0465D0D + 0x5064A246, // xxxx5x64A2465D0D + 0x50A8A15A, // xxxx5xA8A15A5D0D + 0x50B9D14A, // xxxx5xB9D14A5D0D + 0x50C0A046, // xxxx5xC0A0465D0D + 0x602AA046, // xxxx6x2AA0465D0D + 0x6064A246, // xxxx6x64A2465D0D + 0x702AA046, // xxxx7x2AA0465D0D + 0x7064A246, // xxxx7x64A2465D0D + 0x8026A146, // xxxx8x26A1465D0D + 0x9026A146, // xxxx9x26A1465D0D + 0xA02FA046, // xxxxAx2FA0465D0D + 0xB02FA046, // xxxxBx2FA0465D0D + 0xC003B246, // xxxxCx03B2465D0D + 0xC003B248, // xxxxCx03B2485D0D + 0xC091D14A, // xxxxCx91D14A5D0D + 0xC0B8A046, // xxxxCxB8A0465D0D + 0xC0BFB148, // xxxxCxBFB1485D0D + 0xD091D14A, // xxxxDx91D14A5D0D + 0xD0B8A046, // xxxxDxB8A0465D0D + 0xD0BFB148, // xxxxDxBFB1485D0D + 0xE021A146, // xxxxEx21A1465D0D + 0xE0B8A046, // xxxxExB8A0465D0D + 0xE0B9A046, // xxxxExB9A0465D0D + 0xE0BFA046, // xxxxExBFA0465D0D + 0xE0BFB158, // xxxxExBFB1585D0D + 0xF021A146, // xxxxFx21A1465D0D + 0xF0B8A046, // xxxxFxB8A0465D0D + 0xF0B9A046, // xxxxFxB9A0465D0D + 0xF0BFA046, // xxxxFxBFA0465D0D + 0xF0BFB158, // xxxxFxBFB1585D0D +}; + +/* + * Note:In order to save RAM memory, IRAM_ATTR is omitted intentionally + */ +static bool psram_should_use_2t_mode(uint64_t psram_id) +{ + uint32_t idx = 0; + uint32_t low_idx = 0; + uint32_t high_idx = sizeof(psram_check_id) / 4; + uint32_t check_id = PSRAM_2T_CHECK_ID(psram_id); + + while (low_idx <= high_idx) { + idx = (low_idx + high_idx) / 2; + if (check_id < psram_check_id[idx]) { + high_idx = idx - 1; + } else if (check_id > psram_check_id[idx]) { + low_idx = idx + 1; + } else { + return true; + } + } + return false; +} + +#if CONFIG_SPIRAM_2T_MODE +// use SPI user mode to write psram +static void spi_user_psram_write(psram_spi_num_t spi_num, uint32_t address, uint32_t *data_buffer, uint32_t data_len) +{ + uint32_t addr = (PSRAM_QUAD_WRITE << 24) | (address & 0x7fffff); + psram_cmd_t ps_cmd; + ps_cmd.cmdBitLen = 0; + ps_cmd.cmd = 0; + ps_cmd.addr = &addr; + ps_cmd.addrBitLen = 4 * 8; + ps_cmd.txDataBitLen = 32 * 8; + ps_cmd.txData = NULL; + ps_cmd.rxDataBitLen = 0; + ps_cmd.rxData = NULL; + ps_cmd.dummyBitLen = 0; + + for(uint32_t i=0; i