feat: Add fm25q16a patch

This commit is contained in:
Xu Chun Guang
2024-10-21 20:31:18 +08:00
parent e19ff9af0d
commit c611c41d0a
10 changed files with 924 additions and 271 deletions

View File

@@ -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.")

View File

@@ -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"

View File

@@ -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")

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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 <stdlib.h>
#include <string.h>
#include <sys/param.h>
#include <sys/errno.h>
#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);
}
}

View File

@@ -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 <stdlib.h>
#include <string.h>
#include <sys/param.h>
#include <sys/errno.h>
#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;
}

View File

@@ -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 <stdint.h>
#include <stddef.h>
#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 */

View File

@@ -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;