mirror of
git://projects.qi-hardware.com/openwrt-xburst.git
synced 2024-12-27 13:46:26 +02:00
the forgotten one :)
This commit is contained in:
parent
2d3cd80303
commit
6e1aa6e45c
@ -1,531 +0,0 @@
|
||||
#include <linux/fs.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/vmalloc.h>
|
||||
#include <linux/hdreg.h>
|
||||
#include <linux/mtd/mtd.h>
|
||||
#include <linux/mtd/nand.h>
|
||||
#include <linux/mtd/blktrans.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <asm/jzsoc.h>
|
||||
|
||||
#define CACHE_MAX_NUM 256
|
||||
#define SECTOR_SIZE 512
|
||||
|
||||
//#define UDC_CACHE_DEBUG
|
||||
|
||||
#ifdef UDC_CACHE_DEBUG
|
||||
#define dprintk(a...) printk(a)
|
||||
#else
|
||||
#define dprintk(a...) while(0){}
|
||||
#endif
|
||||
|
||||
typedef struct {
|
||||
unsigned short CacheState;
|
||||
unsigned short UseCount;
|
||||
unsigned short CacheChange;
|
||||
unsigned short CacheReserve;
|
||||
unsigned int BlockId;
|
||||
unsigned char *aBlockData;
|
||||
} SSFDC__LB_CACHE;
|
||||
|
||||
#define FREE_CACHE 0
|
||||
#define PREWRITE_CACHE 2
|
||||
#define OFTEN_USE_CACHE 3
|
||||
#define SECTOR_SHIFT 9
|
||||
|
||||
#define CACHE_TO_UNCATCH(x) ((unsigned int)x | 0xa0000000)
|
||||
static unsigned int __aBlockData[SECTOR_SIZE * CACHE_MAX_NUM / 4] __attribute__ ((aligned (32)));
|
||||
static SSFDC__LB_CACHE ssfdc_cache[CACHE_MAX_NUM];
|
||||
static unsigned short Cur_CacheCount = 0;
|
||||
int FlushDataState = 0;
|
||||
static struct mtdblk_dev *g_udc_mtdblk;
|
||||
static struct mtd_info *g_udc_mtd;
|
||||
|
||||
extern int udc_mtdblock_readsect(struct mtdblk_dev *, unsigned long, char *, int);
|
||||
extern int udc_mtdblock_writesect(struct mtdblk_dev *, unsigned long, char *);
|
||||
extern struct mtdblk_dev *udc_get_mtdblk(void);
|
||||
extern struct mtd_info *udc_get_mtd(void);
|
||||
extern void udc_flush_cache(struct mtdblk_dev *mtdblk);
|
||||
|
||||
#define _NAND_LB_Write(pCache) udc_mtdblock_writesect(g_udc_mtdblk, pCache->BlockId,pCache->aBlockData)
|
||||
#define _NAND_LB_Read(Sector,pBuffer) udc_mtdblock_readsect(g_udc_mtdblk, Sector, pBuffer, SECTOR_SIZE);
|
||||
|
||||
#define DMA_ENABLE 0
|
||||
|
||||
#if DMA_ENABLE
|
||||
#define DMA_CHANNEL 5
|
||||
#define PHYSADDR(x) virt_to_phys((void *)x)
|
||||
#else
|
||||
#define lb_memcpy memcpy
|
||||
#endif
|
||||
|
||||
#if DMA_ENABLE
|
||||
static void lb_memcpy(void *target,void* source,unsigned int len)
|
||||
{
|
||||
int ch = DMA_CHANNEL;
|
||||
if(((unsigned int)source < 0xa0000000) && len)
|
||||
dma_cache_wback_inv((unsigned long)source, len);
|
||||
if(((unsigned int)target < 0xa0000000) && len)
|
||||
dma_cache_wback_inv((unsigned long)target, len);
|
||||
|
||||
REG_DMAC_DSAR(ch) = PHYSADDR((unsigned long)source);
|
||||
REG_DMAC_DTAR(ch) = PHYSADDR((unsigned long)target);
|
||||
REG_DMAC_DTCR(ch) = len / 32;
|
||||
REG_DMAC_DRSR(ch) = DMAC_DRSR_RS_AUTO;
|
||||
REG_DMAC_DCMD(ch) = DMAC_DCMD_SAI| DMAC_DCMD_DAI | DMAC_DCMD_SWDH_32 | DMAC_DCMD_DWDH_32|DMAC_DCMD_DS_32BYTE;
|
||||
REG_DMAC_DCCSR(ch) = DMAC_DCCSR_EN | DMAC_DCCSR_NDES;
|
||||
while ( REG_DMAC_DTCR(ch) );
|
||||
}
|
||||
#endif
|
||||
|
||||
static void _NAND_LB_InitCache(void)
|
||||
{
|
||||
int i;
|
||||
SSFDC__LB_CACHE *pCache = ssfdc_cache;
|
||||
#if DMA_ENABLE
|
||||
unsigned char * ptr = (unsigned char *)CACHE_TO_UNCATCH(__aBlockData);
|
||||
#else
|
||||
unsigned char * ptr = (unsigned char *)(__aBlockData);
|
||||
#endif
|
||||
for(i = 0;i < CACHE_MAX_NUM;i++)
|
||||
{
|
||||
pCache->CacheState = FREE_CACHE;
|
||||
pCache->UseCount = 0;
|
||||
pCache->CacheChange = 0;
|
||||
pCache->aBlockData = ptr;
|
||||
ptr+=SECTOR_SIZE;
|
||||
pCache++;
|
||||
}
|
||||
Cur_CacheCount = 0;
|
||||
}
|
||||
|
||||
static SSFDC__LB_CACHE * _NAND_LB_GetFreeCache(void)
|
||||
{
|
||||
int ret = 0;
|
||||
SSFDC__LB_CACHE *pCacheInfo = &ssfdc_cache[Cur_CacheCount];
|
||||
while(1)
|
||||
{
|
||||
if(ret >= CACHE_MAX_NUM)
|
||||
return 0;
|
||||
if(pCacheInfo >= &ssfdc_cache[CACHE_MAX_NUM])
|
||||
{
|
||||
pCacheInfo = ssfdc_cache;
|
||||
Cur_CacheCount = 0;
|
||||
}
|
||||
|
||||
if(pCacheInfo->CacheState == FREE_CACHE)
|
||||
{
|
||||
return pCacheInfo;
|
||||
}
|
||||
pCacheInfo++;
|
||||
Cur_CacheCount++;
|
||||
ret++;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void _NAND_LB_CloseCACHES(unsigned int sectorstart,unsigned int sectorend)
|
||||
{
|
||||
unsigned int i;
|
||||
SSFDC__LB_CACHE *pCache = ssfdc_cache;
|
||||
for( i = 0;i < CACHE_MAX_NUM;i++){
|
||||
if((pCache->CacheState != FREE_CACHE) && (pCache->BlockId >= sectorstart) && (pCache->BlockId < sectorend)){
|
||||
pCache->CacheChange = 0;
|
||||
pCache->CacheState = FREE_CACHE;
|
||||
pCache->UseCount = 0;
|
||||
}
|
||||
pCache++;
|
||||
}
|
||||
}
|
||||
|
||||
static void _NAND_LB_FLUSHCACHES(unsigned int sectorstart,unsigned int sectorend)
|
||||
{
|
||||
unsigned int i;
|
||||
SSFDC__LB_CACHE *pCache = ssfdc_cache;
|
||||
for( i = 0;i < CACHE_MAX_NUM;i++){
|
||||
if((pCache->CacheState != FREE_CACHE) && (pCache->BlockId >= sectorstart) && (pCache->BlockId < sectorend)){
|
||||
if(pCache->CacheChange)
|
||||
_NAND_LB_Write(pCache);
|
||||
pCache->CacheChange = 0;
|
||||
pCache->CacheState = FREE_CACHE;
|
||||
pCache->UseCount = 0;
|
||||
}
|
||||
pCache++;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
inline static int Get_NAND_CacheFreeCount(void)
|
||||
{
|
||||
SSFDC__LB_CACHE *pCache = ssfdc_cache;
|
||||
SSFDC__LB_CACHE *pEndCache = &ssfdc_cache[CACHE_MAX_NUM];
|
||||
unsigned int count = 0;
|
||||
while(pCache < pEndCache)
|
||||
{
|
||||
if(pCache->CacheState == FREE_CACHE)
|
||||
count++;
|
||||
pCache++;
|
||||
}
|
||||
return count;
|
||||
|
||||
}
|
||||
|
||||
static unsigned int _NAND_LB_PreWiteToNand(SSFDC__LB_CACHE *pCache,unsigned short *count,unsigned int update)
|
||||
{
|
||||
SSFDC__LB_CACHE *pWriteCache;
|
||||
SSFDC__LB_CACHE *pEndCache = &ssfdc_cache[CACHE_MAX_NUM];
|
||||
unsigned int sector = -1;
|
||||
unsigned int flag;
|
||||
while(1)
|
||||
{
|
||||
sector = -1;
|
||||
flag = 0;
|
||||
pWriteCache = ssfdc_cache;
|
||||
while(pWriteCache < pEndCache)
|
||||
{
|
||||
if(pWriteCache->CacheState == update) //PREWRITE_CACHE
|
||||
{
|
||||
if(pWriteCache->BlockId < sector)
|
||||
{
|
||||
sector = pWriteCache->BlockId;
|
||||
pCache = pWriteCache;
|
||||
}
|
||||
}else
|
||||
flag++;
|
||||
pWriteCache++;
|
||||
}
|
||||
|
||||
if(flag < CACHE_MAX_NUM)
|
||||
{
|
||||
if(pCache->CacheChange)
|
||||
{
|
||||
_NAND_LB_Write(pCache);
|
||||
pCache->CacheChange = 0;
|
||||
}
|
||||
pCache->CacheState = FREE_CACHE;
|
||||
pCache->UseCount = 0;
|
||||
(*count)++;
|
||||
}else
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void _NAND_LB_OftenToNand(SSFDC__LB_CACHE *pCache,unsigned short *count,unsigned int update)
|
||||
{
|
||||
SSFDC__LB_CACHE *pWriteCache = pCache;
|
||||
SSFDC__LB_CACHE *pOldCache = pCache;
|
||||
SSFDC__LB_CACHE *pEndCache = &ssfdc_cache[CACHE_MAX_NUM];
|
||||
|
||||
dprintk("%s!\n",__FUNCTION__);
|
||||
while(pCache)
|
||||
{
|
||||
if(pCache->CacheState == OFTEN_USE_CACHE)
|
||||
{
|
||||
if(pWriteCache->CacheState != OFTEN_USE_CACHE)
|
||||
pWriteCache = pCache;
|
||||
else if(pWriteCache->UseCount > pCache->UseCount)
|
||||
{
|
||||
pWriteCache = pCache;
|
||||
}
|
||||
}
|
||||
pCache++;
|
||||
if(pCache >= pEndCache)
|
||||
break;
|
||||
}
|
||||
if(pWriteCache->CacheState == OFTEN_USE_CACHE)
|
||||
{
|
||||
(*count)++;
|
||||
if(pWriteCache->CacheChange)
|
||||
_NAND_LB_Write(pWriteCache);
|
||||
pWriteCache->CacheState = FREE_CACHE;
|
||||
|
||||
pWriteCache->UseCount = 0;
|
||||
pWriteCache->CacheChange = 0;
|
||||
if(update != -1)
|
||||
update--;
|
||||
if(update != 0)
|
||||
_NAND_LB_OftenToNand(pOldCache,count,update);
|
||||
}
|
||||
}
|
||||
|
||||
static int _NAND_LB_FreeCache(unsigned int update)
|
||||
{
|
||||
unsigned short freecount = 0,totalfree = 0;
|
||||
|
||||
freecount = 0;
|
||||
_NAND_LB_PreWiteToNand(ssfdc_cache,&freecount,PREWRITE_CACHE);
|
||||
|
||||
totalfree += freecount;
|
||||
dprintk("free count = %d\n",freecount);
|
||||
if(freecount == 0)
|
||||
{
|
||||
freecount = 0;
|
||||
_NAND_LB_PreWiteToNand(ssfdc_cache,&freecount,OFTEN_USE_CACHE);
|
||||
totalfree += freecount;
|
||||
update = 0;
|
||||
}
|
||||
if(update)
|
||||
{
|
||||
if(Get_NAND_CacheFreeCount() < CACHE_MAX_NUM * 1 / 4) // because fat is 4 sector
|
||||
{
|
||||
freecount = 0;
|
||||
_NAND_LB_PreWiteToNand(ssfdc_cache,&freecount,OFTEN_USE_CACHE);
|
||||
totalfree += freecount;
|
||||
}
|
||||
}
|
||||
|
||||
dprintk("Free = %d\r\n",totalfree);
|
||||
return totalfree;
|
||||
}
|
||||
|
||||
static int _NAND_LB_GetFromCache(unsigned int Sector, void *pBuffer) {
|
||||
|
||||
SSFDC__LB_CACHE *pCache = &ssfdc_cache[Cur_CacheCount];
|
||||
SSFDC__LB_CACHE *pUseCache = 0;
|
||||
unsigned short i;
|
||||
dprintk("sector = %x pBuffer = %x\n",Sector,pBuffer);
|
||||
if(pCache >= &ssfdc_cache[CACHE_MAX_NUM])
|
||||
pCache = ssfdc_cache;
|
||||
|
||||
i = 0;
|
||||
while (1) {
|
||||
if(pCache->CacheState != FREE_CACHE)
|
||||
{
|
||||
if (Sector == pCache->BlockId) {
|
||||
dprintk("Cache is use = %d\r\n",pCache->BlockId);
|
||||
pUseCache = pCache;
|
||||
pCache->UseCount++;
|
||||
if(pCache->UseCount == 0)
|
||||
pCache->UseCount = -1;
|
||||
pCache->CacheState = OFTEN_USE_CACHE;
|
||||
}
|
||||
}
|
||||
pCache--;
|
||||
if(pCache < ssfdc_cache)
|
||||
pCache = &ssfdc_cache[CACHE_MAX_NUM - 1];
|
||||
|
||||
i++;
|
||||
if (i >= CACHE_MAX_NUM) {
|
||||
break; /* Sector not in cache */
|
||||
}
|
||||
}
|
||||
if (pUseCache) {
|
||||
dprintk("From Cache %d\r\n",Sector);
|
||||
lb_memcpy(pBuffer, pUseCache->aBlockData, SECTOR_SIZE);
|
||||
return 0;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
static void _NAND_LB_ClearCache(void) {
|
||||
|
||||
unsigned short freecount = 0;
|
||||
dprintk("Clear Cache\r\n");
|
||||
|
||||
_NAND_LB_PreWiteToNand(ssfdc_cache,&freecount,PREWRITE_CACHE);
|
||||
_NAND_LB_PreWiteToNand(ssfdc_cache,&freecount,OFTEN_USE_CACHE);
|
||||
}
|
||||
|
||||
static void _NAND_LB_CopyToCache(unsigned int Sector, void *pBuffer,unsigned short rw)
|
||||
{
|
||||
SSFDC__LB_CACHE *pCache = _NAND_LB_GetFreeCache();
|
||||
dprintk("Copy to Cache = 0x%08x 0x%08x\r\n",pCache,ssfdc_cache);
|
||||
|
||||
if(!pCache)
|
||||
{
|
||||
_NAND_LB_FreeCache(rw);
|
||||
|
||||
pCache = _NAND_LB_GetFreeCache();
|
||||
}
|
||||
pCache->BlockId = Sector;
|
||||
pCache->CacheState = PREWRITE_CACHE;
|
||||
pCache->UseCount = 0;
|
||||
pCache->CacheChange = rw;
|
||||
|
||||
lb_memcpy(pCache->aBlockData,pBuffer,SECTOR_SIZE);
|
||||
}
|
||||
|
||||
|
||||
static int _NAND_LB_UpdateInCache(unsigned int Sector, void *pBuffer) {
|
||||
short i,ret = 0;
|
||||
i = Cur_CacheCount;
|
||||
if(Cur_CacheCount > CACHE_MAX_NUM)
|
||||
i = 0;
|
||||
while(1)
|
||||
{
|
||||
if(ret >= CACHE_MAX_NUM)
|
||||
return -1;
|
||||
if(ssfdc_cache[i].CacheState != FREE_CACHE)
|
||||
{
|
||||
|
||||
if(ssfdc_cache[i].BlockId == Sector)
|
||||
{
|
||||
dprintk("UpdateInCache = %d\r\n",Sector);
|
||||
ssfdc_cache[i].CacheState = OFTEN_USE_CACHE;
|
||||
ssfdc_cache[i].UseCount++;
|
||||
ssfdc_cache[i].CacheChange = 1;
|
||||
lb_memcpy(ssfdc_cache[i].aBlockData,pBuffer,SECTOR_SIZE);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
i--;
|
||||
if(i < 0)
|
||||
i = CACHE_MAX_NUM - 1;
|
||||
ret++;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int NAND_LB_MultiRead(unsigned int Sector, void *pBuffer,unsigned int SectorCount)
|
||||
{
|
||||
int i,ret,end;
|
||||
void *p;
|
||||
|
||||
dprintk("NAND_LB_MultiRead = %d %d \n",Sector,SectorCount);
|
||||
end = Sector + SectorCount;
|
||||
_NAND_LB_FLUSHCACHES(Sector,end);
|
||||
|
||||
p = pBuffer;
|
||||
for (i = Sector; i < end; i ++)
|
||||
{
|
||||
ret = udc_mtdblock_readsect(g_udc_mtdblk, i, p, SECTOR_SIZE);
|
||||
p += SECTOR_SIZE;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int NAND_LB_Read(unsigned int Sector, void *pBuffer)
|
||||
{
|
||||
int x;
|
||||
#if DMA_ENABLE
|
||||
unsigned char *ptr = (unsigned char *)CACHE_TO_UNCATCH(pBuffer);
|
||||
dma_cache_wback_inv(pBuffer,SECTOR_SIZE);
|
||||
#else
|
||||
unsigned char *ptr = (unsigned char *)pBuffer;
|
||||
#endif
|
||||
dprintk("LB_Read = %d \n",Sector);
|
||||
if(_NAND_LB_GetFromCache(Sector,ptr))
|
||||
{
|
||||
x = _NAND_LB_Read(Sector,ptr);
|
||||
_NAND_LB_CopyToCache(Sector,ptr,0);
|
||||
}
|
||||
return 512;
|
||||
}
|
||||
|
||||
static int NAND_LB_MultiWrite(unsigned int Sector, void *pBuffer,unsigned int SectorCount)
|
||||
{
|
||||
int i,ret;
|
||||
unsigned char *p;
|
||||
|
||||
_NAND_LB_CloseCACHES(Sector,Sector + SectorCount);
|
||||
p = (unsigned char *)pBuffer;
|
||||
for (i = Sector; i < Sector + SectorCount; i ++)
|
||||
{
|
||||
ret = udc_mtdblock_writesect(g_udc_mtdblk, i, p);
|
||||
p += 512;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int NAND_LB_Write(unsigned int Sector, void *pBuffer)
|
||||
{
|
||||
#if DMA_ENABLE
|
||||
unsigned char *ptr = (unsigned char *)CACHE_TO_UNCATCH(pBuffer);
|
||||
dma_cache_wback_inv(pBuffer,SECTOR_SIZE);
|
||||
#else
|
||||
unsigned char *ptr = (unsigned char *)pBuffer;
|
||||
#endif
|
||||
dprintk("LB_Write = %x %x\r\n",Sector,pBuffer);
|
||||
if(_NAND_LB_UpdateInCache(Sector,ptr))
|
||||
{
|
||||
_NAND_LB_CopyToCache(Sector,ptr,1);
|
||||
}
|
||||
return 512;
|
||||
}
|
||||
/*********************************************************************
|
||||
*
|
||||
* Global functions
|
||||
*
|
||||
***********************************************************************/
|
||||
|
||||
int NAND_LB_Init(void)
|
||||
{
|
||||
dprintk("UDC CACHE Init \n");
|
||||
_NAND_LB_InitCache();
|
||||
g_udc_mtdblk = udc_get_mtdblk();
|
||||
g_udc_mtd = udc_get_mtd();
|
||||
return 0;
|
||||
}
|
||||
|
||||
int NAND_LB_FLASHCACHE(void)
|
||||
{
|
||||
dprintk("Flush lb cache !\n");
|
||||
_NAND_LB_ClearCache();
|
||||
// dprintk("Flush mtd cache !\n");
|
||||
// udc_flush_cache(g_udc_mtdblk);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int NAND_MTD_FLASHCACHE(void)
|
||||
{
|
||||
dprintk("Flush mtd cache !\n");
|
||||
udc_flush_cache(g_udc_mtdblk);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int udc_read(unsigned int offset, unsigned int len, unsigned char *buf)
|
||||
{
|
||||
unsigned long block,sector,i;
|
||||
|
||||
block = offset >> SECTOR_SHIFT;
|
||||
sector = len >> SECTOR_SHIFT;
|
||||
dprintk("read dev = ia:%x, s:%d c:%d\r\n",buf,block,sector);
|
||||
|
||||
if (sector <= 8)
|
||||
{
|
||||
for(i = 0;i < sector; i++)
|
||||
{
|
||||
NAND_LB_Read(block + i,(void *)(buf));
|
||||
buf += 512;
|
||||
}
|
||||
}
|
||||
else
|
||||
NAND_LB_MultiRead(block, buf, sector);
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
int udc_write(unsigned int offset, unsigned int len, unsigned char *buf)
|
||||
{
|
||||
unsigned long block,sector,i;
|
||||
|
||||
block = offset >> SECTOR_SHIFT;
|
||||
sector = len >> SECTOR_SHIFT;
|
||||
dprintk("write dev s:%d c:%d\r\n",block,sector);
|
||||
|
||||
if(sector <= 8)
|
||||
{
|
||||
for(i = 0;i < sector; i++)
|
||||
{
|
||||
NAND_LB_Write(block + i,(void *)(buf));
|
||||
buf += 512;
|
||||
FlushDataState = 1;
|
||||
}
|
||||
}else
|
||||
NAND_LB_MultiWrite(block,(void *)(buf),sector);
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
EXPORT_SYMBOL_GPL(udc_write);
|
||||
EXPORT_SYMBOL_GPL(udc_read);
|
||||
EXPORT_SYMBOL_GPL(NAND_LB_Init);
|
||||
EXPORT_SYMBOL_GPL(NAND_LB_FLASHCACHE);
|
||||
EXPORT_SYMBOL_GPL(FlushDataState);
|
||||
EXPORT_SYMBOL_GPL(NAND_MTD_FLASHCACHE);
|
Loading…
Reference in New Issue
Block a user