351 lines
11 KiB
C
351 lines
11 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"
|
|
|
|
#include "driver_psram.h"
|
|
|
|
#include "co_util.h"
|
|
|
|
#define PSRAM_ENABLE_Q_MODE 1
|
|
|
|
#define PSRAM_LATENCY_CFG 3
|
|
#define PSRAM_HIGH_SPEED 1
|
|
#define PSRAM_OSPI_IF OSPI
|
|
|
|
#define PSRAM_READ_IDENTIFICATION 0x9F
|
|
|
|
#define PSRAM_READ_OPCODE 0x03
|
|
#define PSRAM_FAST_READ_OPCODE 0x0B
|
|
#define PSRAM_FAST_QUAL_READ_OPCODE 0xEB
|
|
|
|
#define PSRAM_PAGE_PROGRAM_OPCODE 0x02
|
|
#define PSRAM_PAGE_QUAL_PROGRAM_OPCODE 0x38
|
|
|
|
#define PSRAM_ENTER_QUAD_MODE_OPCODE 0x35
|
|
#define PSRAM_EXIT_QUAD_MODE_OPCODE 0xF5
|
|
|
|
#define PSRAM_RESET_ENABLE_OPCODE 0x66
|
|
#define PSRAM_RESET_OPCODE 0x99
|
|
|
|
static const struct qspi_stig_reg_t psram_read_ctrl_cmd = {
|
|
.enable_bank = 0,
|
|
.dummy_cycles = PSRAM_LATENCY_CFG-1,
|
|
.write_bytes = 0,
|
|
.enable_write = 0,
|
|
.addr_bytes = QSPI_STIG_ADDR_BYTES_4,
|
|
.enable_mode = 0,
|
|
.enable_cmd_addr = 1,
|
|
.read_bytes = 2,
|
|
.enable_read = 1,
|
|
.opcode = 0x40,
|
|
};
|
|
|
|
static const struct qspi_stig_reg_t psram_write_ctrl_cmd = {
|
|
.enable_bank = 0,
|
|
.dummy_cycles = 0,
|
|
.write_bytes = 2,
|
|
.enable_write = 1,
|
|
.addr_bytes = QSPI_STIG_ADDR_BYTES_4,
|
|
.enable_mode = 0,
|
|
.enable_cmd_addr = 1,
|
|
.read_bytes = 0,
|
|
.enable_read = 0,
|
|
.opcode = 0xC0,
|
|
};
|
|
|
|
static const struct qspi_stig_reg_t psram_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 = PSRAM_READ_IDENTIFICATION,
|
|
};
|
|
|
|
static const struct qspi_stig_reg_t enter_quad_mode_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 = PSRAM_ENTER_QUAD_MODE_OPCODE,
|
|
};
|
|
|
|
static const struct qspi_stig_reg_t reset_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 = PSRAM_RESET_ENABLE_OPCODE,
|
|
};
|
|
|
|
static const struct qspi_stig_reg_t reset_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 = PSRAM_RESET_OPCODE,
|
|
};
|
|
|
|
static uint8_t psram_read_mode(uint8_t mode)
|
|
{
|
|
uint8_t result[2];
|
|
|
|
__QSPI_CMD_ADDRESS_SET(PSRAM_OSPI_IF, mode);
|
|
qspi_stig_cmd(PSRAM_OSPI_IF, psram_read_ctrl_cmd, QSPI_STIG_CMD_READ, 2, result);
|
|
|
|
return result[0];
|
|
}
|
|
|
|
static void psram_write_mode(uint8_t mode, uint8_t data)
|
|
{
|
|
uint8_t buffer[2];
|
|
|
|
buffer[0] = data;
|
|
buffer[1] = data;
|
|
__QSPI_CMD_ADDRESS_SET(PSRAM_OSPI_IF, mode);
|
|
qspi_stig_cmd(PSRAM_OSPI_IF, psram_write_ctrl_cmd, QSPI_STIG_CMD_WRITE, 2, buffer);
|
|
}
|
|
|
|
#if 0
|
|
static void psram_controller_init(uint16_t page_boundary)
|
|
{
|
|
while(__QSPI_IS_BUSY(PSRAM_OSPI_IF));
|
|
|
|
__QSPI_READ_OPCODE_SET(PSRAM_OSPI_IF, 0x20);
|
|
__QSPI_READ_INSTRUCTION_TYPE_SET(PSRAM_OSPI_IF, QSPI_WIRE_TYPE_OIO);
|
|
__QSPI_READ_ADDRESS_TYPE_SET(PSRAM_OSPI_IF, QSPI_WIRE_TYPE_OIO);
|
|
__QSPI_READ_DATA_TYPE_SET(PSRAM_OSPI_IF, QSPI_WIRE_TYPE_OIO);
|
|
__QSPI_READ_DUMMY_CYCLES_SET(PSRAM_OSPI_IF, (PSRAM_LATENCY_CFG<<1)-1);
|
|
__QSPI_READ_MODE_ENABLE_SET(PSRAM_OSPI_IF, 0);
|
|
__QSPI_MODE_BIT_SET(PSRAM_OSPI_IF, 0);
|
|
|
|
__QSPI_WRITE_OPCODE_SET(PSRAM_OSPI_IF, 0xA0);
|
|
__QSPI_WRITE_ADDRESS_TYPE_SET(PSRAM_OSPI_IF, QSPI_WIRE_TYPE_OIO);
|
|
__QSPI_WRITE_DATA_TYPE_SET(PSRAM_OSPI_IF, QSPI_WIRE_TYPE_OIO);
|
|
__QSPI_WRITE_DUMMY_CYCLES_SET(PSRAM_OSPI_IF, PSRAM_LATENCY_CFG-1);
|
|
__QSPI_WRITE_WEL_DISABLE(PSRAM_OSPI_IF);
|
|
__QSPI_POLL_DISABLE(PSRAM_OSPI_IF);
|
|
|
|
//init configuration register
|
|
__QSPI_CFG_CPOL_SET(PSRAM_OSPI_IF, 0);
|
|
__QSPI_CFG_CPHA_SET(PSRAM_OSPI_IF, 0);
|
|
__QSPI_CFG_DAC_ENABLE(PSRAM_OSPI_IF);
|
|
__QSPI_CFG_LEGACY_DISABLE(PSRAM_OSPI_IF);
|
|
__QSPI_CFG_REMAP_ENABLE(PSRAM_OSPI_IF);
|
|
#if PSRAM_HIGH_SPEED
|
|
__QSPI_CFG_BAUDRATE_SET(PSRAM_OSPI_IF, QSPI_BAUDRATE_DIV_6);
|
|
__QSPI_READ_CAPTURE_DELAY_SET(PSRAM_OSPI_IF, 0);
|
|
#else
|
|
__QSPI_CFG_BAUDRATE_SET(PSRAM_OSPI_IF, QSPI_BAUDRATE_DIV_16);
|
|
__QSPI_READ_CAPTURE_DELAY_SET(PSRAM_OSPI_IF, 0);
|
|
#endif
|
|
|
|
// __QSPI_CFG_AHB_DECODER_ENABLE(PSRAM_OSPI_IF);
|
|
|
|
__QSPI_READ_CAPTURE_LP_CLK_EN(PSRAM_OSPI_IF);
|
|
__QSPI_DELAY_CS_START_SET(PSRAM_OSPI_IF, 2);
|
|
__QSPI_DELAY_CS_END_SET(PSRAM_OSPI_IF, 2);
|
|
__QSPI_DELAY_CS_DESSERT_SET(PSRAM_OSPI_IF, 2);
|
|
|
|
__QSPI_DEVICE_PAGE_SIZE_SET(PSRAM_OSPI_IF, page_boundary);
|
|
// __QSPI_DEVICE_CS0_SIZE_SET(PSRAM_OSPI_IF, 3); // 4Gb space
|
|
|
|
__QSPI_CS_CTRL_RD_BRK_ENABLE(PSRAM_OSPI_IF);
|
|
__QSPI_CS_CTRL_DIS_CS_AFT_FIRST_BYTE_SET(PSRAM_OSPI_IF);
|
|
__QSPI_CS_PAGE_BOUNDARY_SET(PSRAM_OSPI_IF, page_boundary);
|
|
__QSPI_CS_PAGE_BOUNDARY_PROTECT_ENABLE(PSRAM_OSPI_IF);
|
|
|
|
// __QSPI_REMAP_ADDRESS_SET(PSRAM_OSPI_IF, PSRAM_DAC_BASE);
|
|
|
|
__QSPI_DEVICE_ADDR_BYTES_SET(PSRAM_OSPI_IF, QSPI_DEVICE_ADDR_BYTES_4);
|
|
__QSPI_CFG_DTR_ENABLE(PSRAM_OSPI_IF);
|
|
__QSPI_CFG_OCTAL_XCCELA_ENABLE(PSRAM_OSPI_IF);
|
|
|
|
__QSPI_ENABLE(PSRAM_OSPI_IF);
|
|
}
|
|
|
|
void psram_init(void)
|
|
{
|
|
// uint8_t mode[7];
|
|
uint8_t value;
|
|
|
|
#if PSRAM_HIGH_SPEED
|
|
psram_controller_init(0x0040);
|
|
#else
|
|
psram_controller_init(0x0008);
|
|
#endif
|
|
|
|
value = (1<<5) | ((PSRAM_LATENCY_CFG-3)<<2) | (0<<0);
|
|
psram_write_mode(0x00, value);
|
|
#if PSRAM_LATENCY_CFG == 3
|
|
value = (0<<5);
|
|
#elif PSRAM_LATENCY_CFG == 4
|
|
value = (4<<5);
|
|
#elif PSRAM_LATENCY_CFG == 5
|
|
value = (2<<5);
|
|
#elif PSRAM_LATENCY_CFG == 6
|
|
value = (6<<5);
|
|
#elif PSRAM_LATENCY_CFG == 7
|
|
value = (1<<5);
|
|
#else
|
|
#error "UNACCEPTABLE configure"
|
|
#endif
|
|
|
|
printf("write 0x%02x to mode reg4.\r\n", value);
|
|
psram_write_mode(0x04, value);
|
|
co_delay_100us(1);
|
|
|
|
// mode[0] = psram_read_mode(0x00);
|
|
// printf("mode 0: 0x%02x\r\n", mode[0]);
|
|
// mode[1] = psram_read_mode(0x01);
|
|
// printf("mode 1: 0x%02x\r\n", mode[1]);
|
|
// mode[2] = psram_read_mode(0x02);
|
|
// printf("mode 2: 0x%02x\r\n", mode[2]);
|
|
// mode[3] = psram_read_mode(0x03);
|
|
// printf("mode 3: 0x%02x\r\n", mode[3]);
|
|
// mode[4] = psram_read_mode(0x04);
|
|
// printf("mode 4: 0x%02x\r\n", mode[4]);
|
|
// mode[5] = psram_read_mode(0x06);
|
|
// printf("mode 6: 0x%02x\r\n", mode[5]);
|
|
// mode[6] = psram_read_mode(0x08);
|
|
// printf("mode 8: 0x%02x\r\n", mode[6]);
|
|
}
|
|
#else
|
|
static void psram_enter_quad(void)
|
|
{
|
|
qspi_stig_cmd(PSRAM_OSPI_IF, enter_quad_mode_cmd, QSPI_STIG_CMD_EXE, 0, NULL);
|
|
}
|
|
|
|
static void psram_controller_init(uint16_t page_boundary)
|
|
{
|
|
while(__QSPI_IS_BUSY(PSRAM_OSPI_IF));
|
|
|
|
#if PSRAM_ENABLE_Q_MODE == 1
|
|
__QSPI_READ_OPCODE_SET(PSRAM_OSPI_IF, PSRAM_FAST_READ_OPCODE);
|
|
__QSPI_READ_INSTRUCTION_TYPE_SET(PSRAM_OSPI_IF, QSPI_WIRE_TYPE_QIO);
|
|
__QSPI_READ_ADDRESS_TYPE_SET(PSRAM_OSPI_IF, QSPI_WIRE_TYPE_QIO);
|
|
__QSPI_READ_DATA_TYPE_SET(PSRAM_OSPI_IF, QSPI_WIRE_TYPE_QIO);
|
|
__QSPI_READ_DUMMY_CYCLES_SET(PSRAM_OSPI_IF, 4);
|
|
__QSPI_READ_MODE_ENABLE_SET(PSRAM_OSPI_IF, 0);
|
|
__QSPI_MODE_BIT_SET(PSRAM_OSPI_IF, 0);
|
|
|
|
__QSPI_WRITE_OPCODE_SET(PSRAM_OSPI_IF, PSRAM_PAGE_QUAL_PROGRAM_OPCODE);
|
|
__QSPI_WRITE_ADDRESS_TYPE_SET(PSRAM_OSPI_IF, QSPI_WIRE_TYPE_QIO);
|
|
__QSPI_WRITE_DATA_TYPE_SET(PSRAM_OSPI_IF, QSPI_WIRE_TYPE_QIO);
|
|
__QSPI_WRITE_DUMMY_CYCLES_SET(PSRAM_OSPI_IF, 0);
|
|
#else
|
|
__QSPI_READ_OPCODE_SET(PSRAM_OSPI_IF, PSRAM_FAST_QUAL_READ_OPCODE);
|
|
__QSPI_READ_INSTRUCTION_TYPE_SET(PSRAM_OSPI_IF, QSPI_WIRE_TYPE_STAND);
|
|
__QSPI_READ_ADDRESS_TYPE_SET(PSRAM_OSPI_IF, QSPI_WIRE_TYPE_QIO);
|
|
__QSPI_READ_DATA_TYPE_SET(PSRAM_OSPI_IF, QSPI_WIRE_TYPE_QIO);
|
|
__QSPI_READ_DUMMY_CYCLES_SET(PSRAM_OSPI_IF, 6);
|
|
__QSPI_READ_MODE_ENABLE_SET(PSRAM_OSPI_IF, 0);
|
|
__QSPI_MODE_BIT_SET(PSRAM_OSPI_IF, 0);
|
|
|
|
__QSPI_WRITE_OPCODE_SET(PSRAM_OSPI_IF, PSRAM_PAGE_QUAL_PROGRAM_OPCODE);
|
|
__QSPI_WRITE_ADDRESS_TYPE_SET(PSRAM_OSPI_IF, QSPI_WIRE_TYPE_QIO);
|
|
__QSPI_WRITE_DATA_TYPE_SET(PSRAM_OSPI_IF, QSPI_WIRE_TYPE_QIO);
|
|
__QSPI_WRITE_DUMMY_CYCLES_SET(PSRAM_OSPI_IF, 0);
|
|
#endif
|
|
|
|
//init configuration register
|
|
__QSPI_CFG_CPOL_SET(PSRAM_OSPI_IF, 0);
|
|
__QSPI_CFG_CPHA_SET(PSRAM_OSPI_IF, 0);
|
|
__QSPI_CFG_DAC_ENABLE(PSRAM_OSPI_IF);
|
|
__QSPI_CFG_LEGACY_DISABLE(PSRAM_OSPI_IF);
|
|
__QSPI_CFG_REMAP_ENABLE(PSRAM_OSPI_IF);
|
|
#if PSRAM_HIGH_SPEED
|
|
__QSPI_CFG_BAUDRATE_SET(PSRAM_OSPI_IF, QSPI_BAUDRATE_DIV_2);
|
|
__QSPI_READ_CAPTURE_DELAY_SET(PSRAM_OSPI_IF, 4);
|
|
#else
|
|
__QSPI_CFG_BAUDRATE_SET(PSRAM_OSPI_IF, QSPI_BAUDRATE_DIV_8);
|
|
__QSPI_READ_CAPTURE_DELAY_SET(PSRAM_OSPI_IF, 0);
|
|
#endif
|
|
|
|
// __QSPI_CFG_AHB_DECODER_ENABLE(PSRAM_OSPI_IF);
|
|
__QSPI_WRITE_WEL_DISABLE(PSRAM_OSPI_IF);
|
|
__QSPI_POLL_DISABLE(PSRAM_OSPI_IF);
|
|
|
|
__QSPI_READ_CAPTURE_LP_CLK_EN(PSRAM_OSPI_IF);
|
|
__QSPI_DELAY_CS_START_SET(PSRAM_OSPI_IF, 2);
|
|
__QSPI_DELAY_CS_END_SET(PSRAM_OSPI_IF, 2);
|
|
__QSPI_DELAY_CS_DESSERT_SET(PSRAM_OSPI_IF, 2);
|
|
|
|
__QSPI_DEVICE_PAGE_SIZE_SET(PSRAM_OSPI_IF, page_boundary);
|
|
// __QSPI_DEVICE_CS0_SIZE_SET(PSRAM_OSPI_IF, 3); // 4Gb space
|
|
|
|
__QSPI_CS_CTRL_RD_BRK_ENABLE(PSRAM_OSPI_IF);
|
|
__QSPI_CS_CTRL_DIS_CS_AFT_FIRST_BYTE_SET(PSRAM_OSPI_IF);
|
|
__QSPI_CS_PAGE_BOUNDARY_SET(PSRAM_OSPI_IF, page_boundary);
|
|
__QSPI_CS_PAGE_BOUNDARY_PROTECT_ENABLE(PSRAM_OSPI_IF);
|
|
|
|
__QSPI_REMAP_ADDRESS_SET(PSRAM_OSPI_IF, PSRAM_DAC_BASE);
|
|
|
|
__QSPI_CFG_OCTAL_OPI_DISABLE(PSRAM_OSPI_IF);
|
|
__QSPI_CFG_OCTAL_XCCELA_DISABLE(PSRAM_OSPI_IF);
|
|
|
|
__QSPI_ENABLE(PSRAM_OSPI_IF);
|
|
}
|
|
|
|
void psram_init(bool reset)
|
|
{
|
|
if (reset) {
|
|
qspi_stig_cmd(PSRAM_OSPI_IF, reset_enable_cmd, QSPI_STIG_CMD_EXE, 0, NULL);
|
|
// co_delay_10us(1000);
|
|
qspi_stig_cmd(PSRAM_OSPI_IF, reset_cmd, QSPI_STIG_CMD_EXE, 0, NULL);
|
|
// co_delay_10us(1000);
|
|
#if PSRAM_ENABLE_Q_MODE == 1
|
|
psram_enter_quad();
|
|
// co_delay_10us(1000);
|
|
#endif // PSRAM_ENABLE_Q_MODE == 1
|
|
}
|
|
|
|
#if PSRAM_HIGH_SPEED
|
|
psram_controller_init(0x0040);
|
|
#else
|
|
psram_controller_init(0x0010);
|
|
#endif
|
|
}
|
|
|
|
uint32_t psram_read_id(void)
|
|
{
|
|
uint32_t psram_id;
|
|
qspi_stig_cmd(PSRAM_OSPI_IF, psram_read_id_cmd, QSPI_STIG_CMD_READ, 3, (uint8_t *)&psram_id);
|
|
return (psram_id&0xffffff);
|
|
}
|
|
#endif
|
|
|