From 55a20033e7e0bfd0422025d8b0a2e1eedd4cc720 Mon Sep 17 00:00:00 2001 From: chenjianqiang Date: Wed, 16 Oct 2019 10:45:42 +0800 Subject: [PATCH 1/2] bugfix(psram): support psram 2T mode to fix single bit error 1. add enable PSRAM 2T mode function 2. enable PSRAM 2T mode base on PSRAM ID 3. abort when himem and 2T mode are enabled meanwhile 4. set SPIRAM_2T_MODE as "y" by default and modify SPIRAM_BANKSWITCH_ENABLE as "n" by default --- components/esp32/Kconfig | 23 +- components/esp32/spiram_psram.c | 308 ++++++++++++++++++++++++++- tools/unit-test-app/configs/psram_8m | 1 + 3 files changed, 326 insertions(+), 6 deletions(-) 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 Date: Wed, 25 Mar 2020 18:23:43 +0800 Subject: [PATCH 2/2] psram: improve 2T mode enable 1. recover psram bankswitch config 2. set 2T mode enable default config as n 3. remove PSRAM ID check --- components/esp32/Kconfig | 8 +-- components/esp32/spiram_psram.c | 104 +-------------------------- tools/unit-test-app/configs/psram_8m | 1 - 3 files changed, 5 insertions(+), 108 deletions(-) diff --git a/components/esp32/Kconfig b/components/esp32/Kconfig index 910266a37a..ea440a5a9d 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 n + default y 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 @@ -266,17 +266,13 @@ menu "ESP32-specific" config SPIRAM_2T_MODE bool "Enable SPI PSRAM 2T mode" depends on ESP32_SPIRAM_SUPPORT - default "y" + default "n" 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. diff --git a/components/esp32/spiram_psram.c b/components/esp32/spiram_psram.c index b6ec52ce25..a63069d0cc 100644 --- a/components/esp32/spiram_psram.c +++ b/components/esp32/spiram_psram.c @@ -470,99 +470,6 @@ 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) @@ -1043,13 +950,10 @@ esp_err_t IRAM_ATTR psram_enable(psram_cache_mode_t mode, psram_vaddr_mode_t vad psram_set_cs_timing(_SPI_CACHE_PORT, s_clk_mode); psram_enable_qio_mode(PSRAM_SPI_1); - if(((PSRAM_SIZE_ID(s_psram_id) == PSRAM_EID_SIZE_64MBITS) || PSRAM_IS_64MBIT_TRIAL(s_psram_id)) - && (psram_should_use_2t_mode(s_psram_id) == true)) { -#if !CONFIG_SPIRAM_2T_MODE - ESP_EARLY_LOGW(TAG, "This PSRAM has single bit error risk, suggest to enable PSRAM 2T mode, and disable SPIRAM bank switching. Please read the help text for SPIRAM_2T_MODE in the project configuration menu."); -#else + if(((PSRAM_SIZE_ID(s_psram_id) == PSRAM_EID_SIZE_64MBITS) || PSRAM_IS_64MBIT_TRIAL(s_psram_id))) { +#if CONFIG_SPIRAM_2T_MODE #if CONFIG_SPIRAM_BANKSWITCH_ENABLE - ESP_EARLY_LOGE(TAG, "This PSRAM has single bit error risk, suggest to enable PSRAM 2T mode, and disable SPIRAM bank switching. Please read the help text for SPIRAM_2T_MODE in the project configuration menu."); + ESP_EARLY_LOGE(TAG, "PSRAM 2T mode and SPIRAM bank switching can not enabled meanwhile. Please read the help text for SPIRAM_2T_MODE in the project configuration menu."); abort(); #endif /* Note: 2T mode command should not be sent twice, @@ -1064,8 +968,6 @@ esp_err_t IRAM_ATTR psram_enable(psram_cache_mode_t mode, psram_vaddr_mode_t vad s_2t_mode_enabled = true; ESP_EARLY_LOGI(TAG, "PSRAM is in 2T mode"); #endif - } else { - ESP_EARLY_LOGD(TAG, "This 64Mbit PSRAM ID is not at risk of bit errors, not enabling 2T mode workaround."); } psram_cache_init(mode, vaddrmode); diff --git a/tools/unit-test-app/configs/psram_8m b/tools/unit-test-app/configs/psram_8m index e8fa665cc8..62c9c859ce 100644 --- a/tools/unit-test-app/configs/psram_8m +++ b/tools/unit-test-app/configs/psram_8m @@ -1,6 +1,5 @@ TEST_COMPONENTS=esp32 esp_timer CONFIG_ESP32_SPIRAM_SUPPORT=y -CONFIG_SPIRAM_2T_MODE=n CONFIG_SPIRAM_BANKSWITCH_ENABLE=y CONFIG_SPIRAM_BANKSWITCH_RESERVE=8 CONFIG_ESP_INT_WDT_TIMEOUT_MS=800