Files
Michael Sauer 49d6b329b0 fix: printf statt wegkompilierter TLS_DBGPRT_ERR-Meldung bei fls_lock-Fehler
Wie beim s_fls2_lock-Fehlerpfad (T1, Plan 2) blieb auch ein Fehlschlag beim
Anlegen des primaeren fls_lock-Semaphors unsichtbar, weil TLS_DBGPRT_ERR in
diesem Build wegkompiliert ist. tls_fls_init() haette TLS_FLS_STATUS_ENOMEM
stumm zurueckgegeben. Ergaenzt außerdem den Zeitobergrenzen-Kommentar in
nl_recovery.c: die Obergrenze schuetzt nur gegen einen echten Stillstand,
nicht gegen einen langsamen, aber laufenden Download - wm_fwup.c bedient den
Watchdog bei jeder empfangenen Nachricht selbst.
2026-09-12 03:27:13 +02:00

1431 lines
39 KiB
C
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/**
* @file wm_internal_fls.c
*
* @brief flash Driver Module
*
* @author dave
*
* Copyright (c) 2015 Winner Microelectronics Co., Ltd.
*/
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "wm_dbg.h"
#include "wm_mem.h"
#include "list.h"
#include "wm_flash_map.h"
#include "wm_internal_flash.h"
#include "wm_flash.h"
#include "wm_gpio.h"
#include "wm_io.h"
/* ninlight patch 5: the >1 MB (second flash) path switches the SPI pins without any lock;
* serialise it for all callers (SDK params, fwup, ninlight). See sdk/PATCHES.md. */
static tls_os_sem_t *s_fls2_lock = NULL;
#define FLS2_LOCK() do { if (s_fls2_lock) tls_os_sem_acquire(s_fls2_lock, 0); } while (0)
#define FLS2_UNLOCK() do { if (s_fls2_lock) tls_os_sem_release(s_fls2_lock); } while (0)
void tls_spifls_cs_switch(enum tls_io_name flashcs, int openflag);
void tls_spifls_di_switch(enum tls_io_name flashdi, int openflag);
void tls_spifls_do_switch(enum tls_io_name flashdo, int openflag);
void tls_spifls_ck_switch(enum tls_io_name flashck, int openflag);
extern int tls_spifls_chip_erase(void);
extern int tls_spifls_read_id(u32 *id);
extern int tls_spifls_erase(u32 sector);
extern int tls_spifls_probe(void);
static struct tls_inside_fls *inside_fls = NULL;
static u32 inner1flashsize = 0; /*first inner flash size*/
static u32 inner2flashsize = 0; /*second inner flash size*/
u32 flashtotalsize = 0;
static void writeEnable(void)
{
M32(0x40002000) = 0x6;
M32(0x40002004) = 0x10000000;
}
unsigned char readRID(void)
{
M32(0x40002000) = 0x2c09F;
M32(0x40002004) = 0x10000000;
return M32(0x40002200) & 0xFF;
}
void writeGDBpBit(char cmp, char bp4, char bp3, char bp2, char bp1, char bp0)
{
int status = 0;
int bpstatus = 0;
M32(0x40002000) = 0x0C005;
M32(0x40002004) = 0x10000000;
status = M32(0x40002200) & 0xFF;
M32(0x40002000) = 0x0C035;
M32(0x40002004) = 0x10000000;
status |= (M32(0x40002200) & 0xFF) << 8;
/*Write Enable*/
M32(0x40002000) = 0x6;
M32(0x40002004) = 0x10000000;
bpstatus = (bp4 << 6) | (bp3 << 5) | (bp2 << 4) | (bp1 << 3) | (bp0 << 2);
status = (status & 0xBF83) | bpstatus | (cmp << 14);
M32(0x40002200) = status;
M32(0x40002000) = 0x1A001;
M32(0x40002004) = 0x10000000;
}
void writeESMTBpBit(char cmp, char bp4, char bp3, char bp2, char bp1, char bp0)
{
int status = 0;
int bpstatus = 0;
M32(0x40002000) = 0x0C005;
M32(0x40002004) = 0x10000000;
status = M32(0x40002200) & 0xFF;
bpstatus = (bp4 << 6) | (bp3 << 5) | (bp2 << 4) | (bp1 << 3) | (bp0 << 2);
status = (status & 0x83) | bpstatus;
/*Write Enable*/
M32(0x40002000) = 0x6;
M32(0x40002004) = 0x10000000;
bpstatus = (bp4 << 6) | (bp3 << 5) | (bp2 << 4) | (bp1 << 3) | (bp0 << 2);
status = (status & 0x83) | bpstatus | (cmp << 14);
M32(0x40002200) = status;
M32(0x40002000) = 0x0A001;
M32(0x40002004) = 0x10000000;
M32(0x40002000) = 0x0C085;
M32(0x40002004) = 0x10000000;
status = M32(0x40002200) & 0xFF;
/*Write Enable*/
M32(0x40002000) = 0x6;
M32(0x40002004) = 0x10000000;
status = (status & 0xBF) | (cmp << 6);
M32(0x40002200) = status;
M32(0x40002000) = 0x0A0C1;
M32(0x40002004) = 0x10000000;
}
int flashunlock(void)
{
switch(readRID())
{
case SPIFLASH_MID_GD:
case SPIFLASH_MID_PUYA:
writeGDBpBit(0, 0, 0, 0, 0, 0);
break;
case SPIFLASH_MID_ESMT:
writeESMTBpBit(0, 0, 0, 0, 0, 0);
break;
default:
return -1;
}
return 0;
}
int flashlock(void)
{
switch(readRID())
{
case SPIFLASH_MID_GD:
case SPIFLASH_MID_PUYA:
writeGDBpBit(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 = 0x40002200;
size = sz;
while(size)
{
M32(base_addr) = *((unsigned long *)buf);
base_addr += 4;
buf += 4;
size -= 4;
}
writeEnable();
M32(0x40002000) = cmd | ((sz - 1) << 16);
M32(0x40002004) = 0x10000000 | ((addr & 0xFFFFF) << 8);
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();
M32(0x40002000) = cmd;
M32(0x40002004) = 0x10000000 | ((addr & 0xFFFFF) << 8);
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;
M32(0x40002000) = 0x2c09F;
M32(0x40002004) = 0x10000000;
density = ((M32(0x40002200) & 0xFFFFFF) >> 16) & 0xFF;
if ((density == 0x14) || (density == 0x13))
{
return (1 << density);
}
return 0;
}
/*sr start*/
/************************************************************
addr:
For GD, address:0x000,0x100
For ESMT, address:0xFF000,0xFF100
For WINBOND, address:0x1000
*************************************************************/
int readSR(unsigned int 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;
M32(0x40002000) = cmd | ((sz - 1) << 16);
M32(0x40002004) = 0x10000000 | ((addr & 0xFFFFF) << 8);
addr_read = 0x40002200;
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
while(byte)
{
*buf = 0;
buf --;
byte --;
}
}
return 0;
}
void flashSRRW(unsigned long offset, unsigned char *buf, unsigned long sz, unsigned char *backbuf, unsigned int backlen, unsigned int rd)
{
#define SR_TOTAL_SZ (512)
#define SR_PROGRAM_SZE (256)
unsigned int i;
unsigned int j;
unsigned int baseaddr = 0;
unsigned int sectoroffset = 0;
unsigned int sectorsize = 0;
unsigned int sectornum = 0;
unsigned int remainsz;
unsigned int erasecmd = 0;
unsigned int readcmd = 0;
unsigned int writecmd = 0;
unsigned char flashid = 0;
if (!buf || ((rd == 0) && ( !backbuf || (backlen < 512))))
{
return;
}
flashid = readRID();
switch(flashid)
{
case SPIFLASH_MID_GD:
baseaddr = 0x0;
sectoroffset = 256;
sectorsize = 256;
sectornum = 2;
erasecmd = 0x80000844;
readcmd = 0xBC00C048;
writecmd = 0x80009042;
break;
case SPIFLASH_MID_ESMT:
{
baseaddr = 0xFF000;
sectoroffset = 0;
sectorsize = 512;
sectornum = 1;
erasecmd = 0x80000820;
readcmd = 0xBC00C00B;
writecmd = 0x80009002;
M32(0x40002000) = 0x3A; /*enter OTP*/
M32(0x40002004) = 0x10000000;
}
break;
case SPIFLASH_MID_PUYA:
baseaddr = 0x1000;
sectoroffset = 0x1000;
sectorsize = 256;
sectornum = 2;
erasecmd = 0x80000844;
readcmd = 0xBC00C048;
writecmd = 0x80009042;
break;
default:
{
}
break;
}
for (i = 0 ; i < sectornum; i++)
{
readSR(readcmd, baseaddr + sectoroffset * i, backbuf + i * sectorsize, sectorsize);
}
if (rd)
{
for(i = 0; i < sz; i++) //Copy
{
buf[i] = backbuf[i + offset];
}
}
else
{
for (i = 0; i < sectornum ; i++)
{
eraseSR(erasecmd, baseaddr + sectoroffset * i);
}
remainsz = (sz < (SR_TOTAL_SZ - offset)) ? sz : (SR_TOTAL_SZ - offset);
for(i = 0; i < remainsz; i++)
{
backbuf[i + offset] = buf[i];
}
for ( i = 0; i < sectornum; i++)
{
for (j = 0; j < (sectorsize / SR_PROGRAM_SZE); j++)
{
programSR(writecmd, baseaddr + sectoroffset * i + j * SR_PROGRAM_SZE, backbuf, SR_PROGRAM_SZE);
backbuf += SR_PROGRAM_SZE;
}
}
}
if (SPIFLASH_MID_ESMT == flashid)
{
/*Write Disable*/
M32(0x40002000) = 0x4;
M32(0x40002004) = 0x10000000;
}
}
/*sr end*/
int readByCMD(unsigned long addr, unsigned char *buf, unsigned long sz, unsigned int mode)
{
int i = 0;
int word = sz / 4;
int byte = sz % 4;
unsigned long addr_read;
if (mode & 0x1) /*QIO*/
{
addr_read = 0xEC00C0EB;
}
else /*SPI*/
{
addr_read = 0xBC00C00B;
}
M32(0x40002000) = addr_read | (((sz - 1) & 0x3FF) << 16);
M32(0x40002004) = 0x10000000 | ((addr & 0xFFFFF) << 8);
addr_read = 0x40002200;
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;
}
void writeSRLockBit(unsigned char srbitlock)
{
int status = 0;
switch(readRID())
{
case SPIFLASH_MID_PUYA:
{
if(srbitlock >= 8)
{
return;
}
M32(0x40002000) = 0x0C005;
M32(0x40002004) = 0x10000000;
status = M32(0x40002200)&0xFF;
M32(0x40002000) = 0x0C035;
M32(0x40002004) = 0x10000000;
status |= (M32(0x40002200)&0xFF)<<8;
/*Write Enable*/
M32(0x40002000) = 0x6;
M32(0x40002004) = 0x10000000;
status |= (srbitlock)<<11;
M32(0x40002200) = status;
M32(0x40002000) = 0x1A001;
M32(0x40002004) = 0x10000000;
}
break;
default:
break;
}
}
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);
char *cache = NULL;
cache = tls_mem_alloc(INSIDE_FLS_PAGE_SIZE);
if (cache == NULL)
{
TLS_DBGPRT_ERR("allocate sector cache memory fail!\n");
return TLS_FLS_STATUS_ENOMEM;
}
flash_addr = addr & ~(INSIDE_FLS_PAGE_SIZE - 1);
readByCMD(flash_addr, (unsigned char *)cache, INSIDE_FLS_PAGE_SIZE, 0);
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(flash_addr, (unsigned char *)cache, INSIDE_FLS_PAGE_SIZE, 0);
MEMCPY(buf, cache, INSIDE_FLS_PAGE_SIZE);
buf += INSIDE_FLS_PAGE_SIZE;
flash_addr += INSIDE_FLS_PAGE_SIZE;
}
if (sz_remain)
{
readByCMD(flash_addr, (unsigned char *)cache, sz_remain, 0);
MEMCPY(buf, cache, sz_remain);
}
}
else
{
MEMCPY(buf, cache + page_offset, sz);
}
tls_mem_free(cache);
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 semaphore protect.
*
* @param None
*
* @return None
*
* @note None
*/
void tls_fls_sem_lock(void)
{
if (inside_fls == NULL)
{
return;
}
tls_os_sem_acquire(inside_fls->fls_lock, 0);
}
/**
* @brief This function is used to semaphore protect cancel.
*
* @param None
*
* @return None
*
* @note None
*/
void tls_fls_sem_unlock(void)
{
if (inside_fls == NULL)
{
return;
}
tls_os_sem_release(inside_fls->fls_lock);
}
/**
* @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 TLS_FLS_STATUS_OK if read sucsess
* @retval TLS_FLS_STATUS_EPERM if flash driver module not beed installed
* @retval TLS_FLS_STATUS_EINVAL if arguments invalid
* @retval TLS_FLS_STATUS_EIO if read fail
*
* @note None
*/
int tls_fls_read(u32 addr, u8 *buf, u32 len)
{
int err = TLS_FLS_STATUS_EINVAL;
u32 addrfor1M = 0;
u32 lenfor1M = 0;
u32 addrfor2M = 0;
u32 lenfor2M = 0;
addrfor1M = addr < FLASH_1M_END_ADDR ? addr : 0xFFFFFFFF;
if (addrfor1M != 0xFFFFFFFF)
{
lenfor1M = (addr + len ) <= FLASH_1M_END_ADDR ? len : (FLASH_1M_END_ADDR - addr);
if (inside_fls == NULL)
{
TLS_DBGPRT_ERR("flash driver module not beed installed!\n");
return TLS_FLS_STATUS_EPERM;
}
if (((addrfor1M & (INSIDE_FLS_BASE_ADDR - 1)) >= inner1flashsize) || (lenfor1M == 0) || (buf == NULL))
{
return TLS_FLS_STATUS_EINVAL;
}
tls_os_sem_acquire(inside_fls->fls_lock, 0);
flashRead(addrfor1M, buf, lenfor1M);
err = TLS_FLS_STATUS_OK;
tls_os_sem_release(inside_fls->fls_lock);
}
if (inner2flashsize)
{
addrfor2M = addr >= FLASH_1M_END_ADDR ? addr : ((addr + len ) > FLASH_1M_END_ADDR ? FLASH_1M_END_ADDR : 0xFFFFFFFF);
if (addrfor2M != 0xFFFFFFFF)
{
lenfor2M = len - lenfor1M;
lenfor2M = (addrfor2M + lenfor2M) <= (FLASH_BASE_ADDR | flashtotalsize) ? lenfor2M : ((FLASH_BASE_ADDR | flashtotalsize) - addrfor2M);
FLS2_LOCK();
tls_spifls_cs_switch(WM_IO_PA_02, 1);
tls_spifls_ck_switch(WM_IO_PA_11, 1);
tls_spifls_di_switch(WM_IO_PA_03, 1);
tls_spifls_do_switch(WM_IO_PA_09, 1);
err = tls_spifls_read(addrfor2M & 0xFFFFF, buf + lenfor1M, lenfor2M);
tls_spifls_di_switch(WM_IO_PA_03, 0);
tls_spifls_do_switch(WM_IO_PA_09, 0);
tls_spifls_ck_switch(WM_IO_PA_11, 0);
tls_spifls_cs_switch(WM_IO_PA_02, 0);
FLS2_UNLOCK();
return err;
}
}
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 TLS_FLS_STATUS_OK if write flash success
* @retval TLS_FLS_STATUS_EPERM if flash struct point is null
* @retval TLS_FLS_STATUS_ENODRV if flash driver is not installed
* @retval TLS_FLS_STATUS_EINVAL if argument is invalid
* @retval TLS_FLS_STATUS_EIO if io error
*
* @note None
*/
int tls_fls_write(u32 addr, u8 *buf, u32 len)
{
u8 *cache;
unsigned int secpos;
unsigned int secoff;
unsigned int secremain;
unsigned int i;
unsigned int offaddr;
unsigned int writepage;
int err = 0;
unsigned int cntforFF = 0;
u32 addrfor1M = 0;
u32 lenfor1M = 0;
u32 addrfor2M = 0;
u32 lenfor2M = 0;
// u32 cpu_sr = 0;
// u32 elapsedtime = 0;
addrfor1M = addr < FLASH_1M_END_ADDR ? addr : 0xFFFFFFFF;
if (addrfor1M != 0xFFFFFFFF)
{
lenfor1M = (addr + len ) <= FLASH_1M_END_ADDR ? len : (FLASH_1M_END_ADDR - addr);
if (inside_fls == NULL)
{
TLS_DBGPRT_ERR("flash driver module not beed installed!\n");
return TLS_FLS_STATUS_EPERM;
}
if (((addrfor1M & (INSIDE_FLS_BASE_ADDR - 1)) >= inner1flashsize) || (lenfor1M == 0) || (buf == NULL))
{
return TLS_FLS_STATUS_EINVAL;
}
tls_os_sem_acquire(inside_fls->fls_lock, 0);
cache = tls_mem_alloc(INSIDE_FLS_SECTOR_SIZE);
if (cache == NULL)
{
tls_os_sem_release(inside_fls->fls_lock);
TLS_DBGPRT_ERR("allocate sector cache memory fail!\n");
return TLS_FLS_STATUS_ENOMEM;
}
offaddr = addrfor1M & (INSIDE_FLS_BASE_ADDR - 1); //Offset of 0X08000000
secpos = offaddr / INSIDE_FLS_SECTOR_SIZE; //Section addr
secoff = (offaddr % INSIDE_FLS_SECTOR_SIZE); //Offset in section
secremain = INSIDE_FLS_SECTOR_SIZE - secoff; // ����ʣ��ռ��С
if(lenfor1M <= secremain)
{
secremain = lenfor1M; //Not bigger with remain size in section
}
while (1)
{
flashRead(secpos * INSIDE_FLS_SECTOR_SIZE, cache, INSIDE_FLS_SECTOR_SIZE);
cntforFF = 0;
for (i = 0; i < secremain; i++) // ����
{
if(cache[i + secoff] == 0xFF)
{
cntforFF++;
}
cache[i + secoff] = buf[i];
}
if( cntforFF != secremain)
{
eraseSector(secpos * INSIDE_FLS_SECTOR_SIZE);
}
if( (cntforFF != secremain ) || ((secoff == 0) && (secremain == 4096)))
{
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]); //Write
}
}
else
{
writepage = secoff / INSIDE_FLS_PAGE_SIZE == 15 ? 16 : (secoff + secremain) / INSIDE_FLS_PAGE_SIZE + 1;
for(i = (secoff / INSIDE_FLS_PAGE_SIZE); i < writepage; i++)
{
programPage(secpos * INSIDE_FLS_SECTOR_SIZE + i * INSIDE_FLS_PAGE_SIZE, INSIDE_FLS_PAGE_SIZE, &cache[i * INSIDE_FLS_PAGE_SIZE]); //Write
}
}
if(lenfor1M == secremain)
{
break; // ������
}
else // д��δ����
{
secpos++; // ������ַ��1
secoff = 0; // ƫ��λ��Ϊ0
buf += secremain; // ָ��ƫ��
lenfor1M -= secremain;
if(lenfor1M > (INSIDE_FLS_SECTOR_SIZE))
secremain = INSIDE_FLS_SECTOR_SIZE; // ��һ����������д����
else
secremain = lenfor1M; //Next section will finish
}
}
tls_mem_free(cache);
tls_os_sem_release(inside_fls->fls_lock);
}
if (inner2flashsize)
{
addrfor2M = addr >= FLASH_1M_END_ADDR ? addr : ((addr + len ) > FLASH_1M_END_ADDR ? FLASH_1M_END_ADDR : 0xFFFFFFFF);
if (addrfor2M != 0xFFFFFFFF)
{
lenfor2M = len - lenfor1M;
lenfor2M = (addrfor2M + lenfor2M) <= (FLASH_BASE_ADDR | flashtotalsize) ? lenfor2M : ((FLASH_BASE_ADDR | flashtotalsize) - addrfor2M);
FLS2_LOCK();
tls_spifls_cs_switch(WM_IO_PA_02, 1);
tls_spifls_ck_switch(WM_IO_PA_11, 1);
tls_spifls_di_switch(WM_IO_PA_03, 1);
tls_spifls_do_switch(WM_IO_PA_09, 1);
err = tls_spifls_write((addrfor2M & 0xFFFFF), buf + lenfor1M, lenfor2M);
tls_spifls_di_switch(WM_IO_PA_03, 0);
tls_spifls_do_switch(WM_IO_PA_09, 0);
tls_spifls_ck_switch(WM_IO_PA_11, 0);
tls_spifls_cs_switch(WM_IO_PA_02, 0);
FLS2_UNLOCK();
return err;
}
}
return TLS_FLS_STATUS_OK;
}
/**
* @brief This function is used to erase the appoint sector
*
* @param[in] sector sector num of the flash, 4K byte a sector
*
* @retval TLS_FLS_STATUS_OK if read sucsess
* @retval other if read fail
*
* @note None
*/
int tls_fls_erase(u32 sector)
{
u32 addr;
int err = 0;
if (sector < (inner1flashsize / INSIDE_FLS_SECTOR_SIZE + INSIDE_FLS_BASE_ADDR / INSIDE_FLS_SECTOR_SIZE))
{
if (inside_fls == NULL)
{
TLS_DBGPRT_ERR("flash driver module not beed installed!\n");
return TLS_FLS_STATUS_EPERM;
}
tls_os_sem_acquire(inside_fls->fls_lock, 0);
addr = sector * INSIDE_FLS_SECTOR_SIZE;
eraseSector(addr);
tls_os_sem_release(inside_fls->fls_lock);
}
else if (sector < (flashtotalsize / INSIDE_FLS_SECTOR_SIZE + INSIDE_FLS_BASE_ADDR / INSIDE_FLS_SECTOR_SIZE))
{
FLS2_LOCK();
tls_spifls_cs_switch(WM_IO_PA_02, 1);
tls_spifls_ck_switch(WM_IO_PA_11, 1);
tls_spifls_di_switch(WM_IO_PA_03, 1);
tls_spifls_do_switch(WM_IO_PA_09, 1);
err = tls_spifls_erase(sector & 0xFF);
tls_spifls_di_switch(WM_IO_PA_03, 0);
tls_spifls_do_switch(WM_IO_PA_09, 0);
tls_spifls_ck_switch(WM_IO_PA_11, 0);
tls_spifls_cs_switch(WM_IO_PA_02, 0);
FLS2_UNLOCK();
return err;
}
return TLS_FLS_STATUS_OK;
}
static u8 *gsflscache = NULL;
//static u32 gsSecOffset = 0;
static u32 gsSector = 0;
/**
* @brief This function is used to flush the appoint sector
*
* @param None
*
* @return None
*
* @note The caller should use fls_lock semphore to protect flash operation!
*/
static void tls_fls_flush_sector(void)
{
int i;
u32 addr;
if (gsSector < (inner1flashsize / INSIDE_FLS_SECTOR_SIZE + INSIDE_FLS_BASE_ADDR / INSIDE_FLS_SECTOR_SIZE))
{
addr = gsSector * INSIDE_FLS_SECTOR_SIZE;
eraseSector(addr);
for (i = 0; i < INSIDE_FLS_SECTOR_SIZE / INSIDE_FLS_PAGE_SIZE; i++)
{
programPage(gsSector * INSIDE_FLS_SECTOR_SIZE +
i * INSIDE_FLS_PAGE_SIZE, INSIDE_FLS_PAGE_SIZE,
&gsflscache[i * INSIDE_FLS_PAGE_SIZE]);
}
}
else if (gsSector < (flashtotalsize / INSIDE_FLS_SECTOR_SIZE + INSIDE_FLS_BASE_ADDR / INSIDE_FLS_SECTOR_SIZE))
{
addr = gsSector * INSIDE_FLS_SECTOR_SIZE;
FLS2_LOCK();
tls_spifls_cs_switch(WM_IO_PA_02, 1);
tls_spifls_ck_switch(WM_IO_PA_11, 1);
tls_spifls_di_switch(WM_IO_PA_03, 1);
tls_spifls_do_switch(WM_IO_PA_09, 1);
tls_spifls_write(addr & 0xFFFFF, gsflscache, INSIDE_FLS_SECTOR_SIZE);
tls_spifls_di_switch(WM_IO_PA_03, 0);
tls_spifls_do_switch(WM_IO_PA_09, 0);
tls_spifls_ck_switch(WM_IO_PA_11, 0);
tls_spifls_cs_switch(WM_IO_PA_02, 0);
FLS2_UNLOCK();
}
//gsSecOffset = 0;
}
/**
* @brief This function is used to fast write flash initialize
*
* @param None
*
* @retval TLS_FLS_STATUS_OK sucsess
* @retval other fail
*
* @note None
*/
int tls_fls_fast_write_init(void)
{
if (inside_fls == NULL)
{
TLS_DBGPRT_ERR("flash driver module not beed installed!\n");
return TLS_FLS_STATUS_EPERM;
}
if (NULL != gsflscache)
{
TLS_DBGPRT_ERR("tls_fls_fast_write_init installed!\n");
return -1;
}
gsflscache = tls_mem_alloc(INSIDE_FLS_SECTOR_SIZE);
if (NULL == gsflscache)
{
TLS_DBGPRT_ERR("tls_fls_fast_write_init malloc err!\n");
return -1;
}
return TLS_FLS_STATUS_OK;
}
/**
* @brief This function is used to destroy fast write flash
*
* @param None
*
* @return None
*
* @note None
*/
void tls_fls_fast_write_destroy(void)
{
if (NULL != gsflscache)
{
if (inside_fls == NULL)
{
TLS_DBGPRT_ERR("flash driver module not beed installed!\n");
return;
}
else
{
tls_os_sem_acquire(inside_fls->fls_lock, 0);
tls_fls_flush_sector();
tls_os_sem_release(inside_fls->fls_lock);
}
tls_mem_free(gsflscache);
gsflscache = NULL;
}
}
/**
* @brief This function is used to fast 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] length is the byte length want to write
*
* @retval TLS_FLS_STATUS_OK success
* @retval other fail
*
* @note None
*/
int tls_fls_fast_write(u32 addr, u8 *buf, u32 length)
{
u32 sector, offset, maxlen, len;
if (inside_fls == NULL)
{
TLS_DBGPRT_ERR("flash driver module not beed installed!\n");
return TLS_FLS_STATUS_EPERM;
}
if(((addr & (INSIDE_FLS_BASE_ADDR - 1)) >= flashtotalsize) || (length == 0) || (buf == NULL))
{
return TLS_FLS_STATUS_EINVAL;
}
tls_os_sem_acquire(inside_fls->fls_lock, 0);
sector = addr / INSIDE_FLS_SECTOR_SIZE;
offset = addr % INSIDE_FLS_SECTOR_SIZE;
maxlen = INSIDE_FLS_SECTOR_SIZE;
if ((sector != gsSector) && (gsSector != 0))
{
tls_fls_flush_sector();
}
gsSector = sector;
if (offset > 0)
{
maxlen -= offset;
}
while (length > 0)
{
len = (length > maxlen) ? maxlen : length;
MEMCPY(gsflscache + offset, buf, len);
if (offset + len >= INSIDE_FLS_SECTOR_SIZE)
{
tls_fls_flush_sector();
gsSector++;
}
offset = 0;
maxlen = INSIDE_FLS_SECTOR_SIZE;
sector++;
buf += len;
length -= len;
}
tls_os_sem_release(inside_fls->fls_lock);
return TLS_FLS_STATUS_OK;
}
/**
* @brief This function is used to erase flash all chip
*
* @param None
*
* @retval TLS_FLS_STATUS_OK sucsess
* @retval other fail
*
* @note None
*/
int tls_fls_chip_erase(void)
{
int i, j;
u8 *cache;
if (inside_fls == NULL)
{
TLS_DBGPRT_ERR("flash driver module not beed installed!\n");
return TLS_FLS_STATUS_EPERM;
}
tls_os_sem_acquire(inside_fls->fls_lock, 0);
cache = tls_mem_alloc(INSIDE_FLS_SECTOR_SIZE);
if (cache == NULL)
{
tls_os_sem_release(inside_fls->fls_lock);
TLS_DBGPRT_ERR("allocate sector cache memory fail!\n");
return TLS_FLS_STATUS_ENOMEM;
}
for( i = 0; i < ( inner1flashsize - (INSIDE_FLS_SECBOOT_ADDR & 0xFFFFF)) / INSIDE_FLS_SECTOR_SIZE; i ++)
{
flashRead(INSIDE_FLS_SECBOOT_ADDR + i * INSIDE_FLS_SECTOR_SIZE, cache, INSIDE_FLS_SECTOR_SIZE);
for (j = 0; j < INSIDE_FLS_SECTOR_SIZE; j++)
{
if (cache[j] != 0xFF)
{
eraseSector(INSIDE_FLS_SECBOOT_ADDR + i * INSIDE_FLS_SECTOR_SIZE);
break;
}
}
}
if (inner2flashsize)
{
FLS2_LOCK();
tls_spifls_cs_switch(WM_IO_PA_02, 1);
tls_spifls_ck_switch(WM_IO_PA_11, 1);
tls_spifls_di_switch(WM_IO_PA_03, 1);
tls_spifls_do_switch(WM_IO_PA_09, 1);
tls_spifls_chip_erase();
tls_spifls_di_switch(WM_IO_PA_03, 0);
tls_spifls_do_switch(WM_IO_PA_09, 0);
tls_spifls_ck_switch(WM_IO_PA_11, 0);
tls_spifls_cs_switch(WM_IO_PA_02, 0);
FLS2_UNLOCK();
}
tls_mem_free(cache);
tls_os_sem_release(inside_fls->fls_lock);
return TLS_FLS_STATUS_OK;
}
/**
* @brief This function is used to get flash param
*
* @param[in] type the type of the param need to get
* @param[out] param point to addr of out param
*
* @retval TLS_FLS_STATUS_OK sucsess
* @retval other fail
*
* @note None
*/
int tls_fls_get_param(u8 type, void *param)
{
int err;
if (inside_fls == NULL)
{
TLS_DBGPRT_ERR("flash driver module not beed installed!\n");
return TLS_FLS_STATUS_EPERM;
}
if (param == NULL)
{
return TLS_FLS_STATUS_EINVAL;
}
tls_os_sem_acquire(inside_fls->fls_lock, 0);
err = TLS_FLS_STATUS_OK;
switch (type)
{
case TLS_FLS_PARAM_TYPE_ID:
*((u32 *) param) = 0x2013;
break;
case TLS_FLS_PARAM_TYPE_SIZE:
*((u32 *) param) = flashtotalsize;
break;
case TLS_FLS_PARAM_TYPE_PAGE_SIZE:
*((u32 *) param) = INSIDE_FLS_PAGE_SIZE;
break;
case TLS_FLS_PARAM_TYPE_PROG_SIZE:
*((u32 *) param) = INSIDE_FLS_PAGE_SIZE;
break;
case TLS_FLS_PARAM_TYPE_SECTOR_SIZE:
*((u32 *) param) = INSIDE_FLS_SECTOR_SIZE;
break;
default:
TLS_DBGPRT_WARNING("invalid parameter ID!\n");
err = TLS_FLS_STATUS_EINVAL;
break;
}
tls_os_sem_release(inside_fls->fls_lock);
return err;
}
/**
* @brief This function is used to initialize the flash module
*
* @param None
*
* @retval TLS_FLS_STATUS_OK sucsess
* @retval other fail
*
* @note None
*/
int tls_fls_init(void)
{
struct tls_inside_fls *fls;
int err;
u32 id = 0;
if (inside_fls != NULL)
{
TLS_DBGPRT_INFO("flash driver module has been installed!\n");
return TLS_FLS_STATUS_EBUSY;
}
fls = (struct tls_inside_fls *) tls_mem_alloc(sizeof(struct tls_inside_fls));
if (fls == NULL)
{
TLS_DBGPRT_ERR("allocate @inside_fls fail!\n");
return TLS_FLS_STATUS_ENOMEM;
}
memset(fls, 0, sizeof(*fls));
err = tls_os_sem_create(&fls->fls_lock, 1);
if (err != TLS_OS_SUCCESS)
{
tls_mem_free(fls);
/* ninlight patch 5: TLS_DBGPRT_ERR is compiled out in this build, so this failure - the
* whole flash layer stays without its lock and tls_fls_init() returns an error nobody
* prints - would be silent. See sdk/PATCHES.md. */
printf("wm_internal_fls: fls_lock create failed\r\n");
return TLS_FLS_STATUS_ENOMEM;
}
if (tls_os_sem_create(&s_fls2_lock, 1) != TLS_OS_SUCCESS)
printf("wm_internal_fls: s_fls2_lock create failed\r\n");
inside_fls = fls;
inner1flashsize = getFlashDensity();
tls_spifls_cs_switch(WM_IO_PA_02, 1);
tls_spifls_ck_switch(WM_IO_PA_11, 1);
tls_spifls_di_switch(WM_IO_PA_03, 1);
tls_spifls_do_switch(WM_IO_PA_09, 1);
if (TLS_FLS_STATUS_OK == tls_spifls_read_id(&id))
{
id = (id >> 16) & 0xFF;
inner2flashsize = (id ? (1 << id) : 0);
tls_spifls_probe();
}
tls_spifls_di_switch(WM_IO_PA_03, 0);
tls_spifls_do_switch(WM_IO_PA_09, 0);
tls_spifls_ck_switch(WM_IO_PA_11, 0);
tls_spifls_cs_switch(WM_IO_PA_02, 0);
flashtotalsize = inner1flashsize + inner2flashsize;
return TLS_FLS_STATUS_OK;
}
int tls_fls_exit(void)
{
TLS_DBGPRT_FLASH_INFO("Not support flash driver module uninstalled!\n");
return TLS_FLS_STATUS_EPERM;
}
void tls_spifls_di_switch(enum tls_io_name flashdi, int openflag)
{
u32 optvalue = WM_IO_OPTION3;
int i = 0;
static u8 ioclose = 0;
u8 spidi[5][2] = {{WM_IO_PA_03, WM_IO_OPTION3},
{WM_IO_PB_17, WM_IO_OPTION3},
{WM_IO_PB_01, WM_IO_OPTION1},
{WM_IO_PA_05, WM_IO_OPTION3},
{WM_IO_PA_10, WM_IO_OPTION4}
};
if (openflag == 1)
{
for (i = 0; i < sizeof(spidi) / (2 * sizeof(u8)); i++)
{
optvalue = tls_io_cfg_get((enum tls_io_name)spidi[i][0]);
if (flashdi == (enum tls_io_name)spidi[i][0])
{
if (optvalue != spidi[i][1])
{
ioclose &= ~(1 << i);
tls_io_cfg_set(flashdi, spidi[i][1]);
}
}
else
{
if (optvalue == spidi[i][1])
{
ioclose |= (1 << i);
tls_io_cfg_set((enum tls_io_name)spidi[i][0], WM_IO_OPTION5);
}
}
}
}
else
{
for (i = 0; i < sizeof(spidi) / (2 * sizeof(u8)); i++)
{
if (flashdi == (enum tls_io_name)spidi[i][0])
{
tls_io_cfg_set(flashdi, WM_IO_OPTION5);
}
else
{
if (ioclose & (1 << i))
{
ioclose &= ~(1 << i);
tls_io_cfg_set((enum tls_io_name)spidi[i][0], spidi[i][1]);
}
}
}
}
}
void tls_spifls_do_switch(enum tls_io_name flashdo, int openflag)
{
u32 optvalue = WM_IO_OPTION3;
int i = 0;
static u8 ioclose = 0;
u8 spido[5][2] = {{WM_IO_PB_18, WM_IO_OPTION3},
{WM_IO_PB_02, WM_IO_OPTION1},
{WM_IO_PA_04, WM_IO_OPTION3},
{WM_IO_PA_09, WM_IO_OPTION4},
{WM_IO_PA_10, WM_IO_OPTION4}
};
if (openflag == 1)
{
for (i = 0; i < sizeof(spido) / (2 * sizeof(u8)); i++)
{
optvalue = tls_io_cfg_get((enum tls_io_name)spido[i][0]);
if (flashdo == (enum tls_io_name)spido[i][0])
{
if (optvalue != spido[i][1])
{
ioclose &= ~(1 << i);
tls_io_cfg_set(flashdo, spido[i][1]);
}
}
else
{
if (optvalue == spido[i][1])
{
ioclose |= (1 << i);
tls_io_cfg_set((enum tls_io_name)spido[i][0], WM_IO_OPTION5);
}
}
}
}
else
{
for (i = 0; i < sizeof(spido) / (2 * sizeof(u8)); i++)
{
if (flashdo == (enum tls_io_name)spido[i][0])
{
tls_io_cfg_set(flashdo, WM_IO_OPTION5);
}
else
{
if (ioclose & (1 << i))
{
ioclose &= ~(1 << i);
tls_io_cfg_set((enum tls_io_name)spido[i][0], spido[i][1]);
}
}
}
}
}
void tls_spifls_ck_switch(enum tls_io_name flashck, int openflag)
{
u32 optvalue = WM_IO_OPTION3;
int i = 0;
static u8 ioclose = 0;
u8 spick[4][2] = {{WM_IO_PA_01, WM_IO_OPTION3},
{WM_IO_PB_16, WM_IO_OPTION3},
{WM_IO_PB_27, WM_IO_OPTION1},
{WM_IO_PA_11, WM_IO_OPTION4}
};
if (openflag == 1)
{
for (i = 0; i < sizeof(spick) / (2 * sizeof(u8)); i++)
{
optvalue = tls_io_cfg_get((enum tls_io_name)spick[i][0]);
if (flashck == (enum tls_io_name)spick[i][0])
{
if (optvalue != spick[i][1])
{
ioclose &= ~(1 << i);
tls_io_cfg_set(flashck, spick[i][1]);
}
}
else
{
if (optvalue == spick[i][1])
{
ioclose |= (1 << i);
tls_io_cfg_set((enum tls_io_name)spick[i][0], WM_IO_OPTION5);
}
}
}
}
else
{
for (i = 0; i < sizeof(spick) / (2 * sizeof(u8)); i++)
{
if (flashck == (enum tls_io_name)spick[i][0])
{
tls_io_cfg_set(flashck, WM_IO_OPTION5);
}
else
{
if (ioclose & (1 << i))
{
ioclose &= ~(1 << i);
tls_io_cfg_set((enum tls_io_name)spick[i][0], spick[i][1]);
}
}
}
}
}
void tls_spifls_cs_switch(enum tls_io_name flashcs, int openflag)
{
u32 optvalue = WM_IO_OPTION3;
int i = 0;
static u8 ioclose = 0;
u8 spics[5][2] = {{WM_IO_PA_02, WM_IO_OPTION3},
{WM_IO_PB_15, WM_IO_OPTION3},
{WM_IO_PB_00, WM_IO_OPTION1},
{WM_IO_PB_07, WM_IO_OPTION4},
{WM_IO_PA_12, WM_IO_OPTION4}
};
if (openflag == 1)
{
for (i = 0; i < sizeof(spics) / (2 * sizeof(u8)); i++)
{
optvalue = tls_io_cfg_get((enum tls_io_name)spics[i][0]);
if (flashcs == (enum tls_io_name)spics[i][0])
{
if (optvalue != spics[i][1])
{
ioclose &= ~(1 << i);
tls_io_cfg_set(flashcs, spics[i][1]);
}
}
else
{
if (optvalue == spics[i][1])
{
ioclose |= (1 << i);
tls_io_cfg_set((enum tls_io_name)spics[i][0], WM_IO_OPTION5);
}
}
}
}
else
{
for (i = 0; i < sizeof(spics) / (2 * sizeof(u8)); i++)
{
if (flashcs == (enum tls_io_name)spics[i][0])
{
tls_io_cfg_set(flashcs, WM_IO_OPTION5);
}
else
{
if (ioclose & (1 << i))
{
ioclose &= ~(1 << i);
tls_io_cfg_set((enum tls_io_name)spics[i][0], spics[i][1]);
}
}
}
}
}