MXC-A36_2024.04.18/fr3092_mcu/components/drivers/peripheral/Src/driver_flash.c

980 lines
27 KiB
C

/*
******************************************************************************
* @file driver_flash.c
* @author FreqChip Firmware Team
* @version V1.0.0
* @date 2021
* @brief Internal XIP Flash module driver.
* This file provides firmware functions to manage the internal
* stacked xip flash
******************************************************************************
* @attention
*
* Copyright (c) 2022 FreqChip.
* All rights reserved.
******************************************************************************
*/
#include "fr30xx.h"
#define FLASH_ID_PUYA_P25Q32 0x00166085
#define FLASH_ID_XMC_XM25LU32 0x00165020
#define FLASH_ID_GIANTEC_GT25Q16A 0x001560c4
#define FLASH_ID_PUYA_P25Q16 0x00156085
#define FLASH_ID_PUYA_P25Q80 0x00146085
#define FLASH_ID_GD_GD25WQ80E 0x001465c8
struct qspi_stig_reg_t sector_erase_cmd = {
.enable_bank = 0,
.dummy_cycles = 0,
.write_bytes = 0,
.enable_write = 0,
.addr_bytes = QSPI_STIG_ADDR_BYTES_3,
.enable_mode = 0,
.enable_cmd_addr = 1,
.read_bytes = 0,
.enable_read = 0,
.opcode = FLASH_SECTORE_ERASE_OPCODE,
};
struct qspi_stig_reg_t read_id_cmd = {
.enable_bank = 0,
.dummy_cycles = 0,
.write_bytes = 0,
.enable_write = 0,
.addr_bytes = 0,
.enable_mode = 0,
.enable_cmd_addr = 0,
.read_bytes = 3,
.enable_read = 1,
.opcode = FLASH_READ_IDENTIFICATION,
};
struct qspi_stig_reg_t read_status_cmd = {
.enable_bank = 0,
.dummy_cycles = 0,
.write_bytes = 0,
.enable_write = 0,
.addr_bytes = 0,
.enable_mode = 0,
.enable_cmd_addr = 0,
.read_bytes = 1,
.enable_read = 1,
.opcode = 0x05,
};
struct qspi_stig_reg_t read_status_h_cmd = {
.enable_bank = 0,
.dummy_cycles = 0,
.write_bytes = 0,
.enable_write = 0,
.addr_bytes = 0,
.enable_mode = 0,
.enable_cmd_addr = 0,
.read_bytes = 1,
.enable_read = 1,
.opcode = 0x35,
};
struct qspi_stig_reg_t write_enable_cmd = {
.enable_bank = 0,
.dummy_cycles = 0,
.write_bytes = 0,
.enable_write = 0,
.addr_bytes = 0,
.enable_mode = 0,
.enable_cmd_addr = 0,
.read_bytes = 0,
.enable_read = 0,
.opcode = 0x06,
};
struct qspi_stig_reg_t write_volatile_enable_cmd = {
.enable_bank = 0,
.dummy_cycles = 0,
.write_bytes = 0,
.enable_write = 0,
.addr_bytes = 0,
.enable_mode = 0,
.enable_cmd_addr = 0,
.read_bytes = 0,
.enable_read = 0,
.opcode = 0x50,
};
struct qspi_stig_reg_t write_status_cmd = {
.enable_bank = 0,
.dummy_cycles = 0,
.write_bytes = 1,
.enable_write = 1,
.addr_bytes = 0,
.enable_mode = 0,
.enable_cmd_addr = 0,
.read_bytes = 0,
.enable_read = 0,
.opcode = 0x01,
};
struct qspi_stig_reg_t write_status_2_cmd = {
.enable_bank = 0,
.dummy_cycles = 0,
.write_bytes = 1,
.enable_write = 1,
.addr_bytes = 0,
.enable_mode = 0,
.enable_cmd_addr = 0,
.read_bytes = 0,
.enable_read = 0,
.opcode = 0x31,
};
struct qspi_stig_reg_t write_status_3_cmd = {
.enable_bank = 0,
.dummy_cycles = 0,
.write_bytes = 1,
.enable_write = 1,
.addr_bytes = 0,
.enable_mode = 0,
.enable_cmd_addr = 0,
.read_bytes = 0,
.enable_read = 0,
.opcode = 0x11,
};
struct qspi_stig_reg_t write_status_h_cmd = {
.enable_bank = 0,
.dummy_cycles = 0,
.write_bytes = 1,
.enable_write = 1,
.addr_bytes = 0,
.enable_mode = 0,
.enable_cmd_addr = 0,
.read_bytes = 0,
.enable_read = 0,
.opcode = 0x31,
};
struct qspi_stig_reg_t block_erase_cmd = {
.enable_bank = 0,
.dummy_cycles = 0,
.write_bytes = 0,
.enable_write = 0,
.addr_bytes = QSPI_STIG_ADDR_BYTES_3,
.enable_mode = 0,
.enable_cmd_addr = 1,
.read_bytes = 0,
.enable_read = 0,
.opcode = 0xD8,
};
struct qspi_stig_reg_t chip_erase_cmd = {
.enable_bank = 0,
.dummy_cycles = 0,
.write_bytes = 0,
.enable_write = 0,
.addr_bytes = 0,
.enable_mode = 0,
.enable_cmd_addr = 0,
.read_bytes = 0,
.enable_read = 0,
.opcode = 0x60,
};
struct qspi_stig_reg_t write_cmd = {
.enable_bank = 0,
.dummy_cycles = 0,
.write_bytes = 0,
.enable_write = 1,
.addr_bytes = QSPI_STIG_ADDR_BYTES_3,
.enable_mode = 0,
.enable_cmd_addr = 1,
.read_bytes = 0,
.enable_read = 0,
.opcode = 0x02,
};
struct qspi_stig_reg_t write_disable_cmd = {
.enable_bank = 0,
.dummy_cycles = 0,
.write_bytes = 0,
.enable_write = 0,
.addr_bytes = 0,
.enable_mode = 0,
.enable_cmd_addr = 0,
.read_bytes = 0,
.enable_read = 0,
.opcode = 0x04,
};
struct qspi_stig_reg_t read_cmd = {
.enable_bank = 0,
.dummy_cycles = 0,
.write_bytes = 0,
.enable_write = 0,
.addr_bytes = QSPI_STIG_ADDR_BYTES_3,
.enable_mode = 0,
.enable_cmd_addr = 1,
.read_bytes = 0,
.enable_read = 1,
.opcode = 0x03,
};
struct qspi_stig_reg_t deep_sleep_cmd = {
.enable_bank = 0,
.dummy_cycles = 0,
.write_bytes = 0,
.enable_write = 0,
.addr_bytes = 0,
.enable_mode = 0,
.enable_cmd_addr = 0,
.read_bytes = 0,
.enable_read = 0,
.opcode = 0xB9,
};
struct qspi_stig_reg_t wakeup_cmd = {
.enable_bank = 0,
.dummy_cycles = 0,
.write_bytes = 0,
.enable_write = 0,
.addr_bytes = 0,
.enable_mode = 0,
.enable_cmd_addr = 0,
.read_bytes = 0,
.enable_read = 0,
.opcode = 0xAB,
};
struct qspi_stig_reg_t sec_sector_erase_cmd = {
.enable_bank = 0,
.dummy_cycles = 0,
.write_bytes = 0,
.enable_write = 0,
.addr_bytes = QSPI_STIG_ADDR_BYTES_3,
.enable_mode = 0,
.enable_cmd_addr = 1,
.read_bytes = 0,
.enable_read = 0,
.opcode = FLASH_SEC_REG_ERASE_OPCODE,
};
struct qspi_stig_reg_t sec_sector_read_cmd = {
.enable_bank = 0,
.dummy_cycles = 1,
.write_bytes = 0,
.enable_write = 0,
.addr_bytes = QSPI_STIG_ADDR_BYTES_3,
.enable_mode = 0,
.enable_cmd_addr = 1,
.read_bytes = 0,
.enable_read = 1,
.opcode = FLASH_SEC_REG_READ_OPCODE,
};
struct qspi_stig_reg_t sec_sector_write_cmd = {
.enable_bank = 0,
.dummy_cycles = 0,
.write_bytes = 0,
.enable_write = 1,
.addr_bytes = QSPI_STIG_ADDR_BYTES_3,
.enable_mode = 0,
.enable_cmd_addr = 1,
.read_bytes = 0,
.enable_read = 0,
.opcode = FLASH_SEC_REG_PROGRAM_OPCODE,
};
__RAM_CODE void flash_wait_wip_clear(struct qspi_regs_t *qspi)
{
uint8_t status;
while(1) {
system_delay_us(100);
qspi_stig_cmd(qspi, read_status_cmd, QSPI_STIG_CMD_READ, 1, &status);
if((status & 0x01) == 0) {
break;
}
}
}
__RAM_CODE void flash_enable_quad(struct qspi_regs_t *qspi)
{
uint8_t status[2];
uint32_t flash_id;
qspi_stig_cmd(qspi, read_status_cmd, QSPI_STIG_CMD_READ, 1, &status[0]);
qspi_stig_cmd(qspi, read_status_h_cmd, QSPI_STIG_CMD_READ, 1, &status[1]);
if((status[1] & 0x02) == 0x02) {
return;
}
flash_id = flash_read_id(qspi);
if ((flash_id == FLASH_ID_PUYA_P25Q32)
|| (flash_id == FLASH_ID_XMC_XM25LU32)
|| (flash_id == FLASH_ID_GIANTEC_GT25Q16A )
|| (flash_id == FLASH_ID_PUYA_P25Q16)) {
status[1] |= 0x02; //enable quad mode
qspi_stig_cmd(qspi, write_enable_cmd, QSPI_STIG_CMD_EXE, 0, 0);
qspi_stig_cmd(qspi, write_status_h_cmd, QSPI_STIG_CMD_WRITE, 1, &status[1]);
}
else if ((flash_id == FLASH_ID_GD_GD25WQ80E)
|| (flash_id == FLASH_ID_PUYA_P25Q80)) {
status[1] |= 0x02; //enable quad mode
qspi_stig_cmd(qspi, write_enable_cmd, QSPI_STIG_CMD_EXE, 0, 0);
qspi_stig_cmd(qspi, write_status_cmd, QSPI_STIG_CMD_WRITE, 2, &status[0]);
}
else {
while(1);
}
flash_wait_wip_clear(qspi);
}
__RAM_CODE void flash_set_IO_DRV(struct qspi_regs_t *qspi, uint8_t drv)
{
uint8_t data;
data = (drv<<5);
qspi_stig_cmd(qspi, write_volatile_enable_cmd, QSPI_STIG_CMD_EXE, 0, 0);
qspi_stig_cmd(qspi, write_status_3_cmd, QSPI_STIG_CMD_WRITE, 1, &data);
}
__RAM_CODE void flash_set_capture_delay(struct qspi_regs_t *qspi, uint8_t delay)
{
__QSPI_READ_CAPTURE_DELAY_SET(qspi, delay);
}
__RAM_CODE void flash_set_read_dtr_fast_quad(struct qspi_regs_t *qspi)
{
__QSPI_READ_OPCODE_SET(qspi, FLASH_PAGE_DTR_QUAL_READ_OPCODE);
__QSPI_READ_INSTRUCTION_TYPE_SET(qspi, QSPI_WIRE_TYPE_STAND);
__QSPI_READ_ADDRESS_TYPE_SET(qspi, QSPI_WIRE_TYPE_QIO);
__QSPI_READ_DATA_TYPE_SET(qspi, QSPI_WIRE_TYPE_QIO);
__QSPI_READ_DUMMY_CYCLES_SET(qspi, 7);
__QSPI_READ_MODE_ENABLE_SET(qspi, 1);
__QSPI_MODE_BIT_SET(qspi, 0);
// __QSPI_CFG_DTR_ENABLE(qspi);
__QSPI_READ_DDR_ENABLE(qspi);
}
__RAM_CODE void flash_set_read_fast_quad(struct qspi_regs_t *qspi)
{
__QSPI_READ_OPCODE_SET(qspi, FLASH_PAGE_QUAL_READ_OPCODE);
__QSPI_READ_INSTRUCTION_TYPE_SET(qspi, QSPI_WIRE_TYPE_STAND);
__QSPI_READ_ADDRESS_TYPE_SET(qspi, QSPI_WIRE_TYPE_QIO);
__QSPI_READ_DATA_TYPE_SET(qspi, QSPI_WIRE_TYPE_QIO);
__QSPI_READ_DUMMY_CYCLES_SET(qspi, 4);
__QSPI_READ_MODE_ENABLE_SET(qspi, 1);
__QSPI_MODE_BIT_SET(qspi, 0);
}
__RAM_CODE void flash_set_read_quad(struct qspi_regs_t *qspi)
{
__QSPI_READ_OPCODE_SET(qspi, FLASH_PAGE_QUAL_READ_OPCODE_2);
__QSPI_READ_INSTRUCTION_TYPE_SET(qspi, QSPI_WIRE_TYPE_STAND);
__QSPI_READ_ADDRESS_TYPE_SET(qspi, QSPI_WIRE_TYPE_STAND);
__QSPI_READ_DATA_TYPE_SET(qspi, QSPI_WIRE_TYPE_QIO);
__QSPI_READ_DUMMY_CYCLES_SET(qspi, 8);
__QSPI_READ_MODE_ENABLE_SET(qspi, 0);
__QSPI_MODE_BIT_SET(qspi, 0);
}
__RAM_CODE void flash_set_read_dtr_fast_dual(struct qspi_regs_t *qspi)
{
__QSPI_READ_OPCODE_SET(qspi, FLASH_READ_DTR_DUAL_OPCODE);
__QSPI_READ_INSTRUCTION_TYPE_SET(qspi, QSPI_WIRE_TYPE_STAND);
__QSPI_READ_ADDRESS_TYPE_SET(qspi, QSPI_WIRE_TYPE_DIO);
__QSPI_READ_DATA_TYPE_SET(qspi, QSPI_WIRE_TYPE_DIO);
__QSPI_READ_DUMMY_CYCLES_SET(qspi, 0);
__QSPI_READ_MODE_ENABLE_SET(qspi, 0);
__QSPI_MODE_BIT_SET(qspi, 0);
// __QSPI_CFG_DTR_ENABLE(qspi);
__QSPI_READ_DDR_ENABLE(qspi);
}
__RAM_CODE void flash_set_read_fast_dual(struct qspi_regs_t *qspi)
{
__QSPI_READ_OPCODE_SET(qspi, FLASH_READ_DUAL_OPCODE);
__QSPI_READ_INSTRUCTION_TYPE_SET(qspi, QSPI_WIRE_TYPE_STAND);
__QSPI_READ_ADDRESS_TYPE_SET(qspi, QSPI_WIRE_TYPE_DIO);
__QSPI_READ_DATA_TYPE_SET(qspi, QSPI_WIRE_TYPE_DIO);
__QSPI_READ_DUMMY_CYCLES_SET(qspi, 0);
__QSPI_READ_MODE_ENABLE_SET(qspi, 1);
__QSPI_MODE_BIT_SET(qspi, 0);
}
__RAM_CODE void flash_set_read_dual(struct qspi_regs_t *qspi)
{
__QSPI_READ_OPCODE_SET(qspi, FLASH_READ_DUAL_OPCODE_2);
__QSPI_READ_INSTRUCTION_TYPE_SET(qspi, QSPI_WIRE_TYPE_STAND);
__QSPI_READ_ADDRESS_TYPE_SET(qspi, QSPI_WIRE_TYPE_STAND);
__QSPI_READ_DATA_TYPE_SET(qspi, QSPI_WIRE_TYPE_DIO);
__QSPI_READ_DUMMY_CYCLES_SET(qspi, 8);
__QSPI_READ_MODE_ENABLE_SET(qspi, 0);
__QSPI_MODE_BIT_SET(qspi, 0);
}
__RAM_CODE void flash_set_read_dtr_fast_single(struct qspi_regs_t *qspi)
{
__QSPI_READ_OPCODE_SET(qspi, FLASH_FAST_DTR_READ_OPCODE);
__QSPI_READ_INSTRUCTION_TYPE_SET(qspi, QSPI_WIRE_TYPE_STAND);
__QSPI_READ_ADDRESS_TYPE_SET(qspi, QSPI_WIRE_TYPE_STAND);
__QSPI_READ_DATA_TYPE_SET(qspi, QSPI_WIRE_TYPE_STAND);
__QSPI_READ_DUMMY_CYCLES_SET(qspi, 6);
__QSPI_READ_MODE_ENABLE_SET(qspi, 0);
__QSPI_MODE_BIT_SET(qspi, 0);
// __QSPI_CFG_DTR_ENABLE(qspi);
__QSPI_READ_DDR_ENABLE(qspi);
}
__RAM_CODE void flash_set_read_fast_single(struct qspi_regs_t *qspi)
{
__QSPI_READ_OPCODE_SET(qspi, FLASH_FAST_READ_OPCODE);
__QSPI_READ_INSTRUCTION_TYPE_SET(qspi, QSPI_WIRE_TYPE_STAND);
__QSPI_READ_ADDRESS_TYPE_SET(qspi, QSPI_WIRE_TYPE_STAND);
__QSPI_READ_DATA_TYPE_SET(qspi, QSPI_WIRE_TYPE_STAND);
__QSPI_READ_DUMMY_CYCLES_SET(qspi, 8);
__QSPI_READ_MODE_ENABLE_SET(qspi, 0);
__QSPI_MODE_BIT_SET(qspi, 0);
}
__RAM_CODE void flash_set_read_single(struct qspi_regs_t *qspi)
{
__QSPI_READ_OPCODE_SET(qspi, FLASH_READ_OPCODE);
__QSPI_READ_INSTRUCTION_TYPE_SET(qspi, QSPI_WIRE_TYPE_STAND);
__QSPI_READ_ADDRESS_TYPE_SET(qspi, QSPI_WIRE_TYPE_STAND);
__QSPI_READ_DATA_TYPE_SET(qspi, QSPI_WIRE_TYPE_STAND);
__QSPI_READ_DUMMY_CYCLES_SET(qspi, 0);
__QSPI_READ_MODE_ENABLE_SET(qspi, 0);
__QSPI_MODE_BIT_SET(qspi, 0);
}
__RAM_CODE void flash_set_write_quad(struct qspi_regs_t *qspi)
{
__QSPI_WRITE_OPCODE_SET(qspi, FLASH_PAGE_QUAL_PROGRAM_OPCODE);
__QSPI_WRITE_ADDRESS_TYPE_SET(qspi, QSPI_WIRE_TYPE_STAND);
__QSPI_WRITE_DATA_TYPE_SET(qspi, QSPI_WIRE_TYPE_QIO);
__QSPI_WRITE_DUMMY_CYCLES_SET(qspi, 0);
}
__RAM_CODE void flash_set_write_dual(struct qspi_regs_t *qspi)
{
__QSPI_WRITE_OPCODE_SET(qspi, FLASH_PAGE_DUAL_PROGRAM_OPCODE);
__QSPI_WRITE_ADDRESS_TYPE_SET(qspi, QSPI_WIRE_TYPE_STAND);
__QSPI_WRITE_DATA_TYPE_SET(qspi, QSPI_WIRE_TYPE_DIO);
__QSPI_WRITE_DUMMY_CYCLES_SET(qspi, 0);
}
__RAM_CODE void flash_set_write_single(struct qspi_regs_t *qspi)
{
__QSPI_WRITE_OPCODE_SET(qspi, FLASH_PAGE_PROGRAM_OPCODE);
__QSPI_WRITE_ADDRESS_TYPE_SET(qspi, QSPI_WIRE_TYPE_STAND);
__QSPI_WRITE_DATA_TYPE_SET(qspi, QSPI_WIRE_TYPE_STAND);
__QSPI_WRITE_DUMMY_CYCLES_SET(qspi, 0);
}
__RAM_CODE __USED void flash_set_read_type(struct qspi_regs_t *qspi, uint8_t rd_type)
{
switch(rd_type) {
case FLASH_RD_TYPE_SINGLE:
flash_set_read_single(qspi);
break;
case FLASH_RD_TYPE_SINGLE_FAST:
flash_set_read_fast_single(qspi);
break;
case FLASH_RD_TYPE_DUAL:
flash_set_read_dual(qspi);
break;
case FLASH_RD_TYPE_DUAL_FAST:
flash_set_read_fast_dual(qspi);
break;
case FLASH_RD_TYPE_QUAD:
flash_set_read_quad(qspi);
break;
case FLASH_RD_TYPE_QUAD_FAST:
flash_set_read_fast_quad(qspi);
break;
case FLASH_RD_TYPE_DTR_SINGLE_FAST:
flash_set_read_dtr_fast_single(qspi);
break;
case FLASH_RD_TYPE_DTR_DUAL_FAST:
flash_set_read_dtr_fast_dual(qspi);
break;
case FLASH_RD_TYPE_DTR_QUAD_FAST:
flash_set_read_dtr_fast_quad(qspi);
break;
default:
flash_set_read_single(qspi);
break;
}
}
__RAM_CODE __USED void flash_set_write_type(struct qspi_regs_t *qspi, uint8_t wr_type)
{
switch(wr_type) {
case FLASH_WR_TYPE_SINGLE:
flash_set_write_single(qspi);
break;
case FLASH_WR_TYPE_DUAL:
flash_set_write_dual(qspi);
break;
case FLASH_WR_TYPE_QUAD:
flash_set_write_quad(qspi);
break;
default:
flash_set_write_single(qspi);
break;
}
}
__RAM_CODE __USED void flash_init_controller(struct qspi_regs_t *qspi, enum flash_rd_type_t rd_type, enum flash_wr_type_t wr_type)
{
while(__QSPI_IS_BUSY(qspi));
flash_set_read_type(qspi, rd_type);
flash_set_write_type(qspi, wr_type);
__QSPI_POLL_OPCODE_SET(qspi, 0x05);
__QSPI_POLL_BIT_INDEX_SET(qspi, 0);
__QSPI_POLL_POLARITY_SET(qspi, 0);
__QSPI_POLL_EXPIRATION_SET(qspi, 0);
__QSPI_POLL_EXPIRE_DISABLE(qspi);
__QSPI_POLL_COUNT_SET(qspi, 2);
__QSPI_POLL_DELAY_SET(qspi, 16);
__QSPI_POLL_DISABLE(qspi);
//init configuration register
__QSPI_CFG_CPOL_SET(qspi, 1);
__QSPI_CFG_CPHA_SET(qspi, 1);
__QSPI_CFG_DAC_ENABLE(qspi);
__QSPI_CFG_LEGACY_DISABLE(qspi);
__QSPI_CFG_REMAP_ENABLE(qspi);
__QSPI_CFG_BAUDRATE_SET(qspi, QSPI_BAUDRATE_DIV_16);
__QSPI_CFG_AHB_DECODER_ENABLE(qspi);
__QSPI_DELAY_CS_START_SET(qspi, 2);
__QSPI_DELAY_CS_END_SET(qspi, 2);
__QSPI_REMAP_ADDRESS_SET(qspi, 0);
__QSPI_ENABLE(qspi);
}
uint32_t flash_read_id(struct qspi_regs_t *qspi)
{
uint32_t flash_id;
qspi_stig_cmd(qspi, read_id_cmd, QSPI_STIG_CMD_READ, 3, (uint8_t *)&flash_id);
return (flash_id&0xffffff);
}
__RAM_CODE void flash_set_baudrate(struct qspi_regs_t *qspi, uint8_t baudrate)
{
if (baudrate <= QSPI_BAUDRATE_DIV_32) {
GLOBAL_INT_DISABLE();
while(__QSPI_IS_BUSY(qspi));
__QSPI_CFG_BAUDRATE_SET(qspi, baudrate);
if ((baudrate == QSPI_BAUDRATE_DIV_2)
|| ((baudrate == QSPI_BAUDRATE_DIV_4) && (__QSPI_READ_DDR_GET(qspi) == 1))) {
__QSPI_READ_CAPTURE_DELAY_SET(qspi, 2);
}
GLOBAL_INT_RESTORE();
}
}
uint32_t flash_init(struct qspi_regs_t *qspi)
{
flash_exit_deep_sleep(qspi);
return flash_read_id(qspi);
}
uint16_t flash_read_status(struct qspi_regs_t *qspi, bool read_high)
{
uint8_t *status;
uint16_t status_entity;
status = (uint8_t *)&status_entity;
qspi_stig_cmd(qspi, read_status_cmd, QSPI_STIG_CMD_READ, 1, &status[0]);
if(read_high) {
qspi_stig_cmd(qspi, read_status_h_cmd, QSPI_STIG_CMD_READ, 1, &status[1]);
}
return status_entity;
}
__RAM_CODE void flash_write_status(struct qspi_regs_t *qspi, uint16_t status, bool write_high)
{
uint8_t count = 1;
if(write_high) {
count++;
}
qspi_stig_cmd(qspi, write_enable_cmd, QSPI_STIG_CMD_EXE, 0, 0);
qspi_stig_cmd(qspi, write_status_cmd, QSPI_STIG_CMD_WRITE, count, (void *)&status);
flash_wait_wip_clear(qspi);
}
__RAM_CODE void flash_write_status_2(struct qspi_regs_t *qspi, uint8_t status)
{
qspi_stig_cmd(qspi, write_enable_cmd, QSPI_STIG_CMD_EXE, 0, 0);
qspi_stig_cmd(qspi, write_status_2_cmd, QSPI_STIG_CMD_WRITE, 1, (void *)&status);
flash_wait_wip_clear(qspi);
}
__RAM_CODE void flash_write_status_volatile(struct qspi_regs_t *qspi, uint16_t status, bool write_high)
{
uint8_t count = 1;
uint8_t poll_status;
if(write_high) {
count++;
}
qspi_stig_cmd(qspi, write_volatile_enable_cmd, QSPI_STIG_CMD_EXE, 0, 0);
qspi_stig_cmd(qspi, write_status_cmd, QSPI_STIG_CMD_WRITE, count, (void *)&status);
}
__RAM_CODE void flash_write_status_2_volatile(struct qspi_regs_t *qspi, uint8_t status)
{
qspi_stig_cmd(qspi, write_volatile_enable_cmd, QSPI_STIG_CMD_EXE, 0, 0);
qspi_stig_cmd(qspi, write_status_2_cmd, QSPI_STIG_CMD_WRITE, 1, (void *)&status);
}
/************************************************************************************
* @fn flash_protect_bit_set
*
* @brief set flash protection relevant bits.
*
* @param qspi: qspi controller base address
* bits: flash protection bits in status 1, BIT4:0 is valid.
* cmp: flash protection compare bit in status 2.
* 0xff means this field should be ignored
* BIT7: clear or set CMP bit
* BIT0-2: CMP bit offset in status 2
* wr_volatile: write status registers in volatile mode or not
* status_2_separate: write status 2 together with status 1 or separately
*/
__RAM_CODE void flash_protect_bit_set(struct qspi_regs_t *qspi, uint8_t bits, uint8_t cmp, uint8_t wr_volatile, uint8_t status_2_separate)
{
uint8_t status[2];
uint16_t status_tmp;
uint8_t skip_status_1 = 0;
if(cmp != 0xff) {
status_tmp = flash_read_status(qspi, true);
status[0] = status_tmp & 0xff;
status[1] = (status_tmp>>8) & 0xff;
if(cmp & 0x80) {
// set cmp bit
if((status[1] & (1<<(cmp&0x07))) != 0) {
cmp = 0xff;
}
else {
status[1] |= (1<<(cmp&0x07));
}
}
else {
// clear cmp bit
if((status[1] & (1<<(cmp&0x07))) == 0) {
cmp = 0xff;
}
else {
status[1] &= (~(1<<(cmp&0x07)));
}
}
}
else {
status_tmp = flash_read_status(qspi, false);
status[0] = status_tmp & 0xff;
}
bits &= 0x1f;
if((status[0] & 0x7C) == (bits << 2)) {
skip_status_1 = 1;
if (cmp == 0xff) {
return;
}
}
status[0] &= 0x80;
status[0] |= (bits << 2);
GLOBAL_INT_DISABLE();
if(cmp != 0xff) {
if(status_2_separate) {
if(wr_volatile) {
if(skip_status_1 == 0) {
flash_write_status_volatile(qspi, status[0], false);
}
flash_write_status_2_volatile(qspi, status[1]);
}
else {
if(skip_status_1 == 0) {
flash_write_status(qspi, status[0], false);
}
flash_write_status_2(qspi, status[1]);
}
}
else {
status_tmp = status[0] | (status[1]<<8);
if(wr_volatile) {
flash_write_status_volatile(qspi, status_tmp, true);
}
else {
flash_write_status(qspi, status_tmp, true);
}
}
}
else {
if(wr_volatile) {
flash_write_status_volatile(qspi, status[0], false);
}
else {
flash_write_status(qspi, status[0], false);
}
}
GLOBAL_INT_RESTORE();
}
__RAM_CODE __attribute__((noinline)) uint8_t flash_write(struct qspi_regs_t *qspi, uint32_t offset, uint32_t length, const uint8_t *buffer)
{
uint32_t page_left;
uint32_t dac_addr_offset;
uint8_t *dst;
if(length == 0) {
return 0;
}
if ((uint32_t)qspi == FLASH_QSPI_BASE) {
dac_addr_offset = FLASH_DAC_BASE;
}
else if ((uint32_t)qspi == DSP_QSPI_BASE) {
dac_addr_offset = DSP_FLASH_DAC_BASE;
}
else {
return 0;
}
page_left = 0x100 - (offset & 0xff);
if(length < page_left) {
page_left = length;
}
dst = (void *)(offset | dac_addr_offset);
GLOBAL_INT_DISABLE();
if ((uint32_t)qspi == FLASH_QSPI_BASE) {
system_cache_disable();
}
while(length) {
for (int32_t i=0; i<page_left; i++) {
*dst++ = *buffer++;
}
flash_wait_wip_clear(qspi);
length -= page_left;
page_left = (length > 256) ? 256 : length;
}
if ((uint32_t)qspi == FLASH_QSPI_BASE) {
system_cache_enable(true);
}
GLOBAL_INT_RESTORE();
return 0;
}
__USED uint8_t flash_read(struct qspi_regs_t *qspi, uint32_t offset, uint32_t length, uint8_t *buffer)
{
if ((uint32_t)qspi == FLASH_QSPI_BASE) {
memcpy(buffer, (void *)(offset | FLASH_DAC_BASE), length);
}
else if((uint32_t)qspi == DSP_QSPI_BASE) {
memcpy(buffer, (void *)(offset | DSP_FLASH_DAC_BASE), length);
}
return 0;
}
__RAM_CODE __attribute__((noinline)) uint8_t flash_erase(struct qspi_regs_t *qspi, uint32_t offset, uint32_t size)
{
if(size == 0) {
size = 0x1000;
}
offset &= 0xFFFFF000;
GLOBAL_INT_DISABLE();
system_cache_disable();
while(size) {
qspi_stig_cmd(qspi, write_enable_cmd, QSPI_STIG_CMD_EXE, 0, 0);
__QSPI_CMD_ADDRESS_SET(qspi, offset);
qspi_stig_cmd(qspi, sector_erase_cmd, QSPI_STIG_CMD_EXE, 0, 0);
flash_wait_wip_clear(qspi);
offset += 0x1000;
if(size > 0x1000)
size -= 0x1000;
else {
size = 0;
}
}
system_cache_enable(true);
GLOBAL_INT_RESTORE();
return 0;
}
__RAM_CODE void flash_chip_erase(struct qspi_regs_t *qspi)
{
qspi_stig_cmd(qspi, write_enable_cmd, QSPI_STIG_CMD_EXE, 0, 0);
qspi_stig_cmd(qspi, chip_erase_cmd, QSPI_STIG_CMD_EXE, 0, 0);
system_delay_us(20);
flash_wait_wip_clear(qspi);
}
__RAM_CODE void flash_enter_deep_sleep(struct qspi_regs_t *qspi)
{
qspi_stig_cmd(qspi, deep_sleep_cmd, QSPI_STIG_CMD_EXE, 0, 0);
system_delay_us(20);
}
__RAM_CODE void flash_exit_deep_sleep(struct qspi_regs_t *qspi)
{
qspi_stig_cmd(qspi, wakeup_cmd, QSPI_STIG_CMD_EXE, 0, 0);
system_delay_us(20);
}
/*********************************************************************
* @fn flash_OTP_read
*
* @brief read data from OTP sections. otp section size: 512 = 0x200
*
* @param offset - Security flash section offset, only valid for 0x1000,0x2000,0x3000
* length - buffer length to be read from security flash section. rang[1,512]
* buffer - pointer to buffer which will store data
*
* @return None.
*/
__RAM_CODE void flash_OTP_read(struct qspi_regs_t *qspi,uint32_t offset, uint32_t length, uint8_t *buffer)
{
uint32_t i = 0;
offset &= 0x3000;
if(length > 512)
length = 512;
GLOBAL_INT_DISABLE();
for(; (i+8) <= length; )
{
__QSPI_CMD_ADDRESS_SET(qspi, offset);
qspi_stig_cmd(qspi,sec_sector_read_cmd, QSPI_STIG_CMD_READ, 8, buffer + i );
i+=8;
offset+=8;
}
if(i < length)
{
__QSPI_CMD_ADDRESS_SET(qspi, offset);
qspi_stig_cmd(qspi,sec_sector_read_cmd, QSPI_STIG_CMD_READ, (length-i), (buffer+i));
}
GLOBAL_INT_RESTORE();
}
/*********************************************************************
* @fn flash_OTP_write
*
* @brief write data to OTP sections. otp section size: 512 = 0x200
*
* @param offset - Security flash section offset, only valid for 0x1000,0x2000,0x3000
* length - buffer length to be written into security flash section. rang[1,512]
* buffer - pointer to buffer which will be written
*
* @return None.
*/
__RAM_CODE void flash_OTP_write(struct qspi_regs_t *qspi,uint32_t offset, uint32_t length, uint8_t *buffer)
{
uint8_t status[1];
uint32_t i = 0;
#define SINGLE_LENGTH 8
offset &= 0x3000;
if(length > 512)
length = 512;
GLOBAL_INT_DISABLE();
for(; (i+SINGLE_LENGTH) <= length; )
{
qspi_stig_cmd(qspi,write_enable_cmd, QSPI_STIG_CMD_EXE, 0, 0);
__QSPI_CMD_ADDRESS_SET(qspi, offset);
qspi_stig_cmd(qspi,sec_sector_write_cmd, QSPI_STIG_CMD_WRITE, SINGLE_LENGTH, buffer+i);
while(1) {
system_delay_us(20);
qspi_stig_cmd(qspi,read_status_cmd, QSPI_STIG_CMD_READ, 1, &status[0]);
if((status[0] & 0x01) == 0) {
break;
}
}
qspi_stig_cmd(qspi,write_disable_cmd, QSPI_STIG_CMD_EXE, 0, 0);
i+=SINGLE_LENGTH;
offset+=SINGLE_LENGTH;
}
if(i < length)
{
qspi_stig_cmd(qspi,write_enable_cmd, QSPI_STIG_CMD_EXE, 0, 0);
__QSPI_CMD_ADDRESS_SET(qspi, offset);
qspi_stig_cmd(qspi,sec_sector_write_cmd, QSPI_STIG_CMD_WRITE, (length-i), (buffer+i));
while(1) {
system_delay_us(20);
qspi_stig_cmd(qspi,read_status_cmd, QSPI_STIG_CMD_READ, 1, &status[0]);
if((status[0] & 0x01) == 0) {
break;
}
}
qspi_stig_cmd(qspi,write_disable_cmd, QSPI_STIG_CMD_EXE, 0, 0);
}
GLOBAL_INT_RESTORE();
}
/*********************************************************************
* @fn flash_OTP_erase
*
* @brief erase whole OTP section .
*
* @param offset - Security flash section offset, only valid for 0x1000,0x2000,0x3000
*
* @return None.
*/
__RAM_CODE void flash_OTP_erase(struct qspi_regs_t *qspi,uint32_t offset)
{
uint8_t status;
offset &= 0x3000;
GLOBAL_INT_DISABLE();
qspi_stig_cmd(qspi,write_enable_cmd, QSPI_STIG_CMD_EXE, 0, 0);
__QSPI_CMD_ADDRESS_SET(qspi, offset);
qspi_stig_cmd(qspi,sec_sector_erase_cmd, QSPI_STIG_CMD_EXE, 0, 0);
while(1) {
system_delay_us(20);
qspi_stig_cmd(qspi,read_status_cmd, QSPI_STIG_CMD_READ, 1, &status);
if((status & 0x01) == 0) {
break;
}
}
qspi_stig_cmd(qspi,write_disable_cmd, QSPI_STIG_CMD_EXE, 0, 0);
GLOBAL_INT_RESTORE();
}