mirror of
https://gitee.com/Lyon1998/pikapython.git
synced 2025-01-15 17:02:53 +08:00
489 lines
12 KiB
C
489 lines
12 KiB
C
#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;
|
|
}
|
|
|
|
|