www.pudn.com > drivers.rar > amdsbdrv.c


/****************************************************************************** 
 * Flash File System (ffs) 
 * Idea, design and coding by Mads Meisner-Jensen, mmj@ti.com 
 * 
 * FFS AMD single bank low level flash driver RAM code 
 * 
 * $Id: amdsbdrv.c 1.5.1.3 Tue, 06 Jan 2004 10:57:45 +0100 tsj $ 
 * 
 ******************************************************************************/ 
 
 
#ifdef VIRTIO_NOR 
  #define TARGET 1     /* For Virtio simulator */ 
#else 
  #include "ffs.cfg" 
#endif 
 
#include "../ffs.h" 
#include "drv.h" 
#include "ffstrace.h" 
 
 
// Due to long branches, we disable all tracing and led function calls. 
#undef  tlw 
#define tlw(contents) 
#undef  ttw 
#define ttw(contents) 
 
 
asm("        .label _ffsdrv_ram_amd_begin"); 
asm("        .def   _ffsdrv_ram_amd_begin"); 
 
 
// IMPORTANT! Apparently, placing the int_disable/enable() function code 
// here instead of at the bottom of the file, makes the code crash or 
// freeze. Reason is as of yet unknown. 
 
uint32 amd_int_disable(void); 
void amd_int_enable(uint32 tmp); 
 
 
/****************************************************************************** 
 * AMD Single Bank Driver Functions 
 ******************************************************************************/ 
 
void ffsdrv_ram_amd_sb_write_halfword(volatile uint16 *addr, uint16 value) 
{ 
    volatile char *flash = dev.base; 
    uint32 cpsr; 
 
    ttw(ttr(TTrDrv, "wh(%x,%x)" NL, addr, value)); 
 
    if (~*addr & value) { 
        ttw(ttr(TTrFatal, "wh(%x,%x->%x) fatal" NL, addr, *addr, value)); 
        return; 
    } 
 
    cpsr = amd_int_disable(); 
    tlw(led_on(LED_WRITE)); 
 
    flash[0xAAAA] = 0xAA; // AMD unlock cycle 1 
    flash[0x5555] = 0x55; // AMD unlock cycle 2 
    flash[0xAAAA] = 0xA0; 
    *addr         = value; 
 
    while ((*addr ^ value) & 0x80) 
	; 
 
    tlw(led_off(LED_WRITE)); 
    amd_int_enable(cpsr); 
} 
 
// This VERY simple way of erase suspension only works because we run under 
// a pre-emptive operating system, so whenever an interrupt occurs, another 
// task takes the CPU, and at the end of the interrupt, FFS gets the CPU 
// again. 
void ffsdrv_ram_amd_sb_erase(uint8 block) 
{ 
	char *addr = (char *)block2addr(block); 
	ffsdrv.erase_sector(addr); 
} 
 
void ffsdrv_ram_amd_sb_erase_sector(void *dst) 
{ 
    volatile char *flash = dev.base; 
    volatile char *addr; 
    uint32 cpsr; 
    uint16 flashpoll; 
 
    addr = (char *)dst; 
 
    ttw(ttr(TTrDrvEra, "e(%d)" NL, dst)); 
 
    cpsr = amd_int_disable(); 
    tlw(led_on(LED_ERASE)); 
 
    flash[0xAAAA] = 0xAA; // AMD unlock cycle 1 
    flash[0x5555] = 0x55; // AMD unlock cycle 2 
    flash[0xAAAA] = 0x80; 
    flash[0xAAAA] = 0xAA; // AMD unlock cycle 1 
    flash[0x5555] = 0x55; // AMD unlock cycle 2 
    *addr         = 0x30; // AMD erase sector command 
 
    // Wait for erase to finish. 
    while ((*addr & 0x80) == 0) { 
        tlw(led_toggle(LED_ERASE)); 
        // Poll interrupts, taking interrupt mask into account. 
        if (INT_REQUESTED)  
        { 
            // 1. suspend erase 
            // 2. enable interrupts 
            // .. now the interrupt code executes 
            // 3. disable interrupts 
            // 4. resume erase 
 
            tlw(led_on(LED_ERASE_SUSPEND)); 
            *addr = 0xB0; 
 
            // wait for erase suspend to finish 
            while ((*addr & 0x80) == 0) 
                ; 
 
            tlw(led_off(LED_ERASE_SUSPEND)); 
            amd_int_enable(cpsr); 
 
            // Other interrupts and tasks run now... 
 
            cpsr = amd_int_disable(); 
            tlw(led_on(LED_ERASE_SUSPEND)); 
 
            // Before resuming erase we must? check if the erase is really 
            // suspended or if it did finish 
            flashpoll = *addr; 
            *addr = 0x30; 
 
            tlw(led_off(LED_ERASE_SUSPEND)); 
        } 
    } 
 
   tlw(led_on(LED_ERASE)); 
    tlw(led_off(LED_ERASE)); 
    amd_int_enable(cpsr); 
} 
 
 
/****************************************************************************** 
 * Interrupt Enable/Disable 
 ******************************************************************************/ 
 
uint32 amd_int_disable(void) 
{ 
#ifndef VIRTIO_NOR 
    asm("        .state16"); 
    asm("        mov       A1, #0xC0"); 
    asm("        ldr       A2, tct_amd_disable"); 
    asm("        bx        A2      "); 
 
    asm("tct_amd_disable 	.field     _TCT_Control_Interrupts+0,32"); 
    asm("	                .global	   _TCT_Control_Interrupts");  
#endif 
   return 0; 
} 
 
void amd_int_enable(uint32 cpsr) 
{ 
 
#ifndef VIRTIO_NOR 
   asm("        .state16"); 
    asm("        ldr       A2, tct_amd_enable"); 
    asm("        bx        A2      "); 
 
    asm("tct_amd_enable 	.field     _TCT_Control_Interrupts+0,32"); 
    asm("	                .global	   _TCT_Control_Interrupts");  
#endif 
} 
 
// Even though we have this end label, we cannot determine the number of 
// constant/PC-relative data following the code! 
asm("        .state32"); 
asm("        .label _ffsdrv_ram_amd_end"); 
asm("        .def   _ffsdrv_ram_amd_end");