| 
									
										
										
										
											2016-11-02 10:41:58 +11:00
										 |  |  | // Copyright 2015-2016 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.
 | 
					
						
							|  |  |  | #ifndef __BOOTLOADER_FLASH_H
 | 
					
						
							|  |  |  | #define __BOOTLOADER_FLASH_H
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #include <stddef.h>
 | 
					
						
							|  |  |  | #include <stdbool.h>
 | 
					
						
							|  |  |  | #include <stdint.h>
 | 
					
						
							|  |  |  | #include <esp_err.h>
 | 
					
						
							| 
									
										
										
										
											2020-02-25 01:21:41 +05:30
										 |  |  | #include <esp_spi_flash.h> /* including in bootloader for error values */
 | 
					
						
							| 
									
										
											  
											
												bootloader: fix the WRSR format for ISSI flash chips
1. The 2nd bootloader always call `rom_spiflash_unlock()`, but never help to clear the WEL bit when exit. This may cause system unstability.
   This commit helps to clear WEL when flash configuration is done.
   **RISK:** When the app starts, it didn't have to clear the WEL before it actually write/erase. But now the very first write/erase operation should be done after a WEL clear. Though the risk is little (all the following write/erase also need to clear the WEL), we still have to test this carefully, especially for those functions used by the OTA.
2. The `rom_spiflash_unlock()` function in the patch of ESP32 may (1) trigger the QPI, (2) clear the QE or (3) fail to unlock the ISSI chips.
   Status register bitmap of ISSI chip and GD chip:
| SR | ISSI | GD25LQ32C |
| -- | ---- | --------- |
| 0  | WIP  | WIP       |
| 1  | WEL  | WEL       |
| 2  | BP0  | BP0       |
| 3  | BP1  | BP1       |
| 4  | BP2  | BP2       |
| 5  | BP3  | BP3       |
| 6  | QE   | BP4       |
| 7  | SRWD | SRP0      |
| 8  |      | SRP1      |
| 9  |      | QE        |
| 10 |      | SUS2      |
| 11 |      | LB1       |
| 12 |      | LB2       |
| 13 |      | LB3       |
| 14 |      | CMP       |
| 15 |      | SUS1      |
   QE bit of other chips are at the bit 9 of the status register (i.e. bit 1 of SR2), which should be read by RDSR2 command.
   However, the RDSR2 (35H, Read Status 2) command for chip of other vendors happens to be the QIOEN (Enter QPI mode) command of ISSI chips. When the `rom_spiflash_unlock()` function trys to read SR2, it may trigger the QPI of ISSI chips.
   Moreover, when `rom_spiflash_unlock()` try to clear the BP4 bit in the status register, QE (bit 6) of ISSI chip may be cleared by accident. Or if the ISSI chip doesn't accept WRSR command with argument of two bytes (since it only have status register of one byte), it may fail to clear the other protect bits (BP0~BP3) as expected.
   This commit makes the `rom_spiflash_unlock()` check whether the vendor is issi. if so, `rom_spiflash_unlock()` only send RDSR to read the status register, send WRSR with only 1 byte argument, and also avoid clearing the QE bit (bit 6).
3. `rom_spiflash_unlock()` always send WRSR command to clear protection bits even when there is no protection bit active. And the execution of clearing status registers, which takes about 700us, will also happen even when there's no bits cleared.
   This commit skips the clearing of status register if there is no protection bits active.
Also move the execute_flash_command to be a bootloader API; move
implementation of spi_flash_wrap_set to the bootloader
											
										 
											2020-03-12 18:20:31 +08:00
										 |  |  | #include "sdkconfig.h"
 | 
					
						
							| 
									
										
										
										
											2020-07-13 03:23:12 +08:00
										 |  |  | #include "bootloader_flash.h"
 | 
					
						
							| 
									
										
										
										
											2016-11-11 17:00:34 +11:00
										 |  |  | 
 | 
					
						
							|  |  |  | #define FLASH_SECTOR_SIZE 0x1000
 | 
					
						
							| 
									
										
										
										
											2018-08-24 17:58:04 +05:30
										 |  |  | #define FLASH_BLOCK_SIZE 0x10000
 | 
					
						
							| 
									
										
										
										
											2020-02-25 01:21:41 +05:30
										 |  |  | #define MMAP_ALIGNED_MASK 0x0000FFFF
 | 
					
						
							| 
									
										
										
										
											2016-11-02 10:41:58 +11:00
										 |  |  | 
 | 
					
						
							| 
									
										
											  
											
												bootloader: fix the WRSR format for ISSI flash chips
1. The 2nd bootloader always call `rom_spiflash_unlock()`, but never help to clear the WEL bit when exit. This may cause system unstability.
   This commit helps to clear WEL when flash configuration is done.
   **RISK:** When the app starts, it didn't have to clear the WEL before it actually write/erase. But now the very first write/erase operation should be done after a WEL clear. Though the risk is little (all the following write/erase also need to clear the WEL), we still have to test this carefully, especially for those functions used by the OTA.
2. The `rom_spiflash_unlock()` function in the patch of ESP32 may (1) trigger the QPI, (2) clear the QE or (3) fail to unlock the ISSI chips.
   Status register bitmap of ISSI chip and GD chip:
| SR | ISSI | GD25LQ32C |
| -- | ---- | --------- |
| 0  | WIP  | WIP       |
| 1  | WEL  | WEL       |
| 2  | BP0  | BP0       |
| 3  | BP1  | BP1       |
| 4  | BP2  | BP2       |
| 5  | BP3  | BP3       |
| 6  | QE   | BP4       |
| 7  | SRWD | SRP0      |
| 8  |      | SRP1      |
| 9  |      | QE        |
| 10 |      | SUS2      |
| 11 |      | LB1       |
| 12 |      | LB2       |
| 13 |      | LB3       |
| 14 |      | CMP       |
| 15 |      | SUS1      |
   QE bit of other chips are at the bit 9 of the status register (i.e. bit 1 of SR2), which should be read by RDSR2 command.
   However, the RDSR2 (35H, Read Status 2) command for chip of other vendors happens to be the QIOEN (Enter QPI mode) command of ISSI chips. When the `rom_spiflash_unlock()` function trys to read SR2, it may trigger the QPI of ISSI chips.
   Moreover, when `rom_spiflash_unlock()` try to clear the BP4 bit in the status register, QE (bit 6) of ISSI chip may be cleared by accident. Or if the ISSI chip doesn't accept WRSR command with argument of two bytes (since it only have status register of one byte), it may fail to clear the other protect bits (BP0~BP3) as expected.
   This commit makes the `rom_spiflash_unlock()` check whether the vendor is issi. if so, `rom_spiflash_unlock()` only send RDSR to read the status register, send WRSR with only 1 byte argument, and also avoid clearing the QE bit (bit 6).
3. `rom_spiflash_unlock()` always send WRSR command to clear protection bits even when there is no protection bit active. And the execution of clearing status registers, which takes about 700us, will also happen even when there's no bits cleared.
   This commit skips the clearing of status register if there is no protection bits active.
Also move the execute_flash_command to be a bootloader API; move
implementation of spi_flash_wrap_set to the bootloader
											
										 
											2020-03-12 18:20:31 +08:00
										 |  |  | /* SPI commands (actual on-wire commands not SPI controller bitmasks)
 | 
					
						
							|  |  |  |    Suitable for use with the bootloader_execute_flash_command static function. | 
					
						
							|  |  |  | */ | 
					
						
							|  |  |  | #define CMD_RDID       0x9F
 | 
					
						
							|  |  |  | #define CMD_WRSR       0x01
 | 
					
						
							|  |  |  | #define CMD_WRSR2      0x31 /* Not all SPI flash uses this command */
 | 
					
						
							|  |  |  | #define CMD_WREN       0x06
 | 
					
						
							|  |  |  | #define CMD_WRDI       0x04
 | 
					
						
							|  |  |  | #define CMD_RDSR       0x05
 | 
					
						
							|  |  |  | #define CMD_RDSR2      0x35 /* Not all SPI flash uses this command */
 | 
					
						
							|  |  |  | #define CMD_OTPEN      0x3A /* Enable OTP mode, not all SPI flash uses this command */
 | 
					
						
							| 
									
										
										
										
											2021-08-01 14:23:36 +08:00
										 |  |  | #define CMD_RDSFDP     0x5A /* Read the SFDP of the flash */
 | 
					
						
							| 
									
										
											  
											
												bootloader: fix the WRSR format for ISSI flash chips
1. The 2nd bootloader always call `rom_spiflash_unlock()`, but never help to clear the WEL bit when exit. This may cause system unstability.
   This commit helps to clear WEL when flash configuration is done.
   **RISK:** When the app starts, it didn't have to clear the WEL before it actually write/erase. But now the very first write/erase operation should be done after a WEL clear. Though the risk is little (all the following write/erase also need to clear the WEL), we still have to test this carefully, especially for those functions used by the OTA.
2. The `rom_spiflash_unlock()` function in the patch of ESP32 may (1) trigger the QPI, (2) clear the QE or (3) fail to unlock the ISSI chips.
   Status register bitmap of ISSI chip and GD chip:
| SR | ISSI | GD25LQ32C |
| -- | ---- | --------- |
| 0  | WIP  | WIP       |
| 1  | WEL  | WEL       |
| 2  | BP0  | BP0       |
| 3  | BP1  | BP1       |
| 4  | BP2  | BP2       |
| 5  | BP3  | BP3       |
| 6  | QE   | BP4       |
| 7  | SRWD | SRP0      |
| 8  |      | SRP1      |
| 9  |      | QE        |
| 10 |      | SUS2      |
| 11 |      | LB1       |
| 12 |      | LB2       |
| 13 |      | LB3       |
| 14 |      | CMP       |
| 15 |      | SUS1      |
   QE bit of other chips are at the bit 9 of the status register (i.e. bit 1 of SR2), which should be read by RDSR2 command.
   However, the RDSR2 (35H, Read Status 2) command for chip of other vendors happens to be the QIOEN (Enter QPI mode) command of ISSI chips. When the `rom_spiflash_unlock()` function trys to read SR2, it may trigger the QPI of ISSI chips.
   Moreover, when `rom_spiflash_unlock()` try to clear the BP4 bit in the status register, QE (bit 6) of ISSI chip may be cleared by accident. Or if the ISSI chip doesn't accept WRSR command with argument of two bytes (since it only have status register of one byte), it may fail to clear the other protect bits (BP0~BP3) as expected.
   This commit makes the `rom_spiflash_unlock()` check whether the vendor is issi. if so, `rom_spiflash_unlock()` only send RDSR to read the status register, send WRSR with only 1 byte argument, and also avoid clearing the QE bit (bit 6).
3. `rom_spiflash_unlock()` always send WRSR command to clear protection bits even when there is no protection bit active. And the execution of clearing status registers, which takes about 700us, will also happen even when there's no bits cleared.
   This commit skips the clearing of status register if there is no protection bits active.
Also move the execute_flash_command to be a bootloader API; move
implementation of spi_flash_wrap_set to the bootloader
											
										 
											2020-03-12 18:20:31 +08:00
										 |  |  | #define CMD_WRAP       0x77 /* Set burst with wrap command */
 | 
					
						
							| 
									
										
										
										
											2020-12-18 12:57:55 +08:00
										 |  |  | #define CMD_RESUME     0x7A /* Resume command to clear flash suspend bit */
 | 
					
						
							| 
									
										
											  
											
												bootloader: fix the WRSR format for ISSI flash chips
1. The 2nd bootloader always call `rom_spiflash_unlock()`, but never help to clear the WEL bit when exit. This may cause system unstability.
   This commit helps to clear WEL when flash configuration is done.
   **RISK:** When the app starts, it didn't have to clear the WEL before it actually write/erase. But now the very first write/erase operation should be done after a WEL clear. Though the risk is little (all the following write/erase also need to clear the WEL), we still have to test this carefully, especially for those functions used by the OTA.
2. The `rom_spiflash_unlock()` function in the patch of ESP32 may (1) trigger the QPI, (2) clear the QE or (3) fail to unlock the ISSI chips.
   Status register bitmap of ISSI chip and GD chip:
| SR | ISSI | GD25LQ32C |
| -- | ---- | --------- |
| 0  | WIP  | WIP       |
| 1  | WEL  | WEL       |
| 2  | BP0  | BP0       |
| 3  | BP1  | BP1       |
| 4  | BP2  | BP2       |
| 5  | BP3  | BP3       |
| 6  | QE   | BP4       |
| 7  | SRWD | SRP0      |
| 8  |      | SRP1      |
| 9  |      | QE        |
| 10 |      | SUS2      |
| 11 |      | LB1       |
| 12 |      | LB2       |
| 13 |      | LB3       |
| 14 |      | CMP       |
| 15 |      | SUS1      |
   QE bit of other chips are at the bit 9 of the status register (i.e. bit 1 of SR2), which should be read by RDSR2 command.
   However, the RDSR2 (35H, Read Status 2) command for chip of other vendors happens to be the QIOEN (Enter QPI mode) command of ISSI chips. When the `rom_spiflash_unlock()` function trys to read SR2, it may trigger the QPI of ISSI chips.
   Moreover, when `rom_spiflash_unlock()` try to clear the BP4 bit in the status register, QE (bit 6) of ISSI chip may be cleared by accident. Or if the ISSI chip doesn't accept WRSR command with argument of two bytes (since it only have status register of one byte), it may fail to clear the other protect bits (BP0~BP3) as expected.
   This commit makes the `rom_spiflash_unlock()` check whether the vendor is issi. if so, `rom_spiflash_unlock()` only send RDSR to read the status register, send WRSR with only 1 byte argument, and also avoid clearing the QE bit (bit 6).
3. `rom_spiflash_unlock()` always send WRSR command to clear protection bits even when there is no protection bit active. And the execution of clearing status registers, which takes about 700us, will also happen even when there's no bits cleared.
   This commit skips the clearing of status register if there is no protection bits active.
Also move the execute_flash_command to be a bootloader API; move
implementation of spi_flash_wrap_set to the bootloader
											
										 
											2020-03-12 18:20:31 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-11-02 10:41:58 +11:00
										 |  |  | /* Provide a Flash API for bootloader_support code,
 | 
					
						
							|  |  |  |    that can be used from bootloader or app code. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |    This header is available to source code in the bootloader & | 
					
						
							|  |  |  |    bootloader_support components only. | 
					
						
							|  |  |  | */ | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-06-15 15:13:51 +05:30
										 |  |  | /**
 | 
					
						
							|  |  |  |  * @brief Get number of free pages | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * @return Number of free pages | 
					
						
							|  |  |  |  */ | 
					
						
							| 
									
										
										
										
											2019-07-16 16:33:30 +07:00
										 |  |  | uint32_t bootloader_mmap_get_free_pages(void); | 
					
						
							| 
									
										
										
										
											2019-06-15 15:13:51 +05:30
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-11-02 10:41:58 +11:00
										 |  |  | /**
 | 
					
						
							|  |  |  |  * @brief Map a region of flash to data memory | 
					
						
							|  |  |  |  * | 
					
						
							| 
									
										
										
										
											2016-11-07 15:45:57 +11:00
										 |  |  |  * @important In bootloader code, only one region can be bootloader_mmaped at once. The previous region must be bootloader_munmapped before another region is mapped. | 
					
						
							| 
									
										
										
										
											2016-11-02 10:41:58 +11:00
										 |  |  |  * | 
					
						
							|  |  |  |  * @important In app code, these functions are not thread safe. | 
					
						
							|  |  |  |  * | 
					
						
							| 
									
										
										
										
											2016-11-07 15:45:57 +11:00
										 |  |  |  * Call bootloader_munmap once for each successful call to bootloader_mmap. | 
					
						
							| 
									
										
										
										
											2016-11-02 10:41:58 +11:00
										 |  |  |  * | 
					
						
							|  |  |  |  * In esp-idf app, this function maps directly to spi_flash_mmap. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * @param offset - Starting flash offset to map to memory. | 
					
						
							|  |  |  |  * @param length - Length of data to map. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * @return Pointer to mapped data memory (at src_addr), or NULL | 
					
						
							|  |  |  |  * if an allocation error occured. | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | const void *bootloader_mmap(uint32_t src_addr, uint32_t size); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /**
 | 
					
						
							|  |  |  |  * @brief Unmap a previously mapped region of flash | 
					
						
							|  |  |  |  * | 
					
						
							| 
									
										
										
										
											2016-11-07 15:45:57 +11:00
										 |  |  |  * Call bootloader_munmap once for each successful call to bootloader_mmap. | 
					
						
							| 
									
										
										
										
											2016-11-02 10:41:58 +11:00
										 |  |  |  */ | 
					
						
							| 
									
										
										
										
											2016-11-07 15:45:57 +11:00
										 |  |  | void bootloader_munmap(const void *mapping); | 
					
						
							| 
									
										
										
										
											2016-11-02 10:41:58 +11:00
										 |  |  | 
 | 
					
						
							|  |  |  | /**
 | 
					
						
							|  |  |  |  * @brief  Read data from Flash. | 
					
						
							|  |  |  |  * | 
					
						
							| 
									
										
										
										
											2016-11-11 17:00:34 +11:00
										 |  |  |  * | 
					
						
							|  |  |  |  * @note All of src, dest and size have to be 4-byte aligned. | 
					
						
							| 
									
										
										
										
											2016-11-02 10:41:58 +11:00
										 |  |  |  * | 
					
						
							|  |  |  |  * @param  src   source address of the data in Flash. | 
					
						
							|  |  |  |  * @param  dest  pointer to the destination buffer | 
					
						
							|  |  |  |  * @param  size  length of data | 
					
						
							| 
									
										
										
										
											2016-11-11 17:00:34 +11:00
										 |  |  |  * @param  allow_decrypt If true and flash encryption is enabled, data on flash | 
					
						
							|  |  |  |  *         will be decrypted transparently as part of the read. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * @return ESP_OK on success, ESP_ERR_FLASH_OP_FAIL on SPI failure, | 
					
						
							|  |  |  |  * ESP_ERR_FLASH_OP_TIMEOUT on SPI timeout. | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | esp_err_t bootloader_flash_read(size_t src_addr, void *dest, size_t size, bool allow_decrypt); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /**
 | 
					
						
							|  |  |  |  * @brief  Write data to Flash. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * @note All of dest_addr, src and size have to be 4-byte aligned. If write_encrypted is set, dest_addr and size must be 32-byte aligned. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * Note: In bootloader, when write_encrypted == true, the src buffer is encrypted in place. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * @param  dest_addr Destination address to write in Flash. | 
					
						
							|  |  |  |  * @param  src Pointer to the data to write to flash | 
					
						
							|  |  |  |  * @param  size Length of data in bytes. | 
					
						
							|  |  |  |  * @param  write_encrypted If true, data will be written encrypted on flash. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * @return ESP_OK on success, ESP_ERR_FLASH_OP_FAIL on SPI failure, | 
					
						
							|  |  |  |  * ESP_ERR_FLASH_OP_TIMEOUT on SPI timeout. | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | esp_err_t bootloader_flash_write(size_t dest_addr, void *src, size_t size, bool write_encrypted); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /**
 | 
					
						
							|  |  |  |  * @brief  Erase the Flash sector. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * @param  sector  Sector number, the count starts at sector 0, 4KB per sector. | 
					
						
							| 
									
										
										
										
											2016-11-02 10:41:58 +11:00
										 |  |  |  * | 
					
						
							|  |  |  |  * @return esp_err_t | 
					
						
							|  |  |  |  */ | 
					
						
							| 
									
										
										
										
											2016-11-11 17:00:34 +11:00
										 |  |  | esp_err_t bootloader_flash_erase_sector(size_t sector); | 
					
						
							| 
									
										
										
										
											2016-11-02 10:41:58 +11:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-08-24 17:58:04 +05:30
										 |  |  | /**
 | 
					
						
							|  |  |  |  * @brief  Erase the Flash range. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * @param  start_addr start address of flash offset | 
					
						
							|  |  |  |  * @param  size       sector aligned size to be erased | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * @return esp_err_t | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | esp_err_t bootloader_flash_erase_range(uint32_t start_addr, uint32_t size); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-09-03 18:15:20 +08:00
										 |  |  | /* Cache MMU block size */ | 
					
						
							|  |  |  | #define MMU_BLOCK_SIZE    0x00010000
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /* Cache MMU address mask (MMU tables ignore bits which are zero) */ | 
					
						
							|  |  |  | #define MMU_FLASH_MASK    (~(MMU_BLOCK_SIZE - 1))
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /**
 | 
					
						
							|  |  |  |  * @brief Calculate the number of cache pages to map | 
					
						
							|  |  |  |  * @param size  size of data to map | 
					
						
							|  |  |  |  * @param vaddr  virtual address where data will be mapped | 
					
						
							|  |  |  |  * @return number of cache MMU pages required to do the mapping | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | static inline uint32_t bootloader_cache_pages_to_map(uint32_t size, uint32_t vaddr) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     return (size + (vaddr - (vaddr & MMU_FLASH_MASK)) + MMU_BLOCK_SIZE - 1) / MMU_BLOCK_SIZE; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
											  
											
												bootloader: fix the WRSR format for ISSI flash chips
1. The 2nd bootloader always call `rom_spiflash_unlock()`, but never help to clear the WEL bit when exit. This may cause system unstability.
   This commit helps to clear WEL when flash configuration is done.
   **RISK:** When the app starts, it didn't have to clear the WEL before it actually write/erase. But now the very first write/erase operation should be done after a WEL clear. Though the risk is little (all the following write/erase also need to clear the WEL), we still have to test this carefully, especially for those functions used by the OTA.
2. The `rom_spiflash_unlock()` function in the patch of ESP32 may (1) trigger the QPI, (2) clear the QE or (3) fail to unlock the ISSI chips.
   Status register bitmap of ISSI chip and GD chip:
| SR | ISSI | GD25LQ32C |
| -- | ---- | --------- |
| 0  | WIP  | WIP       |
| 1  | WEL  | WEL       |
| 2  | BP0  | BP0       |
| 3  | BP1  | BP1       |
| 4  | BP2  | BP2       |
| 5  | BP3  | BP3       |
| 6  | QE   | BP4       |
| 7  | SRWD | SRP0      |
| 8  |      | SRP1      |
| 9  |      | QE        |
| 10 |      | SUS2      |
| 11 |      | LB1       |
| 12 |      | LB2       |
| 13 |      | LB3       |
| 14 |      | CMP       |
| 15 |      | SUS1      |
   QE bit of other chips are at the bit 9 of the status register (i.e. bit 1 of SR2), which should be read by RDSR2 command.
   However, the RDSR2 (35H, Read Status 2) command for chip of other vendors happens to be the QIOEN (Enter QPI mode) command of ISSI chips. When the `rom_spiflash_unlock()` function trys to read SR2, it may trigger the QPI of ISSI chips.
   Moreover, when `rom_spiflash_unlock()` try to clear the BP4 bit in the status register, QE (bit 6) of ISSI chip may be cleared by accident. Or if the ISSI chip doesn't accept WRSR command with argument of two bytes (since it only have status register of one byte), it may fail to clear the other protect bits (BP0~BP3) as expected.
   This commit makes the `rom_spiflash_unlock()` check whether the vendor is issi. if so, `rom_spiflash_unlock()` only send RDSR to read the status register, send WRSR with only 1 byte argument, and also avoid clearing the QE bit (bit 6).
3. `rom_spiflash_unlock()` always send WRSR command to clear protection bits even when there is no protection bit active. And the execution of clearing status registers, which takes about 700us, will also happen even when there's no bits cleared.
   This commit skips the clearing of status register if there is no protection bits active.
Also move the execute_flash_command to be a bootloader API; move
implementation of spi_flash_wrap_set to the bootloader
											
										 
											2020-03-12 18:20:31 +08:00
										 |  |  | /**
 | 
					
						
							|  |  |  |  * @brief Execute a user command on the flash | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * @param command The command value to execute. | 
					
						
							|  |  |  |  * @param mosi_data MOSI data to send | 
					
						
							|  |  |  |  * @param mosi_len Length of MOSI data, in bits | 
					
						
							|  |  |  |  * @param miso_len Length of MISO data to receive, in bits | 
					
						
							|  |  |  |  * @return Received MISO data | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | uint32_t bootloader_execute_flash_command(uint8_t command, uint32_t mosi_data, uint8_t mosi_len, uint8_t miso_len); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-08-01 14:23:36 +08:00
										 |  |  | /**
 | 
					
						
							|  |  |  |  * @brief Read the SFDP of the flash | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * @param sfdp_addr Address of the parameter to read | 
					
						
							|  |  |  |  * @param miso_byte_num Bytes to read | 
					
						
							|  |  |  |  * @return The read SFDP, little endian, 4 bytes at most | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | uint32_t bootloader_flash_read_sfdp(uint32_t sfdp_addr, unsigned int miso_byte_num); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
											  
											
												bootloader: fix the WRSR format for ISSI flash chips
1. The 2nd bootloader always call `rom_spiflash_unlock()`, but never help to clear the WEL bit when exit. This may cause system unstability.
   This commit helps to clear WEL when flash configuration is done.
   **RISK:** When the app starts, it didn't have to clear the WEL before it actually write/erase. But now the very first write/erase operation should be done after a WEL clear. Though the risk is little (all the following write/erase also need to clear the WEL), we still have to test this carefully, especially for those functions used by the OTA.
2. The `rom_spiflash_unlock()` function in the patch of ESP32 may (1) trigger the QPI, (2) clear the QE or (3) fail to unlock the ISSI chips.
   Status register bitmap of ISSI chip and GD chip:
| SR | ISSI | GD25LQ32C |
| -- | ---- | --------- |
| 0  | WIP  | WIP       |
| 1  | WEL  | WEL       |
| 2  | BP0  | BP0       |
| 3  | BP1  | BP1       |
| 4  | BP2  | BP2       |
| 5  | BP3  | BP3       |
| 6  | QE   | BP4       |
| 7  | SRWD | SRP0      |
| 8  |      | SRP1      |
| 9  |      | QE        |
| 10 |      | SUS2      |
| 11 |      | LB1       |
| 12 |      | LB2       |
| 13 |      | LB3       |
| 14 |      | CMP       |
| 15 |      | SUS1      |
   QE bit of other chips are at the bit 9 of the status register (i.e. bit 1 of SR2), which should be read by RDSR2 command.
   However, the RDSR2 (35H, Read Status 2) command for chip of other vendors happens to be the QIOEN (Enter QPI mode) command of ISSI chips. When the `rom_spiflash_unlock()` function trys to read SR2, it may trigger the QPI of ISSI chips.
   Moreover, when `rom_spiflash_unlock()` try to clear the BP4 bit in the status register, QE (bit 6) of ISSI chip may be cleared by accident. Or if the ISSI chip doesn't accept WRSR command with argument of two bytes (since it only have status register of one byte), it may fail to clear the other protect bits (BP0~BP3) as expected.
   This commit makes the `rom_spiflash_unlock()` check whether the vendor is issi. if so, `rom_spiflash_unlock()` only send RDSR to read the status register, send WRSR with only 1 byte argument, and also avoid clearing the QE bit (bit 6).
3. `rom_spiflash_unlock()` always send WRSR command to clear protection bits even when there is no protection bit active. And the execution of clearing status registers, which takes about 700us, will also happen even when there's no bits cleared.
   This commit skips the clearing of status register if there is no protection bits active.
Also move the execute_flash_command to be a bootloader API; move
implementation of spi_flash_wrap_set to the bootloader
											
										 
											2020-03-12 18:20:31 +08:00
										 |  |  | /**
 | 
					
						
							|  |  |  |  * @brief Enable the flash write protect (WEL bit). | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | void bootloader_enable_wp(void); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-11-02 10:41:58 +11:00
										 |  |  | #endif
 |