/* ****************************************************************************** * @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 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(); }