From c611c41d0a4c425cba58c1b7ad5ea5bcfda99992 Mon Sep 17 00:00:00 2001 From: Xu Chun Guang Date: Mon, 21 Oct 2024 20:31:18 +0800 Subject: [PATCH] feat: Add fm25q16a patch --- components/esp8266/ld/esp8266.project.ld.in | 18 + components/esp8266/source/startup.c | 17 +- components/spi_flash/CMakeLists.txt | 12 +- components/spi_flash/Kconfig | 14 + components/spi_flash/component.mk | 9 +- components/spi_flash/include/spi_flash.h | 4 + components/spi_flash/src/patch/common.c | 218 +++++++ components/spi_flash/src/patch/fm25q16a.c | 549 ++++++++++++++++++ .../spi_flash/src/patch/spi_flash_patch.h | 58 ++ components/spi_flash/src/patch/th25q16hb.c | 296 +--------- 10 files changed, 924 insertions(+), 271 deletions(-) create mode 100644 components/spi_flash/src/patch/common.c create mode 100644 components/spi_flash/src/patch/fm25q16a.c create mode 100644 components/spi_flash/src/patch/spi_flash_patch.h diff --git a/components/esp8266/ld/esp8266.project.ld.in b/components/esp8266/ld/esp8266.project.ld.in index 54d7bb48..a1c4ba09 100644 --- a/components/esp8266/ld/esp8266.project.ld.in +++ b/components/esp8266/ld/esp8266.project.ld.in @@ -94,6 +94,15 @@ SECTIONS _iram_end = ABSOLUTE(.); } > iram0_0_seg + .patch.text : + { + . = ALIGN (4); + _iram_patch_text_start = ABSOLUTE(.); + *(.flash.patch.literal .flash.patch.text) + _iram_patch_text_end = ABSOLUTE(.); + _iram_text_end = ABSOLUTE(.); + } > iram0_0_seg + ASSERT(((_iram_end - ORIGIN(iram0_0_seg)) <= LENGTH(iram0_0_seg)), "IRAM0 segment data does not fit.") @@ -155,6 +164,15 @@ SECTIONS _bss_end = ABSOLUTE(.); } > dram0_0_seg + .patch.bss : + { + . = ALIGN (4); + _iram_patch_bss_start = ABSOLUTE(.); + *(.flash.patch.bss) + _iram_patch_bss_end = ABSOLUTE(.); + *(.flash.patch.rodata) + } > dram0_0_seg + ASSERT(((_bss_end - ORIGIN(dram0_0_seg)) <= LENGTH(dram0_0_seg)), "DRAM segment data does not fit.") diff --git a/components/esp8266/source/startup.c b/components/esp8266/source/startup.c index 42fc1882..ecd02057 100644 --- a/components/esp8266/source/startup.c +++ b/components/esp8266/source/startup.c @@ -93,10 +93,6 @@ static void user_init_entry(void *param) esp_set_cpu_freq(ESP_CPU_FREQ_160M); #endif -#ifdef CONFIG_ENABLE_TH25Q16HB_PATCH_0 - assert(th25q16hb_apply_patch_0() == 0); -#endif - app_main(); vTaskDelete(NULL); @@ -109,6 +105,7 @@ void call_start_cpu(size_t start_addr) extern int _bss_start, _bss_end; extern int _iram_bss_start, _iram_bss_end; + extern int _iram_patch_bss_start, _iram_patch_bss_end; #ifdef CONFIG_BOOTLOADER_FAST_BOOT REG_SET_BIT(DPORT_CTL_REG, DPORT_CTL_DOUBLE_CLK); @@ -155,6 +152,18 @@ void call_start_cpu(size_t start_addr) for (p = &_iram_bss_start; p < &_iram_bss_end; p++) *p = 0; + + for (p = &_iram_patch_bss_start; p < &_iram_patch_bss_end; p++) + *p = 0; + +#ifdef CONFIG_ENABLE_TH25Q16HB_PATCH_0 + assert(th25q16hb_apply_patch_0() == 0); +#endif + +#ifdef CONFIG_ENABLE_FM25Q16A_PATCH_0 + assert(fm25q16a_apply_patch_0() == 0); +#endif + __asm__ __volatile__( "rsil a2, 2\n" "movi a1, _chip_interrupt_tmp\n" diff --git a/components/spi_flash/CMakeLists.txt b/components/spi_flash/CMakeLists.txt index 255eff8e..7b6adf80 100644 --- a/components/spi_flash/CMakeLists.txt +++ b/components/spi_flash/CMakeLists.txt @@ -5,8 +5,16 @@ if(BOOTLOADER_BUILD) set(srcs "${srcs}" "port/port.c") set(priv_requires "bootloader_support") else() - if(CONFIG_ENABLE_TH25Q16HB_PATCH_0) - list(APPEND srcs "src/patch/th25q16hb.c") + + if (CONFIG_ENABLE_SPI_FLASH_PATCH) + list(APPEND srcs "src/patch/common.c") + if(CONFIG_ENABLE_TH25Q16HB_PATCH_0) + list(APPEND srcs "src/patch/th25q16hb.c") + endif() + + if(CONFIG_ENABLE_FM25Q16A_PATCH_0) + list(APPEND srcs "src/patch/fm25q16a.c") + endif() endif() set(priv_requires "esp8266" "freertos" "bootloader_support") diff --git a/components/spi_flash/Kconfig b/components/spi_flash/Kconfig index 3d97ba10..e67bd5f1 100644 --- a/components/spi_flash/Kconfig +++ b/components/spi_flash/Kconfig @@ -1,12 +1,26 @@ menu "SPI Flash" menu "Patch" + config ENABLE_SPI_FLASH_PATCH + bool "Enable TH25Q16HB Patch 0" + default n + config ENABLE_TH25Q16HB_PATCH_0 bool "Enable TH25Q16HB Patch 0" + depends on ENABLE_SPI_FLASH_PATCH default n help WARNING: If you don't use TH25Q16HB, you must not enable this option. Although you use TH25Q16HB, you should ask your flash manufacturer if your flash need use this patch. + + config ENABLE_FM25Q16A_PATCH_0 + bool "Enable FM25Q16A Patch 0" + depends on ENABLE_SPI_FLASH_PATCH + default n + help + WARNING: If you don't use FM25Q16A, you must not enable this option. + Although you use FM25Q16A, you should ask your flash manufacturer + if your flash need use this patch. endmenu endmenu diff --git a/components/spi_flash/component.mk b/components/spi_flash/component.mk index c4dfc940..6e574d95 100644 --- a/components/spi_flash/component.mk +++ b/components/spi_flash/component.mk @@ -16,7 +16,14 @@ ifdef IS_BOOTLOADER_BUILD COMPONENT_SRCDIRS += port COMPONENT_OBJS += port/port.o else -ifdef CONFIG_ENABLE_TH25Q16HB_PATCH_0 +ifdef CONFIG_ENABLE_SPI_FLASH_PATCH COMPONENT_SRCDIRS += src/patch +ifdef CONFIG_ENABLE_TH25Q16HB_PATCH_0 +COMPONENT_SRCDIRS += src/patch/th25q16hb.c +endif + +ifdef CONFIG_ENABLE_FM25Q16A_PATCH_0 +COMPONENT_SRCDIRS += src/patch/fm25q16a.c" +endif endif endif diff --git a/components/spi_flash/include/spi_flash.h b/components/spi_flash/include/spi_flash.h index 7dfeb6a2..13e10f09 100644 --- a/components/spi_flash/include/spi_flash.h +++ b/components/spi_flash/include/spi_flash.h @@ -213,6 +213,10 @@ int esp_patition_copy_ota1_to_ota0(const void *partition_info); int th25q16hb_apply_patch_0(void); #endif +#ifdef CONFIG_ENABLE_FM25Q16A_PATCH_0 +int fm25q16a_apply_patch_0(); +#endif + #ifdef __cplusplus } #endif diff --git a/components/spi_flash/src/patch/common.c b/components/spi_flash/src/patch/common.c new file mode 100644 index 00000000..84aa395d --- /dev/null +++ b/components/spi_flash/src/patch/common.c @@ -0,0 +1,218 @@ +// Copyright 2023 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 +#include +#include + +#include "esp_log.h" +#include "esp_attr.h" +#include "spi_flash.h" +#include "priv/esp_spi_flash_raw.h" +#include "FreeRTOS.h" + +#include "esp8266/eagle_soc.h" +#include "esp8266/pin_mux_register.h" +#include "esp8266/spi_register.h" +#include "esp8266/spi_struct.h" + +#include "driver/gpio.h" +#include "esp_attr.h" + +#include "spi_flash_patch.h" + +#define SPI_FLASH SPI0 +#define SPI_BLOCK_SIZE 32 +#define ADDR_SHIFT_BITS 8 + +extern void Cache_Read_Disable_2(void); +extern void Cache_Read_Enable_2(); +extern void vPortEnterCritical(void); +extern void vPortExitCritical(void); + +void FLASH_PATCH_TEXT_ATTR patch_delay(int ms) +{ + for (volatile int i = 0; i < ms; i++) { + for (volatile int j = 0; j < 7800; j++) { + } + } +} + +void FLASH_PATCH_TEXT_ATTR spi_enter(spi_state_t *state) +{ + vPortEnterCritical(); + Cache_Read_Disable_2(); + + Wait_SPI_Idle(&g_rom_flashchip); + + state->io_mux_reg = READ_PERI_REG(PERIPHS_IO_MUX_CONF_U); + state->spi_clk_reg = SPI_FLASH.clock.val; + state->spi_ctrl_reg = SPI_FLASH.ctrl.val; + state->spi_user_reg = SPI_FLASH.user.val; + + SPI_FLASH.user.usr_command = 1; + SPI_FLASH.user.flash_mode = 0; + SPI_FLASH.user.usr_miso_highpart = 0; + + CLEAR_PERI_REG_MASK(PERIPHS_IO_MUX_CONF_U, SPI0_CLK_EQU_SYS_CLK); + + SPI_FLASH.user.cs_setup = 1; + SPI_FLASH.user.cs_hold = 1; + SPI_FLASH.user.usr_mosi = 1; + + SPI_FLASH.user.usr_command = 1; + SPI_FLASH.user.flash_mode = 0; + + SPI_FLASH.ctrl.fread_qio = 0; + SPI_FLASH.ctrl.fread_dio = 0; + SPI_FLASH.ctrl.fread_quad = 0; + SPI_FLASH.ctrl.fread_dual = 0; + + SPI_FLASH.clock.val = 0; + SPI_FLASH.clock.clkcnt_l = 3; + SPI_FLASH.clock.clkcnt_h = 1; + SPI_FLASH.clock.clkcnt_n = 3; + + SPI_FLASH.ctrl.fastrd_mode = 1; + + while (SPI_FLASH.cmd.usr) { + ; + } +} + +void FLASH_PATCH_TEXT_ATTR spi_exit(spi_state_t *state) +{ + while (SPI_FLASH.cmd.usr) { + ; + } + + WRITE_PERI_REG(PERIPHS_IO_MUX_CONF_U, state->io_mux_reg); + + SPI_FLASH.ctrl.val = state->spi_ctrl_reg; + SPI_FLASH.clock.val = state->spi_clk_reg; + SPI_FLASH.user.val = state->spi_user_reg; + + Cache_Read_Enable_2(); + vPortExitCritical(); +} + +static void FLASH_PATCH_TEXT_ATTR spi_trans_block(bool write_mode, + uint32_t cmd, + uint32_t cmd_bits, + uint32_t addr, + uint32_t addr_bits, + uint8_t *data, + uint32_t data_bytes, + uint32_t dummy_bits) +{ + if ((uint32_t)data & 0x3) { + ROM_PRINTF(FLASH_PATCH_STR("ERROR: data=%p\n"), data); + return; + } + + if (cmd_bits) { + SPI_FLASH.user.usr_command = 1; + SPI_FLASH.user2.usr_command_value = cmd; + SPI_FLASH.user2.usr_command_bitlen = cmd_bits - 1; + } else { + SPI_FLASH.user.usr_command = 0; + SPI_FLASH.user2.usr_command_bitlen = 0; + } + + if (addr_bits) { + SPI_FLASH.user.usr_addr = 1; + SPI_FLASH.addr = addr << ADDR_SHIFT_BITS; + SPI_FLASH.user1.usr_addr_bitlen = addr_bits - 1; + } else { + SPI_FLASH.user.usr_addr = 0; + SPI_FLASH.user1.usr_addr_bitlen = 0; + } + + if (dummy_bits) { + SPI_FLASH.user.usr_dummy = 1; + SPI_FLASH.user1.usr_dummy_cyclelen = dummy_bits - 1; + } else { + SPI_FLASH.user.usr_dummy = 0; + SPI_FLASH.user1.usr_dummy_cyclelen = 0; + } + + if (data_bytes) { + if (write_mode) { + int words = (data_bytes + 3) / 4; + uint32_t *p = (uint32_t *)data; + + SPI_FLASH.user.usr_mosi = 1; + SPI_FLASH.user.usr_miso = 0; + SPI_FLASH.user1.usr_mosi_bitlen = data_bytes * 8 - 1; + SPI_FLASH.user1.usr_miso_bitlen = 0; + for (int i = 0; i < words; i++) { + SPI_FLASH.data_buf[i] = p[i]; + } + } else { + int words = (data_bytes + 3) / 4; + + SPI_FLASH.user.usr_mosi = 0; + SPI_FLASH.user.usr_miso = 1; + SPI_FLASH.user1.usr_miso_bitlen = data_bytes * 8 - 1; + SPI_FLASH.user1.usr_mosi_bitlen = 0; + + for (int i = 0; i < words; i++) { + SPI_FLASH.data_buf[i] = 0; + } + } + } else { + SPI_FLASH.user.usr_mosi = 0; + SPI_FLASH.user1.usr_mosi_bitlen = 0; + SPI_FLASH.user.usr_miso = 0; + SPI_FLASH.user1.usr_miso_bitlen = 0; + } + + SPI_FLASH.cmd.usr = 1; + while (SPI_FLASH.cmd.usr) { + ; + } + + if (!write_mode && data_bytes) { + int words = (data_bytes + 3) / 4; + uint32_t *p = (uint32_t *)data; + + for (int i = 0; i < words; i++) { + p[i] = SPI_FLASH.data_buf[i]; + } + } +} + +void FLASH_PATCH_TEXT_ATTR spi_trans(bool write_mode, + uint32_t cmd, + uint32_t cmd_bits, + uint32_t addr, + uint32_t addr_bits, + uint8_t *data, + uint32_t data_bytes, + uint32_t dummy_bits) + +{ + if (!data_bytes || data_bytes <= SPI_BLOCK_SIZE) { + return spi_trans_block(write_mode, cmd, cmd_bits, addr, + addr_bits, data, data_bytes, dummy_bits); + } + + for (int i = 0; i < data_bytes; i += SPI_BLOCK_SIZE) { + uint32_t n = MIN(SPI_BLOCK_SIZE, data_bytes - i); + + spi_trans_block(write_mode, cmd, cmd_bits, addr + i, + addr_bits, data + i, n, dummy_bits); + } +} diff --git a/components/spi_flash/src/patch/fm25q16a.c b/components/spi_flash/src/patch/fm25q16a.c new file mode 100644 index 00000000..dbd290af --- /dev/null +++ b/components/spi_flash/src/patch/fm25q16a.c @@ -0,0 +1,549 @@ +// Copyright 2023 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 +#include +#include + +#include "esp_log.h" +#include "esp_attr.h" +#include "spi_flash.h" +#include "priv/esp_spi_flash_raw.h" +#include "FreeRTOS.h" + +#include "esp8266/eagle_soc.h" +#include "esp8266/pin_mux_register.h" +#include "esp8266/spi_register.h" +#include "esp8266/spi_struct.h" +#include "driver/gpio.h" +#include "spi_flash_patch.h" + +#define DEBUG(fmt,...) fm_printf(fmt, ##__VA_ARGS__) +#define INFO(fmt,...) fm_printf(fmt, ##__VA_ARGS__) +#define ERROR(fmt,...) fm_printf(fmt, ##__VA_ARGS__) + +#ifndef IRAM_FUNC_ATTR +#define IRAM_FUNC_ATTR +#endif + +#define fm_printf ROM_PRINTF + +extern bool IRAM_FUNC_ATTR spi_user_cmd(spi_cmd_dir_t mode, spi_cmd_t *p_cmd); +extern uint32_t IRAM_FUNC_ATTR spi_flash_get_id(void); + +static void FLASH_PATCH_TEXT_ATTR fm_send_spi_cmd(uint8_t cmd, uint8_t cmd_len, uint32_t addr, uint8_t addr_len, void* mosi_data, int mosi_len, void* miso_data, int miso_len, uint8_t dummy_bits) +{ + bool write_mode = false; + uint32_t data_bytes = 0; + + if (mosi_len > 0) { + write_mode = true; + data_bytes = mosi_len / 8; + } else if (miso_len > 0) { + write_mode = false; + data_bytes = miso_len / 8; + } + uint32_t data[(data_bytes+3)/4]; + if (write_mode && mosi_data) { + memcpy(data, mosi_data, data_bytes); + } + + spi_trans(write_mode, cmd, cmd_len, addr, addr_len, (uint8_t *)data, data_bytes, dummy_bits); + + if (!write_mode && miso_data) { + memcpy(miso_data, data, data_bytes); + } +} + +static void FLASH_PATCH_TEXT_ATTR fm_cam_cmd_start() +{ + fm_send_spi_cmd(0x66, 1*8, 0, 0, NULL, 0, NULL, 0, 0); + fm_send_spi_cmd(0x3C, 1*8, 0, 0, NULL, 0, NULL, 0, 0); + fm_send_spi_cmd(0xC3, 1*8, 0, 0, NULL, 0, NULL, 0, 0); +} + +static void FLASH_PATCH_TEXT_ATTR fm_cam_cmd_end() +{ + fm_send_spi_cmd(0xff, 1*8, 0, 0, NULL, 0, NULL, 0, 0); +} + +static void FLASH_PATCH_TEXT_ATTR fm_cam_pre_cmd_generic(uint8_t (*send_list)[5], int lines) +{ + int i; + fm_cam_cmd_start(); + for(i = 0; i < lines; i++) { + fm_send_spi_cmd(0x0, 0, 0, 0, &send_list[i][0], 5*8, NULL, 0, 0); + } + + fm_cam_cmd_end(); +} + +static const uint8_t FLASH_PATCH_RODATA_ATTR read_after_erase_pre_send_list[7][5] = { + {0x32,0x00,0x03,0xc0,0x88}, + {0x32,0x00,0x00,0x80,0x01}, + {0x32,0x00,0x00,0x84,0x47}, + {0x32,0x00,0x00,0x88,0x47}, + {0x32,0x00,0x00,0x8c,0x04}, + {0x32,0x00,0x00,0x90,0x19}, + {0x32,0x00,0x00,0x94,0x03}, +}; + +static void FLASH_PATCH_TEXT_ATTR fm_cam_read_after_erase_pre(void) +{ + // cmd NO.7 in the doc + uint8_t send_list[7][5]; + + memcpy(send_list, read_after_erase_pre_send_list, 7 * 5); + + fm_cam_pre_cmd_generic(send_list, sizeof(send_list) / sizeof(send_list[0])); +} + +static const uint8_t FLASH_PATCH_RODATA_ATTR step_prog_pre_send_list[8][5] = { + {0x32,0x00,0x03,0xc0,0x88}, + {0x32,0x00,0x00,0x64,0xb7}, + {0x32,0x00,0x00,0x80,0x13}, + {0x32,0x00,0x00,0x84,0x4f}, + {0x32,0x00,0x00,0x88,0x78}, + {0x32,0x00,0x00,0x8c,0x10}, + {0x32,0x00,0x00,0x90,0x40}, + {0x32,0x00,0x00,0x94,0xff}, +}; + +static void FLASH_PATCH_TEXT_ATTR fm_cam_step_prog_pre(void) +{ + // cmd NO.6 in the doc + uint8_t send_list[8][5]; + + memcpy(send_list, step_prog_pre_send_list, 8 * 5); + + fm_cam_pre_cmd_generic(send_list, sizeof(send_list) / sizeof(send_list[0])); +} + +static const uint8_t FLASH_PATCH_RODATA_ATTR step_erase_pre_send_list[8][5] = { + {0x32,0x00,0x00,0x64,0x77}, + {0x32,0x00,0x03,0xc0,0x88}, + {0x32,0x00,0x00,0x80,0x01}, + {0x32,0x00,0x00,0x84,0x46}, + {0x32,0x00,0x00,0x88,0x7e}, + {0x32,0x00,0x00,0x8c,0x06}, + {0x32,0x00,0x00,0x90,0x31}, + {0x32,0x00,0x00,0x94,0x01}, +}; + +static void FLASH_PATCH_TEXT_ATTR fm_cam_step_erase_pre(void) +{ + // cmd NO.5 in the doc + uint8_t send_list[8][5]; + + memcpy(send_list, step_erase_pre_send_list, 8 * 5); + + fm_cam_pre_cmd_generic(send_list, sizeof(send_list) / sizeof(send_list[0])); +} + +static const uint8_t FLASH_PATCH_RODATA_ATTR preprog_pre_send_list[8][5] = { + {0x32,0x00,0x03,0xc0,0x88}, + {0x32,0x00,0x00,0x64,0xf1}, + {0x32,0x00,0x00,0x80,0x53}, + {0x32,0x00,0x00,0x84,0x5c}, + {0x32,0x00,0x00,0x88,0x7c}, + {0x32,0x00,0x00,0x8c,0x04}, + {0x32,0x00,0x00,0x90,0x1f}, + {0x32,0x00,0x00,0x94,0xff}, +}; + +static void FLASH_PATCH_TEXT_ATTR fm_cam_preprog_pre(void) +{ + // cmd NO.4 in the doc + uint8_t send_list[8][5]; + + memcpy(send_list, preprog_pre_send_list, 8 * 5); + + fm_cam_pre_cmd_generic(send_list, sizeof(send_list) / sizeof(send_list[0])); +} + +static const uint8_t FLASH_PATCH_RODATA_ATTR prog_pre_send_list[7][5] = { + {0x32,0x00,0x03,0xc0,0x88}, + {0x32,0x00,0x00,0x80,0x53}, + {0x32,0x00,0x00,0x84,0x7c}, + {0x32,0x00,0x00,0x88,0x7f}, + {0x32,0x00,0x00,0x8c,0x10}, + {0x32,0x00,0x00,0x90,0xff}, + {0x32,0x00,0x00,0x94,0xff}, +}; + +static void FLASH_PATCH_TEXT_ATTR fm_cam_prog_pre(void) +{ + // cmd NO.3 in the doc + uint8_t send_list[7][5]; + + memcpy(send_list, prog_pre_send_list, 7 * 5); + + fm_cam_pre_cmd_generic(send_list, sizeof(send_list) / sizeof(send_list[0])); +} + +static const uint8_t FLASH_PATCH_RODATA_ATTR uid_pre_send_list[7][5] = { + {0x32,0x00,0x03,0xc0,0x48}, + {0x32,0x00,0x00,0x80,0x00}, + {0x32,0x00,0x00,0x84,0x47}, + {0x32,0x00,0x00,0x88,0x47}, + {0x32,0x00,0x00,0x8c,0x04}, + {0x32,0x00,0x00,0x90,0x19}, + {0x32,0x00,0x00,0x94,0x03}, +}; + +static void FLASH_PATCH_TEXT_ATTR fm_cam_uid_pre(void) +{ + // cmd NO.2 in the doc + uint8_t send_list[7][5]; + + memcpy(send_list, uid_pre_send_list, 7 * 5); + + fm_cam_pre_cmd_generic(send_list, sizeof(send_list) / sizeof(send_list[0])); +} + +static const uint8_t FLASH_PATCH_RODATA_ATTR read_pre_send_list[7][5] = { + {0x32,0x00,0x03,0xc0,0x88}, + {0x32,0x00,0x00,0x80,0x00}, + {0x32,0x00,0x00,0x84,0x47}, + {0x32,0x00,0x00,0x88,0x47}, + {0x32,0x00,0x00,0x8c,0x04}, + {0x32,0x00,0x00,0x90,0x19}, + {0x32,0x00,0x00,0x94,0x03}, +}; + +static void FLASH_PATCH_TEXT_ATTR fm_cam_read_pre(void) +{ + // cmd NO.1 in the doc + uint8_t send_list[7][5]; + + memcpy(send_list, read_pre_send_list, 7 * 5); + + // fm_cam_pre_cmd_generic(send_list, sizeof(send_list) / sizeof(send_list[0])); + fm_cam_pre_cmd_generic(send_list, 7); +} + +static void FLASH_PATCH_TEXT_ATTR fm_soft_reset() +{ + fm_send_spi_cmd(0x66, 1*8, 0, 0, NULL, 0, NULL, 0, 0); + // ets_delay_us(100); + fm_send_spi_cmd(0x99, 1*8, 0, 0, NULL, 0, NULL, 0, 0); +} + +static bool FLASH_PATCH_TEXT_ATTR fm_flash_wait_idle() +{ + uint8_t status = 0x1; + while ((status&0x1) == 0x1) { + fm_send_spi_cmd(0x05, 1*8, 0, 0, NULL, 0, &status, 1*8, 0); + } + return true; +} + +static bool FLASH_PATCH_TEXT_ATTR fm_erase_sector(uint32_t addr) +{ + // write en + fm_send_spi_cmd(0x06, 1*8, 0, 0, NULL, 0, NULL, 0, 0); + fm_send_spi_cmd(0x20, 1*8, addr, 24, 0, 0, 0, 0, 0); + return fm_flash_wait_idle(); +} + +static bool FLASH_PATCH_TEXT_ATTR fm_cam_erase_and_fix(uint8_t (*buf)[32]) +{ + INFO(FLASH_PATCH_STR("Start erase and program cam buf\n")); + // cmd 4. + fm_cam_preprog_pre(); + if (!fm_erase_sector(0x0)) { + ERROR(FLASH_PATCH_STR("ERR in ERASE %d\n"), __LINE__); + return false; + } + int retry = 40; + while (retry > 0) { + WDT_FEED(); + // cmd 5. + fm_cam_step_erase_pre(); + if (!fm_erase_sector(0x0)) { + ERROR(FLASH_PATCH_STR("ERR in ERASE %d\n"), __LINE__); + return false; + } + // cmd 6. + fm_cam_step_prog_pre(); + if (!fm_erase_sector(0x0)) { + ERROR(FLASH_PATCH_STR("ERR in ERASE %d\n"), __LINE__); + return false; + } + + // + INFO(FLASH_PATCH_STR("Start programming 5 page\n")); + fm_cam_prog_pre(); + int line = 0; + for (line = 0; line < 5; line++) { + // write en + fm_send_spi_cmd(0x06, 1*8, 0, 0, NULL, 0, NULL, 0, 0); + // prog + fm_send_spi_cmd(0x02, 8, 0x20*line, 24, &buf[line][0], 32*8, 0, 0, 0); + fm_flash_wait_idle(); + WDT_FEED(); + // for (uint32_t loop = 0; loop < 32; loop++) { + // DEBUG(FLASH_PATCH_STR("%02x "), buf[line][loop]); + // } + // INFO(FLASH_PATCH_STR("\n")); + } + INFO(FLASH_PATCH_STR("Programming Done\n")); + + // cmd 7. + fm_cam_read_after_erase_pre(); + int found_error = false; + for (line = 0; line < 5; line++) { + uint32_t cam_rd[8]; + fm_send_spi_cmd(0x03, 8, 0x20 * line, 24, 0, 0, cam_rd, 32*8, 0); + int idx = 0; + for (idx = 0;idx < 8; idx++) { + uint32_t* p = buf[line]; + if (cam_rd[idx] != p[idx]) { + found_error = true; + ERROR(FLASH_PATCH_STR("erase check error, retry...%d, %d, 0x%08x\n"), retry, idx, cam_rd[idx]); + break; + } + } + retry -= 1; + } + + if (!found_error) { + for (line = 5; line < 20; line++) { + uint32_t cam_rd[8]; + fm_send_spi_cmd(0x03, 8, 0x20 * line, 24, 0, 0, cam_rd, 32*8, 0); + int idx = 0; + for (idx = 0;idx < 8; idx++) { + if (cam_rd[idx] != 0x000000ff) { + found_error = true; + ERROR(FLASH_PATCH_STR("erase check error, retry...%d, %d, 0x%08x\n"), retry, idx, cam_rd[idx]); + break; + } + } + retry -= 1; + } + } + + if (! found_error) { + INFO(FLASH_PATCH_STR("Erase Pass !!!\n")); + break; + } + } + if (retry <= 0) { + ERROR(FLASH_PATCH_STR("Erase fail !!!\n")); + return false; + } + + // cmd 3. + INFO(FLASH_PATCH_STR("Start programming\n")); + fm_cam_prog_pre(); + int line = 0; + for (line = 5; line < 20; line++) { + // write en + fm_send_spi_cmd(0x06, 1*8, 0, 0, NULL, 0, NULL, 0, 0); + // prog + fm_send_spi_cmd(0x02, 8, 0x20*line, 24, &buf[line][0], 32*8, 0, 0, 0); + fm_flash_wait_idle(); + WDT_FEED(); + for (uint32_t loop = 0; loop < 32; loop++) { + DEBUG(FLASH_PATCH_STR("%02x "), buf[line][loop]); + } + INFO(FLASH_PATCH_STR("\n")); + } + + // read buffer + INFO(FLASH_PATCH_STR("Prog done, read and check")); + fm_cam_read_pre(); + for (line = 0;line < 20; line++) { + WDT_FEED(); + uint8_t cam_check[32]; + fm_send_spi_cmd(0x03, 8, 0x20*line, 24, 0, 0, cam_check, 32*8, 0); + int j = 0; + for (j = 0; j < 32; j++) { + DEBUG(FLASH_PATCH_STR("%02x "), cam_check[j]); + if ((j + 1) % 16 == 0) { + DEBUG(FLASH_PATCH_STR("\n")); + } + } + if (memcmp(cam_check, buf[line], 32) != 0) { + ERROR(FLASH_PATCH_STR("CAM BUF[%d] check error\n"), line); + ets_delay_us(50000); + return false; + } + } + + INFO(FLASH_PATCH_STR("CAM prog done !!!\n")); + return true; +} + +static const uint8_t FLASH_PATCH_RODATA_ATTR cam_buf_default_rodata[20][32] = { + {0x55, 0x00, 0x00, 0x00, 0xaa, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, + {0x0b, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, + {0x00, 0x00, 0x00, 0x00, 0x47, 0x00, 0x00, 0x00, 0x47, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x19, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, + {0x53, 0x00, 0x00, 0x00, 0x5c, 0x00, 0x00, 0x00, 0x7c, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, + {0x53, 0x00, 0x00, 0x00, 0x4f, 0x00, 0x00, 0x00, 0x7a, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x19, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, + {0x23, 0x00, 0x00, 0x00, 0x4f, 0x00, 0x00, 0x00, 0x7c, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, + {0xe3, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x7c, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, + {0x23, 0x00, 0x00, 0x00, 0x53, 0x00, 0x00, 0x00, 0x78, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x19, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, + {0x01, 0x00, 0x00, 0x00, 0x47, 0x00, 0x00, 0x00, 0x63, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x3f, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, + {0x01, 0x00, 0x00, 0x00, 0x47, 0x00, 0x00, 0x00, 0x67, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x3f, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, + {0x01, 0x00, 0x00, 0x00, 0x47, 0x00, 0x00, 0x00, 0x6c, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x3f, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, + {0x01, 0x00, 0x00, 0x00, 0x47, 0x00, 0x00, 0x00, 0x6e, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x3f, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, + {0x01, 0x00, 0x00, 0x00, 0x47, 0x00, 0x00, 0x00, 0x79, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x3f, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, + {0x01, 0x00, 0x00, 0x00, 0x47, 0x00, 0x00, 0x00, 0x7a, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x3f, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, + {0x01, 0x00, 0x00, 0x00, 0x47, 0x00, 0x00, 0x00, 0x7c, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x3f, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, + {0x01, 0x00, 0x00, 0x00, 0x47, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x3f, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, +}; + +static bool FLASH_PATCH_TEXT_ATTR esp_fm_check_uid() +{ + uint8_t cam_buf_default[20][32]; + + memcpy(cam_buf_default, cam_buf_default_rodata, 20*32); + + // cmd 2. + fm_cam_uid_pre(); + uint8_t uid[6]; + fm_send_spi_cmd(0x03, 1*8, 0x25, 3*8, NULL, 0, uid, 6*8, 0); + if(uid[0] == ~uid[1] && uid[2] == ~uid[3] && uid[4] == ~uid[5]) { + INFO(FLASH_PATCH_STR("UID check correct, update buf\n")); + cam_buf_default[3][12] = uid[0] & 0xff; + cam_buf_default[5][0] = uid[2] & 0xff; + cam_buf_default[6][0] = uid[2] & 0xff; + cam_buf_default[7][0] = uid[4] & 0xff; + cam_buf_default[9][0] = uid[4] & 0xff; + } else { + INFO(FLASH_PATCH_STR("UID check error, use default buf\n")); + } + WDT_FEED(); + bool res = fm_cam_erase_and_fix(cam_buf_default); + WDT_FEED(); + fm_soft_reset(); + return res; +} + +static bool FLASH_PATCH_TEXT_ATTR fm_cam_check_buf_valid(uint8_t (*buf)[32]) +{ + bool res = false; + // cmd 1. + fm_cam_read_pre(); + + int i = 0, j = 0; + for (i = 0; i < 20; i++) { + // read buf + fm_send_spi_cmd(0x03, 8, 0x20 * i, 24, 0, 0, &buf[i][0], 32*8, 0); + for (j = 0; j < 32; j++) { + DEBUG(FLASH_PATCH_STR("%02x "), buf[i][j]); + if ((j + 1) % 16 == 0) { + DEBUG(FLASH_PATCH_STR("\n")); + INFO(FLASH_PATCH_STR("\r")); + } + } + } + + if (buf[0][0] == 0x55 && buf[0][4] == 0xaa \ + && buf[4][0] == 0x00 \ + && buf[10][0] == 0x1 && buf[10][20] == 0xff\ + && buf[11][0] == 0x1 && buf[11][20] == 0xff\ + && buf[12][0] == 0x1 && buf[12][20] == 0xff\ + && buf[13][0] == 0x1 && buf[13][20] == 0xff\ + && buf[14][0] == 0x1 && buf[14][20] == 0xff\ + && buf[15][0] == 0x1 && buf[15][20] == 0xff\ + && buf[16][0] == 0x1 && buf[16][20] == 0xff\ + && buf[17][0] == 0x1 && buf[17][20] == 0xff + ) { + INFO(FLASH_PATCH_STR("CAM buffer check valid !!!\n")); + res = true; + } else { + INFO(FLASH_PATCH_STR("CAM buffer check IN-Valid !!!\n")); + res = false; + } + // while(1); + return res; +} + +static bool FLASH_PATCH_TEXT_ATTR fm_fix_cam() +{ + uint8_t check_buf[20][32]; + + if (fm_cam_check_buf_valid(check_buf) == false) { + ERROR(FLASH_PATCH_STR("Cam buf not valid\n")); + return esp_fm_check_uid(); + } else { + INFO(FLASH_PATCH_STR("Cam buf valid\n")); + + if ((check_buf[3][0] & 0x08) == 0x08) { + INFO(FLASH_PATCH_STR("Bit3 == 1, already fixed....\n")); + fm_soft_reset(); + } else { + check_buf[3][0] |= 0x08; + bool res = fm_cam_erase_and_fix(check_buf); + fm_soft_reset(); + return res; + } + } + + return true; +} + +static uint32_t FLASH_PATCH_TEXT_ATTR fm_flash_id(void) +{ + uint32_t data[6]; + uint8_t* id = (uint8_t*)data; +#if 1 + fm_send_spi_cmd(0x9f, 8, 0, 0, 0, 0, id, 24*8, 0); + return (id[0]<<16 | id[1]<<8 | id[2]); +#else + uint32_t flash_id = spi_flash_get_id(); + memcpy(id, &flash_id, 3); + return (id[0]<<16 | id[1]<<8 | id[2]); +#endif +} + +int FLASH_PATCH_TEXT_ATTR fm25q16a_apply_patch_0() +{ + bool res = false; + + spi_state_t state; + spi_enter(&state); + uint32_t flash_id = fm_flash_id(); + DEBUG(FLASH_PATCH_STR("Flash id: 0x%x\n"), flash_id); + + WDT_FEED(); + if (flash_id == 0xa14015) { + INFO(DRAM_STR("Found FM25Q16A, check CAM buf\n")); + res = fm_fix_cam(); + } else if ((flash_id&0xffffff) == 0x0 || (flash_id&0xffffff) == 0xffffff) { + INFO(FLASH_PATCH_STR("Found ID error, recover default CAM buf\n")); + res = esp_fm_check_uid(); + } else { + INFO(FLASH_PATCH_STR("Normal flash, continue...\n")); + res = true; + } + WDT_FEED(); + + spi_exit(&state); + + if (res != true) { + fm_printf(FLASH_PATCH_STR("fix fail\n")); + return 1; + } + + fm_printf(FLASH_PATCH_STR("fix done\n")); + return 0; +} diff --git a/components/spi_flash/src/patch/spi_flash_patch.h b/components/spi_flash/src/patch/spi_flash_patch.h new file mode 100644 index 00000000..3052418d --- /dev/null +++ b/components/spi_flash/src/patch/spi_flash_patch.h @@ -0,0 +1,58 @@ +// Copyright 2024-2026 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 _SPI_FLASH_PATCH_H +#define _SPI_FLASH_PATCH_H + +#include +#include + +#include "esp_err.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define FLASH_PATCH_TEXT_ATTR __attribute__((section(".flash.patch.text"))) +#define FLASH_PATCH_RODATA_ATTR __attribute__((section(".flash.patch.rodata"))) +#define FLASH_PATCH_BSS_ATTR __attribute__((section(".flash.patch.bss"))) + +#define FLASH_PATCH_STR(str) (__extension__({static const FLASH_PATCH_RODATA_ATTR char __c[] = (str); (const char *)&__c;})) + +#if 1 +typedef int (*__ets_printf_t)(const char *fmt, ...); +#define ROM_PRINTF(_fmt, ...) ((__ets_printf_t)(0x400024cc))(_fmt, ##__VA_ARGS__) +#else +#define ROM_PRINTF(_fmt, ...) +#endif + +typedef struct spi_state { + uint32_t io_mux_reg; + uint32_t spi_clk_reg; + uint32_t spi_ctrl_reg; + uint32_t spi_user_reg; +} spi_state_t; + +void spi_enter(spi_state_t *state); +void spi_exit(spi_state_t *state); + +void spi_trans(bool write_mode, uint32_t cmd, uint32_t cmd_bits, uint32_t addr, uint32_t addr_bits, uint8_t *data, + uint32_t data_bytes, uint32_t dummy_bits); +void patch_delay(int ms); + +#ifdef __cplusplus +} +#endif + +#endif /* _SPI_FLASH_H */ diff --git a/components/spi_flash/src/patch/th25q16hb.c b/components/spi_flash/src/patch/th25q16hb.c index 425096f9..4548e2c6 100644 --- a/components/spi_flash/src/patch/th25q16hb.c +++ b/components/spi_flash/src/patch/th25q16hb.c @@ -28,279 +28,55 @@ #include "esp8266/spi_register.h" #include "esp8266/spi_struct.h" -#define SPI_FLASH SPI0 -#define SPI_BLOCK_SIZE 32 -#define ADDR_SHIFT_BITS 8 +#include "spi_flash_patch.h" -#if 0 -typedef int (*__ets_printf_t)(const char *fmt, ...); -#define ROM_PRINTF(_fmt, ...) ((__ets_printf_t)(0x400024cc))(_fmt, ##__VA_ARGS__) -#else -#define ROM_PRINTF(_fmt, ...) -#endif +#define SPI_BLOCK_SIZE 32 + +void spi_trans(bool write_mode, uint32_t cmd, uint32_t cmd_bits, uint32_t addr, uint32_t addr_bits, uint8_t *data, + uint32_t data_bytes, uint32_t dummy_bits); +void patch_delay(int ms); #define TOCHAR(_v) #_v -#define PRINT_STEP(_s) ROM_PRINTF("Step %d\n", (_s)); -#define JUMP_TO_STEP(_s) { ROM_PRINTF("Jump to " TOCHAR(_s) "\n"); goto _s; } -#define GOTO_FAILED(_s) { ROM_PRINTF("ERROR: " TOCHAR(_s) " failed\n"); ret = -EIO; JUMP_TO_STEP(step17); } +#define PRINT_STEP(_s) ROM_PRINTF(FLASH_PATCH_STR("Step %d\n"), (_s)); +#define JUMP_TO_STEP(_s) { ROM_PRINTF(FLASH_PATCH_STR("%d line Jump to " TOCHAR(_s) "\n"), __LINE__); goto _s; } +#define GOTO_FAILED(_s) { ROM_PRINTF(FLASH_PATCH_STR("ERROR: " TOCHAR(_s) " failed\n")); ret = -EIO; JUMP_TO_STEP(step17); } #define write_u8_dummy(_c, _a, _d8,_d) {uint32_t __data = _d8; spi_trans(1, (_c), 8, (_a), 24, (uint8_t *)&__data, 1, (_d));} #define write_u8(_c, _a, _d8) write_u8_dummy((_c), (_a), (_d8), 0) -extern void Cache_Read_Disable_2(void); -extern void Cache_Read_Enable_2(); -extern void vPortEnterCritical(void); -extern void vPortExitCritical(void); extern uint32_t spi_flash_get_id(void); -static void delay(int ms) -{ - for (volatile int i = 0; i < ms; i++) { - for (volatile int j = 0; j < 7800; j++) { - } - } -} +static uint8_t FLASH_PATCH_BSS_ATTR buffer1024[1024]; -#if 0 -static void dump_hex(const uint8_t *ptr, int n) -{ - const uint8_t *s1 = ptr; - const int line_bytes = 16; - - ROM_PRINTF("\nHex:\n"); - for (int i = 0; i < n ; i += line_bytes) - { - int m = MIN(n - i, line_bytes); - - ROM_PRINTF("\t"); - for (int j = 0; j < m; j++) - { - ROM_PRINTF("%02x ", s1[i + j]); - } - - ROM_PRINTF("\n"); - } - - ROM_PRINTF("\n"); -} - -static void dump_hex_compare(const uint8_t *s1, const uint8_t *s2, int n) -{ - const int line_bytes = 16; - - ROM_PRINTF("\nHex:\n"); - for (int i = 0; i < n ; i += line_bytes) - { - int m = MIN(n - i, line_bytes); - - ROM_PRINTF("\t"); - for (int j = 0; j < m; j++) - { - ROM_PRINTF("%02x:%02x ", s1[i + j], s2[i + j]); - } - - ROM_PRINTF("\n"); - } - - ROM_PRINTF("\n"); -} -#endif - -typedef struct spi_state { - uint32_t io_mux_reg; - uint32_t spi_clk_reg; - uint32_t spi_ctrl_reg; - uint32_t spi_user_reg; -} spi_state_t; - -static void spi_enter(spi_state_t *state) -{ - vPortEnterCritical(); - Cache_Read_Disable_2(); - - Wait_SPI_Idle(&g_rom_flashchip); - - state->io_mux_reg = READ_PERI_REG(PERIPHS_IO_MUX_CONF_U); - state->spi_clk_reg = SPI_FLASH.clock.val; - state->spi_ctrl_reg = SPI_FLASH.ctrl.val; - state->spi_user_reg = SPI_FLASH.user.val; - - SPI_FLASH.user.usr_command = 1; - SPI_FLASH.user.flash_mode = 0; - SPI_FLASH.user.usr_miso_highpart = 0; - - CLEAR_PERI_REG_MASK(PERIPHS_IO_MUX_CONF_U, SPI0_CLK_EQU_SYS_CLK); - - SPI_FLASH.user.cs_setup = 1; - SPI_FLASH.user.cs_hold = 1; - SPI_FLASH.user.usr_mosi = 1; - - SPI_FLASH.user.usr_command = 1; - SPI_FLASH.user.flash_mode = 0; - - SPI_FLASH.ctrl.fread_qio = 0; - SPI_FLASH.ctrl.fread_dio = 0; - SPI_FLASH.ctrl.fread_quad = 0; - SPI_FLASH.ctrl.fread_dual = 0; - - SPI_FLASH.clock.val = 0; - SPI_FLASH.clock.clkcnt_l = 3; - SPI_FLASH.clock.clkcnt_h = 1; - SPI_FLASH.clock.clkcnt_n = 3; - - SPI_FLASH.ctrl.fastrd_mode = 1; - - while (SPI_FLASH.cmd.usr) { - ; - } -} - -static void spi_exit(spi_state_t *state) -{ - while (SPI_FLASH.cmd.usr) { - ; - } - - WRITE_PERI_REG(PERIPHS_IO_MUX_CONF_U, state->io_mux_reg); - - SPI_FLASH.ctrl.val = state->spi_ctrl_reg; - SPI_FLASH.clock.val = state->spi_clk_reg; - SPI_FLASH.user.val = state->spi_user_reg; - - Cache_Read_Enable_2(); - vPortExitCritical(); -} - -static void spi_trans_block(bool write_mode, - uint32_t cmd, - uint32_t cmd_bits, - uint32_t addr, - uint32_t addr_bits, - uint8_t *data, - uint32_t data_bytes, - uint32_t dummy_bits) -{ - if ((uint32_t)data & 0x3) { - ROM_PRINTF("ERROR: data=%p\n", data); - return; - } - - if (cmd_bits) { - SPI_FLASH.user.usr_command = 1; - SPI_FLASH.user2.usr_command_value = cmd; - SPI_FLASH.user2.usr_command_bitlen = cmd_bits - 1; - } else { - SPI_FLASH.user.usr_command = 0; - } - - if (addr_bits) { - SPI_FLASH.user.usr_addr = 1; - SPI_FLASH.addr = addr << ADDR_SHIFT_BITS; - SPI_FLASH.user1.usr_addr_bitlen = addr_bits - 1; - } else { - SPI_FLASH.user.usr_addr = 0; - } - - if (dummy_bits) { - SPI_FLASH.user.usr_dummy = 1; - SPI_FLASH.user1.usr_dummy_cyclelen = dummy_bits - 1; - } else { - SPI_FLASH.user.usr_dummy = 0; - } - - if (write_mode && data_bytes) { - int words = (data_bytes + 3) / 4; - uint32_t *p = (uint32_t *)data; - - SPI_FLASH.user.usr_mosi = 1; - SPI_FLASH.user.usr_miso = 0; - SPI_FLASH.user1.usr_mosi_bitlen = data_bytes * 8 - 1; - - for (int i = 0; i < words; i++) { - SPI_FLASH.data_buf[i] = p[i]; - } - } else if (!write_mode && data_bytes) { - int words = (data_bytes + 3) / 4; - - SPI_FLASH.user.usr_mosi = 0; - SPI_FLASH.user.usr_miso = 1; - SPI_FLASH.user1.usr_miso_bitlen = data_bytes * 8 - 1; - - for (int i = 0; i < words; i++) { - SPI_FLASH.data_buf[i] = 0; - } - } else { - SPI_FLASH.user.usr_mosi = 0; - SPI_FLASH.user.usr_miso = 0; - } - - SPI_FLASH.cmd.usr = 1; - while (SPI_FLASH.cmd.usr) { - ; - } - - if (!write_mode && data_bytes) { - int words = (data_bytes + 3) / 4; - uint32_t *p = (uint32_t *)data; - - for (int i = 0; i < words; i++) { - p[i] = SPI_FLASH.data_buf[i]; - } - } -} - -static void spi_trans(bool write_mode, - uint32_t cmd, - uint32_t cmd_bits, - uint32_t addr, - uint32_t addr_bits, - uint8_t *data, - uint32_t data_bytes, - uint32_t dummy_bits) - -{ - if (!data_bytes || data_bytes <= SPI_BLOCK_SIZE) { - return spi_trans_block(write_mode, cmd, cmd_bits, addr, - addr_bits, data, data_bytes, dummy_bits); - } - - for (int i = 0; i < data_bytes; i += SPI_BLOCK_SIZE) { - uint32_t n = MIN(SPI_BLOCK_SIZE, data_bytes - i); - - spi_trans_block(write_mode, cmd, cmd_bits, addr + i, - addr_bits, data + i, n, dummy_bits); - } -} - -static void write_cmd(uint32_t cmd) +static void FLASH_PATCH_TEXT_ATTR write_cmd(uint32_t cmd) { spi_trans(1, cmd, 8, 0, 0, NULL, 0, 0); } -static void write_buffer(uint32_t addr, uint8_t *buffer, int size) +static void FLASH_PATCH_TEXT_ATTR write_buffer(uint32_t addr, uint8_t *buffer, int size) { for (int i = 0; i < size; i += SPI_BLOCK_SIZE) { int n = MIN(size - i, SPI_BLOCK_SIZE); write_cmd(0x6); spi_trans(1, 0x42, 8, addr + i, 24, buffer + i, n, 0); - delay(3); + patch_delay(3); } } -static void read_buffer(uint32_t addr, uint8_t *buffer, int n) +static void FLASH_PATCH_TEXT_ATTR read_buffer(uint32_t addr, uint8_t *buffer, int n) { spi_trans(0, 0x48, 8, addr, 24, buffer, n, 8); } -static void erase_sector(uint32_t addr) +static void FLASH_PATCH_TEXT_ATTR erase_sector(uint32_t addr) { write_cmd(0x6); spi_trans(1, 0x44, 8, addr, 24, NULL, 0, 0); - delay(8); + patch_delay(8); } -int th25q16hb_apply_patch_0(void) +int FLASH_PATCH_TEXT_ATTR th25q16hb_apply_patch_0(void) { int ret = 0; uint32_t flash_id; @@ -309,19 +85,13 @@ int th25q16hb_apply_patch_0(void) uint8_t *buffer256_0; uint8_t *buffer256_1; uint8_t *buffer256_2; - uint8_t *buffer1024; flash_id = spi_flash_get_id(); if (flash_id != 0x1560eb) { - ROM_PRINTF("WARN: id=0x%x, is not TH25Q16HB\n", flash_id); + ROM_PRINTF(FLASH_PATCH_STR("WARN: id=0x%x, is not TH25Q16HB\n"), flash_id); return 0; } - buffer1024 = heap_caps_malloc(1024, MALLOC_CAP_8BIT); - if (!buffer1024) { - return -ENOMEM; - } - buffer256_0 = buffer1024; buffer256_1 = buffer1024 + 256; buffer256_2 = buffer1024 + 512; @@ -351,7 +121,7 @@ int th25q16hb_apply_patch_0(void) if (buffer256_0[0] == 0xff && buffer256_0[1] == 0xff && buffer256_0[2] == 0xff) { - ROM_PRINTF("INFO: check done 0\n"); + ROM_PRINTF(FLASH_PATCH_STR("INFO: check done 0\n")); } else if (buffer256_0[0] == 0x55 && buffer256_0[1] == 0xff && buffer256_0[2] == 0xff) { @@ -365,20 +135,20 @@ int th25q16hb_apply_patch_0(void) buffer256_0[2] == 0x55) { JUMP_TO_STEP(step17); } else { - ROM_PRINTF("ERROR: 0xbed=0x%x 0xbee=0x%x 0xbef=0x%x\n", + ROM_PRINTF(FLASH_PATCH_STR("ERROR: 0xbed=0x%x 0xbee=0x%x 0xbef=0x%x\n"), buffer256_0[0], buffer256_0[1], buffer256_0[2]); GOTO_FAILED(5-1); } - +JUMP_TO_STEP(step17); // Step 5-2 read_buffer(0x50d, buffer256_0, 1); buffer256_0[0] &= 0x7f; if (buffer256_0[0] == 0x7c) { JUMP_TO_STEP(step17); } else if (buffer256_0[0] == 0x3c) { - ROM_PRINTF("INFO: check done 1\n"); + ROM_PRINTF(FLASH_PATCH_STR("INFO: check done 1\n")); } else { - ROM_PRINTF("ERROR: 0x50d=0x%x\n", buffer256_0[0]); + ROM_PRINTF(FLASH_PATCH_STR("ERROR: 0x50d=0x%x\n"), buffer256_0[0]); GOTO_FAILED(5-2); } @@ -392,7 +162,7 @@ int th25q16hb_apply_patch_0(void) for (int i = 0; i < 1024; i++) { if (buffer1024[i] != 0xff) { check_done = false; - ROM_PRINTF("ERROR: buffer1024[%d]=0x%x\n", i, buffer1024[i]); + ROM_PRINTF(FLASH_PATCH_STR("ERROR: buffer1024[%d]=0x%x\n"), i, buffer1024[i]); break; } } @@ -465,7 +235,7 @@ int th25q16hb_apply_patch_0(void) read_buffer(0x0, buffer256_0, 1); read_buffer(0x23, buffer256_1, 1); if (buffer256_0[0] != 0x13 || buffer256_1[0] != 0x14) { - ROM_PRINTF("ERROR: 0x0=0x%x 0x23=0x%x\n", buffer256_0[0], buffer256_1[0]); + ROM_PRINTF(FLASH_PATCH_STR("ERROR: 0x0=0x%x 0x23=0x%x\n"), buffer256_0[0], buffer256_1[0]); GOTO_FAILED(8); } @@ -473,7 +243,7 @@ int th25q16hb_apply_patch_0(void) PRINT_STEP(9); read_buffer(0x140, buffer256_0, 2); if (buffer256_0[0] != 0 || buffer256_0[1] != 0xff) { - ROM_PRINTF("ERROR: 0x140=0x%x 0x141=0x%x\n", buffer256_0[0], buffer256_0[1]); + ROM_PRINTF(FLASH_PATCH_STR("ERROR: 0x140=0x%x 0x141=0x%x\n"), buffer256_0[0], buffer256_0[1]); GOTO_FAILED(9-1); } @@ -507,7 +277,7 @@ step10: for (int i = 0; i < 1024; i++) { if (buffer1024[i] != 0xff) { check_done = false; - ROM_PRINTF("ERROR: buffer1024[%d]=0x%x\n", i, buffer1024[i]); + ROM_PRINTF(FLASH_PATCH_STR("ERROR: buffer1024[%d]=0x%x\n"), i, buffer1024[i]); break; } } @@ -585,7 +355,7 @@ step10: read_buffer(0x400, buffer256_0, 1); read_buffer(0x423, buffer256_1, 1); if (buffer256_0[0] != 0x13 || buffer256_1[0] != 0x14) { - ROM_PRINTF("ERROR: 0x400=0x%x 0x423=0x%x\n", buffer256_0[0], buffer256_1[0]); + ROM_PRINTF(FLASH_PATCH_STR("ERROR: 0x400=0x%x 0x423=0x%x\n"), buffer256_0[0], buffer256_1[0]); break; } } @@ -597,7 +367,7 @@ step10: for (count = 0; count < 3; count++) { read_buffer(0x540, buffer256_0, 2); if (buffer256_0[0] != 0 || buffer256_0[1] != 0xff) { - ROM_PRINTF("ERROR: 0x540=0x%x 0x541=0x%x\n", buffer256_0[0], buffer256_0[1]); + ROM_PRINTF(FLASH_PATCH_STR("ERROR: 0x540=0x%x 0x541=0x%x\n"), buffer256_0[0], buffer256_0[1]); break; } } @@ -610,7 +380,7 @@ step10: read_buffer(0x50d, buffer256_0, 1); buffer256_0[0] &= 0x7f; if (buffer256_0[0] != 0x7c) { - ROM_PRINTF("ERROR: 0x50d=0x%x\n", buffer256_0[0]); + ROM_PRINTF(FLASH_PATCH_STR("ERROR: 0x50d=0x%x\n"), buffer256_0[0]); break; } } @@ -652,7 +422,7 @@ step14: for (int i = 0; i < 1024; i++) { if (buffer1024[i] != 0xff) { check_done = false; - ROM_PRINTF("ERROR: buffer1024[%d]=0x%x\n", i, buffer1024[i]); + ROM_PRINTF(FLASH_PATCH_STR("ERROR: buffer1024[%d]=0x%x\n"), i, buffer1024[i]); break; } } @@ -699,10 +469,8 @@ step17: spi_exit(&state); - heap_caps_free(buffer1024); - if (!ret) { - ROM_PRINTF("INFO: Patch for TH25Q16HB is done\n"); + ROM_PRINTF(FLASH_PATCH_STR("INFO: Patch for TH25Q16HB is done\n")); } return ret;