www.pudn.com > drivers.rar > intelsbdrv.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: intelsbdrv.c 1.13 Thu, 08 Jan 2004 15:05:23 +0100 tsj $ 
 * 
 ******************************************************************************/ 
 
#ifdef VIRTIO_NOR 
#define TARGET 1 
#else 
#include "ffs.cfg" 
#endif 
 
#include "../ffs.h" 
#include "drv.h" 
#include "ffstrace.h" 
 
 
#define INTEL_UNLOCK_SLOW 1 
 
 
#undef  tlw 
#define tlw(contents) 
#undef  ttw 
#define ttw(contents) 
 
// Status bits for Intel flash memory devices 
#define INTEL_STATE_MACHINE_DONE     (1<<7) 
#define FLASH_READ(addr)        (*(volatile uint16 *) (addr)) 
#define FLASH_WRITE(addr, data) (*(volatile uint16 *) (addr)) = data 
 
asm("        .label _ffsdrv_ram_intel_begin"); 
asm("        .def   _ffsdrv_ram_intel_begin"); 
 
uint32 intel_int_disable(void); 
void intel_int_enable(uint32 tmp); 
 
/****************************************************************************** 
 * INTEL Single Bank Driver Functions 
 ******************************************************************************/ 
// Actually we should have disabled and enable the interrupts in this 
// function, but when the interrupt functions are used Target don't run! 
// Anyway, currently the interrupts are already disabled at this point thus 
// it does not cause any problems. 
int ffsdrv_ram_intel_sb_init(void) 
{ 
    uint32 cpsr, i; 
    volatile char *addr; 
	uint16 status; 
 
    cpsr = intel_int_disable(); 
 
    for (i = 0; i < dev.numblocks; i++) 
    { 
        addr = block2addr(i); 
 
        *addr = 0x50; // Intel Clear Status Register 
        *addr = 0xFF; // Intel read array 
 
        *addr = 0x60; // Intel Config Setup 
        *addr = 0xD0; // Intel Unlock Block 
 
		// Wait for unlock to finish 
		do { 
            status = FLASH_READ(addr); 
        } while (!(status & INTEL_STATE_MACHINE_DONE)); 
 
		*addr = 0x70; // Intel Read Status Register 
		status = FLASH_READ(addr); 
		 
		// Is there an erase suspended? 
		if ((status & 0x40) != 0) { 
			*addr = 0xD0; // Intel erase resume 
 
			*addr = 0x70; // Intel Read Status Register 
			// wait for erase to finish 
			do { 
				status = FLASH_READ(addr); 
			} while (!(status & INTEL_STATE_MACHINE_DONE)); 
		} 
 
        *addr = 0xFF; // Intel Read Array 
    } 
 
    intel_int_enable(cpsr); 
 
    return 0; 
} 
 
void ffsdrv_ram_intel_sb_write_halfword(volatile uint16 *addr, uint16 value) 
{ 
    uint32 cpsr; 
    uint16 poll; 
 
    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 = intel_int_disable(); 
    dev.state = DEV_WRITE; 
 
#if (INTEL_UNLOCK_SLOW == 1) 
    *addr = 0x60; // Intel Config Setup 
    *addr = 0xD0; // Intel Unlock Block 
#endif 
 
    *addr = 0x50; // Intel Clear Status Register 
    *addr = 0x40; // Intel program byte/word 
    *addr = value; 
 
    while ((*addr & 0x80) == 0) { 
        // Poll interrupts, taking interrupt mask into account. 
        if (INT_REQUESTED) 
        { 
            *addr = 0xB0; // Intel Suspend 
            *addr = 0x70; // Intel Read Status Register 
            while (((poll = *addr) & 0x80) == 0) 
                ; 
 
            // If write is complete, exit immediately 
            if ((*addr & 0x04) == 0) 
                break; 
 
            dev.state = DEV_WRITE_SUSPEND; 
            *addr = 0xFF; // Intel read array 
 
            intel_int_enable(cpsr); 
            // Other interrupts and tasks run now... 
            cpsr = intel_int_disable(); 
 
            *addr = 0xD0; // Intel resume 
			*addr = 0x70; // Intel Read Status Register 
            dev.state = DEV_WRITE; 
        } 
    } 
 
    dev.state = DEV_READ; 
    *addr = 0xFF; // Intel read array 
    intel_int_enable(cpsr); 
} 
 
void ffsdrv_ram_intel_sb_erase(uint8 block) 
{ 
    char *addr = block2addr(block); 
    ffsdrv.erase_sector(addr); 
} 
 
void ffsdrv_ram_intel_sb_erase_sector(void *dst) 
{ 
    volatile char *addr; 
    uint32 cpsr; 
    uint16 poll; 
 
    ttw(ttr(TTrDrvEra, "e(%d)" NL, dst)); 
 
    addr = (char *)dst; 
 
    cpsr = intel_int_disable(); 
    tlw(led_on(LED_ERASE)); 
 
#if (INTEL_UNLOCK_SLOW == 1) 
    *addr = 0x60; // Intel Config Setup 
    *addr = 0xD0; // Intel Unlock Block 
#endif 
 
    *addr = 0x50; // Intel Clear Status Register 
    *addr = 0x20; // Intel Erase Setup 
    *addr = 0xD0; // Intel Erase Confirm 
    *addr = 0x70; // Intel Read Status Register 
 
    // 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; // Intel Erase Suspend 
            *addr = 0x70; // Intel Read Status Register 
            while (((poll = *addr) & 0x80) == 0) 
                ; 
 
            // If erase is complete, exit immediately 
            if ((poll & 0x40) == 0) 
                break; 
 
            *addr = 0xFF; // Intel read array 
 
            tlw(led_off(LED_ERASE_SUSPEND)); 
            intel_int_enable(cpsr); 
 
            // Other interrupts and tasks run now... 
 
            cpsr = intel_int_disable(); 
            tlw(led_on(LED_ERASE_SUSPEND)); 
 
            *addr = 0xD0; // Intel erase resume 
// The following "extra" Read Status command is required because Intel has 
// changed the specification of the W30 flash! (See "1.8 Volt Intel®  
// Wireless Flash Memory with 3 Volt I/O 28F6408W30, 28F640W30, 28F320W30 
// Specification Update") 
			*addr = 0x70; // Intel Read Status Register 
 
            tlw(led_off(LED_ERASE_SUSPEND)); 
        } 
    } 
    *addr = 0xFF; // Intel read array 
 
    tlw(led_on(LED_ERASE)); 
    tlw(led_off(LED_ERASE)); 
    intel_int_enable(cpsr); 
} 
 
 
/****************************************************************************** 
 * Interrupt Enable/Disable 
 ******************************************************************************/ 
 
uint32 intel_int_disable(void) 
{ 
#ifndef VIRTIO_NOR 
    asm("        .state16"); 
    asm("        mov       A1, #0xC0"); 
    asm("        ldr       A2, tct_intel_disable"); 
    asm("        bx        A2      "); 
 
    asm("tct_intel_disable 	.field     _TCT_Control_Interrupts+0,32"); 
    asm("	                .global	   _TCT_Control_Interrupts"); 
#endif 
   return 0; 
} 
 
void intel_int_enable(uint32 cpsr) 
{ 
#ifndef VIRTIO_NOR 
    asm("        .state16"); 
    asm("        ldr       A2, tct_intel_enable"); 
    asm("        bx        A2      "); 
 
    asm("tct_intel_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_intel_end"); 
asm("        .def   _ffsdrv_ram_intel_end");