1106 lines
35 KiB
C
1106 lines
35 KiB
C
/*
|
||
* Copyright : (C) 2022 Phytium Information Technology, Inc.
|
||
* All Rights Reserved.
|
||
*
|
||
* This program is OPEN SOURCE software: you can redistribute it and/or modify it
|
||
* under the terms of the Phytium Public License as published by the Phytium Technology Co.,Ltd,
|
||
* either version 1.0 of the License, or (at your option) any later version.
|
||
*
|
||
* This program is distributed in the hope that it will be useful,but WITHOUT ANY WARRANTY;
|
||
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||
* See the Phytium Public License for more details.
|
||
*
|
||
*
|
||
* FilePath: fqspi_flash.c
|
||
* Date: 2022-07-12 15:42:55
|
||
* LastEditTime: 2022-07-12 15:42:56
|
||
* Description: This file is for S25FS256, GD25Q256, GD25Q64 norflash program functions
|
||
*
|
||
* Modify History:
|
||
* Ver Who Date Changes
|
||
* ----- ------ -------- --------------------------------------
|
||
* 1.0 wangxiaodong 2022/3/29 first release
|
||
* 1.1 wangxiaodong 2022/9/9 improve functions
|
||
*/
|
||
|
||
#include <string.h>
|
||
#include "fkernel.h"
|
||
#include "fassert.h"
|
||
#include "fqspi_flash.h"
|
||
#include "fqspi_hw.h"
|
||
#include "fqspi.h"
|
||
#include "sdkconfig.h"
|
||
|
||
#define FQSPI_DEBUG_TAG "FQSPI_FLASH"
|
||
#define FQSPI_ERROR(format, ...) FT_DEBUG_PRINT_E(FQSPI_DEBUG_TAG, format, ##__VA_ARGS__)
|
||
#define FQSPI_WARN(format, ...) FT_DEBUG_PRINT_W(FQSPI_DEBUG_TAG, format, ##__VA_ARGS__)
|
||
#define FQSPI_INFO(format, ...) FT_DEBUG_PRINT_I(FQSPI_DEBUG_TAG, format, ##__VA_ARGS__)
|
||
#define FQSPI_DEBUG(format, ...) FT_DEBUG_PRINT_D(FQSPI_DEBUG_TAG, format, ##__VA_ARGS__)
|
||
|
||
/* When entering direct address access mode,
|
||
read and write memory addresses need to be accessed in 4-byte alignment */
|
||
#define FQSPI_ALIGNED_BYTE 4
|
||
|
||
typedef struct
|
||
{
|
||
char *name;
|
||
u8 mf_id;
|
||
u8 type_id;
|
||
u8 capacity_id;
|
||
u32 capacity;
|
||
} FQspiFlashInfo;
|
||
|
||
/* supported manufacturer information table */
|
||
static const FQspiFlashInfo flash_info_table[] = FQSPI_FLASH_INFO_TABLE;
|
||
|
||
/*
|
||
* @name: FQspiFlashDetect
|
||
* @msg: detect qspi flash information, include id, type, capacity, set qspi capacity register.
|
||
* @param {FQspiCtrl} *pctrl, instance of FQSPI controller
|
||
* @return {FError} err code information, FQSPI_SUCCESS indicates success,others indicates failed
|
||
*/
|
||
FError FQspiFlashDetect(FQspiCtrl *pctrl)
|
||
{
|
||
FASSERT(pctrl);
|
||
FError ret = FQSPI_SUCCESS;
|
||
u8 flash_id[3] = {0};
|
||
u8 i = 0;
|
||
u32 index;
|
||
u32 cs_number = 0;
|
||
u32 min_detected_cs = FQSPI_CS_NUM ;
|
||
|
||
for (index = 0; index < FQSPI_CS_NUM ; index++)
|
||
{
|
||
/* read id to flash_id */
|
||
pctrl->config.channel = index;
|
||
ret = FQspiFlashSpecialInstruction(pctrl, FQSPI_FLASH_CMD_RDID, flash_id, sizeof(flash_id));
|
||
if (FQSPI_SUCCESS != ret)
|
||
{
|
||
FQSPI_ERROR("Read flash id failed, ret 0x%x\r\n", ret);
|
||
return ret;
|
||
}
|
||
|
||
if (flash_id[0] != 0xff)
|
||
{
|
||
FQSPI_INFO("CSN%d flash id = 0x%x, 0x%x, 0x%x\r\n", index, flash_id[0], flash_id[1], flash_id[2]);
|
||
}
|
||
else
|
||
{
|
||
FQSPI_ERROR("The Detected CSN%d flash is not matched", index);
|
||
}
|
||
|
||
for (i = 0; i < sizeof(flash_info_table) / sizeof(FQspiFlashInfo); i++)
|
||
{
|
||
if ((flash_info_table[i].mf_id == flash_id[0]) && (flash_info_table[i].type_id == flash_id[1])
|
||
&& (flash_info_table[i].capacity_id == flash_id[2]))
|
||
{
|
||
pctrl->mf_id = flash_info_table[i].mf_id;
|
||
pctrl->config.capacity = flash_info_table[i].capacity;
|
||
cs_number++;
|
||
/*get the min detected flash channel*/
|
||
min_detected_cs = (min_detected_cs > index)?index:min_detected_cs ;
|
||
FQSPI_INFO("CSN%d Find a %s flash chip.\n", index, flash_info_table[i].name);
|
||
break;
|
||
}
|
||
}
|
||
/*The default channel is the min detected flash*/
|
||
pctrl->config.channel = min_detected_cs;
|
||
|
||
if (i == sizeof(flash_info_table) / sizeof(FQspiFlashInfo) && flash_id[0] != 0xff)
|
||
{
|
||
FQSPI_ERROR("The Detected CSN%d flash not detected, id = 0x%x, 0x%x, 0x%x\r\n", index, flash_id[0], flash_id[1], flash_id[2]);
|
||
}
|
||
|
||
}
|
||
|
||
pctrl->config.dev_num = cs_number - 1;
|
||
/* set flash num and flash capacity */
|
||
FQspiSetCapacityAndNum(pctrl);
|
||
return ret;
|
||
}
|
||
|
||
/*
|
||
* @name: FQspiFlashReset
|
||
* @msg: qspi Flash soft reset, FQSPI_CMD_ENABLE_RESET and FQSPI_CMD_RESET.
|
||
* @param {FQspiCtrl} *pctrl, instance of FQSPI controller
|
||
* @return {FError} err code information, FQSPI_SUCCESS indicates success,others indicates failed
|
||
*/
|
||
static FError FQspiFlashReset(FQspiCtrl *pctrl)
|
||
{
|
||
FASSERT(pctrl);
|
||
FError ret = FQSPI_SUCCESS;
|
||
ret = FQspiFlashWriteReg(pctrl, FQSPI_CMD_ENABLE_RESET, NULL, 0);
|
||
if (FQSPI_SUCCESS != ret)
|
||
{
|
||
FQSPI_ERROR("Failed to enable reset, test result 0x%x\r\n", ret);
|
||
return ret;
|
||
}
|
||
|
||
ret = FQspiFlashWriteReg(pctrl, FQSPI_CMD_RESET, NULL, 0);
|
||
if (FQSPI_SUCCESS != ret)
|
||
{
|
||
FQSPI_ERROR("Failed to reset, test result 0x%x\r\n", ret);
|
||
return ret;
|
||
}
|
||
|
||
return ret;
|
||
}
|
||
|
||
/**
|
||
* @name: FQspiFlashSpecialInstruction
|
||
* @msg: Read some flash information by different cmd
|
||
* @param {FQspiCtrl} *pctrl, instance of FQSPI controller
|
||
* @param {u8} cmd, read register value command, include RDID, RDSR1, RDSR2, RDCR...
|
||
* @param {u8} *buf, read buffer
|
||
* @param {size_t} len, read length
|
||
* @return {FError} err code information, FQSPI_SUCCESS indicates success,others indicates failed
|
||
*/
|
||
FError FQspiFlashSpecialInstruction(FQspiCtrl *pctrl, u8 cmd, u8 *buf, size_t len)
|
||
{
|
||
FASSERT(pctrl && buf);
|
||
FError ret = FQSPI_SUCCESS;
|
||
if (FT_COMPONENT_IS_READY != pctrl->is_ready)
|
||
{
|
||
FQSPI_ERROR("Nor flash not ready !!!");
|
||
return FQSPI_NOT_READY;
|
||
}
|
||
|
||
uintptr base_addr = pctrl->config.base_addr;
|
||
|
||
memset(&pctrl->cmd_def, 0, sizeof(pctrl->cmd_def));
|
||
pctrl->cmd_def.cmd = cmd;
|
||
pctrl->cmd_def.wait = FQSPI_WAIT_DISABLE;
|
||
pctrl->cmd_def.through = 0;
|
||
pctrl->cmd_def.cs = pctrl->config.channel;
|
||
pctrl->cmd_def.transfer = FQSPI_TRANSFER_1_1_1;
|
||
pctrl->cmd_def.cmd_addr = FQSPI_CMD_ADDR_DISABLE;
|
||
pctrl->cmd_def.latency = FQSPI_CMD_LATENCY_DISABLE;
|
||
pctrl->cmd_def.data_transfer = FQSPI_CMD_DATA_ENABLE;
|
||
pctrl->cmd_def.addr_sel = FQSPI_ADDR_SEL_3;
|
||
pctrl->cmd_def.dummy = 0;
|
||
pctrl->cmd_def.p_buffer = FQSPI_USE_BUFFER_ENABLE;
|
||
pctrl->cmd_def.rw_num = (len - 1);
|
||
pctrl->cmd_def.sck_sel = FQSPI_SCK_DIV_128;
|
||
|
||
ret = FQspiCommandPortConfig(pctrl);
|
||
if (ret != FT_SUCCESS)
|
||
{
|
||
FQSPI_ERROR("FQspiFlashSpecialInstruction FQspiCommandPortConfig failed!");
|
||
return ret;
|
||
}
|
||
|
||
FQspiCommandPortSend(base_addr);
|
||
|
||
FQspiGetLdPortData(base_addr, buf, len);
|
||
|
||
return ret;
|
||
}
|
||
|
||
/**
|
||
* @name: FQspiFlashReadSfdp
|
||
* @msg: Read flash Serial Flash Discoverable Parameters
|
||
* @param {FQspiCtrl} *pctrl, instance of FQSPI controller
|
||
* @param {u32} offset,Relative Byte Address Offset
|
||
* @param {u8} *buf, read buffer
|
||
* @param {size_t} len, read length
|
||
* @return {FError} err code information, FQSPI_SUCCESS indicates success,others indicates failed
|
||
*/
|
||
FError FQspiFlashReadSfdp(FQspiCtrl *pctrl, u32 offset, u8 *buf, size_t len)
|
||
{
|
||
FASSERT(pctrl && buf);
|
||
FError ret = FQSPI_SUCCESS;
|
||
if (FT_COMPONENT_IS_READY != pctrl->is_ready)
|
||
{
|
||
FQSPI_ERROR("Nor flash not ready !!!");
|
||
return FQSPI_NOT_READY;
|
||
}
|
||
|
||
uintptr base_addr = pctrl->config.base_addr;
|
||
|
||
memset(&pctrl->cmd_def, 0, sizeof(pctrl->cmd_def));
|
||
pctrl->cmd_def.cmd = FQSPI_FLASH_CMD_SFDP;
|
||
pctrl->cmd_def.wait = FQSPI_WAIT_DISABLE;
|
||
pctrl->cmd_def.through = 0;
|
||
pctrl->cmd_def.cs = pctrl->config.channel;
|
||
pctrl->cmd_def.transfer = FQSPI_TRANSFER_1_1_1;
|
||
pctrl->cmd_def.cmd_addr = FQSPI_CMD_ADDR_ENABLE;
|
||
pctrl->cmd_def.latency = FQSPI_CMD_LATENCY_ENABLE;
|
||
pctrl->cmd_def.data_transfer = FQSPI_CMD_DATA_ENABLE;
|
||
pctrl->cmd_def.addr_sel = FQSPI_ADDR_SEL_3;
|
||
pctrl->cmd_def.dummy = 8;
|
||
pctrl->cmd_def.p_buffer = FQSPI_USE_BUFFER_ENABLE;
|
||
pctrl->cmd_def.rw_num = (len - 1);
|
||
pctrl->cmd_def.sck_sel = FQSPI_SCK_DIV_128;
|
||
|
||
ret = FQspiCommandPortConfig(pctrl);
|
||
if (ret != FT_SUCCESS)
|
||
{
|
||
FQSPI_ERROR("FQspiFlashReadSfdp FQspiCommandPortConfig failed!");
|
||
return ret;
|
||
}
|
||
|
||
/* write addr port register */
|
||
FQspiAddrPortConfig(base_addr, offset);
|
||
|
||
FQspiCommandPortSend(base_addr);
|
||
|
||
FQspiGetLdPortData(base_addr, buf, len);
|
||
|
||
return ret;
|
||
}
|
||
|
||
/**
|
||
* @name: FQspiFlashReadReg
|
||
* @msg: Read Qspi register value
|
||
* @param {FQspiCtrl} *pctrl, instance of FQSPI controller
|
||
* @param {u32} offset,Relative Byte Address Offset
|
||
* @param {u8} *buf, read buffer
|
||
* @param {size_t} len, read length
|
||
* @return {FError} err code information, FQSPI_SUCCESS indicates success,others indicates failed
|
||
*/
|
||
FError FQspiFlashReadReg(FQspiCtrl *pctrl, u32 offset, u8 *buf, size_t len)
|
||
{
|
||
FASSERT(pctrl && buf);
|
||
FError ret = FQSPI_SUCCESS;
|
||
u32 cmd_reg = 0;
|
||
uintptr base_addr = pctrl->config.base_addr;
|
||
|
||
if (FT_COMPONENT_IS_READY != pctrl->is_ready)
|
||
{
|
||
FQSPI_ERROR("Nor flash not ready !!!");
|
||
return FQSPI_NOT_READY;
|
||
}
|
||
|
||
memset(&pctrl->cmd_def, 0, sizeof(pctrl->cmd_def));
|
||
pctrl->cmd_def.cmd = FQSPI_FLASH_CMD_RDAR;
|
||
pctrl->cmd_def.wait = FQSPI_WAIT_DISABLE;
|
||
pctrl->cmd_def.through = 0;
|
||
pctrl->cmd_def.cs = pctrl->config.channel;
|
||
pctrl->cmd_def.transfer = FQSPI_TRANSFER_1_1_1;
|
||
pctrl->cmd_def.cmd_addr = FQSPI_CMD_ADDR_ENABLE;
|
||
pctrl->cmd_def.latency = FQSPI_CMD_LATENCY_ENABLE;
|
||
pctrl->cmd_def.data_transfer = FQSPI_CMD_DATA_ENABLE;
|
||
pctrl->cmd_def.addr_sel = FQSPI_ADDR_SEL_3;
|
||
pctrl->cmd_def.dummy = 8;
|
||
pctrl->cmd_def.p_buffer = FQSPI_USE_BUFFER_ENABLE;
|
||
pctrl->cmd_def.rw_num = (len - 1);
|
||
pctrl->cmd_def.sck_sel = FQSPI_SCK_DIV_128;
|
||
|
||
ret = FQspiCommandPortConfig(pctrl);
|
||
if (ret != FT_SUCCESS)
|
||
{
|
||
FQSPI_ERROR("FQspiFlashReadReg FQspiCommandPortConfig failed!");
|
||
return ret;
|
||
}
|
||
|
||
/* write addr port register */
|
||
FQspiAddrPortConfig(base_addr, offset);
|
||
|
||
FQspiCommandPortSend(base_addr);
|
||
|
||
FQspiGetLdPortData(base_addr, buf, len);
|
||
|
||
/* wait SR1V bit0 WIP is ready, not device busy */
|
||
ret = FQspiFlashWaitForCmd(pctrl);
|
||
if (ret != FT_SUCCESS)
|
||
{
|
||
FQSPI_ERROR("FQspiFlashReadReg FQspiCommandPortConfig failed!");
|
||
return ret;
|
||
}
|
||
|
||
return ret;
|
||
}
|
||
|
||
/**
|
||
* @name: FQspiFlashReadData
|
||
* @msg: read flash data
|
||
* @param {FQspiCtrl} *pctrl, instance of FQSPI controller
|
||
* @param {u32} chip_addr, The start address of the chip to read
|
||
* @param {u8} *buf, read buffer
|
||
* @param {size_t} len, read length
|
||
* @return size_t Indicates the length of the data read, zero indicates read fails
|
||
*/
|
||
size_t FQspiFlashReadData(FQspiCtrl *pctrl, u32 chip_addr, u8 *buf, size_t len)
|
||
{
|
||
/* addr of copy dst or src might be zero */
|
||
FASSERT(pctrl && buf);
|
||
size_t loop = 0;
|
||
const size_t cnt = len / FQSPI_ALIGNED_BYTE; /* cnt number of 4-bytes need copy */
|
||
const size_t remain = len % FQSPI_ALIGNED_BYTE; /* remain number of 1-byte not aligned */
|
||
u8 align_buf[FQSPI_ALIGNED_BYTE];
|
||
size_t copy_len = 0;
|
||
u32 addr = pctrl->config.mem_start + pctrl->config.channel * pctrl->flash_size + chip_addr;
|
||
intptr src_addr = (intptr)addr; /* conver to 32/64 bit addr */
|
||
intptr dst_addr = (intptr)buf;
|
||
|
||
if (FT_COMPONENT_IS_READY != pctrl->is_ready)
|
||
{
|
||
FQSPI_ERROR("Nor flash not ready !!!");
|
||
return 0;
|
||
}
|
||
if (0 == pctrl->rd_cfg.rd_cmd)
|
||
{
|
||
FQSPI_ERROR("Nor flash read command is not ready !!!");
|
||
return 0;
|
||
}
|
||
|
||
if (0 == len)
|
||
{
|
||
return 0;
|
||
}
|
||
|
||
if (IS_ALIGNED(src_addr, FQSPI_ALIGNED_BYTE)) /* if copy src is aligned by 4 bytes */
|
||
{
|
||
/* read 4-bytes aligned buf part */
|
||
for (loop = 0; loop < cnt; loop++)
|
||
{
|
||
*(u32 *)dst_addr = *(volatile u32 *)(src_addr);
|
||
src_addr += FQSPI_ALIGNED_BYTE;
|
||
dst_addr += FQSPI_ALIGNED_BYTE;
|
||
}
|
||
|
||
copy_len += (loop << 2);
|
||
|
||
if (remain > 0)
|
||
{
|
||
*(u32 *)align_buf = *(volatile u32 *)(src_addr);
|
||
}
|
||
|
||
/* read remain un-aligned buf byte by byte */
|
||
for (loop = 0; loop < remain; loop++)
|
||
{
|
||
*(u8 *)dst_addr = align_buf[loop];
|
||
dst_addr += 1;
|
||
}
|
||
|
||
copy_len += loop;
|
||
|
||
}
|
||
else /* if copy src is not aligned */
|
||
{
|
||
/* read byte by byte */
|
||
for (loop = 0; loop < len; loop++)
|
||
{
|
||
*(u8 *)dst_addr = *(volatile u8 *)(src_addr);
|
||
dst_addr += 1;
|
||
src_addr += 1;
|
||
}
|
||
copy_len += loop;
|
||
|
||
}
|
||
|
||
return copy_len;
|
||
}
|
||
|
||
/**
|
||
* @name: FQspiFlashReadDataConfig
|
||
* @msg: read flash data configuration
|
||
* @param {FQspiCtrl} *pctrl, instance of FQSPI controller
|
||
* @param {u8} command, command to read flash,see the Flash manual for details
|
||
* @return {FError} err code information, FQSPI_SUCCESS indicates success,others indicates failed 表示配置成功,其它返回值表示配置失败
|
||
*/
|
||
FError FQspiFlashReadDataConfig(FQspiCtrl *pctrl, u8 command)
|
||
{
|
||
FASSERT(pctrl);
|
||
FError ret = FQSPI_SUCCESS;
|
||
|
||
if (FT_COMPONENT_IS_READY != pctrl->is_ready)
|
||
{
|
||
FQSPI_ERROR("Nor flash not ready !!!");
|
||
ret |= FQSPI_NOT_READY;
|
||
return ret;
|
||
}
|
||
|
||
uintptr base_addr = pctrl->config.base_addr;
|
||
|
||
/* clear sr1 = 0, set config register1 bit1 quad = 1 */
|
||
u8 wrr_buf[2] = {0x0, 0x02};
|
||
|
||
FQspiXIPModeSet(base_addr, FQSPI_XIP_ENTER);
|
||
|
||
/* set cmd region, command */
|
||
memset(&pctrl->rd_cfg, 0, sizeof(pctrl->rd_cfg));
|
||
pctrl->rd_cfg.rd_cmd = command;
|
||
|
||
/* read buffer */
|
||
pctrl->rd_cfg.d_buffer = FQSPI_USE_BUFFER_ENABLE;
|
||
pctrl->rd_cfg.rd_sck_sel = FQSPI_SCK_DIV_128;
|
||
|
||
switch (command)
|
||
{
|
||
case FQSPI_FLASH_CMD_READ:
|
||
FQspiFlashReset(pctrl);
|
||
pctrl->rd_cfg.rd_addr_sel = FQSPI_ADDR_SEL_3;
|
||
pctrl->rd_cfg.rd_transfer = FQSPI_TRANSFER_1_1_1;
|
||
break;
|
||
|
||
case FQSPI_FLASH_CMD_4READ:
|
||
pctrl->rd_cfg.rd_addr_sel = FQSPI_ADDR_SEL_4;
|
||
pctrl->rd_cfg.rd_transfer = FQSPI_TRANSFER_1_1_1;
|
||
break;
|
||
|
||
case FQSPI_FLASH_CMD_FAST_READ:
|
||
pctrl->rd_cfg.rd_addr_sel = FQSPI_ADDR_SEL_3;
|
||
pctrl->rd_cfg.rd_transfer = FQSPI_TRANSFER_1_1_1;
|
||
pctrl->rd_cfg.dummy = 8;
|
||
pctrl->rd_cfg.rd_latency = FQSPI_CMD_LATENCY_ENABLE;
|
||
break;
|
||
|
||
case FQSPI_FLASH_CMD_4FAST_READ:
|
||
pctrl->rd_cfg.rd_addr_sel = FQSPI_ADDR_SEL_4;
|
||
pctrl->rd_cfg.rd_transfer = FQSPI_TRANSFER_1_1_1;
|
||
pctrl->rd_cfg.dummy = 8;
|
||
pctrl->rd_cfg.rd_latency = FQSPI_CMD_LATENCY_ENABLE;
|
||
break;
|
||
|
||
case FQSPI_FLASH_CMD_DOR:
|
||
pctrl->rd_cfg.rd_addr_sel = FQSPI_ADDR_SEL_3;
|
||
pctrl->rd_cfg.rd_transfer = FQSPI_TRANSFER_1_1_2;
|
||
pctrl->rd_cfg.dummy = 8;
|
||
pctrl->rd_cfg.rd_latency = FQSPI_CMD_LATENCY_ENABLE;
|
||
break;
|
||
|
||
case FQSPI_FLASH_CMD_QOR:
|
||
pctrl->rd_cfg.rd_addr_sel = FQSPI_ADDR_SEL_3;
|
||
pctrl->rd_cfg.rd_transfer = FQSPI_TRANSFER_1_1_4;
|
||
pctrl->rd_cfg.dummy = 8;
|
||
pctrl->rd_cfg.rd_latency = FQSPI_CMD_LATENCY_ENABLE;
|
||
break;
|
||
|
||
case FQSPI_FLASH_CMD_QWFR:
|
||
pctrl->rd_cfg.rd_addr_sel = FQSPI_ADDR_SEL_3;
|
||
pctrl->rd_cfg.rd_transfer = FQSPI_TRANSFER_1_4_4;
|
||
pctrl->rd_cfg.dummy = 2;
|
||
pctrl->rd_cfg.rd_latency = FQSPI_CMD_LATENCY_ENABLE;
|
||
break;
|
||
|
||
case FQSPI_FLASH_CMD_DUAL_READ:
|
||
pctrl->rd_cfg.rd_addr_sel = FQSPI_ADDR_SEL_3;
|
||
pctrl->rd_cfg.rd_transfer = FQSPI_TRANSFER_1_2_2;
|
||
pctrl->rd_cfg.rd_latency = FQSPI_CMD_LATENCY_ENABLE;
|
||
|
||
if (pctrl->mf_id == FQSPI_FLASH_MF_ID_CYPRESS)
|
||
{
|
||
pctrl->rd_cfg.mode_byte = 0x1;
|
||
pctrl->rd_cfg.cmd_sign = FQSPI_QUAD_READ_MODE_CMD;
|
||
pctrl->rd_cfg.dummy = 8;
|
||
}
|
||
else if (pctrl->mf_id == FQSPI_FLASH_MF_ID_GIGADEVICE)
|
||
{
|
||
pctrl->rd_cfg.dummy = 4;
|
||
}
|
||
else if (pctrl->mf_id == FQSPI_FLASH_MF_ID_BOYA)
|
||
{
|
||
pctrl->rd_cfg.dummy = 4;
|
||
}
|
||
break;
|
||
|
||
case FQSPI_FLASH_CMD_QIOR:
|
||
/* set SR1V and CR1V */
|
||
FQspiFlashEnableWrite(pctrl);
|
||
|
||
pctrl->rd_cfg.rd_addr_sel = FQSPI_ADDR_SEL_3;
|
||
pctrl->rd_cfg.rd_transfer = FQSPI_TRANSFER_1_4_4;
|
||
pctrl->rd_cfg.rd_latency = FQSPI_CMD_LATENCY_ENABLE;
|
||
|
||
if (pctrl->mf_id == FQSPI_FLASH_MF_ID_CYPRESS)
|
||
{
|
||
pctrl->rd_cfg.dummy = 10;
|
||
/* use wrr write config register 1 */
|
||
ret = FQspiFlashWriteReg(pctrl, FQSPI_FLASH_CMD_WRR, wrr_buf, sizeof(wrr_buf));
|
||
if (FQSPI_SUCCESS != ret)
|
||
{
|
||
FQSPI_ERROR("Failed to write cmd wrr, test result 0x%x", ret);
|
||
return 0;
|
||
}
|
||
}
|
||
else if (pctrl->mf_id == FQSPI_FLASH_MF_ID_GIGADEVICE)
|
||
{
|
||
pctrl->rd_cfg.dummy = 6;
|
||
/* use wrr write config register 1 */
|
||
ret = FQspiFlashWriteReg(pctrl, FQSPI_FLASH_CMD_WRR, wrr_buf, sizeof(wrr_buf));
|
||
if (FQSPI_SUCCESS != ret)
|
||
{
|
||
FQSPI_ERROR("Failed to write cmd wrr, test result 0x%x", ret);
|
||
return 0;
|
||
}
|
||
}
|
||
else if (pctrl->mf_id == FQSPI_FLASH_MF_ID_BOYA)
|
||
{
|
||
pctrl->rd_cfg.dummy = 6;
|
||
ret = FQspiFlashWriteReg(pctrl, FQSPI_FLASH_CMD_WRITE_SR2, &wrr_buf[1], 1);
|
||
if (FQSPI_SUCCESS != ret)
|
||
{
|
||
FQSPI_ERROR("Failed to write cmd wrr, test result 0x%x", ret);
|
||
return 0;
|
||
}
|
||
}
|
||
|
||
break;
|
||
|
||
case FQSPI_FLASH_CMD_4QIOR:
|
||
pctrl->rd_cfg.rd_addr_sel = FQSPI_ADDR_SEL_4;
|
||
pctrl->rd_cfg.rd_transfer = FQSPI_TRANSFER_1_4_4;
|
||
pctrl->rd_cfg.mode_byte = 0x1;
|
||
pctrl->rd_cfg.cmd_sign = FQSPI_QUAD_READ_MODE_CMD;
|
||
pctrl->rd_cfg.rd_latency = FQSPI_CMD_LATENCY_ENABLE;
|
||
pctrl->rd_cfg.dummy = 8;
|
||
|
||
/* set SR1V and CR1V */
|
||
FQspiFlashEnableWrite(pctrl);
|
||
/* use wrr write config register 1 */
|
||
ret = FQspiFlashWriteReg(pctrl, FQSPI_FLASH_CMD_WRR, wrr_buf, sizeof(wrr_buf));
|
||
if (FQSPI_SUCCESS != ret)
|
||
{
|
||
FQSPI_ERROR("Failed to write cmd wrr, test result 0x%x\r\n", ret);
|
||
return ret;
|
||
}
|
||
break;
|
||
|
||
default:
|
||
return FQSPI_INVAL_PARAM;
|
||
break;
|
||
}
|
||
|
||
ret = FQspiRdCfgConfig(pctrl);
|
||
|
||
return ret;
|
||
}
|
||
|
||
/**
|
||
* @name: FQspiFlashWriteData
|
||
* @msg: write flash data
|
||
* @param {FQspiCtrl} *pctrl, instance of FQSPI controller
|
||
* @param {u8} command, command to write flash,see the Flash manual for details
|
||
* @param {u32} chip_addr, The start address of the chip to write
|
||
* @param {u8} *buf, write buffer
|
||
* @param {size_t} len, write length
|
||
* @return {FError} err code information, FQSPI_SUCCESS indicates success,others indicates failed 表示写入成功,其它返回值表示写入失败
|
||
*/
|
||
FError FQspiFlashWriteData(FQspiCtrl *pctrl, u8 command, u32 chip_addr, const u8 *buf, size_t len)
|
||
{
|
||
FASSERT(pctrl && buf);
|
||
FError ret = FQSPI_SUCCESS;
|
||
u32 loop = 0;
|
||
const u32 mask = (u32)GENMASK(1, 0);
|
||
u32 reg_val = 0;
|
||
u32 val = 0;
|
||
u32 aligned_bit = 0;
|
||
|
||
u8 tmp[FQSPI_ALIGNED_BYTE] = {0xff, 0xff, 0xff, 0xff};
|
||
u32 addr = pctrl->config.mem_start + pctrl->config.channel * pctrl->flash_size + chip_addr;
|
||
uintptr base_addr = pctrl->config.base_addr;
|
||
|
||
if (FT_COMPONENT_IS_READY != pctrl->is_ready)
|
||
{
|
||
FQSPI_ERROR("Nor flash not ready !!!");
|
||
return FQSPI_NOT_READY;
|
||
}
|
||
|
||
/* Flash write enable */
|
||
FQspiFlashEnableWrite(pctrl);
|
||
|
||
memset(&pctrl->wr_cfg, 0, sizeof(pctrl->wr_cfg));
|
||
/* set cmd region, command */
|
||
pctrl->wr_cfg.wr_cmd = command;
|
||
pctrl->wr_cfg.wr_wait = FQSPI_WAIT_ENABLE;
|
||
/* clear addr select bit */
|
||
pctrl->wr_cfg.wr_addr_sel = 0;
|
||
/* set wr mode, use buffer */
|
||
pctrl->wr_cfg.wr_mode = FQSPI_USE_BUFFER_ENABLE;
|
||
/* set sck_sel region, clk_div */
|
||
pctrl->wr_cfg.wr_sck_sel = FQSPI_SCK_DIV_128;
|
||
|
||
/* set addr_sel region, FQSPI_ADDR_SEL_3 or FQSPI_ADDR_SEL_4 */
|
||
switch (command)
|
||
{
|
||
case FQSPI_FLASH_CMD_PP:
|
||
case FQSPI_FLASH_CMD_QPP:
|
||
pctrl->wr_cfg.wr_addr_sel = FQSPI_ADDR_SEL_3;
|
||
break;
|
||
case FQSPI_FLASH_CMD_4PP:
|
||
case FQSPI_FLASH_CMD_4QPP:
|
||
pctrl->wr_cfg.wr_addr_sel = FQSPI_ADDR_SEL_4;
|
||
break;
|
||
default:
|
||
ret |= FQSPI_NOT_SUPPORT;
|
||
return ret;
|
||
break;
|
||
}
|
||
|
||
/*write wr_cfg to Write config register 0x08 */
|
||
FQspiWrCfgConfig(pctrl);
|
||
|
||
if (IS_ALIGNED(addr, FQSPI_ALIGNED_BYTE)) /* if copy src is aligned by 4 bytes */
|
||
{
|
||
/* write alligned data into memory space */
|
||
for (loop = 0; loop < (len >> 2); loop++)
|
||
{
|
||
FQSPI_DAT_WRITE(addr + FQSPI_ALIGNED_BYTE * loop, *(u32 *)(buf + FQSPI_ALIGNED_BYTE * loop));
|
||
}
|
||
/* write not alligned data into memory space */
|
||
if (len & mask)
|
||
{
|
||
addr = addr + (len & ~mask);
|
||
memcpy(tmp, buf + (len & ~mask), len & mask);
|
||
FQSPI_DAT_WRITE(addr, *(u32 *)(tmp));
|
||
}
|
||
}
|
||
else
|
||
{
|
||
aligned_bit = (addr & mask);
|
||
addr = addr - aligned_bit;
|
||
reg_val = FQSPI_READ_REG32(addr, 0);
|
||
|
||
for (loop = 0; loop < (FQSPI_ALIGNED_BYTE - aligned_bit); loop++)
|
||
{
|
||
val = (val << 8) | (buf[loop]);
|
||
reg_val &= (~(0xff << (loop * 8)));
|
||
}
|
||
|
||
reg_val |= val;
|
||
reg_val = __builtin_bswap32(reg_val);
|
||
FQSPI_DAT_WRITE(addr, reg_val);
|
||
|
||
buf = buf + loop;
|
||
len = len - loop;
|
||
addr = addr + FQSPI_ALIGNED_BYTE;
|
||
|
||
FQSPI_DEBUG("addr=%p, buf=%p, len=%d, value=%#x\r\n", addr, buf, len, *(u32 *)(buf));
|
||
|
||
for (loop = 0; loop < (len >> 2); loop++)
|
||
{
|
||
FQSPI_DAT_WRITE(addr + FQSPI_ALIGNED_BYTE * loop, *(u32 *)(buf + FQSPI_ALIGNED_BYTE * loop));
|
||
}
|
||
|
||
if (!IS_ALIGNED(len, FQSPI_ALIGNED_BYTE))
|
||
{
|
||
buf = buf + FQSPI_ALIGNED_BYTE * loop;
|
||
len = len - FQSPI_ALIGNED_BYTE * loop;
|
||
addr = addr + FQSPI_ALIGNED_BYTE * loop;
|
||
memcpy(tmp, buf, len);
|
||
FQSPI_DAT_WRITE(addr, *(u32 *)(tmp));
|
||
}
|
||
}
|
||
|
||
/* flush buffer data to Flash */
|
||
FQspiWriteFlush(base_addr);
|
||
|
||
ret = FQspiFlashWaitForCmd(pctrl);
|
||
|
||
return ret;
|
||
}
|
||
|
||
/**
|
||
* @name: FQspiFlashPortReadData
|
||
* @msg: read flash data use register port
|
||
* @param {FQspiCtrl} *pctrl, instance of FQSPI controller
|
||
* @param {u8} cmd, command to read flash,see the Flash manual for details
|
||
* @param {u32} chip_addr, The start address of the chip to read
|
||
* @param {u8} *buf, read buffer
|
||
* @param {size_t} len, read length
|
||
* @return {FError} err code information, FQSPI_SUCCESS indicates success,others indicates failed
|
||
*/
|
||
FError FQspiFlashPortReadData(FQspiCtrl *pctrl, u8 cmd, u32 chip_addr, u8 *buf, size_t len)
|
||
{
|
||
FASSERT(pctrl && buf);
|
||
if (FT_COMPONENT_IS_READY != pctrl->is_ready)
|
||
{
|
||
FQSPI_ERROR("Nor flash not ready !!!");
|
||
return FQSPI_NOT_READY;
|
||
}
|
||
|
||
FError ret = FQSPI_SUCCESS;
|
||
u32 addr = chip_addr + pctrl->config.channel * pctrl->flash_size;
|
||
uintptr base_addr = pctrl->config.base_addr;
|
||
|
||
FQspiXIPModeSet(base_addr, FQSPI_XIP_EXIT);
|
||
|
||
memset(&pctrl->cmd_def, 0, sizeof(pctrl->cmd_def));
|
||
pctrl->cmd_def.cmd = cmd;
|
||
pctrl->cmd_def.wait = FQSPI_WAIT_ENABLE;
|
||
pctrl->cmd_def.through = 0;
|
||
pctrl->cmd_def.cs = pctrl->config.channel;
|
||
pctrl->cmd_def.transfer = FQSPI_TRANSFER_1_1_1;
|
||
pctrl->cmd_def.cmd_addr = FQSPI_CMD_ADDR_ENABLE;
|
||
pctrl->cmd_def.latency = FQSPI_CMD_LATENCY_DISABLE;
|
||
pctrl->cmd_def.data_transfer = FQSPI_CMD_DATA_ENABLE;
|
||
pctrl->cmd_def.addr_sel = FQSPI_ADDR_SEL_3;
|
||
pctrl->cmd_def.dummy = 0;
|
||
pctrl->cmd_def.p_buffer = FQSPI_USE_BUFFER_ENABLE;
|
||
pctrl->cmd_def.rw_num = (len - 1);
|
||
pctrl->cmd_def.sck_sel = FQSPI_SCK_DIV_128;
|
||
|
||
ret = FQspiCommandPortConfig(pctrl);
|
||
if (ret != FT_SUCCESS)
|
||
{
|
||
FQSPI_ERROR("FQspiFlashPortReadData FQspiCommandPortConfig failed!");
|
||
return ret;
|
||
}
|
||
|
||
/* write addr port register */
|
||
FQspiAddrPortConfig(base_addr, addr);
|
||
|
||
FQspiCommandPortSend(base_addr);
|
||
|
||
FQspiGetLdPortData(base_addr, buf, len);
|
||
|
||
/* wait SR1V bit0 WIP is ready, not device busy */
|
||
ret = FQspiFlashWaitForCmd(pctrl);
|
||
|
||
return ret;
|
||
}
|
||
|
||
/**
|
||
* @name: FQspiFlashPortWriteData
|
||
* @msg: write flash data use register port
|
||
* @param {FQspiCtrl} *pctrl, instance of FQSPI controller
|
||
* @param {u8} cmd, command to write flash,see the Flash manual for details
|
||
* @param {u32} chip_addr, The start address of the chip to write
|
||
* @param {u8} *buf, write buffer
|
||
* @param {size_t} len, write length
|
||
* @return {FError} err code information, FQSPI_SUCCESS indicates success,others indicates failed
|
||
*/
|
||
FError FQspiFlashPortWriteData(FQspiCtrl *pctrl, u8 cmd, u32 chip_addr, u8 *buf, size_t len)
|
||
{
|
||
FASSERT(pctrl && buf);
|
||
FASSERT(len <= FQSPI_CMD_PORT_CMD_RW_MAX);
|
||
|
||
if (FT_COMPONENT_IS_READY != pctrl->is_ready)
|
||
{
|
||
FQSPI_ERROR("Nor flash not ready !!!");
|
||
return FQSPI_NOT_READY;
|
||
}
|
||
|
||
FError ret = FQSPI_SUCCESS;
|
||
u32 addr = chip_addr + pctrl->config.channel * pctrl->flash_size;
|
||
uintptr base_addr = pctrl->config.base_addr;
|
||
|
||
/* Flash write enable */
|
||
FQspiFlashEnableWrite(pctrl);
|
||
|
||
memset(&pctrl->cmd_def, 0, sizeof(pctrl->cmd_def));
|
||
pctrl->cmd_def.cmd = cmd;
|
||
pctrl->cmd_def.wait = FQSPI_WAIT_ENABLE;
|
||
pctrl->cmd_def.through = 0;
|
||
pctrl->cmd_def.cs = pctrl->config.channel;
|
||
pctrl->cmd_def.transfer = FQSPI_TRANSFER_1_1_1;
|
||
pctrl->cmd_def.cmd_addr = FQSPI_CMD_ADDR_ENABLE;
|
||
pctrl->cmd_def.latency = FQSPI_CMD_LATENCY_DISABLE;
|
||
pctrl->cmd_def.data_transfer = FQSPI_CMD_DATA_ENABLE;
|
||
pctrl->cmd_def.addr_sel = FQSPI_ADDR_SEL_3;
|
||
pctrl->cmd_def.dummy = 0;
|
||
pctrl->cmd_def.p_buffer = FQSPI_USE_BUFFER_DISABLE;
|
||
pctrl->cmd_def.rw_num = (len - 1);
|
||
pctrl->cmd_def.sck_sel = FQSPI_SCK_DIV_128;
|
||
|
||
/*write cmd_reg to Command port register 0x10 */
|
||
ret = FQspiCommandPortConfig(pctrl);
|
||
if (ret != FT_SUCCESS)
|
||
{
|
||
FQSPI_ERROR("FQspiFlashPortWriteData FQspiCommandPortConfig failed!");
|
||
return ret;
|
||
}
|
||
|
||
/* write addr port register */
|
||
FQspiAddrPortConfig(base_addr, addr);
|
||
|
||
FQspiSetLdPortData(base_addr, buf, len);
|
||
|
||
/* wait SR1V bit0 WIP is ready, not device busy */
|
||
ret = FQspiFlashWaitForCmd(pctrl);
|
||
|
||
return ret;
|
||
}
|
||
|
||
|
||
/**
|
||
* @name: FQspiFlashErase
|
||
* @msg: erase flash data
|
||
* @param {FQspiCtrl} *pctrl, instance of FQSPI controller
|
||
* @param {u8} command, command to erase flash, see the Flash manual for details
|
||
* @param {u32} offset,Relative Byte Address Offset
|
||
* @return {FError} err code information, FQSPI_SUCCESS indicates success,others indicates failed 表示擦除成功,其它返回值表示擦除失败
|
||
*/
|
||
FError FQspiFlashErase(FQspiCtrl *pctrl, u8 command, u32 offset)
|
||
{
|
||
FASSERT(pctrl);
|
||
FError ret = FQSPI_SUCCESS;
|
||
if (FT_COMPONENT_IS_READY != pctrl->is_ready)
|
||
{
|
||
FQSPI_ERROR("Nor flash not ready !!!");
|
||
return FQSPI_NOT_READY;
|
||
}
|
||
|
||
uintptr base_addr = pctrl->config.base_addr;
|
||
|
||
/* Flash write enable */
|
||
FQspiFlashEnableWrite(pctrl);
|
||
|
||
memset(&pctrl->cmd_def, 0, sizeof(pctrl->cmd_def));
|
||
pctrl->cmd_def.cmd = command;
|
||
pctrl->cmd_def.cs = pctrl->config.channel;
|
||
pctrl->cmd_def.sck_sel = FQSPI_SCK_DIV_128;
|
||
|
||
switch (command)
|
||
{
|
||
case FQSPI_FLASH_CMD_SE:
|
||
/* set addr_sel region, FQSPI_ADDR_SEL_3 or FQSPI_ADDR_SEL_4 */
|
||
pctrl->cmd_def.addr_sel = FQSPI_ADDR_SEL_3;
|
||
|
||
/* set cmd_addr region, by command, have addr transfer */
|
||
pctrl->cmd_def.cmd_addr = FQSPI_CMD_ADDR_ENABLE;
|
||
|
||
/* need some execution time */
|
||
pctrl->cmd_def.wait = FQSPI_WAIT_ENABLE;
|
||
|
||
break;
|
||
case FQSPI_FLASH_CMD_4SE:
|
||
pctrl->cmd_def.addr_sel = FQSPI_ADDR_SEL_4;
|
||
pctrl->cmd_def.cmd_addr = FQSPI_CMD_ADDR_ENABLE;
|
||
pctrl->cmd_def.wait = FQSPI_WAIT_ENABLE;
|
||
|
||
break;
|
||
case FQSPI_FLASH_CMD_P4E:
|
||
pctrl->cmd_def.addr_sel = FQSPI_ADDR_SEL_3;
|
||
pctrl->cmd_def.cmd_addr = FQSPI_CMD_ADDR_ENABLE;
|
||
|
||
break;
|
||
case FQSPI_FLASH_CMD_4P4E:
|
||
pctrl->cmd_def.addr_sel = FQSPI_ADDR_SEL_4;
|
||
pctrl->cmd_def.cmd_addr = FQSPI_CMD_ADDR_ENABLE;
|
||
|
||
break;
|
||
case FQSPI_FLASH_CMD_BE:
|
||
pctrl->cmd_def.addr_sel = FQSPI_ADDR_SEL_3;
|
||
break;
|
||
case FQSPI_FLASH_CMD_4BE:
|
||
pctrl->cmd_def.addr_sel = FQSPI_ADDR_SEL_3;
|
||
break;
|
||
default:
|
||
return FQSPI_NOT_SUPPORT;
|
||
}
|
||
|
||
/*write cmd_reg to Command port register 0x10 */
|
||
ret = FQspiCommandPortConfig(pctrl);
|
||
if (ret != FT_SUCCESS)
|
||
{
|
||
FQSPI_ERROR("FQspiFlashErase FQspiCommandPortConfig failed!");
|
||
return ret;
|
||
}
|
||
|
||
/* set addr port register, specify addr transfer */
|
||
FQspiAddrPortConfig(base_addr, offset);
|
||
|
||
/*write value to low bit port register 0x1c, make command valid */
|
||
FQspiCommandPortSend(base_addr);
|
||
|
||
/* wait command perform end */
|
||
ret = FQspiFlashWaitForCmd(pctrl);
|
||
|
||
return ret;
|
||
}
|
||
|
||
/**
|
||
* @name: FQspiFlashEnableWrite
|
||
* @msg: Flash write enable
|
||
* @param {FQspiCtrl} *pctrl, instance of FQSPI controller
|
||
* @return {FError} err code information, FQSPI_SUCCESS indicates success,others indicates failed 表示执行成功,其它返回值表示执行失败
|
||
*/
|
||
FError FQspiFlashEnableWrite(FQspiCtrl *pctrl)
|
||
{
|
||
FASSERT(pctrl);
|
||
FError ret = FQSPI_SUCCESS;
|
||
u32 timeout = FQSPI_BUSY_TIMEOUT_US;
|
||
|
||
if (FT_COMPONENT_IS_READY != pctrl->is_ready)
|
||
{
|
||
FQSPI_ERROR("Nor flash not ready !!!");
|
||
return FQSPI_NOT_READY;
|
||
}
|
||
uintptr base_addr = pctrl->config.base_addr;
|
||
|
||
memset(&pctrl->cmd_def, 0, sizeof(pctrl->cmd_def));
|
||
pctrl->cmd_def.cmd = FQSPI_FLASH_CMD_WREN;
|
||
pctrl->cmd_def.cs = pctrl->config.channel;
|
||
pctrl->cmd_def.sck_sel = FQSPI_SCK_DIV_128;
|
||
|
||
/*write cmd_reg to Command port register 0x10 */
|
||
ret = FQspiCommandPortConfig(pctrl);
|
||
if (ret != FT_SUCCESS)
|
||
{
|
||
FQSPI_ERROR("FQspiFlashEnableWrite FQspiCommandPortConfig failed!");
|
||
return ret;
|
||
}
|
||
|
||
/*write value to low bit port register 0x1c, make command valid */
|
||
FQspiCommandPortSend(base_addr);
|
||
|
||
/* wait SR1V bit0 WIP is ready, not device busy */
|
||
ret = FQspiFlashWaitForCmd(pctrl);
|
||
|
||
return ret;
|
||
}
|
||
|
||
/**
|
||
* @name: FQspiFlashDisableWrite
|
||
* @msg: Flash write disable
|
||
* @param {FQspiCtrl} *pctrl, instance of FQSPI controller
|
||
* @return {FError} err code information, FQSPI_SUCCESS indicates success,others indicates failed 表示执行成功,其它返回值表示执行失败
|
||
*/
|
||
FError FQspiFlashDisableWrite(FQspiCtrl *pctrl)
|
||
{
|
||
FASSERT(pctrl);
|
||
FError ret = FQSPI_SUCCESS;
|
||
if (FT_COMPONENT_IS_READY != pctrl->is_ready)
|
||
{
|
||
FQSPI_ERROR("Nor flash not ready !!!");
|
||
return FQSPI_NOT_READY;
|
||
}
|
||
uintptr base_addr = pctrl->config.base_addr;
|
||
|
||
memset(&pctrl->cmd_def, 0, sizeof(pctrl->cmd_def));
|
||
pctrl->cmd_def.cmd = FQSPI_FLASH_CMD_WRDI;
|
||
pctrl->cmd_def.cs = pctrl->config.channel;
|
||
pctrl->cmd_def.sck_sel = FQSPI_SCK_DIV_128;
|
||
|
||
/*write cmd_reg to Command port register 0x10 */
|
||
ret = FQspiCommandPortConfig(pctrl);
|
||
if (ret != FT_SUCCESS)
|
||
{
|
||
FQSPI_ERROR("FQspiFlashDisableWrite FQspiCommandPortConfig failed!");
|
||
return ret;
|
||
}
|
||
|
||
/*write value to low bit port register 0x1c, make command valid */
|
||
FQspiCommandPortSend(base_addr);
|
||
|
||
return ret;
|
||
}
|
||
|
||
/**
|
||
* @name: FQspiFlashWriteReg
|
||
* @msg: write flash register
|
||
* @param {FQspiCtrl} *pctrl, instance of FQSPI controller
|
||
* @param {u8} command, command to write flash register,see the Flash manual for details
|
||
* @param {u8} *buf, write buffer
|
||
* @param {size_t} len, write length
|
||
* @return {FError} err code information, FQSPI_SUCCESS indicates success,others indicates failed 表示写入成功,其它返回值表示写入失败
|
||
*/
|
||
FError FQspiFlashWriteReg(FQspiCtrl *pctrl, u8 command, const u8 *buf, size_t len)
|
||
{
|
||
FASSERT(pctrl);
|
||
FError ret = FQSPI_SUCCESS;
|
||
u8 sr1_v = 0;
|
||
|
||
if (FT_COMPONENT_IS_READY != pctrl->is_ready)
|
||
{
|
||
FQSPI_ERROR("Nor flash not ready !!!");
|
||
return FQSPI_NOT_READY;
|
||
}
|
||
|
||
uintptr base_addr = pctrl->config.base_addr;
|
||
|
||
memset(&pctrl->cmd_def, 0, sizeof(pctrl->cmd_def));
|
||
pctrl->cmd_def.cmd = command;
|
||
pctrl->cmd_def.cs = pctrl->config.channel;
|
||
pctrl->cmd_def.data_transfer = FQSPI_CMD_DATA_ENABLE;
|
||
pctrl->cmd_def.p_buffer = FQSPI_USE_BUFFER_ENABLE;
|
||
pctrl->cmd_def.sck_sel = FQSPI_SCK_DIV_128;
|
||
|
||
if (len > 4)
|
||
{
|
||
FQSPI_ERROR("Data length exceed. commad 0x%lx, len:%d \n", command, len);
|
||
return FQSPI_INVAL_PARAM;
|
||
}
|
||
else if ((len > 0) && (buf != NULL))
|
||
{
|
||
/* set rw_num region, len - 1 */
|
||
pctrl->cmd_def.rw_num = (len - 1);
|
||
|
||
/*write cmd_reg to Command port register 0x10 */
|
||
FQspiCommandPortConfig(pctrl);
|
||
|
||
/* set ld port data(buf) and make command valid */
|
||
FQspiSetLdPortData(base_addr, buf, len);
|
||
}
|
||
else
|
||
{
|
||
/*write cmd_reg to Command port register 0x10 */
|
||
FQspiCommandPortConfig(pctrl);
|
||
|
||
FQspiCommandPortSend(base_addr);
|
||
}
|
||
|
||
/* wait SR1V bit0 WIP is ready, not device busy */
|
||
ret = FQspiFlashWaitForCmd(pctrl);
|
||
|
||
return ret;
|
||
}
|
||
|
||
/**
|
||
* @name: FQspiFlashWaitForCmd
|
||
* @msg: wait flash command execution complete
|
||
* @param {FQspiCtrl} *pctrl, instance of FQSPI controller
|
||
* @return {FError} err code information, FQSPI_SUCCESS indicates success,others indicates failed 表示成功完成,其它返回值表示失败
|
||
*/
|
||
FError FQspiFlashWaitForCmd(FQspiCtrl *pctrl)
|
||
{
|
||
FASSERT(pctrl);
|
||
u32 timeout = FQSPI_BUSY_TIMEOUT_US;
|
||
FError ret = FQSPI_SUCCESS;
|
||
u8 sr1 = 0;
|
||
|
||
uintptr base_addr = pctrl->config.base_addr;
|
||
|
||
ret = FQspiFlashSpecialInstruction(pctrl, FQSPI_FLASH_CMD_RDSR1, &sr1, sizeof(sr1));
|
||
if (FQSPI_SUCCESS != ret)
|
||
{
|
||
FQSPI_ERROR("Failed to read sr1, result 0x%x\r\n", ret);
|
||
return ret;
|
||
}
|
||
|
||
do
|
||
{
|
||
timeout--;
|
||
/* read value from low bit port register 0x1c,
|
||
Read Status Register 1 is related to SR1V WIP field (bit0) */
|
||
FQspiGetLdPortData(base_addr, &sr1, 1);
|
||
|
||
if (!timeout)
|
||
{
|
||
FQSPI_ERROR("Wait cmd timeout !!!");
|
||
ret = FQSPI_TIMEOUT;
|
||
break;
|
||
}
|
||
|
||
}
|
||
while (sr1 & FQSPI_NOR_FLASH_STATE_BUSY);
|
||
|
||
return ret;
|
||
}
|
||
|
||
/**
|
||
* @name: FQspiFlashWProtectSet
|
||
* @msg: Set qspi write protection function
|
||
* @param {FQspiCtrl} *pctrl, instance of FQSPI controller
|
||
* @param {u32} Write protect function enable/disable 1:enable,0:disable
|
||
* @return err code information, FQSPI_SUCCESS indicates success,others indicates failed
|
||
*/
|
||
FError FQspiFlashWProtectSet(FQspiCtrl *pctrl, boolean wprotect, u8 channel)
|
||
{
|
||
FASSERT(pctrl);
|
||
FError ret = FQSPI_SUCCESS;
|
||
u8 wp_block[2] = {FQSPI_FLASH_WP_ENABLE, FQSPI_FLASH_WP_DISABLE};
|
||
FQspiChannelSet(pctrl, channel);
|
||
ret = FQspiFlashEnableWrite(pctrl);
|
||
if (wprotect == TRUE)
|
||
{
|
||
ret = FQspiFlashWriteReg(pctrl, FQSPI_FLASH_CMD_WRR, &wp_block[0], 1);
|
||
}
|
||
else if (wprotect == FALSE)
|
||
{
|
||
ret = FQspiFlashWriteReg(pctrl, FQSPI_FLASH_CMD_WRR, &wp_block[1], 1);
|
||
}
|
||
return ret;
|
||
} |