From eb104aa16f80fb9d54b3e5bf3b79550e95d51294 Mon Sep 17 00:00:00 2001 From: "Michael (XIAO Xufeng)" Date: Tue, 10 Sep 2019 00:56:46 +0800 Subject: [PATCH] esp_flash: fix the quad issue for some GD flash chips The GD flash with product ID 40H, is already used in Wrover-nosufix modules. --- components/spi_flash/CMakeLists.txt | 3 +- components/spi_flash/Kconfig | 19 ++- components/spi_flash/esp_flash_api.c | 23 ++-- components/spi_flash/include/esp_flash.h | 1 + .../spi_flash/include/spi_flash_chip_gd.h | 32 ++++++ components/spi_flash/linker.lf | 1 + components/spi_flash/spi_flash_chip_drivers.c | 4 + components/spi_flash/spi_flash_chip_gd.c | 108 ++++++++++++++++++ components/spi_flash/spi_flash_chip_generic.c | 6 +- 9 files changed, 180 insertions(+), 17 deletions(-) create mode 100644 components/spi_flash/include/spi_flash_chip_gd.h create mode 100644 components/spi_flash/spi_flash_chip_gd.c diff --git a/components/spi_flash/CMakeLists.txt b/components/spi_flash/CMakeLists.txt index 497125e47b..61900d09ba 100644 --- a/components/spi_flash/CMakeLists.txt +++ b/components/spi_flash/CMakeLists.txt @@ -14,7 +14,7 @@ else() "partition.c" "spi_flash_rom_patch.c" ) - # New implementation + # New implementation after IDF v4.0 list(APPEND cache_srcs "esp_flash_api.c" "esp_flash_spi_init.c" @@ -25,6 +25,7 @@ else() "spi_flash_chip_drivers.c" "spi_flash_chip_generic.c" "spi_flash_chip_issi.c" + "spi_flash_chip_gd.c" "memspi_host_driver.c" ) list(APPEND srcs ${cache_srcs}) diff --git a/components/spi_flash/Kconfig b/components/spi_flash/Kconfig index 8a10651ff0..046146e006 100644 --- a/components/spi_flash/Kconfig +++ b/components/spi_flash/Kconfig @@ -90,8 +90,23 @@ menu "SPI Flash driver" bool "ISSI" default y help - Enable this to support auto detection of ISSI chips if chip vendor not specified. - This adds support for variant chips, however will extend detecting time. + Enable this to support auto detection of ISSI chips if chip vendor not directly + given by ``chip_drv`` member of the chip struct. This adds support for variant + chips, however will extend detecting time. + + config SPI_FLASH_SUPPORT_GD_CHIP + bool "GigaDevice" + default y + help + Enable this to support auto detection of GD (GigaDevice) chips if chip vendor not + directly given by ``chip_drv`` member of the chip struct. If you are using Wrover + modules, please don't disable this, otherwise your flash may not work in 4-bit + mode. + + This adds support for variant chips, however will extend detecting time and image + size. Note that the default chip driver supports the GD chips with product ID + 60H. + endmenu #auto detect flash chips endmenu diff --git a/components/spi_flash/esp_flash_api.c b/components/spi_flash/esp_flash_api.c index 7cb0e0d139..ff9c49e4d4 100644 --- a/components/spi_flash/esp_flash_api.c +++ b/components/spi_flash/esp_flash_api.c @@ -62,6 +62,7 @@ static const char io_mode_str[][IO_STR_LEN] = { _Static_assert(sizeof(io_mode_str)/IO_STR_LEN == SPI_FLASH_READ_MODE_MAX, "the io_mode_str should be consistent with the esp_flash_io_mode_t defined in spi_flash_ll.h"); +esp_err_t esp_flash_read_chip_id(esp_flash_t* chip, uint32_t* flash_id); /* Static function to notify OS of a new SPI flash operation. @@ -115,6 +116,18 @@ esp_err_t IRAM_ATTR esp_flash_init(esp_flash_t *chip) return ESP_ERR_INVALID_ARG; } + //read chip id + uint32_t flash_id; + int retries = 10; + do { + err = esp_flash_read_chip_id(chip, &flash_id); + } while (err == ESP_ERR_FLASH_NOT_INITIALISED && retries-- > 0); + + if (err != ESP_OK) { + return err; + } + chip->chip_id = flash_id; + if (!esp_flash_chip_driver_initialized(chip)) { // Detect chip_drv err = detect_spi_flash_chip(chip); @@ -175,15 +188,7 @@ esp_err_t IRAM_ATTR esp_flash_read_chip_id(esp_flash_t* chip, uint32_t* flash_id static esp_err_t IRAM_ATTR detect_spi_flash_chip(esp_flash_t *chip) { esp_err_t err; - uint32_t flash_id; - int retries = 10; - do { - err = esp_flash_read_chip_id(chip, &flash_id); - } while (err == ESP_ERR_FLASH_NOT_INITIALISED && retries-- > 0); - - if (err != ESP_OK) { - return err; - } + uint32_t flash_id = chip->chip_id; // Detect the chip and set the chip_drv structure for it const spi_flash_chip_t **drivers = esp_flash_registered_chips; diff --git a/components/spi_flash/include/esp_flash.h b/components/spi_flash/include/esp_flash.h index b2b38806d9..afce78c5e6 100644 --- a/components/spi_flash/include/esp_flash.h +++ b/components/spi_flash/include/esp_flash.h @@ -65,6 +65,7 @@ struct esp_flash_t { esp_flash_io_mode_t read_mode; ///< Configured SPI flash read mode. Set before ``esp_flash_init`` is called. uint32_t size; ///< Size of SPI flash in bytes. If 0, size will be detected during initialisation. + uint32_t chip_id; ///< Detected chip id. }; diff --git a/components/spi_flash/include/spi_flash_chip_gd.h b/components/spi_flash/include/spi_flash_chip_gd.h new file mode 100644 index 0000000000..0d52435a38 --- /dev/null +++ b/components/spi_flash/include/spi_flash_chip_gd.h @@ -0,0 +1,32 @@ +// Copyright 2015-2019 Espressif Systems (Shanghai) PTE LTD +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#pragma once + +#include +#include "esp_flash.h" +#include "spi_flash_chip_driver.h" + + +/** + * GD (GigaDevice) SPI flash chip_drv, uses all the above functions for its operations. In + * default autodetection, this is used as a catchall if a more specific chip_drv + * is not found. + * + * Note that this is for GD chips with product ID 40H (GD25Q) and 60H (GD25LQ). The chip diver uses + * different commands to write the SR2 register according to the chip ID. For GD25Q40 - GD25Q16 + * chips, and GD25LQ chips, WRSR (01H) command is used; while WRSR2 (31H) is used for GD25Q32 - + * GD25Q127 chips. + */ +extern const spi_flash_chip_t esp_flash_chip_gd; diff --git a/components/spi_flash/linker.lf b/components/spi_flash/linker.lf index e5d886ca4b..5e2c1af32f 100644 --- a/components/spi_flash/linker.lf +++ b/components/spi_flash/linker.lf @@ -4,5 +4,6 @@ entries: spi_flash_rom_patch (noflash_text) spi_flash_chip_generic (noflash) spi_flash_chip_issi (noflash) + spi_flash_chip_gd(noflash) memspi_host_driver (noflash) diff --git a/components/spi_flash/spi_flash_chip_drivers.c b/components/spi_flash/spi_flash_chip_drivers.c index ae10bcec37..316ac9ae17 100644 --- a/components/spi_flash/spi_flash_chip_drivers.c +++ b/components/spi_flash/spi_flash_chip_drivers.c @@ -16,6 +16,7 @@ #include "spi_flash_chip_driver.h" #include "spi_flash_chip_generic.h" #include "spi_flash_chip_issi.h" +#include "spi_flash_chip_gd.h" #include "sdkconfig.h" /* @@ -30,6 +31,9 @@ static const spi_flash_chip_t *default_registered_chips[] = { #ifdef CONFIG_SPI_FLASH_SUPPORT_ISSI_CHIP &esp_flash_chip_issi, +#endif +#ifdef CONFIG_SPI_FLASH_SUPPORT_GD_CHIP + &esp_flash_chip_gd, #endif &esp_flash_chip_generic, NULL, diff --git a/components/spi_flash/spi_flash_chip_gd.c b/components/spi_flash/spi_flash_chip_gd.c new file mode 100644 index 0000000000..bc877d2cb1 --- /dev/null +++ b/components/spi_flash/spi_flash_chip_gd.c @@ -0,0 +1,108 @@ +// Copyright 2015-2019 Espressif Systems (Shanghai) PTE LTD +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include +#include "spi_flash_chip_generic.h" +#include "spi_flash_defs.h" + +#define FLASH_ID_MASK 0xFF00 +#define FLASH_SIZE_MASK 0xFF +#define GD25Q_PRODUCT_ID 0x4000 +#define GD25LQ_PRODUCT_ID 0x6000 + +#define WRSR_16B_REQUIRED(chip_id) (((chip_id) & FLASH_ID_MASK) == GD25LQ_PRODUCT_ID || \ + ((chip_id) & FLASH_SIZE_MASK) <= 0x15) + +/* Driver for GD flash chip */ + +esp_err_t spi_flash_chip_gd_probe(esp_flash_t *chip, uint32_t flash_id) +{ + /* Check manufacturer and product IDs match our desired masks */ + const uint8_t MFG_ID = 0xC8; + if (flash_id >> 16 != MFG_ID) { + return ESP_ERR_NOT_FOUND; + } + + uint32_t product_id = flash_id & FLASH_ID_MASK; + if (product_id != GD25Q_PRODUCT_ID && product_id != GD25LQ_PRODUCT_ID) { + return ESP_ERR_NOT_FOUND; + } + + return ESP_OK; +} + +esp_err_t spi_flash_chip_gd_set_io_mode(esp_flash_t *chip) +{ + if (WRSR_16B_REQUIRED(chip->chip_id)) { + const uint32_t qe = 1<<9; + return spi_flash_common_set_io_mode(chip, + spi_flash_common_write_status_16b_wrsr, + spi_flash_common_read_status_16b_rdsr_rdsr2, + qe); + } else { + const uint32_t qe = 1<<1; + return spi_flash_common_set_io_mode(chip, + spi_flash_common_write_status_8b_wrsr2, + spi_flash_common_read_status_8b_rdsr2, + qe); + } +} + +esp_err_t spi_flash_chip_gd_get_io_mode(esp_flash_t *chip, esp_flash_io_mode_t* out_io_mode) +{ + /* GD uses bit 1 of SR2 as Quad Enable */ + const uint8_t BIT_QE = 1 << 1; + uint32_t sr; + esp_err_t ret = spi_flash_common_read_status_8b_rdsr2(chip, &sr); + if (ret == ESP_OK) { + *out_io_mode = ((sr & BIT_QE)? SPI_FLASH_QOUT: 0); + } + return ret; +} + + +static const char chip_name[] = "gd"; + +// The issi chip can use the functions for generic chips except from set read mode and probe, +// So we only replace these two functions. +const spi_flash_chip_t esp_flash_chip_gd = { + .name = chip_name, + .probe = spi_flash_chip_gd_probe, + .reset = spi_flash_chip_generic_reset, + .detect_size = spi_flash_chip_generic_detect_size, + .erase_chip = spi_flash_chip_generic_erase_chip, + .erase_sector = spi_flash_chip_generic_erase_sector, + .erase_block = spi_flash_chip_generic_erase_block, + .sector_size = 4 * 1024, + .block_erase_size = 64 * 1024, + + .get_chip_write_protect = spi_flash_chip_generic_get_write_protect, + .set_chip_write_protect = spi_flash_chip_generic_set_write_protect, + + // TODO support protected regions on ISSI flash + .num_protectable_regions = 0, + .protectable_regions = NULL, + .get_protected_regions = NULL, + .set_protected_regions = NULL, + + .read = spi_flash_chip_generic_read, + .write = spi_flash_chip_generic_write, + .program_page = spi_flash_chip_generic_page_program, + .page_size = 256, + .write_encrypted = spi_flash_chip_generic_write_encrypted, + + .wait_idle = spi_flash_chip_generic_wait_idle, + .set_io_mode = spi_flash_chip_gd_set_io_mode, + .get_io_mode = spi_flash_chip_gd_get_io_mode, +}; diff --git a/components/spi_flash/spi_flash_chip_generic.c b/components/spi_flash/spi_flash_chip_generic.c index 16d6b85e16..23172fb938 100644 --- a/components/spi_flash/spi_flash_chip_generic.c +++ b/components/spi_flash/spi_flash_chip_generic.c @@ -60,12 +60,8 @@ esp_err_t spi_flash_chip_generic_reset(esp_flash_t *chip) esp_err_t spi_flash_chip_generic_detect_size(esp_flash_t *chip, uint32_t *size) { - uint32_t id = 0; + uint32_t id = chip->chip_id; *size = 0; - esp_err_t err = chip->host->read_id(chip->host, &id); - if (err != ESP_OK) { - return err; - } /* Can't detect size unless the high byte of the product ID matches the same convention, which is usually 0x40 or * 0xC0 or similar. */