// 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 "esp8266/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_rom_spiflash_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_rom_spiflash_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_rom_spiflash_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_rom_spiflash_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_rom_spiflash_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_rom_spiflash_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_rom_spiflash_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_rom_spiflash_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); }