770 lines
24 KiB
C
770 lines
24 KiB
C
/************************************************************************************************
|
|
* Copyright (c) Fenda Technologies Co., Ltd. 2012-2020. All rights reserved.
|
|
* Description: nand flash
|
|
* Author: luca.hutianjun 029191
|
|
* Create: 2021-11-27
|
|
************************************************************************************************/
|
|
#include <stdint.h>
|
|
#include <stdbool.h>
|
|
#include <string.h>
|
|
#include <stdlib.h>
|
|
#include <stdio.h>
|
|
#include "am_util_delay.h"
|
|
#include "drv_mspi.h"
|
|
#include "ds35m1ga.h"
|
|
|
|
|
|
/**********mspi module*****************************/
|
|
#define DS35M_MSPI_MODULE 1
|
|
|
|
#define DS35M_WR_DATA_LINE_1 0
|
|
#define DS35M_WR_DATA_LINE_4 1
|
|
#define DS35M_WR_DATA_LINE_MODE DS35M_WR_DATA_LINE_4
|
|
|
|
/**********command********************************/
|
|
#define DS35M_CMD_WRITE_ENABLE (0x06)
|
|
#define DS35M_CMD_WRITE_DISABLE (0x04)
|
|
#define DS35M_CMD_GET_FEATURE (0x0F)
|
|
#define DS35M_CMD_SET_FEATURE (0x1F)
|
|
#define DS35M_CMD_READ_PAGE_TO_CACHE (0x13)
|
|
#define DS35M_CMD_READ_FROM_CACHE (0x03) // 0x0B
|
|
#define DS35M_CMD_READ_FROM_CACHE_2 (0x3B)
|
|
#define DS35M_CMD_READ_FROM_CACHE_4 (0x6B)
|
|
#define DS35M_CMD_READ_FROM_CACHE_DTR (0xEE)
|
|
#define DS35M_CMD_READ_ID (0x9F)
|
|
#define DS35M_CMD_READ_PARAM_PAGE (0x13)
|
|
#define DS35M_CMD_READ_UID (0x13)
|
|
#define DS35M_CMD_PROGRAM_LOAD (0x02)
|
|
#define DS35M_CMD_PROGRAM_LOAD_4 (0x32)
|
|
#define DS35M_CMD_PROGRAM_EXECUTE (0x10)
|
|
#define DS35M_CMD_PROGRAM_LOAD_RAND (0x84)
|
|
#define DS35M_CMD_PROGRAM_LOAD_RAND_4 (0xC4) // 0x34
|
|
#define DS35M_CMD_ERASE_BLOCK (0xD8)
|
|
#define DS35M_CMD_RESET (0xFF)
|
|
#define DS35M_CMD_EN_POWER_ON_RESET (0x66)
|
|
#define DS35M_CMD_POWER_ON_RESET (0x99)
|
|
|
|
/**********features add***************************/
|
|
#define DS35M_FEATURES_ADD_PROTECT 0xA0
|
|
#define DS35M_FEATURES_ADD_FEATURE_0 0xB0
|
|
#define DS35M_FEATURES_ADD_STATUS_0 0xC0
|
|
#define DS35M_FEATURES_ADD_FEATURE_1 0xD0
|
|
#define DS35M_FEATURES_ADD_STATUS_1 0xF0
|
|
|
|
/**************** Protection mark******************/
|
|
#define DS35M_PROTECTION_MASK_CMP 0x02
|
|
#define DS35M_PROTECTION_MASK_INV 0x04
|
|
#define DS35M_PROTECTION_MASK_BP 0x38
|
|
#define DS35M_PROTECTION_MASK_BRWD 0x80
|
|
/***************** feature 0 mark******************/
|
|
#define DS35M_FEATURE_0_MASK_QE 0x01
|
|
#define DS35M_FEATURE_0_MASK_BPL 0x08
|
|
#define DS35M_FEATURE_0_MASK_ECC_EN 0x10
|
|
#define DS35M_FEATURE_0_MASK_OTP_EN 0x40
|
|
#define DS35M_FEATURE_0_MASK_OTP_PRT 0x80
|
|
/***************** status 0 mark******************/
|
|
#define DS35M_STATUS_0_MASK_OIP 0x01
|
|
#define DS35M_STATUS_0_MASK_WEL 0x02
|
|
#define DS35M_STATUS_0_MASK_E_FAIL 0x04
|
|
#define DS35M_STATUS_0_MASK_P_FAIL 0x08
|
|
#define DS35M_STATUS_0_MASK_ECCS0 0x10
|
|
#define DS35M_STATUS_0_MASK_ECCS1 0x20
|
|
#define DS35M_STATUS_0_MASK_ECCS 0x30
|
|
/***************** feature 1 mark******************/
|
|
#define DS35M_FEATURE_1_MASK_DS_IO 0x60
|
|
/***************** status 1 mark******************/
|
|
#define DS35M_STATUS_1_MASK_BPS 0x08
|
|
#define DS35M_STATUS_1_MASK_ECCSE0 0x10
|
|
#define DS35M_STATUS_1_MASK_ECCSE1 0x20
|
|
|
|
|
|
#if defined(EXT_FLASH_CHIP_DS35M1GA)
|
|
|
|
typedef enum {
|
|
DS35M_TRANS_1_1_1 = 0,
|
|
DS35M_TRANS_1_1_2,
|
|
DS35M_TRANS_1_1_4,
|
|
DS35M_TRANS_1_1_8,
|
|
DS35M_TRANS_1_4_4,
|
|
DS35M_TRANS_ERR,
|
|
} ds35mTransMode_e;
|
|
|
|
|
|
typedef enum {
|
|
DS35M_TRANS_TX = 0,
|
|
DS35M_TRANS_RX,
|
|
} ds35mTransDirect_e;
|
|
|
|
|
|
typedef struct {
|
|
uint8_t cmd;
|
|
uint8_t addrByte;
|
|
uint32_t addrVal;
|
|
uint8_t dummyByte;
|
|
ds35mTransDirect_e direct;
|
|
} ds35mTransInfo_s;
|
|
|
|
|
|
|
|
typedef enum {
|
|
DS35M_IOCTL_QE_ENABLE = 0x10,
|
|
DS35M_IOCTL_QE_DISABLE,
|
|
|
|
DS35M_IOCTL_GET_READ_STA,
|
|
|
|
DS35M_IOCTL_DIS_PROTECT_BLOCK,
|
|
DS35M_IOCTL_ECC_ENABLE,
|
|
DS35M_IOCTL_ECC_DISABLE,
|
|
} DS35MIoctlEvent_e;
|
|
|
|
|
|
static uint32_t ds35m_DmaBuffer[(AM_HAL_MSPI_CQ_ENTRY_SIZE / 4) * (2 + 1)] = {0};
|
|
|
|
static volatile uint8_t ds35m_dmaCompleteFlg = 0;
|
|
|
|
/*spare area
|
|
M2: 0-3, 16-19,32-35,48-51
|
|
M1: 4-7, 20-23,36-39,52-55
|
|
R1: 8-15,24-31,40-47,56-63 ECC(512B对应一组)
|
|
*/
|
|
//static bool ds35m_chipEccSw = true;
|
|
|
|
|
|
static void Bsp_Ds35m_DmaComplete(void *pCallbackCtxt, uint32_t transactionStatus)
|
|
{
|
|
if(transactionStatus != AM_HAL_STATUS_SUCCESS) {
|
|
|
|
} else {
|
|
ds35m_dmaCompleteFlg = 1;
|
|
}
|
|
}
|
|
|
|
static void Bsp_Ds35m_SwitchTransMode(ds35mTransMode_e mode)
|
|
{
|
|
static ds35mTransMode_e tmpMode = DS35M_TRANS_ERR;
|
|
|
|
if(mode == tmpMode) {
|
|
return;
|
|
}
|
|
|
|
switch(mode) {
|
|
case DS35M_TRANS_1_1_1:
|
|
MSPIn(DS35M_MSPI_MODULE)->CFG_b.DEVCFG = MSPI0_CFG_DEVCFG_SERIAL0;
|
|
MSPIn(DS35M_MSPI_MODULE)->CFG_b.SEPIO = 1;
|
|
MSPIn(DS35M_MSPI_MODULE)->FLASH_b.XIPMIXED = 0;
|
|
MSPIn(DS35M_MSPI_MODULE)->PADCFG = 0;
|
|
MSPIn(DS35M_MSPI_MODULE)->PADOUTEN = 0x103;
|
|
break;
|
|
|
|
case DS35M_TRANS_1_1_4:
|
|
MSPIn(DS35M_MSPI_MODULE)->CFG_b.DEVCFG = MSPI0_CFG_DEVCFG_SERIAL0;
|
|
MSPIn(DS35M_MSPI_MODULE)->CFG_b.SEPIO = 0;
|
|
MSPIn(DS35M_MSPI_MODULE)->FLASH_b.XIPMIXED = 5;
|
|
MSPIn(DS35M_MSPI_MODULE)->PADCFG = 0;
|
|
MSPIn(DS35M_MSPI_MODULE)->PADOUTEN = 0x10F;
|
|
break;
|
|
|
|
case DS35M_TRANS_1_4_4:
|
|
MSPIn(DS35M_MSPI_MODULE)->CFG_b.DEVCFG = MSPI0_CFG_DEVCFG_SERIAL0;
|
|
MSPIn(DS35M_MSPI_MODULE)->CFG_b.SEPIO = 0;
|
|
MSPIn(DS35M_MSPI_MODULE)->FLASH_b.XIPMIXED = 7;
|
|
MSPIn(DS35M_MSPI_MODULE)->PADCFG = 0;
|
|
MSPIn(DS35M_MSPI_MODULE)->PADOUTEN = 0x10F;
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
tmpMode = mode;
|
|
}
|
|
|
|
|
|
static uint32_t Bsp_Ds35m_TransSerial(ds35mTransInfo_s *pTrans, uint8_t *pData, uint32_t len)
|
|
{
|
|
uint32_t ui32Status;
|
|
drv_mspi_t *pDs35m = &g_mspi_dev[DS35M_MSPI_MODULE];
|
|
am_hal_mspi_pio_transfer_t Transaction = {0};
|
|
|
|
|
|
// Create the individual write transaction.
|
|
if(pTrans->direct == DS35M_TRANS_TX) {
|
|
Transaction.eDirection = AM_HAL_MSPI_TX;
|
|
} else {
|
|
Transaction.eDirection = AM_HAL_MSPI_RX;
|
|
}
|
|
|
|
// cmd
|
|
MSPIn(DS35M_MSPI_MODULE)->CFG_b.ISIZE = 0;
|
|
Transaction.bSendInstr = true;
|
|
Transaction.ui16DeviceInstr = pTrans->cmd;
|
|
|
|
if(pTrans->addrByte) {
|
|
Transaction.bSendAddr = true;
|
|
Transaction.ui32DeviceAddr = pTrans->addrVal;
|
|
MSPIn(DS35M_MSPI_MODULE)->CFG_b.ASIZE = pTrans->addrByte - 1;
|
|
} else {
|
|
Transaction.bSendAddr = false;
|
|
}
|
|
|
|
if((pTrans->dummyByte) && (pTrans->direct == DS35M_TRANS_TX)) {
|
|
MSPIn(DS35M_MSPI_MODULE)->CFG_b.WRITELATENCY = 8;
|
|
Transaction.bEnWRLatency = true;
|
|
} else if((pTrans->dummyByte) && (pTrans->direct == DS35M_TRANS_RX)) {
|
|
MSPIn(DS35M_MSPI_MODULE)->CFG_b.TURNAROUND = 8;
|
|
Transaction.bTurnaround = true;
|
|
} else {
|
|
Transaction.bEnWRLatency = false;
|
|
Transaction.bTurnaround = false;
|
|
}
|
|
|
|
Transaction.pui32Buffer = (uint32_t *)pData;
|
|
Transaction.ui32NumBytes = len;
|
|
|
|
Transaction.bContinue = false;
|
|
Transaction.bQuadCmd = false;
|
|
|
|
ui32Status = am_hal_mspi_blocking_transfer(pDs35m->pHandle, &Transaction, MSPI_TIMEOUT);
|
|
|
|
return ui32Status;
|
|
}
|
|
|
|
#if (DS35M_WR_DATA_LINE_MODE == DS35M_WR_DATA_LINE_4)
|
|
static uint32_t byteToUintBit(uint8_t byte)
|
|
{
|
|
uint32_t tmpData = 0;
|
|
uint8_t i;
|
|
|
|
for(i = 0; i < 8; i++) {
|
|
tmpData <<= 4;
|
|
|
|
if(byte & 0x80) {
|
|
tmpData |= 0x01;
|
|
}
|
|
|
|
byte <<= 1;
|
|
}
|
|
|
|
return tmpData;
|
|
}
|
|
static uint32_t Bsp_Ds35m_TransQuad(ds35mTransInfo_s *pTrans, uint8_t *pData, uint32_t len)
|
|
{
|
|
uint32_t ui32Status;
|
|
drv_mspi_t *pDs35m = &g_mspi_dev[DS35M_MSPI_MODULE];
|
|
am_hal_mspi_dma_transfer_t Transaction = {0};
|
|
|
|
// 切换1-4-4传输模式
|
|
Bsp_Ds35m_SwitchTransMode(DS35M_TRANS_1_4_4);
|
|
|
|
// dirct cmd
|
|
if(pTrans->direct == DS35M_TRANS_TX) {
|
|
Transaction.eDirection = AM_HAL_MSPI_TX;
|
|
} else {
|
|
Transaction.eDirection = AM_HAL_MSPI_RX;
|
|
}
|
|
|
|
// cmd 2byte = cmd(1) + dummy(1/2) + addr(11-8bit)
|
|
MSPIn(DS35M_MSPI_MODULE)->XIPINSTR_b.READINSTR = (DS35M_CMD_READ_FROM_CACHE_4 << 8) | ((pTrans->addrVal >> 8) & 0x0F);
|
|
MSPIn(DS35M_MSPI_MODULE)->XIPINSTR_b.WRITEINSTR = (DS35M_CMD_PROGRAM_LOAD_4 << 8) | (pTrans->addrVal >> 8) & 0x0F;
|
|
MSPIn(DS35M_MSPI_MODULE)->CFG_b.ISIZE = 1;
|
|
MSPIn(DS35M_MSPI_MODULE)->FLASH_b.XIPSENDI = 1;
|
|
|
|
// address 4byte = addr(7-0bit)
|
|
// MSPIn(DS35M_MSPI_MODULE)->ADDR = byteToUintBit(pTrans->addrVal&0xFF);
|
|
MSPIn(DS35M_MSPI_MODULE)->CFG_b.ASIZE = 3;
|
|
MSPIn(DS35M_MSPI_MODULE)->FLASH_b.XIPSENDA = 1;
|
|
|
|
// dummy byte
|
|
if((pTrans->dummyByte) && (pTrans->direct == DS35M_TRANS_TX)) {
|
|
MSPIn(DS35M_MSPI_MODULE)->CFG_b.WRITELATENCY = 8;
|
|
MSPIn(DS35M_MSPI_MODULE)->FLASH_b.XIPENWLAT = 1;
|
|
} else if((pTrans->dummyByte) && (pTrans->direct == DS35M_TRANS_RX)) {
|
|
MSPIn(DS35M_MSPI_MODULE)->CFG_b.TURNAROUND = 8;
|
|
MSPIn(DS35M_MSPI_MODULE)->FLASH_b.XIPENTURN = 1;
|
|
} else {
|
|
MSPIn(DS35M_MSPI_MODULE)->FLASH_b.XIPENWLAT = 0;
|
|
MSPIn(DS35M_MSPI_MODULE)->FLASH_b.XIPENTURN = 0;
|
|
}
|
|
|
|
Transaction.ui32DeviceAddress = byteToUintBit(pTrans->addrVal & 0xFF);
|
|
Transaction.ui32PauseCondition = 0;
|
|
Transaction.ui32SRAMAddress = (uint32_t)pData;
|
|
Transaction.ui32StatusSetClr = 0;
|
|
Transaction.ui32TransferCount = len;
|
|
Transaction.ui8Priority = 1;
|
|
|
|
ds35m_dmaCompleteFlg = 0;
|
|
ui32Status = am_hal_mspi_nonblocking_transfer(pDs35m->pHandle, &Transaction, AM_HAL_MSPI_TRANS_DMA, Bsp_Ds35m_DmaComplete, NULL);
|
|
while(ds35m_dmaCompleteFlg == 0) {
|
|
/*if(osKernelGetState() == osKernelRunning) {
|
|
osDelay(1);
|
|
} else {
|
|
am_util_delay_ms(1);
|
|
}*/
|
|
}
|
|
|
|
// 切换回1-1-1传输模式
|
|
Bsp_Ds35m_SwitchTransMode(DS35M_TRANS_1_1_1);
|
|
return ui32Status;
|
|
}
|
|
#endif
|
|
|
|
int Ds35m_FeaturesGet(uint8_t u8Addr, uint8_t *u8Value);
|
|
int Ds35m_FeaturesSet(uint8_t u8Addr, uint8_t u8Value);
|
|
|
|
static uint32_t Bsp_Ds35m_Ioctl(DS35MIoctlEvent_e event, void *pConfig)
|
|
{
|
|
uint8_t u8TmpValue, u8TmpValue2;
|
|
|
|
switch(event) {
|
|
case DS35M_IOCTL_QE_ENABLE:
|
|
Ds35m_FeaturesGet(DS35M_FEATURES_ADD_FEATURE_0, &u8TmpValue);
|
|
if(u8TmpValue & DS35M_FEATURE_0_MASK_QE) {
|
|
return 0;
|
|
}
|
|
u8TmpValue |= DS35M_FEATURE_0_MASK_QE;
|
|
Ds35m_FeaturesSet(DS35M_FEATURES_ADD_FEATURE_0, u8TmpValue);
|
|
Ds35m_FeaturesGet(DS35M_FEATURES_ADD_FEATURE_0, &u8TmpValue2);
|
|
if(u8TmpValue != u8TmpValue2) {
|
|
// printf("event:%d error!!!\r\n", event);
|
|
}
|
|
break;
|
|
|
|
case DS35M_IOCTL_QE_DISABLE:
|
|
Ds35m_FeaturesGet(DS35M_FEATURES_ADD_FEATURE_0, &u8TmpValue);
|
|
if((u8TmpValue & DS35M_FEATURE_0_MASK_QE) == 0) {
|
|
return 0;
|
|
}
|
|
u8TmpValue &= ~(DS35M_FEATURE_0_MASK_QE);
|
|
Ds35m_FeaturesSet(DS35M_FEATURES_ADD_FEATURE_0, u8TmpValue);
|
|
Ds35m_FeaturesGet(DS35M_FEATURES_ADD_FEATURE_0, &u8TmpValue2);
|
|
if(u8TmpValue != u8TmpValue2) {
|
|
//printf("event:%d error!!!\r\n", event);
|
|
}
|
|
break;
|
|
|
|
case DS35M_IOCTL_GET_READ_STA:
|
|
Ds35m_FeaturesGet(DS35M_FEATURES_ADD_STATUS_0, &u8TmpValue);
|
|
*((uint8_t *)pConfig) = u8TmpValue & DS35M_STATUS_0_MASK_OIP;
|
|
break;
|
|
|
|
case DS35M_IOCTL_DIS_PROTECT_BLOCK:
|
|
Ds35m_FeaturesGet(DS35M_FEATURES_ADD_PROTECT, &u8TmpValue);
|
|
if((u8TmpValue & DS35M_PROTECTION_MASK_BP) == 0) {
|
|
return 0;
|
|
}
|
|
u8TmpValue &= (~DS35M_PROTECTION_MASK_BP);
|
|
Ds35m_FeaturesSet(DS35M_FEATURES_ADD_PROTECT, u8TmpValue);
|
|
Ds35m_FeaturesGet(DS35M_FEATURES_ADD_PROTECT, &u8TmpValue2);
|
|
if(u8TmpValue != u8TmpValue2) {
|
|
//printf("event:%d error!!!\r\n", event);
|
|
}
|
|
break;
|
|
|
|
case DS35M_IOCTL_ECC_ENABLE:
|
|
Ds35m_FeaturesGet(DS35M_FEATURES_ADD_FEATURE_0, &u8TmpValue);
|
|
if(u8TmpValue & DS35M_FEATURE_0_MASK_ECC_EN) {
|
|
return 0;
|
|
}
|
|
u8TmpValue |= DS35M_FEATURE_0_MASK_ECC_EN;
|
|
Ds35m_FeaturesSet(DS35M_FEATURES_ADD_FEATURE_0, u8TmpValue);
|
|
Ds35m_FeaturesGet(DS35M_FEATURES_ADD_FEATURE_0, &u8TmpValue2);
|
|
if(u8TmpValue != u8TmpValue2) {
|
|
//printf("event:%d error!!!\r\n", event);
|
|
}
|
|
break;
|
|
|
|
case DS35M_IOCTL_ECC_DISABLE:
|
|
Ds35m_FeaturesGet(DS35M_FEATURES_ADD_FEATURE_0, &u8TmpValue);
|
|
if((u8TmpValue & DS35M_FEATURE_0_MASK_ECC_EN) == 0) {
|
|
return 0;
|
|
}
|
|
u8TmpValue &= ~(DS35M_FEATURE_0_MASK_ECC_EN);
|
|
Ds35m_FeaturesSet(DS35M_FEATURES_ADD_FEATURE_0, u8TmpValue);
|
|
Ds35m_FeaturesGet(DS35M_FEATURES_ADD_FEATURE_0, &u8TmpValue2);
|
|
if(u8TmpValue != u8TmpValue2) {
|
|
//printf("event:%d error!!!\r\n", event);
|
|
}
|
|
break;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
int Ds35m_Reset(void)
|
|
{
|
|
ds35mTransInfo_s tmpTansInfo = {0};
|
|
|
|
tmpTansInfo.cmd = DS35M_CMD_RESET;
|
|
tmpTansInfo.addrByte = 0;
|
|
tmpTansInfo.dummyByte = 0;
|
|
tmpTansInfo.direct = DS35M_TRANS_TX;
|
|
Bsp_Ds35m_TransSerial(&tmpTansInfo, NULL, 0);
|
|
|
|
return 0;
|
|
}
|
|
|
|
int Ds35m_WirteEnable(void)
|
|
{
|
|
ds35mTransInfo_s tmpTansInfo = {0};
|
|
|
|
tmpTansInfo.cmd = DS35M_CMD_WRITE_ENABLE;
|
|
tmpTansInfo.addrByte = 0;
|
|
tmpTansInfo.dummyByte = 0;
|
|
tmpTansInfo.direct = DS35M_TRANS_TX;
|
|
Bsp_Ds35m_TransSerial(&tmpTansInfo, NULL, 0);
|
|
|
|
return 0;
|
|
}
|
|
|
|
int Ds35m_WirteDisable(void)
|
|
{
|
|
ds35mTransInfo_s tmpTansInfo = {0};
|
|
|
|
tmpTansInfo.cmd = DS35M_CMD_WRITE_DISABLE;
|
|
tmpTansInfo.addrByte = 0;
|
|
tmpTansInfo.dummyByte = 0;
|
|
tmpTansInfo.direct = DS35M_TRANS_TX;
|
|
Bsp_Ds35m_TransSerial(&tmpTansInfo, NULL, 0);
|
|
|
|
return 0;
|
|
}
|
|
|
|
int Ds35m_EccEnable(void)
|
|
{
|
|
return Bsp_Ds35m_Ioctl(DS35M_IOCTL_ECC_ENABLE, NULL);
|
|
}
|
|
|
|
int Ds35m_EccDisable(void)
|
|
{
|
|
return Bsp_Ds35m_Ioctl(DS35M_IOCTL_ECC_DISABLE, NULL);
|
|
}
|
|
|
|
int Ds35m_PageReadToCache(uint32_t pageOffsetNum)
|
|
{
|
|
ds35mTransInfo_s tmpTansInfo = {0};
|
|
|
|
tmpTansInfo.cmd = DS35M_CMD_READ_PAGE_TO_CACHE;
|
|
tmpTansInfo.addrByte = 3;
|
|
tmpTansInfo.addrVal = pageOffsetNum;
|
|
tmpTansInfo.dummyByte = 0;
|
|
tmpTansInfo.direct = DS35M_TRANS_TX;
|
|
Bsp_Ds35m_TransSerial(&tmpTansInfo, NULL, 0);
|
|
|
|
return 0;
|
|
}
|
|
|
|
int Ds35m_ProgramExecute(uint32_t pageOffsetNum)
|
|
{
|
|
ds35mTransInfo_s tmpTansInfo = {0};
|
|
|
|
tmpTansInfo.cmd = DS35M_CMD_PROGRAM_EXECUTE;
|
|
tmpTansInfo.addrByte = 3;
|
|
tmpTansInfo.addrVal = pageOffsetNum;
|
|
tmpTansInfo.dummyByte = 0;
|
|
tmpTansInfo.direct = DS35M_TRANS_TX;
|
|
Bsp_Ds35m_TransSerial(&tmpTansInfo, NULL, 0);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
int Ds35m_FeaturesGet(uint8_t u8Addr, uint8_t *u8Value)
|
|
{
|
|
ds35mTransInfo_s tmpTansInfo = {0};
|
|
|
|
tmpTansInfo.cmd = DS35M_CMD_GET_FEATURE;
|
|
tmpTansInfo.addrByte = 1;
|
|
tmpTansInfo.addrVal = u8Addr;
|
|
tmpTansInfo.dummyByte = 0;
|
|
tmpTansInfo.direct = DS35M_TRANS_RX;
|
|
Bsp_Ds35m_TransSerial(&tmpTansInfo, u8Value, 1);
|
|
|
|
return 0;
|
|
}
|
|
|
|
int Ds35m_FeaturesSet(uint8_t u8Addr, uint8_t u8Value)
|
|
{
|
|
ds35mTransInfo_s tmpTansInfo = {0};
|
|
|
|
tmpTansInfo.cmd = DS35M_CMD_SET_FEATURE;
|
|
tmpTansInfo.addrByte = 1;
|
|
tmpTansInfo.addrVal = u8Addr;
|
|
tmpTansInfo.dummyByte = 0;
|
|
tmpTansInfo.direct = DS35M_TRANS_TX;
|
|
Bsp_Ds35m_TransSerial(&tmpTansInfo, &u8Value, 1);
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
int Ds35m_ReadId(uint16_t *u16DeviceId)
|
|
{
|
|
ds35mTransInfo_s tmpTansInfo = {0};
|
|
uint8_t tmpData[2] = {0};
|
|
|
|
tmpTansInfo.cmd = DS35M_CMD_READ_ID;
|
|
tmpTansInfo.addrByte = 0;
|
|
tmpTansInfo.dummyByte = 1;
|
|
tmpTansInfo.direct = DS35M_TRANS_RX;
|
|
Bsp_Ds35m_TransSerial(&tmpTansInfo, tmpData, 2);
|
|
|
|
*u16DeviceId = (tmpData[0] << 8) & 0xFF00;
|
|
*u16DeviceId |= tmpData[1];
|
|
|
|
return 0;
|
|
}
|
|
|
|
int Ds35m_InitConfig(void)
|
|
{
|
|
uint16_t u16DeviceId = 0;
|
|
|
|
// reset flash chip
|
|
Ds35m_Reset();
|
|
am_util_delay_ms(10);
|
|
|
|
// read id
|
|
// Ds35m_ReadId(&u16DeviceId);
|
|
// //printf("u16DeviceId:%X\r\n", u16DeviceId);
|
|
// if(u16DeviceId != BSP_DS35M_CHIP_ID) {
|
|
// return -1;
|
|
// }
|
|
// am_util_stdio_printf("-----------------------ds35id =%d\r\n",u16DeviceId);
|
|
// set QE
|
|
#if(DS35M_WR_DATA_LINE_MODE == DS35M_WR_DATA_LINE_1)
|
|
Bsp_Ds35m_Ioctl(DS35M_IOCTL_QE_DISABLE, NULL);
|
|
#elif(DS35M_WR_DATA_LINE_MODE == DS35M_WR_DATA_LINE_4)
|
|
Bsp_Ds35m_Ioctl(DS35M_IOCTL_QE_ENABLE, NULL);
|
|
#endif
|
|
|
|
// disable protect block
|
|
Bsp_Ds35m_Ioctl(DS35M_IOCTL_DIS_PROTECT_BLOCK, NULL);
|
|
//disable chip Ecc
|
|
Ds35m_EccDisable();
|
|
return 0;
|
|
}
|
|
|
|
int Ds35m_Init(void)
|
|
{
|
|
drv_mspi_t *pDs35m = &g_mspi_dev[DS35M_MSPI_MODULE];
|
|
|
|
// config mspi
|
|
pDs35m->module = DS35M_MSPI_MODULE;
|
|
|
|
pDs35m->hal_config.eSpiMode = AM_HAL_MSPI_SPI_MODE_0;
|
|
pDs35m->hal_config.eClockFreq = AM_HAL_MSPI_CLK_48MHZ;
|
|
pDs35m->hal_config.ui8TurnAround = 8,
|
|
pDs35m->hal_config.eAddrCfg = AM_HAL_MSPI_ADDR_1_BYTE;
|
|
pDs35m->hal_config.eInstrCfg = AM_HAL_MSPI_INSTR_1_BYTE;
|
|
pDs35m->hal_config.eDeviceConfig = AM_HAL_MSPI_FLASH_SERIAL_CE0;
|
|
//pDs35m->hal_config.eXipMixedMode = AM_HAL_MSPI_XIPMIXED_NORMAL;
|
|
//pDs35m->hal_config.bSeparateIO = true;
|
|
pDs35m->hal_config.bSendInstr = true;
|
|
pDs35m->hal_config.bSendAddr = true;
|
|
pDs35m->hal_config.bTurnaround = true;
|
|
pDs35m->hal_config.ui8ReadInstr = DS35M_CMD_READ_FROM_CACHE_4;
|
|
pDs35m->hal_config.ui8WriteInstr = DS35M_CMD_PROGRAM_LOAD_4;
|
|
pDs35m->hal_config.ui32TCBSize = sizeof(ds35m_DmaBuffer) / sizeof(uint32_t);
|
|
pDs35m->hal_config.pTCB = ds35m_DmaBuffer;
|
|
pDs35m->hal_config.scramblingStartAddr = 0;
|
|
pDs35m->hal_config.scramblingEndAddr = 0;
|
|
|
|
pDs35m->hal_config.ui16DMATimeLimit = 0;
|
|
pDs35m->hal_config.eDMABoundary = AM_HAL_MSPI_BOUNDARY_NONE;
|
|
|
|
pDs35m->hal_config.ui8WriteLatency = 8;
|
|
pDs35m->hal_config.bEnWriteLatency = false;
|
|
|
|
|
|
if(mspi_open(pDs35m->module))
|
|
{
|
|
// am_util_stdio_printf("-------------open pDs35m fail =%d\r\n",pDs35m->module);
|
|
return AM_HAL_STATUS_FAIL;
|
|
}
|
|
// am_util_stdio_printf("-------------open pDs35m suss =%d\r\n",pDs35m->module);
|
|
am_bsp_mspi_pins_enable(pDs35m->module, AM_HAL_MSPI_FLASH_QUAD_CE0);
|
|
// am_hal_mspi_interrupt_clear(pDs35m->pHandle, AM_HAL_MSPI_INT_CQUPD | AM_HAL_MSPI_INT_ERR);
|
|
// am_hal_mspi_interrupt_enable(pDs35m->pHandle, AM_HAL_MSPI_INT_CQUPD | AM_HAL_MSPI_INT_ERR);
|
|
|
|
NVIC_EnableIRQ(mspi_interrupts[pDs35m->module]);
|
|
|
|
return Ds35m_InitConfig();
|
|
}
|
|
|
|
int Ds35m_Deinit(void)
|
|
{
|
|
Ds35m_WirteEnable();
|
|
Ds35m_Reset();
|
|
|
|
NVIC_DisableIRQ(mspi_interrupts[DS35M_MSPI_MODULE]);
|
|
mspi_close(DS35M_MSPI_MODULE);
|
|
return 0;
|
|
}
|
|
|
|
int Ds35m_ReadPageData(uint32_t pageOffsetNum, uint16_t addrOffset, uint8_t *outData, uint16_t len)
|
|
{
|
|
uint8_t u8TmpSta = 0;
|
|
ds35mTransInfo_s tmpTansInfo = {0};
|
|
uint8_t tmpCnt = 200;
|
|
|
|
|
|
Ds35m_PageReadToCache(pageOffsetNum);
|
|
// am_util_delay_us(20); // ?会耗时一点时间
|
|
|
|
while(tmpCnt--) {
|
|
Ds35m_FeaturesGet(DS35M_FEATURES_ADD_STATUS_0, &u8TmpSta);
|
|
if((u8TmpSta & DS35M_STATUS_0_MASK_OIP) == 0) {
|
|
if((u8TmpSta & DS35M_STATUS_0_MASK_ECCS) == 0x20) {
|
|
// am_util_stdio_printf("read err:ecc\r\n");
|
|
return -1;
|
|
}
|
|
|
|
break;
|
|
}
|
|
}
|
|
|
|
if(tmpCnt == 0) {
|
|
// am_util_stdio_printf("read timeout err. page:%d",pageOffsetNum);
|
|
return -2;
|
|
}
|
|
|
|
#if(DS35M_WR_DATA_LINE_MODE == DS35M_WR_DATA_LINE_1)
|
|
tmpTansInfo.cmd = DS35M_CMD_READ_FROM_CACHE;
|
|
#elif(DS35M_WR_DATA_LINE_MODE == DS35M_WR_DATA_LINE_4)
|
|
tmpTansInfo.cmd = DS35M_CMD_READ_FROM_CACHE_4;
|
|
#endif
|
|
tmpTansInfo.addrByte = 2;
|
|
tmpTansInfo.addrVal = addrOffset;
|
|
tmpTansInfo.dummyByte = 1;
|
|
tmpTansInfo.direct = DS35M_TRANS_RX;
|
|
#if(DS35M_WR_DATA_LINE_MODE == DS35M_WR_DATA_LINE_1)
|
|
Bsp_Ds35m_TransSerial(&tmpTansInfo, (uint8_t*)outData, len);
|
|
#elif(DS35M_WR_DATA_LINE_MODE == DS35M_WR_DATA_LINE_4)
|
|
Bsp_Ds35m_TransQuad(&tmpTansInfo, (uint8_t*)outData, len);
|
|
#endif
|
|
|
|
return 0;
|
|
}
|
|
|
|
int Ds35m_WritePageData(uint32_t pageOffsetNum, uint16_t addrOffset, uint8_t *inData, uint16_t len)
|
|
{
|
|
uint8_t u8TmpSta = 0;
|
|
ds35mTransInfo_s tmpTansInfo = {0};
|
|
uint8_t tmpCnt = 200;
|
|
|
|
|
|
Ds35m_WirteEnable();
|
|
|
|
#if(DS35M_WR_DATA_LINE_MODE == DS35M_WR_DATA_LINE_1)
|
|
tmpTansInfo.cmd = DS35M_CMD_PROGRAM_LOAD;
|
|
#elif(DS35M_WR_DATA_LINE_MODE == DS35M_WR_DATA_LINE_4)
|
|
tmpTansInfo.cmd = DS35M_CMD_PROGRAM_LOAD_4;
|
|
#endif
|
|
tmpTansInfo.addrByte = 2;
|
|
tmpTansInfo.addrVal = addrOffset;
|
|
tmpTansInfo.dummyByte = 0;
|
|
tmpTansInfo.direct = DS35M_TRANS_TX;
|
|
#if(DS35M_WR_DATA_LINE_MODE == DS35M_WR_DATA_LINE_1)
|
|
Bsp_Ds35m_TransSerial(&tmpTansInfo, (uint8_t*)inData, len);
|
|
#elif(DS35M_WR_DATA_LINE_MODE == DS35M_WR_DATA_LINE_4)
|
|
Bsp_Ds35m_TransQuad(&tmpTansInfo, (uint8_t*)inData, len);
|
|
#endif
|
|
|
|
// Ds35m_WirteEnable();
|
|
|
|
Ds35m_ProgramExecute(pageOffsetNum);
|
|
|
|
while(tmpCnt--) {
|
|
Ds35m_FeaturesGet(DS35M_FEATURES_ADD_STATUS_0, &u8TmpSta);
|
|
if(u8TmpSta & DS35M_STATUS_0_MASK_P_FAIL) {
|
|
Ds35m_WirteDisable();
|
|
// am_util_stdio_printf("%s:write fail 1\r\n", __func__);
|
|
return -1;
|
|
} else if((u8TmpSta & DS35M_STATUS_0_MASK_OIP) == 0) {
|
|
break;
|
|
}
|
|
//am_util_delay_ms(1); // datasheet的写时间no ecc:300-600us/have ecc:400-600us
|
|
}
|
|
|
|
if(tmpCnt == 0) {
|
|
Ds35m_WirteDisable();
|
|
// am_util_stdio_printf("%s:write fail 2\r\n", __func__);
|
|
return -2;
|
|
}
|
|
|
|
Ds35m_WirteDisable();
|
|
|
|
return 0;
|
|
}
|
|
|
|
int Ds35m_ReadOnePage(uint32_t chunkNum, uint8_t *outData)
|
|
{
|
|
return Ds35m_ReadPageData(chunkNum, 0, outData, BSP_DS35M_BYTES_PER_PAGE_DATA);
|
|
}
|
|
|
|
int Ds35m_WriteOnePage(int chunkNum, uint8_t *inData)
|
|
{
|
|
return Ds35m_WritePageData(chunkNum, 0, inData, BSP_DS35M_BYTES_PER_PAGE_DATA);
|
|
}
|
|
|
|
int Ds35m_ReadSpare(uint32_t chunkNum, uint8_t *outData, uint8_t len)
|
|
{
|
|
return Ds35m_ReadPageData(chunkNum, BSP_DS35M_BYTES_PER_PAGE_DATA, outData, len);
|
|
}
|
|
|
|
int Ds35m_WriteSpare(int chunkNum, uint8_t *inData, uint8_t len)
|
|
{
|
|
return Ds35m_WritePageData(chunkNum, BSP_DS35M_BYTES_PER_PAGE_DATA, inData, len);
|
|
}
|
|
|
|
|
|
int Ds35m_EraseBlock(int blockNum)
|
|
{
|
|
ds35mTransInfo_s tmpTansInfo = {0};
|
|
uint8_t u8TmpSta = 0;
|
|
uint8_t tmpCnt = 100;
|
|
|
|
Ds35m_WirteEnable();
|
|
|
|
tmpTansInfo.cmd = DS35M_CMD_ERASE_BLOCK;
|
|
tmpTansInfo.addrByte = 3;
|
|
tmpTansInfo.addrVal = blockNum << 6; // 换算page地址
|
|
tmpTansInfo.dummyByte = 0;
|
|
tmpTansInfo.direct = DS35M_TRANS_TX;
|
|
Bsp_Ds35m_TransSerial(&tmpTansInfo, NULL, 0);
|
|
|
|
while(tmpCnt--) {
|
|
Ds35m_FeaturesGet(DS35M_FEATURES_ADD_STATUS_0, &u8TmpSta);
|
|
if(u8TmpSta & DS35M_STATUS_0_MASK_E_FAIL) {
|
|
//printf("%s:erase fail 1 :%d\r\n", __func__,blockNum);
|
|
return -1;
|
|
} else if((u8TmpSta & DS35M_STATUS_0_MASK_OIP) == 0) {
|
|
break;
|
|
}
|
|
am_util_delay_ms(1); // datasheet的块擦除时间3-10ms
|
|
}
|
|
|
|
|
|
if(tmpCnt == 0) {
|
|
// printf("%s:erase fail 2\r\n", __func__);
|
|
return -2;
|
|
}
|
|
|
|
Ds35m_WirteDisable();
|
|
return 0;
|
|
}
|
|
|
|
int Ds35m_SwitchEcc(bool sw)
|
|
{
|
|
if(sw) {
|
|
Bsp_Ds35m_Ioctl(DS35M_IOCTL_ECC_ENABLE, NULL);
|
|
} else {
|
|
Bsp_Ds35m_Ioctl(DS35M_IOCTL_ECC_DISABLE, NULL);
|
|
}
|
|
|
|
// ds35m_chipEccSw = sw;
|
|
return 0;
|
|
}
|
|
|
|
#endif //defined(EXT_FLASH_CHIP_DS35M1GA)
|