pikapython/bsp/w806/Libraries/drivers/wm_internal_flash.c

489 lines
12 KiB
C
Raw Normal View History

2022-02-18 11:27:58 +08:00
#include "wm_internal_flash.h"
FLASH_ProcessTypeDef pFlash;
static vu32 read_first_value(void)
{
return M32(RSA_BASE);
}
static void writeEnable(void)
{
FLASH->CMD_INFO = 0x6;
FLASH->CMD_START = FLASH_CMD_START_CMD;
}
static unsigned char readRID(void)
{
FLASH->CMD_INFO = 0x2c09F;
FLASH->CMD_START = FLASH_CMD_START_CMD;
return read_first_value() & 0xFF;
}
static void writeBpBit_for_1wreg(char cmp, char bp4, char bp3, char bp2, char bp1, char bp0)
{
int status = 0;
int bpstatus = 0;
FLASH->CMD_INFO = 0x0C005;
FLASH->CMD_START = FLASH_CMD_START_CMD;
status = read_first_value() & 0xFF;
FLASH->CMD_INFO = 0x0C035;
FLASH->CMD_START = FLASH_CMD_START_CMD;
status |= (read_first_value() & 0xFF) << 8;
/*Write Enable*/
FLASH->CMD_INFO = 0x6;
FLASH->CMD_START = FLASH_CMD_START_CMD;
bpstatus = (bp4 << 6) | (bp3 << 5) | (bp2 << 4) | (bp1 << 3) | (bp0 << 2);
status = (status & 0xBF83) | bpstatus | (cmp << 14);
M32(RSA_BASE) = status;
FLASH->CMD_INFO = 0x1A001;
FLASH->CMD_START = FLASH_CMD_START_CMD;
}
static void writeBpBit_for_2wreg(char cmp, char bp4, char bp3, char bp2, char bp1, char bp0)
{
int status = 0;
int bpstatus = 0;
FLASH->CMD_INFO = 0x0C005;
FLASH->CMD_START = FLASH_CMD_START_CMD;
status = read_first_value() & 0xFF;
FLASH->CMD_INFO = 0x0C035;
FLASH->CMD_START = FLASH_CMD_START_CMD;
status |= (read_first_value() & 0xFF) << 8;
/*Write Enable*/
FLASH->CMD_INFO = 0x6;
FLASH->CMD_START = FLASH_CMD_START_CMD;
bpstatus = (bp4 << 6) | (bp3 << 5) | (bp2 << 4) | (bp1 << 3) | (bp0 << 2);
bpstatus = (status & 0x83) | bpstatus;
M32(RSA_BASE) = bpstatus;
FLASH->CMD_INFO = 0xA001;
FLASH->CMD_START = FLASH_CMD_START_CMD;
FLASH->CMD_INFO = 0x6;
FLASH->CMD_START = FLASH_CMD_START_CMD;
status = ((status>>8) & 0xBF) | (cmp << 6);
M32(RSA_BASE) = status;
FLASH->CMD_INFO = 0xA031;
FLASH->CMD_START = FLASH_CMD_START_CMD;
}
static void writeESMTBpBit(char cmp, char bp4, char bp3, char bp2, char bp1, char bp0)
{
int status = 0;
int bpstatus = 0;
FLASH->CMD_INFO = 0x0C005;
FLASH->CMD_START = FLASH_CMD_START_CMD;
status = read_first_value() & 0xFF;
bpstatus = (bp4 << 6) | (bp3 << 5) | (bp2 << 4) | (bp1 << 3) | (bp0 << 2);
status = (status & 0x83) | bpstatus;
/*Write Enable*/
FLASH->CMD_INFO = 0x6;
FLASH->CMD_START = FLASH_CMD_START_CMD;
bpstatus = (bp4 << 6) | (bp3 << 5) | (bp2 << 4) | (bp1 << 3) | (bp0 << 2);
status = (status & 0x83) | bpstatus | (cmp << 14);
M32(RSA_BASE) = status;
FLASH->CMD_INFO = 0x0A001;
FLASH->CMD_START = FLASH_CMD_START_CMD;
FLASH->CMD_INFO = 0x0C085;
FLASH->CMD_START = FLASH_CMD_START_CMD;
status = read_first_value() & 0xFF;
/*Write Enable*/
FLASH->CMD_INFO = 0x6;
FLASH->CMD_START = FLASH_CMD_START_CMD;
status = (status & 0xBF) | (cmp << 6);
M32(RSA_BASE) = status;
FLASH->CMD_INFO = 0x0A0C1;
FLASH->CMD_START = FLASH_CMD_START_CMD;
}
static int flashunlock(void)
{
switch(readRID())
{
case SPIFLASH_MID_GD:
case SPIFLASH_MID_TSINGTENG:
writeBpBit_for_1wreg(0, 0, 0, 0, 0, 0);
break;
case SPIFLASH_MID_PUYA:
case SPIFLASH_MID_XTX:
case SPIFLASH_MID_BOYA:
case SPIFLASH_MID_FUDANMICRO:
case SPIFLASH_MID_XMC:
writeBpBit_for_2wreg(0, 0, 0, 0, 0, 0);
break;
case SPIFLASH_MID_ESMT:
writeESMTBpBit(0, 0, 0, 0, 0, 0);
break;
default:
return -1;
}
return 0;
}
static int flashlock(void)
{
switch(readRID())
{
case SPIFLASH_MID_GD:
case SPIFLASH_MID_TSINGTENG:
writeBpBit_for_1wreg(0, 1, 1, 0, 1, 0);
break;
case SPIFLASH_MID_PUYA:
case SPIFLASH_MID_XTX:
case SPIFLASH_MID_BOYA:
case SPIFLASH_MID_FUDANMICRO:
case SPIFLASH_MID_XMC:
writeBpBit_for_2wreg(0, 1, 1, 0, 1, 0);
break;
case SPIFLASH_MID_ESMT:
writeESMTBpBit(0, 1, 1, 0, 1, 0);
break;
default:
return -1;/*do not clear QIO Mode*/
}
return 0;
}
static int programSR(unsigned int cmd, unsigned long addr, unsigned char *buf, unsigned int sz)
{
unsigned long base_addr = 0;
unsigned int size = 0;
if (sz > INSIDE_FLS_PAGE_SIZE)
{
sz = INSIDE_FLS_PAGE_SIZE;
}
base_addr = RSA_BASE;
size = sz;
while(size)
{
M32(base_addr) = *((unsigned long *)buf);
base_addr += 4;
buf += 4;
size -= 4;
}
writeEnable();
FLASH->CMD_INFO = cmd | ((sz - 1) << 16);
FLASH->ADDR = (addr & 0x1FFFFFF);
FLASH->CMD_START = FLASH_CMD_START_CMD;
return 0;
}
static int programPage (unsigned long adr, unsigned long sz, unsigned char *buf)
{
programSR(0x80009002, adr, buf, sz);
return(0);
}
static int eraseSR(unsigned int cmd, unsigned long addr)
{
/*Write Enable*/
writeEnable();
FLASH->CMD_INFO = cmd;
FLASH->ADDR = (addr & 0x1FFFFFF);
FLASH->CMD_START = FLASH_CMD_START_CMD;
return 0;
}
static int eraseSector (unsigned long adr)
{
eraseSR(0x80000820, adr);
return (0); // Finished without Errors
}
static unsigned int getFlashDensity(void)
{
unsigned char density = 0;
FLASH->CMD_INFO = 0x2c09F;
FLASH->CMD_START = FLASH_CMD_START_CMD;
density = ((read_first_value() & 0xFFFFFF) >> 16) & 0xFF;
// printf("density %x\n", density);
if (density && (density <= 0x21)) /*just limit to (1<<33UL) Byte*/
{
return (1 << density);
}
return 0;
}
/*sr end*/
static int __readByCMD(unsigned char cmd, unsigned long addr, unsigned char *buf, unsigned long sz)
{
int i = 0;
int word = sz / 4;
int byte = sz % 4;
unsigned long addr_read;
if (!(FLASH->FLASH_CR&0x1))/*non-QIO mode, only single line command can be used*/
{
if (cmd > 0x0B)
{
cmd = 0x0B;
}
}
switch (cmd)
{
case 0x03:
FLASH->CMD_INFO = 0x8000C003 | (((sz - 1) & 0x3FF) << 16);
FLASH->ADDR = addr & 0x1FFFFFF;
FLASH->CMD_START = FLASH_CMD_START_CMD;
break;
case 0x0B:
if((FLASH->FLASH_CR & 0x2) == 0x2)
{
FLASH->CMD_INFO = 0xB400C00B | (((sz - 1) & 0x3FF) << 16);
}
else
{
FLASH->CMD_INFO = 0xBC00C00B | (((sz - 1) & 0x3FF) << 16);
}
FLASH->ADDR = addr & 0x1FFFFFF;
FLASH->CMD_START = FLASH_CMD_START_CMD;
break;
case 0xBB:
FLASH->CMD_INFO = 0xE400C0BB | (((sz - 1) & 0x3FF) << 16);
FLASH->ADDR = addr & 0x1FFFFFF;
FLASH->CMD_START = FLASH_CMD_START_CMD;
break;
case 0xEB:
FLASH->CMD_INFO = 0xEC00C0EB | (((sz - 1) & 0x3FF) << 16);
FLASH->ADDR = addr & 0x1FFFFFF;
FLASH->CMD_START = FLASH_CMD_START_CMD;
break;
default:
return -1;
}
// printf("delay delay delay delay\n");
// dumpUint32("readByCMD RSA_BASE", RSA_BASE, sz/4);
addr_read = RSA_BASE;
for(i = 0; i < word; i ++)
{
M32(buf) = M32(addr_read);
buf += 4;
addr_read += 4;
}
if(byte > 0)
{
M32(buf) = M32(addr_read);
buf += 3; //point last byte
byte = 4 - byte;
while(byte)
{
*buf = 0;
buf --;
byte --;
}
}
return 0;
}
static int flashRead(unsigned long addr, unsigned char *buf, unsigned long sz)
{
unsigned int flash_addr;
unsigned int sz_pagenum = 0;
unsigned int sz_remain = 0;
int i = 0;
int page_offset = addr & (INSIDE_FLS_PAGE_SIZE - 1);
static char cache[INSIDE_FLS_PAGE_SIZE] = {0};
flash_addr = addr & ~(INSIDE_FLS_PAGE_SIZE - 1);
__readByCMD(0xEB, flash_addr, (unsigned char *)cache, INSIDE_FLS_PAGE_SIZE);
if (sz > INSIDE_FLS_PAGE_SIZE - page_offset)
{
memcpy(buf, cache + page_offset, INSIDE_FLS_PAGE_SIZE - page_offset);
buf += INSIDE_FLS_PAGE_SIZE - page_offset;
flash_addr += INSIDE_FLS_PAGE_SIZE;
sz_pagenum = (sz - (INSIDE_FLS_PAGE_SIZE - page_offset)) / INSIDE_FLS_PAGE_SIZE;
sz_remain = (sz - (INSIDE_FLS_PAGE_SIZE - page_offset)) % INSIDE_FLS_PAGE_SIZE;
for (i = 0; i < sz_pagenum; i++)
{
__readByCMD(0xEB, flash_addr, (unsigned char *)cache, INSIDE_FLS_PAGE_SIZE);
memcpy(buf, cache, INSIDE_FLS_PAGE_SIZE);
buf += INSIDE_FLS_PAGE_SIZE;
flash_addr += INSIDE_FLS_PAGE_SIZE;
}
if (sz_remain)
{
__readByCMD(0xEB, flash_addr, (unsigned char *)cache, sz_remain);
memcpy(buf, cache, sz_remain);
}
}
else
{
memcpy(buf, cache + page_offset, sz);
}
return 0;
}
/**
* @brief This function is used to unlock flash protect area [0x0~0x2000].
*
* @param None
*
* @return None
*
* @note None
*/
int tls_flash_unlock(void)
{
return flashunlock();
}
/**
* @brief This function is used to lock flash protect area [0x0~0x2000].
*
* @param None
*
* @return None
*
* @note None
*/
int tls_flash_lock(void)
{
return flashlock();
}
/**
* @brief This function is used to read data from the flash.
*
* @param[in] addr is byte offset addr for read from the flash.
* @param[in] buf is user for data buffer of flash read
* @param[in] len is byte length for read.
*
* @retval HAL_OK if read sucsess
* @retval HAL_ERROR if read fail
*
* @note None
*/
HAL_StatusTypeDef HAL_FLASH_Read(uint32_t addr, uint8_t *buf, uint32_t len)
{
int err;
if (((addr & (INSIDE_FLS_BASE_ADDR - 1)) >= getFlashDensity()) || (len == 0) || (buf == NULL))
{
return HAL_ERROR;
}
__HAL_LOCK(&pFlash);
flashRead(addr, buf, len);
err = HAL_OK;
__HAL_UNLOCK(&pFlash);
return err;
}
/**
* @brief This function is used to write data to the flash.
*
* @param[in] addr is byte offset addr for write to the flash
* @param[in] buf is the data buffer want to write to flash
* @param[in] len is the byte length want to write
*
* @retval HAL_OK if write flash success
* @retval HAL_ERROR if argument is invalid
*
* @note None
*/
HAL_StatusTypeDef HAL_FLASH_Write(uint32_t addr, uint8_t *buf, uint32_t len)
{
static uint8_t cache[INSIDE_FLS_SECTOR_SIZE] = {0};
unsigned int secpos;
unsigned int secoff;
unsigned int secremain;
unsigned int i;
unsigned int offaddr;
if (((addr & (INSIDE_FLS_BASE_ADDR - 1)) >= getFlashDensity()) || (len == 0) || (buf == NULL))
{
return HAL_ERROR;
}
__HAL_LOCK(&pFlash);
offaddr = addr & (INSIDE_FLS_BASE_ADDR - 1);
secpos = offaddr / INSIDE_FLS_SECTOR_SIZE;
secoff = (offaddr % INSIDE_FLS_SECTOR_SIZE);
secremain = INSIDE_FLS_SECTOR_SIZE - secoff;
if(len <= secremain)
{
secremain = len;
}
while (1)
{
flashRead(secpos * INSIDE_FLS_SECTOR_SIZE, cache, INSIDE_FLS_SECTOR_SIZE);
eraseSector(secpos * INSIDE_FLS_SECTOR_SIZE);
for (i = 0; i < secremain; i++)
{
cache[i + secoff] = buf[i];
}
for (i = 0; i < (INSIDE_FLS_SECTOR_SIZE / INSIDE_FLS_PAGE_SIZE); i++)
{
programPage(secpos * INSIDE_FLS_SECTOR_SIZE + i * INSIDE_FLS_PAGE_SIZE, INSIDE_FLS_PAGE_SIZE, &cache[i * INSIDE_FLS_PAGE_SIZE]);
}
if(len == secremain)
{
break;
}
else
{
secpos++;
secoff = 0;
buf += secremain;
len -= secremain;
if(len > (INSIDE_FLS_SECTOR_SIZE))
secremain = INSIDE_FLS_SECTOR_SIZE;
else
secremain = len;
}
}
__HAL_UNLOCK(&pFlash);
return HAL_OK;
}