diff --git a/components/esp8266/include/driver/spi_register.h b/components/esp8266/include/driver/spi_register.h index c7aed690..9591c382 100644 --- a/components/esp8266/include/driver/spi_register.h +++ b/components/esp8266/include/driver/spi_register.h @@ -211,4 +211,49 @@ #define SPI_EXT3(i) (REG_SPI_BASE(i) + 0xFC) #define SPI_INT_HOLD_ENA 0x00000003 #define SPI_INT_HOLD_ENA_S 0 + +#define SPI_EXT2(i) (REG_SPI_BASE(i) + 0xF8) +#define SPI_EXT3(i) (REG_SPI_BASE(i) + 0xFC) + +#define SPI_ENABLE_AHB BIT17 + +#define SPI_FLASH_CLK_EQU_SYSCLK BIT12 + +//SPI flash command +#define SPI_FLASH_READ BIT31 +#define SPI_FLASH_WREN BIT30 +#define SPI_FLASH_WRDI BIT29 +#define SPI_FLASH_RDID BIT28 +#define SPI_FLASH_RDSR BIT27 +#define SPI_FLASH_WRSR BIT26 +#define SPI_FLASH_PP BIT25 +#define SPI_FLASH_SE BIT24 +#define SPI_FLASH_BE BIT23 +#define SPI_FLASH_CE BIT22 +#define SPI_FLASH_RES BIT20 +#define SPI_FLASH_DPD BIT21 +#define SPI_FLASH_HPM BIT19 + +//SPI address register +#define SPI_FLASH_BYTES_LEN 24 +#define SPI_BUFF_BYTE_NUM 32 +#define IODATA_START_ADDR BIT0 + +//SPI status register +#define SPI_FLASH_BUSY_FLAG BIT0 +#define SPI_FLASH_WRENABLE_FLAG BIT1 +#define SPI_FLASH_BP0 BIT2 +#define SPI_FLASH_BP1 BIT3 +#define SPI_FLASH_BP2 BIT4 +#define SPI_FLASH_TOP_BOT_PRO_FLAG BIT5 +#define SPI_FLASH_STATUS_PRO_FLAG BIT7 + +#define FLASH_WR_PROTECT (SPI_FLASH_BP0|SPI_FLASH_BP1|SPI_FLASH_BP2) + +#define SPI 0 + +#define PERIPHS_SPI_FLASH_C0 SPI_W0(SPI) +#define PERIPHS_SPI_FLASH_CTRL SPI_CTRL(SPI) +#define PERIPHS_SPI_FLASH_CMD SPI_CMD(SPI) + #endif // SPI_REGISTER_H_INCLUDED diff --git a/components/esp8266/ld/esp8266.common.ld b/components/esp8266/ld/esp8266.common.ld index 5bd6239e..0edd9f0a 100644 --- a/components/esp8266/ld/esp8266.common.ld +++ b/components/esp8266/ld/esp8266.common.ld @@ -103,7 +103,7 @@ SECTIONS *(.init.literal) *(.init) *(.iram1 .iram1.*) - *libspi_flash.a:spi_flash.o(.literal .text .literal.* .text.*) + *libspi_flash.a:spi_flash_raw.o(.literal .text .literal.* .text.*) *(.literal .text .stub .gnu.warning .gnu.linkonce.literal.* .gnu.linkonce.t.*.literal .gnu.linkonce.t.*) *(.fini.literal) *(.fini) diff --git a/components/spi_flash/include/priv/esp_spi_flash_raw.h b/components/spi_flash/include/priv/esp_spi_flash_raw.h new file mode 100644 index 00000000..c3c6931b --- /dev/null +++ b/components/spi_flash/include/priv/esp_spi_flash_raw.h @@ -0,0 +1,71 @@ +// Copyright 2018-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 +#include +#include "esp_err.h" + +#include "esp8266/rom_functions.h" + +#ifdef __cplusplus +extern "C" { +#endif + +enum GD25Q32C_status { + GD25Q32C_STATUS1=0, + GD25Q32C_STATUS2, + GD25Q32C_STATUS3, +}; + +typedef enum { + SPI_TX = 0x1, + SPI_RX = 0x2, + SPI_WRSR = 0x4, + SPI_RAW = 0x8, /*!< No wait spi idle and no read status */ +} spi_cmd_dir_t; + +typedef struct { + uint16_t cmd; + uint8_t cmd_len; + uint32_t *addr; + uint8_t addr_len; + uint32_t *data; + uint8_t data_len; + uint8_t dummy_bits; +} spi_cmd_t; + +bool spi_user_cmd_raw(esp_spi_flash_chip_t *chip, spi_cmd_dir_t mode, spi_cmd_t *p_cmd); + +uint32_t spi_flash_get_id_raw(esp_spi_flash_chip_t *chip); + +esp_err_t spi_flash_enable_qmode_raw(esp_spi_flash_chip_t *chip); + +esp_err_t spi_flash_read_status_raw(esp_spi_flash_chip_t *chip, uint32_t *status); + +esp_err_t spi_flash_write_status_raw(esp_spi_flash_chip_t *chip, uint32_t status_value); + +esp_err_t spi_flash_read_raw(esp_spi_flash_chip_t *chip, size_t src_addr, void *dest, size_t size); + +esp_err_t spi_flash_write_raw(esp_spi_flash_chip_t *chip, size_t dest_addr, const void *src, size_t size); + +esp_err_t spi_flash_erase_sector_raw(esp_spi_flash_chip_t *chip, size_t sec, size_t sec_size); + +void spi_flash_switch_to_qio_raw(void); + +#ifdef __cplusplus +} +#endif diff --git a/components/spi_flash/src/spi_flash.c b/components/spi_flash/src/spi_flash.c index 3866bee5..c82be03d 100644 --- a/components/spi_flash/src/spi_flash.c +++ b/components/spi_flash/src/spi_flash.c @@ -15,67 +15,14 @@ #include #include "spi_flash.h" +#include "priv/esp_spi_flash_raw.h" #include "esp_attr.h" #include "esp_wifi_osi.h" #include "esp_system.h" #include "esp_log.h" #include "esp_task_wdt.h" -#include "esp8266/eagle_soc.h" -#include "esp8266/rom_functions.h" -#include "esp8266/pin_mux_register.h" -#include "driver/spi_register.h" -/* Todo: Refactor SPI debug */ -#define spi_debug(fmt, ...) //ESP_LOGD(TAG, fmt, ##__VA_ARGS__) - -#define SPI_EXT2(i) (REG_SPI_BASE(i) + 0xF8) -#define SPI_EXT3(i) (REG_SPI_BASE(i) + 0xFC) - -#define SPI_ENABLE_AHB BIT17 - -#define SPI_FLASH_CLK_EQU_SYSCLK BIT12 - -//SPI flash command -#define SPI_FLASH_READ BIT31 -#define SPI_FLASH_WREN BIT30 -#define SPI_FLASH_WRDI BIT29 -#define SPI_FLASH_RDID BIT28 -#define SPI_FLASH_RDSR BIT27 -#define SPI_FLASH_WRSR BIT26 -#define SPI_FLASH_PP BIT25 -#define SPI_FLASH_SE BIT24 -#define SPI_FLASH_BE BIT23 -#define SPI_FLASH_CE BIT22 -#define SPI_FLASH_RES BIT20 -#define SPI_FLASH_DPD BIT21 -#define SPI_FLASH_HPM BIT19 - -//SPI address register -#define SPI_FLASH_BYTES_LEN 24 -#define SPI_BUFF_BYTE_NUM 32 -#define IODATA_START_ADDR BIT0 - -//SPI status register -#define SPI_FLASH_BUSY_FLAG BIT0 -#define SPI_FLASH_WRENABLE_FLAG BIT1 -#define SPI_FLASH_BP0 BIT2 -#define SPI_FLASH_BP1 BIT3 -#define SPI_FLASH_BP2 BIT4 -#define SPI_FLASH_TOP_BOT_PRO_FLAG BIT5 -#define SPI_FLASH_STATUS_PRO_FLAG BIT7 - -#define FLASH_WR_PROTECT (SPI_FLASH_BP0|SPI_FLASH_BP1|SPI_FLASH_BP2) - -#define SPI 0 - -#define PERIPHS_SPI_FLASH_C0 SPI_W0(SPI) -#define PERIPHS_SPI_FLASH_CTRL SPI_CTRL(SPI) -#define PERIPHS_SPI_FLASH_CMD SPI_CMD(SPI) - -//flash cmd -#define SPI_FLASH_READ_UNIQUE_CMD 0x4B -#define SPI_FLASH_WRITE_STATUS_REGISTER 0X01 #define SPI_FLASH_ISSI_ENABLE_QIO_MODE (BIT(6)) /*gd25q32c*/ @@ -106,37 +53,6 @@ #define NOT_ALIGN(addr) (((size_t)addr) & (FLASH_ALIGN_BYTES - 1)) #define IS_ALIGN(addr) (NOT_ALIGN(addr) == 0) -enum GD25Q32C_status { - GD25Q32C_STATUS1=0, - GD25Q32C_STATUS2, - GD25Q32C_STATUS3, -}; - -typedef enum { - SPI_TX = 0x1, - SPI_RX = 0x2, - SPI_WRSR = 0x4, - SPI_RAW = 0x8, /*!< No wait spi idle and no read status */ -} spi_cmd_dir_t; - -typedef struct { - uint16_t cmd; - uint8_t cmd_len; - uint32_t *addr; - uint8_t addr_len; - uint32_t *data; - uint8_t data_len; - uint8_t dummy_bits; -} spi_cmd_t; - -extern uint32_t esp_get_time(); - -bool IRAM_ATTR spi_user_cmd(spi_cmd_dir_t mode, spi_cmd_t *p_cmd); -bool special_flash_read_status(uint8_t command, uint32_t* status, int len); -bool special_flash_write_status(uint8_t command, uint32_t status, int len, bool write_en); -esp_err_t spi_flash_read(size_t src_addr, void *dest, size_t size); -uint8_t en25q16x_read_sfdp(); - extern void pp_soft_wdt_stop(void); extern void pp_soft_wdt_restart(void); @@ -154,92 +70,97 @@ esp_spi_flash_chip_t flashchip = { uint8_t FlashIsOnGoing = 0; -const char *TAG = "spi_flash"; - -esp_err_t IRAM_ATTR SPIWrite(uint32_t target, uint32_t *src_addr, size_t len) +bool spi_user_cmd(spi_cmd_dir_t mode, spi_cmd_t *p_cmd) { - uint32_t page_size; - uint32_t pgm_len, pgm_num; - uint8_t i; + bool ret; + FLASH_INTR_DECLARE(c_tmp); - //check program size - if ((target + len) > (flashchip.chip_size)) { - return ESP_ERR_FLASH_OP_FAIL; + if ((p_cmd->addr_len != 0 && p_cmd->addr == NULL) + || (p_cmd->data_len != 0 && p_cmd->data == NULL) + || (p_cmd == NULL)) { + return false; } - page_size = flashchip.page_size; - pgm_len = page_size - (target % page_size); + FLASH_INTR_LOCK(c_tmp); + FlashIsOnGoing = 1; - if (len < pgm_len) { - if (ESP_OK != SPI_page_program(&flashchip, target, src_addr, len)) { - return ESP_ERR_FLASH_OP_FAIL; - } + ret = spi_user_cmd_raw(&flashchip, mode, p_cmd); + + FlashIsOnGoing = 0; + FLASH_INTR_UNLOCK(c_tmp); + + return ret; +} + +bool special_flash_read_status(uint8_t command, uint32_t* status, int len) +{ + bool ret; + spi_cmd_t cmd; + + if( len > 2 || len < 1) { + return false; + } + + cmd.cmd = command; + cmd.cmd_len = 1; + cmd.addr = NULL; + cmd.addr_len = 0; + cmd.dummy_bits = 0; + cmd.data = status; + cmd.data_len = len; + + ret = spi_user_cmd(SPI_RX, &cmd); + + return ret; +} + +bool special_flash_write_status(uint8_t command, uint32_t status, int len, bool write_en) +{ + bool ret; + spi_cmd_t cmd; + + if (len > 2 || len < 1) { + return false; + } + + cmd.cmd = command; + cmd.cmd_len = 1; + cmd.addr = NULL; + cmd.addr_len = 0; + cmd.dummy_bits = 0; + cmd.data = &status; + cmd.data_len = len > 1 ? 2 : 1; + if (write_en) { + ret = spi_user_cmd(SPI_WRSR, &cmd); } else { - if (ESP_OK != SPI_page_program(&flashchip, target, src_addr, pgm_len)) { - return ESP_ERR_FLASH_OP_FAIL; - } - - //whole page program - pgm_num = (len - pgm_len) / page_size; - - for (i = 0; i < pgm_num; i++) { - if (ESP_OK != SPI_page_program(&flashchip, target + pgm_len, src_addr + (pgm_len >> 2), page_size)) { - return ESP_ERR_FLASH_OP_FAIL; - } - - pgm_len += page_size; - } - - //remain parts to program - if (ESP_OK != SPI_page_program(&flashchip, target + pgm_len, src_addr + (pgm_len >> 2), len - pgm_len)) { - return ESP_ERR_FLASH_OP_FAIL; - } + ret = spi_user_cmd(SPI_TX | SPI_RAW, &cmd); } - return ESP_OK; + return ret; } -esp_err_t IRAM_ATTR SPIRead(uint32_t target, uint32_t *dest_addr, size_t len) +uint8_t en25q16x_read_sfdp() { - if (ESP_OK != SPI_read_data(&flashchip, target, dest_addr, len)) { - return ESP_ERR_FLASH_OP_FAIL; - } + spi_cmd_t cmd; + uint32_t addr = 0x00003000; + uint32_t data = 0; - return ESP_OK; + cmd.cmd = 0x5a; + cmd.cmd_len = 1; + + cmd.addr = &addr; + cmd.addr_len = 3; + cmd.dummy_bits = 8; + + cmd.data = &data; + cmd.data_len = 1; + + spi_user_cmd(SPI_RX, &cmd); + + return ((uint8_t) data); } -static esp_err_t IRAM_ATTR SPIEraseSector(uint32_t sector_num) -{ - if (sector_num >= ((flashchip.chip_size) / (flashchip.sector_size))) { - return ESP_ERR_FLASH_OP_FAIL; - } - - if (ESP_OK != SPI_write_enable(&flashchip)) { - return ESP_ERR_FLASH_OP_FAIL; - } - - if (ESP_OK != SPI_sector_erase(&flashchip, sector_num * (flashchip.sector_size))) { - return ESP_ERR_FLASH_OP_FAIL; - } - - return ESP_OK; -} - -static void IRAM_ATTR Cache_Read_Disable_2(void) -{ - CLEAR_PERI_REG_MASK(CACHE_FLASH_CTRL_REG,CACHE_READ_EN_BIT); - while(REG_READ(SPI_EXT2(0)) != 0) { } - CLEAR_PERI_REG_MASK(PERIPHS_SPI_FLASH_CTRL,SPI_ENABLE_AHB); -} - -void IRAM_ATTR Cache_Read_Enable_2() -{ - SET_PERI_REG_MASK(PERIPHS_SPI_FLASH_CTRL,SPI_ENABLE_AHB); - SET_PERI_REG_MASK(CACHE_FLASH_CTRL_REG,CACHE_READ_EN_BIT); -} -void Cache_Read_Enable_New(void) __attribute__((alias("Cache_Read_Enable_2"))); - -static uint32_t IRAM_ATTR spi_flash_get_id(void) +uint32_t spi_flash_get_id(void) { uint32_t rdid = 0; FLASH_INTR_DECLARE(c_tmp); @@ -248,17 +169,7 @@ static uint32_t IRAM_ATTR spi_flash_get_id(void) FlashIsOnGoing = 1; - Cache_Read_Disable(); - - Wait_SPI_Idle(&flashchip); - - WRITE_PERI_REG(PERIPHS_SPI_FLASH_C0, 0); // clear regisrter - WRITE_PERI_REG(PERIPHS_SPI_FLASH_CMD, SPI_FLASH_RDID); - while(READ_PERI_REG(PERIPHS_SPI_FLASH_CMD)!=0); - - rdid = READ_PERI_REG(PERIPHS_SPI_FLASH_C0)&0xffffff; - - Cache_Read_Enable_New(); + rdid = spi_flash_get_id_raw(&flashchip); FlashIsOnGoing = 0; @@ -267,7 +178,7 @@ static uint32_t IRAM_ATTR spi_flash_get_id(void) return rdid; } -static esp_err_t IRAM_ATTR spi_flash_read_status(uint32_t *status) +esp_err_t spi_flash_read_status(uint32_t *status) { esp_err_t ret; FLASH_INTR_DECLARE(c_tmp); @@ -276,11 +187,7 @@ static esp_err_t IRAM_ATTR spi_flash_read_status(uint32_t *status) FlashIsOnGoing = 1; - Cache_Read_Disable_2(); - - ret = SPI_read_status(&flashchip, status); - - Cache_Read_Enable_2(); + ret = spi_flash_read_status_raw(&flashchip, status); FlashIsOnGoing = 0; @@ -289,7 +196,7 @@ static esp_err_t IRAM_ATTR spi_flash_read_status(uint32_t *status) return ret; } -static esp_err_t IRAM_ATTR spi_flash_write_status(uint32_t status_value) +esp_err_t spi_flash_write_status(uint32_t status_value) { FLASH_INTR_DECLARE(c_tmp); @@ -297,20 +204,7 @@ static esp_err_t IRAM_ATTR spi_flash_write_status(uint32_t status_value) FlashIsOnGoing = 1; - Cache_Read_Disable_2(); - - Wait_SPI_Idle(&flashchip); - if(ESP_OK != SPI_write_enable(&flashchip)){ - FLASH_INTR_UNLOCK(c_tmp); - return ESP_ERR_FLASH_OP_FAIL; - } - if(ESP_OK != SPI_write_status(&flashchip,status_value)){ - FLASH_INTR_UNLOCK(c_tmp); - return ESP_ERR_FLASH_OP_FAIL; - } - Wait_SPI_Idle(&flashchip); - - Cache_Read_Enable_2(); + spi_flash_write_status_raw(&flashchip, status_value); FlashIsOnGoing = 0; @@ -319,46 +213,7 @@ static esp_err_t IRAM_ATTR spi_flash_write_status(uint32_t status_value) return ESP_OK; } -static uint8_t IRAM_ATTR flash_gd25q32c_read_status(enum GD25Q32C_status status_index) -{ - uint8_t rdsr_cmd=0; - if(GD25Q32C_STATUS1 == status_index) { - rdsr_cmd = SPI_FLASH_GD25Q32C_READ_STATUSE1_CMD; - } - else if(GD25Q32C_STATUS2 == status_index) { - rdsr_cmd = SPI_FLASH_GD25Q32C_READ_STATUSE2_CMD; - } - else if(GD25Q32C_STATUS3 == status_index) { - rdsr_cmd = SPI_FLASH_GD25Q32C_READ_STATUSE3_CMD; - } - else { - - } - uint32_t status; - special_flash_read_status(rdsr_cmd, &status, 1); - return ((uint8_t)status); -} - -static void flash_gd25q32c_write_status(enum GD25Q32C_status status_index,uint8_t status) -{ - uint32_t wrsr_cmd=0; - uint32_t new_status = status; - if(GD25Q32C_STATUS1 == status_index) { - wrsr_cmd = SPI_FLASH_GD25Q32C_WRITE_STATUSE1_CMD; - } - else if(GD25Q32C_STATUS2 == status_index) { - wrsr_cmd = SPI_FLASH_GD25Q32C_WRITE_STATUSE2_CMD; - } - else if(GD25Q32C_STATUS3 == status_index) { - wrsr_cmd = SPI_FLASH_GD25Q32C_WRITE_STATUSE3_CMD; - } - else { - //ets_printf("[ERR]Not konw GD25Q32C status idx %d\n ",spi_wr_status_cmd); - } - special_flash_write_status(wrsr_cmd, new_status, 1, true); -} - -static bool spi_flash_check_wr_protect(void) +bool spi_flash_check_wr_protect(void) { uint32_t flash_id=spi_flash_get_id(); uint32_t status=0; @@ -366,7 +221,6 @@ static bool spi_flash_check_wr_protect(void) if ((flash_id & 0xffffff) == 0x15701c) { uint8_t sfdp = en25q16x_read_sfdp(); if (sfdp == 0xE5) { - spi_debug("EN25Q16A\n"); //This is EN25Q16A, set bit6 in the same way as issi flash chips. if(spi_flash_read_status(&status)==0) { //Read status Ok if(status&(SPI_EON_25Q16A_WRITE_PROTECT_STATUS)) { //Write_protect @@ -374,7 +228,6 @@ static bool spi_flash_check_wr_protect(void) } } } else if (sfdp == 0xED) { - spi_debug("EN25Q16B\n"); //This is EN25Q16B if(spi_flash_read_status(&status)==0) { //Read status Ok if(status&(SPI_EON_25Q16B_WRITE_PROTECT_STATUS)) { //Write_protect @@ -417,84 +270,267 @@ static bool spi_flash_check_wr_protect(void) return true; } -/****************************************************************************** - * FunctionName : spi_flash_erase_sector - * Description : a - * Parameters : - * Returns : -*******************************************************************************/ -esp_err_t IRAM_ATTR spi_flash_erase_sector(size_t sec) +static void spi_flash_enable_qio_bit6(void) +{ + uint8_t wrsr_cmd = 0x1; + uint32_t issi_qio = SPI_FLASH_ISSI_ENABLE_QIO_MODE; + special_flash_write_status(wrsr_cmd, issi_qio, 1, true); +} + +static bool spi_flash_issi_enable_QIO_mode(void) +{ + uint32_t status = 0; + if(spi_flash_read_status(&status) == 0) { + if((status&SPI_FLASH_ISSI_ENABLE_QIO_MODE)) { + return true; + } + } + else { + return false; + } + + spi_flash_enable_qio_bit6(); + + if(spi_flash_read_status(&status) == 0) { + if((status&SPI_FLASH_ISSI_ENABLE_QIO_MODE)) { + return true; + } else { + return false; + } + } else { + return false; + } +} + +static uint8_t flash_gd25q32c_read_status(enum GD25Q32C_status status_index) +{ + uint8_t rdsr_cmd=0; + if(GD25Q32C_STATUS1 == status_index) { + rdsr_cmd = SPI_FLASH_GD25Q32C_READ_STATUSE1_CMD; + } + else if(GD25Q32C_STATUS2 == status_index) { + rdsr_cmd = SPI_FLASH_GD25Q32C_READ_STATUSE2_CMD; + } + else if(GD25Q32C_STATUS3 == status_index) { + rdsr_cmd = SPI_FLASH_GD25Q32C_READ_STATUSE3_CMD; + } + else { + + } + uint32_t status; + special_flash_read_status(rdsr_cmd, &status, 1); + return ((uint8_t)status); +} + +static void flash_gd25q32c_write_status(enum GD25Q32C_status status_index,uint8_t status) +{ + uint32_t wrsr_cmd=0; + uint32_t new_status = status; + if(GD25Q32C_STATUS1 == status_index) { + wrsr_cmd = SPI_FLASH_GD25Q32C_WRITE_STATUSE1_CMD; + } + else if(GD25Q32C_STATUS2 == status_index) { + wrsr_cmd = SPI_FLASH_GD25Q32C_WRITE_STATUSE2_CMD; + } + else if(GD25Q32C_STATUS3 == status_index) { + wrsr_cmd = SPI_FLASH_GD25Q32C_WRITE_STATUSE3_CMD; + } + else { + //ets_printf("[ERR]Not konw GD25Q32C status idx %d\n ",spi_wr_status_cmd); + } + special_flash_write_status(wrsr_cmd, new_status, 1, true); +} + +static bool flash_gd25q32c_enable_QIO_mode() +{ + uint8_t data = 0; + if((data=flash_gd25q32c_read_status(GD25Q32C_STATUS2))&SPI_FLASH_GD25Q32C_QIO_MODE) { + return true; + } + else { + flash_gd25q32c_write_status(GD25Q32C_STATUS2,SPI_FLASH_GD25Q32C_QIO_MODE); + if(flash_gd25q32c_read_status(GD25Q32C_STATUS2)&SPI_FLASH_GD25Q32C_QIO_MODE) { + return true; + } + else { + return false; + } + } +} + +void special_flash_set_mode(uint8_t command, bool disable_wait_idle) +{ + spi_cmd_t cmd; + cmd.cmd = command; + cmd.cmd_len = 1; + cmd.addr = NULL; + cmd.addr_len = 0; + cmd.dummy_bits = 0; + cmd.data = NULL; + cmd.data_len = 0; + if (disable_wait_idle) { + spi_user_cmd(SPI_TX | SPI_RAW, &cmd); + } else { + spi_user_cmd(SPI_TX, &cmd); + } +} + +bool en25q16x_write_volatile_status(uint8_t vsr) +{ + //enter OTP mode + special_flash_set_mode(0x3a, true); + //volatile status register write enable + special_flash_set_mode(0x50, true); + //send 0x01 + 0x40 to set WHDIS bit + special_flash_write_status(0x01, vsr, 1, false); + //check + uint32_t status = 0; + special_flash_read_status(0x05, &status, 1); + //Leave OTP mode + special_flash_set_mode(0x04, false); + + if (status == 0x40) { + return true; + } else { + return false; + } +} + +void user_spi_flash_dio_to_qio_pre_init(void) +{ + uint32_t flash_id = spi_flash_get_id(); + bool to_qio = false; + //check for EN25Q16A/B flash chips + if ((flash_id & 0xffffff) == 0x15701c) { + uint8_t sfdp = en25q16x_read_sfdp(); + if (sfdp == 0xE5) { + //This is EN25Q16A, set bit6 in the same way as issi flash chips. + if (spi_flash_issi_enable_QIO_mode() == true) { + to_qio = true; + } + } else if (sfdp == 0xED) { + //This is EN25Q16B + if (en25q16x_write_volatile_status(0x40) == true) { + to_qio = true; + } + } + } + // ISSI : 0x9D + // MXIC : 0xC2 + // GD25Q32C & GD25Q128C : 0x1640C8 + // EON : 0X1C + // ENABLE FLASH QIO 0X01H+BIT6 + else if (((flash_id & 0xFF) == 0x9D) || ((flash_id & 0xFF) == 0xC2) || ((flash_id & 0xFF) == 0x1C) ) { + if (spi_flash_issi_enable_QIO_mode() == true) { + to_qio = true; + } + //ENABLE FLASH QIO 0X31H+BIT2 + } else if (((flash_id & 0xFFFFFF) == 0x1640C8) || ((flash_id & 0xFFFFFF) == 0x1840C8)) { + if (flash_gd25q32c_enable_QIO_mode() == true) { + to_qio = true; + } + //ENBALE FLASH QIO 0X01H+0X00+0X02 + } else { + if (spi_flash_enable_qmode_raw(&flashchip) == ESP_OK) { + to_qio = true; + } + } + + if (to_qio == true) { + spi_flash_switch_to_qio_raw(); + } +} + +esp_err_t spi_flash_erase_sector(size_t sec) { FLASH_INTR_DECLARE(c_tmp); esp_err_t ret; + if (sec >= (flashchip.chip_size / flashchip.sector_size)) { + return ESP_ERR_FLASH_OP_FAIL; + } + if (spi_flash_check_wr_protect() == false) { return ESP_ERR_FLASH_OP_FAIL; } - spi_debug("E[%x] %d-", sec, esp_get_time()); - FLASH_INTR_LOCK(c_tmp); pp_soft_wdt_stop(); FlashIsOnGoing = 1; - Cache_Read_Disable_2(); + + ret = spi_flash_erase_sector_raw(&flashchip, sec, flashchip.sector_size); - ret = SPIEraseSector(sec); - - Cache_Read_Enable_2(); FlashIsOnGoing = 0; pp_soft_wdt_restart(); FLASH_INTR_UNLOCK(c_tmp); - spi_debug("%d\n", esp_get_time()); - return ret; } -esp_err_t spi_flash_enable_qmode(void) +static esp_err_t spi_flash_program(uint32_t target, uint32_t *src_addr, size_t len) { - esp_err_t ret; + uint32_t page_size; + uint32_t pgm_len, pgm_num; + uint8_t i; - Cache_Read_Disable_2(); - ret = Enable_QMode(&flashchip); - Wait_SPI_Idle(&flashchip); - Cache_Read_Enable_2(); + page_size = flashchip.page_size; + pgm_len = page_size - (target % page_size); - return ret; + if (len < pgm_len) { + if (ESP_OK != spi_flash_write_raw(&flashchip, target, src_addr, len)) { + return ESP_ERR_FLASH_OP_FAIL; + } + } else { + if (ESP_OK != spi_flash_write_raw(&flashchip, target, src_addr, pgm_len)) { + return ESP_ERR_FLASH_OP_FAIL; + } + + //whole page program + pgm_num = (len - pgm_len) / page_size; + + for (i = 0; i < pgm_num; i++) { + if (ESP_OK != spi_flash_write_raw(&flashchip, target + pgm_len, src_addr + (pgm_len >> 2), page_size)) { + return ESP_ERR_FLASH_OP_FAIL; + } + + pgm_len += page_size; + } + + //remain parts to program + if (ESP_OK != spi_flash_write_raw(&flashchip, target + pgm_len, src_addr + (pgm_len >> 2), len - pgm_len)) { + return ESP_ERR_FLASH_OP_FAIL; + } + } + + return ESP_OK; } -static esp_err_t IRAM_ATTR spi_flash_write_raw(size_t dest_addr, const void *src, size_t size) +static esp_err_t __spi_flash_write(size_t dest_addr, const void *src, size_t size) { esp_err_t ret; FLASH_INTR_DECLARE(c_tmp); - spi_debug("W[%x] %d-", dest_addr / 4096, esp_get_time()); - FLASH_INTR_LOCK(c_tmp); pp_soft_wdt_stop(); FlashIsOnGoing = 1; - Cache_Read_Disable_2(); - ret = SPIWrite(dest_addr, (uint32_t *)src, size); + ret = spi_flash_program(dest_addr, (uint32_t *)src, size); - Cache_Read_Enable_2(); FlashIsOnGoing = 0; pp_soft_wdt_restart(); FLASH_INTR_UNLOCK(c_tmp); - spi_debug("%d\n", esp_get_time()); - return ret; } -esp_err_t IRAM_ATTR spi_flash_write(size_t dest_addr, const void *src, size_t size) +esp_err_t spi_flash_write(size_t dest_addr, const void *src, size_t size) { #undef FLASH_WRITE #define FLASH_WRITE(dest, src, size) \ { \ - ret = spi_flash_write_raw(dest, src, size); \ - esp_task_wdt_reset(); \ + ret = __spi_flash_write(dest, src, size); \ + esp_task_wdt_reset(); \ if (ret) { \ return ret; \ } \ @@ -519,6 +555,10 @@ esp_err_t IRAM_ATTR spi_flash_write(size_t dest_addr, const void *src, size_t si return ESP_ERR_FLASH_OP_FAIL; } + if ((dest_addr + size) > flashchip.chip_size) { + return ESP_ERR_FLASH_OP_FAIL; + } + if (spi_flash_check_wr_protect() == false) { return ESP_ERR_FLASH_OP_FAIL; } @@ -570,44 +610,31 @@ esp_err_t IRAM_ATTR spi_flash_write(size_t dest_addr, const void *src, size_t si return ret; } - -/****************************************************************************** - * FunctionName : spi_flash_read_raw - * Description : a - * Parameters : - * Returns : -*******************************************************************************/ -static esp_err_t IRAM_ATTR spi_flash_read_raw(size_t src_addr, void *dest, size_t size) +static esp_err_t __spi_flash_read(size_t src_addr, void *dest, size_t size) { esp_err_t ret; FLASH_INTR_DECLARE(c_tmp); - spi_debug("R[%x] %d-", src_addr / 4096, esp_get_time()); - FLASH_INTR_LOCK(c_tmp); pp_soft_wdt_stop(); FlashIsOnGoing = 1; - Cache_Read_Disable_2(); - ret = SPIRead(src_addr, dest, size); + ret = spi_flash_read_raw(&flashchip, src_addr, dest, size); - Cache_Read_Enable_2(); FlashIsOnGoing = 0; pp_soft_wdt_restart(); FLASH_INTR_UNLOCK(c_tmp); - spi_debug("%d\n", esp_get_time()); - - return ret; + return ret == 0 ? ESP_OK : ESP_ERR_FLASH_OP_FAIL; } -esp_err_t IRAM_ATTR spi_flash_read(size_t src_addr, void *dest, size_t size) +esp_err_t spi_flash_read(size_t src_addr, void *dest, size_t size) { #undef FLASH_READ #define FLASH_READ(addr, dest, size) \ { \ - ret = spi_flash_read_raw(addr, dest, size); \ - esp_task_wdt_reset(); \ + ret = __spi_flash_read(addr, dest, size); \ + esp_task_wdt_reset(); \ if (ret) \ return ret; \ } @@ -661,350 +688,10 @@ esp_err_t IRAM_ATTR spi_flash_read(size_t src_addr, void *dest, size_t size) return ESP_OK; } -static void spi_flash_enable_qio_bit6(void) -{ - uint8_t wrsr_cmd = 0x1; - uint32_t issi_qio = SPI_FLASH_ISSI_ENABLE_QIO_MODE; - special_flash_write_status(wrsr_cmd, issi_qio, 1, true); -} - -/* -if the QIO_ENABLE bit not in Bit9,in Bit6 -the SPI send 0x01(CMD)+(1<<6) -*/ -static bool spi_flash_issi_enable_QIO_mode(void) -{ - uint32_t status = 0; - if(spi_flash_read_status(&status) == 0) { - if((status&SPI_FLASH_ISSI_ENABLE_QIO_MODE)) { - return true; - } - } - else { - return false; - } - - spi_flash_enable_qio_bit6(); - - if(spi_flash_read_status(&status) == 0) { - if((status&SPI_FLASH_ISSI_ENABLE_QIO_MODE)) { - return true; - } else { - return false; - } - } else { - return false; - } -} - -static bool flash_gd25q32c_enable_QIO_mode() -{ - uint8_t data = 0; - if((data=flash_gd25q32c_read_status(GD25Q32C_STATUS2))&SPI_FLASH_GD25Q32C_QIO_MODE) { - return true; - } - else { - flash_gd25q32c_write_status(GD25Q32C_STATUS2,SPI_FLASH_GD25Q32C_QIO_MODE); - if(flash_gd25q32c_read_status(GD25Q32C_STATUS2)&SPI_FLASH_GD25Q32C_QIO_MODE) { - return true; - - } - else { - return false; - } - } -} - -bool special_flash_read_status(uint8_t command, uint32_t* status, int len) -{ - if( len > 2 || len < 1) { - return false; - } - spi_cmd_t cmd; - cmd.cmd = command; - cmd.cmd_len = 1; - cmd.addr = NULL; - cmd.addr_len = 0; - cmd.dummy_bits = 0; - cmd.data = status; - cmd.data_len = len; - spi_user_cmd(SPI_RX, &cmd); - return true; -} - -bool special_flash_write_status(uint8_t command, uint32_t status, int len, bool write_en) -{ - if (len > 2 || len < 1) { - return false; - } - spi_cmd_t cmd; - cmd.cmd = command; - cmd.cmd_len = 1; - cmd.addr = NULL; - cmd.addr_len = 0; - cmd.dummy_bits = 0; - cmd.data = &status; - cmd.data_len = len > 1 ? 2 : 1; - if (write_en) { - spi_user_cmd(SPI_WRSR, &cmd); - } else { - spi_user_cmd(SPI_TX | SPI_RAW, &cmd); - } - return true; -} - -void special_flash_set_mode(uint8_t command, bool disable_wait_idle) -{ - spi_cmd_t cmd; - cmd.cmd = command; - cmd.cmd_len = 1; - cmd.addr = NULL; - cmd.addr_len = 0; - cmd.dummy_bits = 0; - cmd.data = NULL; - cmd.data_len = 0; - if (disable_wait_idle) { - spi_user_cmd(SPI_TX | SPI_RAW, &cmd); - } else { - spi_user_cmd(SPI_TX, &cmd); - } -} - -bool en25q16x_write_volatile_status(uint8_t vsr) -{ - //enter OTP mode - special_flash_set_mode(0x3a, true); - //volatile status register write enable - special_flash_set_mode(0x50, true); - //send 0x01 + 0x40 to set WHDIS bit - special_flash_write_status(0x01, vsr, 1, false); - //check - uint32_t status = 0; - special_flash_read_status(0x05, &status, 1); - //Leave OTP mode - special_flash_set_mode(0x04, false); - - if (status == 0x40) { - return true; - } else { - return false; - } -} - -uint8_t en25q16x_read_sfdp() -{ - spi_cmd_t cmd; - cmd.cmd = 0x5a; - cmd.cmd_len = 1; - uint32_t addr = 0x00003000; - cmd.addr = &addr; - cmd.addr_len = 3; - cmd.dummy_bits = 8; - uint32_t data = 0; - cmd.data = &data; - cmd.data_len = 1; - spi_user_cmd(SPI_RX, &cmd); - spi_debug("0x5a cmd: 0x%08x\n", data); - return ((uint8_t) data); -} - -bool IRAM_ATTR spi_user_cmd(spi_cmd_dir_t mode, spi_cmd_t *p_cmd) -{ - if ((p_cmd->addr_len != 0 && p_cmd->addr == NULL) - || (p_cmd->data_len != 0 && p_cmd->data == NULL) - || (p_cmd == NULL)) { - return false; - } - int idx = 0; - FLASH_INTR_DECLARE(c_tmp); - - FLASH_INTR_LOCK(c_tmp); - - FlashIsOnGoing = 1; - // Cache Disable - Cache_Read_Disable_2(); - //wait spi idle - if((mode & SPI_RAW) == 0) { - Wait_SPI_Idle(&flashchip); - } - //save reg - uint32_t io_mux_reg = READ_PERI_REG(PERIPHS_IO_MUX_CONF_U); - uint32_t spi_clk_reg = READ_PERI_REG(SPI_CLOCK(SPI)); - uint32_t spi_ctrl_reg = READ_PERI_REG(SPI_CTRL(SPI)); - uint32_t spi_user_reg = READ_PERI_REG(SPI_USER(SPI)); - - if (mode & SPI_WRSR) { - // enable write register - SPI_write_enable(&flashchip); - } - - SET_PERI_REG_MASK(SPI_USER(SPI),SPI_USR_COMMAND); - - //Disable flash operation mode - CLEAR_PERI_REG_MASK(SPI_USER(SPI), SPI_FLASH_MODE); - //SET SPI SEND BUFFER MODE - CLEAR_PERI_REG_MASK(SPI_USER(SPI), SPI_USR_MISO_HIGHPART); - //CLEAR EQU SYS CLK - CLEAR_PERI_REG_MASK(PERIPHS_IO_MUX_CONF_U,SPI0_CLK_EQU_SYS_CLK); - - SET_PERI_REG_MASK(SPI_USER(SPI), SPI_CS_SETUP|SPI_CS_HOLD|SPI_USR_COMMAND|SPI_USR_MOSI); - CLEAR_PERI_REG_MASK(SPI_USER(SPI), SPI_FLASH_MODE); - //CLEAR DAUL OR QUAD LINES TRANSMISSION MODE - CLEAR_PERI_REG_MASK(SPI_CTRL(SPI), SPI_QIO_MODE|SPI_DIO_MODE|SPI_DOUT_MODE|SPI_QOUT_MODE); - WRITE_PERI_REG(SPI_CLOCK(SPI), - ((3&SPI_CLKCNT_N)<cmd_len != 0) { - //Max CMD length is 16 bits - SET_PERI_REG_BITS(SPI_USER2(SPI), SPI_USR_COMMAND_BITLEN, p_cmd->cmd_len * 8 - 1, SPI_USR_COMMAND_BITLEN_S); - //Enable CMD - SET_PERI_REG_MASK(SPI_USER(SPI), SPI_USR_COMMAND); - //LOAD CMD - SET_PERI_REG_BITS(SPI_USER2(SPI), SPI_USR_COMMAND_VALUE, p_cmd->cmd, SPI_USR_COMMAND_VALUE_S); - } else { - //CLEAR CMD - CLEAR_PERI_REG_MASK(SPI_USER(SPI), SPI_USR_COMMAND); - SET_PERI_REG_BITS(SPI_USER2(SPI), SPI_USR_COMMAND_BITLEN, 0, SPI_USR_COMMAND_BITLEN_S); - } - if (p_cmd->dummy_bits != 0) { - //SET dummy bits - SET_PERI_REG_BITS(SPI_USER1(SPI), SPI_USR_DUMMY_CYCLELEN, p_cmd->dummy_bits - 1, SPI_USR_DUMMY_CYCLELEN_S); - //Enable dummy - SET_PERI_REG_MASK(SPI_USER(SPI), SPI_USR_DUMMY); - } else { - //CLEAR DUMMY - SET_PERI_REG_BITS(SPI_USER1(SPI), SPI_USR_DUMMY_CYCLELEN, 0, SPI_USR_DUMMY_CYCLELEN_S); - CLEAR_PERI_REG_MASK(SPI_USER(SPI), SPI_USR_DUMMY); - } - - //SET USER ADDRESS - if (p_cmd->addr_len != 0) { - //Set addr lenght - SET_PERI_REG_BITS(SPI_USER1(SPI), SPI_USR_ADDR_BITLEN, p_cmd->addr_len * 8 - 1, SPI_USR_ADDR_BITLEN_S); - //Enable user address - SET_PERI_REG_MASK(SPI_USER(SPI), SPI_USR_ADDR); - WRITE_PERI_REG(SPI_ADDR(SPI), *p_cmd->addr); - } else { - //CLEAR ADDR - CLEAR_PERI_REG_MASK(SPI_USER(SPI), SPI_USR_ADDR); - SET_PERI_REG_BITS(SPI_USER1(SPI), SPI_USR_ADDR_BITLEN, 0, SPI_USR_ADDR_BITLEN_S); - } - - uint32_t *value = p_cmd->data; - if (((mode & SPI_TX) || (mode & SPI_WRSR)) && p_cmd->data_len != 0) { - //Enable MOSI, disable MISO - SET_PERI_REG_MASK(SPI_USER(SPI), SPI_USR_MOSI); - CLEAR_PERI_REG_MASK(SPI_USER(SPI), SPI_USR_MISO); - do { - WRITE_PERI_REG((SPI_W0(SPI) + (idx << 2)), *value++); - } while ( ++idx < (p_cmd->data_len / 4)); - SET_PERI_REG_BITS(SPI_USER1(SPI), SPI_USR_MOSI_BITLEN, ((p_cmd->data_len) * 8 - 1), SPI_USR_MOSI_BITLEN_S); - - } else if ((mode & SPI_RX) && p_cmd->data_len != 0) { - //Enable MISO, disable MOSI - CLEAR_PERI_REG_MASK(SPI_USER(SPI), SPI_USR_MOSI); - SET_PERI_REG_MASK(SPI_USER(SPI), SPI_USR_MISO); - SET_PERI_REG_BITS(SPI_USER1(SPI),SPI_USR_MISO_BITLEN, p_cmd->data_len * 8 - 1, SPI_USR_MISO_BITLEN_S); - int fifo_idx = 0; - do { - WRITE_PERI_REG((SPI_W0(SPI) + (fifo_idx << 2)), 0); - } while ( ++fifo_idx < (p_cmd->data_len / 4)); - } else { - CLEAR_PERI_REG_MASK(SPI_USER(SPI), SPI_USR_MOSI); - CLEAR_PERI_REG_MASK(SPI_USER(SPI), SPI_USR_MISO); - SET_PERI_REG_BITS(SPI_USER1(SPI), SPI_USR_MISO_BITLEN, 0, SPI_USR_MISO_BITLEN_S); - SET_PERI_REG_BITS(SPI_USER1(SPI), SPI_USR_MOSI_BITLEN, 0, SPI_USR_MOSI_BITLEN_S); - } - - //Start command - SET_PERI_REG_MASK(SPI_CMD(SPI), SPI_USR); - while (READ_PERI_REG(SPI_CMD(SPI)) & SPI_USR); - - if (mode & SPI_RX) { - do { - *p_cmd->data ++ = READ_PERI_REG(SPI_W0(SPI) + (idx << 2)); - } while (++idx < (p_cmd->data_len / 4)); - } - - //recover - WRITE_PERI_REG(PERIPHS_IO_MUX_CONF_U,io_mux_reg); - WRITE_PERI_REG(SPI_CTRL(SPI),spi_ctrl_reg); - WRITE_PERI_REG(SPI_CLOCK(SPI),spi_clk_reg); - WRITE_PERI_REG(SPI_USER(SPI),spi_user_reg); - - if((mode & SPI_RAW) == 0) { - Wait_SPI_Idle(&flashchip); - } - //enable icache - Cache_Read_Enable_2(); - - FlashIsOnGoing = 0; - FLASH_INTR_UNLOCK(c_tmp); - return true; -} - -void user_spi_flash_dio_to_qio_pre_init(void) -{ - uint32_t flash_id = spi_flash_get_id(); - bool to_qio = false; - //check for EN25Q16A/B flash chips - if ((flash_id & 0xffffff) == 0x15701c) { - uint8_t sfdp = en25q16x_read_sfdp(); - if (sfdp == 0xE5) { - //This is EN25Q16A, set bit6 in the same way as issi flash chips. - if (spi_flash_issi_enable_QIO_mode() == true) { - to_qio = true; - } - } else if (sfdp == 0xED) { - //This is EN25Q16B - if (en25q16x_write_volatile_status(0x40) == true) { - to_qio = true; - } - } - } - // ISSI : 0x9D - // MXIC : 0xC2 - // GD25Q32C & GD25Q128C : 0x1640C8 - // EON : 0X1C - // ENABLE FLASH QIO 0X01H+BIT6 - else if (((flash_id & 0xFF) == 0x9D) || ((flash_id & 0xFF) == 0xC2) || ((flash_id & 0xFF) == 0x1C) ) { - if (spi_flash_issi_enable_QIO_mode() == true) { - to_qio = true; - } - //ENABLE FLASH QIO 0X31H+BIT2 - } else if (((flash_id & 0xFFFFFF) == 0x1640C8) || ((flash_id & 0xFFFFFF) == 0x1840C8)) { - if (flash_gd25q32c_enable_QIO_mode() == true) { - to_qio = true; - } - //ENBALE FLASH QIO 0X01H+0X00+0X02 - } else { - if (spi_flash_enable_qmode() == ESP_OK) { - to_qio = true; - } - } - - if (to_qio == true) { - CLEAR_PERI_REG_MASK(PERIPHS_SPI_FLASH_CTRL, SPI_QIO_MODE - |SPI_QOUT_MODE - |SPI_DIO_MODE - |SPI_DOUT_MODE - |SPI_FASTRD_MODE); - SET_PERI_REG_MASK(PERIPHS_SPI_FLASH_CTRL, SPI_QIO_MODE | SPI_FASTRD_MODE); - } -} - /** * @brief Erase a range of flash sectors */ -esp_err_t IRAM_ATTR spi_flash_erase_range(size_t start_address, size_t size) +esp_err_t spi_flash_erase_range(size_t start_address, size_t size) { esp_err_t ret; size_t sec, num; diff --git a/components/spi_flash/src/spi_flash_raw.c b/components/spi_flash/src/spi_flash_raw.c new file mode 100644 index 00000000..355f7aca --- /dev/null +++ b/components/spi_flash/src/spi_flash_raw.c @@ -0,0 +1,290 @@ +// Copyright 2018-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.h" +#include "priv/esp_spi_flash_raw.h" + +#include "esp8266/eagle_soc.h" +#include "esp8266/pin_mux_register.h" +#include "driver/spi_register.h" + +void Cache_Read_Disable_2(void) +{ + CLEAR_PERI_REG_MASK(CACHE_FLASH_CTRL_REG,CACHE_READ_EN_BIT); + while(REG_READ(SPI_EXT2(0)) != 0) { } + CLEAR_PERI_REG_MASK(PERIPHS_SPI_FLASH_CTRL,SPI_ENABLE_AHB); +} + +void Cache_Read_Enable_2() +{ + SET_PERI_REG_MASK(PERIPHS_SPI_FLASH_CTRL,SPI_ENABLE_AHB); + SET_PERI_REG_MASK(CACHE_FLASH_CTRL_REG,CACHE_READ_EN_BIT); +} +void Cache_Read_Enable_New(void) __attribute__((alias("Cache_Read_Enable_2"))); + +uint32_t spi_flash_get_id_raw(esp_spi_flash_chip_t *chip) +{ + uint32_t rdid = 0; + + Cache_Read_Disable(); + + Wait_SPI_Idle(chip); + + WRITE_PERI_REG(PERIPHS_SPI_FLASH_C0, 0); // clear regisrter + WRITE_PERI_REG(PERIPHS_SPI_FLASH_CMD, SPI_FLASH_RDID); + while(READ_PERI_REG(PERIPHS_SPI_FLASH_CMD)!=0); + + rdid = READ_PERI_REG(PERIPHS_SPI_FLASH_C0)&0xffffff; + + Cache_Read_Enable_New(); + + return rdid; +} + +esp_err_t spi_flash_read_status_raw(esp_spi_flash_chip_t *chip, uint32_t *status) +{ + esp_err_t ret; + + Cache_Read_Disable_2(); + + ret = SPI_read_status(chip, status); + + Cache_Read_Enable_2(); + + return ret; +} + +esp_err_t spi_flash_write_status_raw(esp_spi_flash_chip_t *chip, uint32_t status_value) +{ + Cache_Read_Disable_2(); + + Wait_SPI_Idle(chip); + + if (ESP_OK != SPI_write_enable(chip)) + return ESP_ERR_FLASH_OP_FAIL; + + if(ESP_OK != SPI_write_status(chip, status_value)) + return ESP_ERR_FLASH_OP_FAIL; + + Wait_SPI_Idle(chip); + + Cache_Read_Enable_2(); + + return ESP_OK; +} + +esp_err_t spi_flash_erase_sector_raw(esp_spi_flash_chip_t *chip, size_t sec, size_t sec_size) +{ + esp_err_t ret = ESP_OK; + + Cache_Read_Disable_2(); + + if (ESP_OK != SPI_write_enable(chip)) { + ret = ESP_ERR_FLASH_OP_FAIL; + } + + if (ESP_OK != SPI_sector_erase(chip, sec * sec_size)) { + ret = ESP_ERR_FLASH_OP_FAIL; + } + + Cache_Read_Enable_2(); + + return ret; +} + +esp_err_t spi_flash_enable_qmode_raw(esp_spi_flash_chip_t *chip) +{ + esp_err_t ret; + + Cache_Read_Disable_2(); + + ret = Enable_QMode(chip); + + Wait_SPI_Idle(chip); + + Cache_Read_Enable_2(); + + return ret; +} + +esp_err_t spi_flash_write_raw(esp_spi_flash_chip_t *chip, size_t dest_addr, const void *src, size_t size) +{ + esp_err_t ret; + + Cache_Read_Disable_2(); + + ret = SPI_page_program(chip, dest_addr, (void *)src, size); + + Cache_Read_Enable_2(); + + return ret; +} + +esp_err_t spi_flash_read_raw(esp_spi_flash_chip_t *chip, size_t src_addr, void *dest, size_t size) +{ + esp_err_t ret; + + Cache_Read_Disable_2(); + + ret = SPI_read_data(chip, src_addr, dest, size); + + Cache_Read_Enable_2(); + + return ret; +} + +bool spi_user_cmd_raw(esp_spi_flash_chip_t *chip, spi_cmd_dir_t mode, spi_cmd_t *p_cmd) +{ + int idx = 0; + + // Cache Disable + Cache_Read_Disable_2(); + //wait spi idle + if((mode & SPI_RAW) == 0) { + Wait_SPI_Idle(chip); + } + //save reg + uint32_t io_mux_reg = READ_PERI_REG(PERIPHS_IO_MUX_CONF_U); + uint32_t spi_clk_reg = READ_PERI_REG(SPI_CLOCK(SPI)); + uint32_t spi_ctrl_reg = READ_PERI_REG(SPI_CTRL(SPI)); + uint32_t spi_user_reg = READ_PERI_REG(SPI_USER(SPI)); + + if (mode & SPI_WRSR) { + // enable write register + SPI_write_enable(chip); + } + + SET_PERI_REG_MASK(SPI_USER(SPI),SPI_USR_COMMAND); + + //Disable flash operation mode + CLEAR_PERI_REG_MASK(SPI_USER(SPI), SPI_FLASH_MODE); + //SET SPI SEND BUFFER MODE + CLEAR_PERI_REG_MASK(SPI_USER(SPI), SPI_USR_MISO_HIGHPART); + //CLEAR EQU SYS CLK + CLEAR_PERI_REG_MASK(PERIPHS_IO_MUX_CONF_U,SPI0_CLK_EQU_SYS_CLK); + + SET_PERI_REG_MASK(SPI_USER(SPI), SPI_CS_SETUP|SPI_CS_HOLD|SPI_USR_COMMAND|SPI_USR_MOSI); + CLEAR_PERI_REG_MASK(SPI_USER(SPI), SPI_FLASH_MODE); + //CLEAR DAUL OR QUAD LINES TRANSMISSION MODE + CLEAR_PERI_REG_MASK(SPI_CTRL(SPI), SPI_QIO_MODE|SPI_DIO_MODE|SPI_DOUT_MODE|SPI_QOUT_MODE); + WRITE_PERI_REG(SPI_CLOCK(SPI), + ((3&SPI_CLKCNT_N)<cmd_len != 0) { + //Max CMD length is 16 bits + SET_PERI_REG_BITS(SPI_USER2(SPI), SPI_USR_COMMAND_BITLEN, p_cmd->cmd_len * 8 - 1, SPI_USR_COMMAND_BITLEN_S); + //Enable CMD + SET_PERI_REG_MASK(SPI_USER(SPI), SPI_USR_COMMAND); + //LOAD CMD + SET_PERI_REG_BITS(SPI_USER2(SPI), SPI_USR_COMMAND_VALUE, p_cmd->cmd, SPI_USR_COMMAND_VALUE_S); + } else { + //CLEAR CMD + CLEAR_PERI_REG_MASK(SPI_USER(SPI), SPI_USR_COMMAND); + SET_PERI_REG_BITS(SPI_USER2(SPI), SPI_USR_COMMAND_BITLEN, 0, SPI_USR_COMMAND_BITLEN_S); + } + if (p_cmd->dummy_bits != 0) { + //SET dummy bits + SET_PERI_REG_BITS(SPI_USER1(SPI), SPI_USR_DUMMY_CYCLELEN, p_cmd->dummy_bits - 1, SPI_USR_DUMMY_CYCLELEN_S); + //Enable dummy + SET_PERI_REG_MASK(SPI_USER(SPI), SPI_USR_DUMMY); + } else { + //CLEAR DUMMY + SET_PERI_REG_BITS(SPI_USER1(SPI), SPI_USR_DUMMY_CYCLELEN, 0, SPI_USR_DUMMY_CYCLELEN_S); + CLEAR_PERI_REG_MASK(SPI_USER(SPI), SPI_USR_DUMMY); + } + + //SET USER ADDRESS + if (p_cmd->addr_len != 0) { + //Set addr lenght + SET_PERI_REG_BITS(SPI_USER1(SPI), SPI_USR_ADDR_BITLEN, p_cmd->addr_len * 8 - 1, SPI_USR_ADDR_BITLEN_S); + //Enable user address + SET_PERI_REG_MASK(SPI_USER(SPI), SPI_USR_ADDR); + WRITE_PERI_REG(SPI_ADDR(SPI), *p_cmd->addr); + } else { + //CLEAR ADDR + CLEAR_PERI_REG_MASK(SPI_USER(SPI), SPI_USR_ADDR); + SET_PERI_REG_BITS(SPI_USER1(SPI), SPI_USR_ADDR_BITLEN, 0, SPI_USR_ADDR_BITLEN_S); + } + + uint32_t *value = p_cmd->data; + if (((mode & SPI_TX) || (mode & SPI_WRSR)) && p_cmd->data_len != 0) { + //Enable MOSI, disable MISO + SET_PERI_REG_MASK(SPI_USER(SPI), SPI_USR_MOSI); + CLEAR_PERI_REG_MASK(SPI_USER(SPI), SPI_USR_MISO); + do { + WRITE_PERI_REG((SPI_W0(SPI) + (idx << 2)), *value++); + } while ( ++idx < (p_cmd->data_len / 4)); + SET_PERI_REG_BITS(SPI_USER1(SPI), SPI_USR_MOSI_BITLEN, ((p_cmd->data_len) * 8 - 1), SPI_USR_MOSI_BITLEN_S); + + } else if ((mode & SPI_RX) && p_cmd->data_len != 0) { + //Enable MISO, disable MOSI + CLEAR_PERI_REG_MASK(SPI_USER(SPI), SPI_USR_MOSI); + SET_PERI_REG_MASK(SPI_USER(SPI), SPI_USR_MISO); + SET_PERI_REG_BITS(SPI_USER1(SPI),SPI_USR_MISO_BITLEN, p_cmd->data_len * 8 - 1, SPI_USR_MISO_BITLEN_S); + int fifo_idx = 0; + do { + WRITE_PERI_REG((SPI_W0(SPI) + (fifo_idx << 2)), 0); + } while ( ++fifo_idx < (p_cmd->data_len / 4)); + } else { + CLEAR_PERI_REG_MASK(SPI_USER(SPI), SPI_USR_MOSI); + CLEAR_PERI_REG_MASK(SPI_USER(SPI), SPI_USR_MISO); + SET_PERI_REG_BITS(SPI_USER1(SPI), SPI_USR_MISO_BITLEN, 0, SPI_USR_MISO_BITLEN_S); + SET_PERI_REG_BITS(SPI_USER1(SPI), SPI_USR_MOSI_BITLEN, 0, SPI_USR_MOSI_BITLEN_S); + } + + //Start command + SET_PERI_REG_MASK(SPI_CMD(SPI), SPI_USR); + while (READ_PERI_REG(SPI_CMD(SPI)) & SPI_USR); + + if (mode & SPI_RX) { + do { + *p_cmd->data ++ = READ_PERI_REG(SPI_W0(SPI) + (idx << 2)); + } while (++idx < (p_cmd->data_len / 4)); + } + + //recover + WRITE_PERI_REG(PERIPHS_IO_MUX_CONF_U,io_mux_reg); + WRITE_PERI_REG(SPI_CTRL(SPI),spi_ctrl_reg); + WRITE_PERI_REG(SPI_CLOCK(SPI),spi_clk_reg); + WRITE_PERI_REG(SPI_USER(SPI),spi_user_reg); + + if((mode & SPI_RAW) == 0) { + Wait_SPI_Idle(chip); + } + //enable icache + Cache_Read_Enable_2(); + + return true; +} + +void spi_flash_switch_to_qio_raw(void) +{ + CLEAR_PERI_REG_MASK(PERIPHS_SPI_FLASH_CTRL, SPI_QIO_MODE + |SPI_QOUT_MODE + |SPI_DIO_MODE + |SPI_DOUT_MODE + |SPI_FASTRD_MODE); + + SET_PERI_REG_MASK(PERIPHS_SPI_FLASH_CTRL, SPI_QIO_MODE | SPI_FASTRD_MODE); +}