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