⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 drv.c

📁 是一个手机功能的模拟程序
💻 C
📖 第 1 页 / 共 3 页
字号:
/******************************************************************************
 * Flash File System (ffs)
 * Idea, design and coding by Mads Meisner-Jensen, mmj@ti.com
 *
 * ffs low level flash driver
 *
 * $Id: drv.c,v 1.1.1.1 2004/06/19 06:00:30 root Exp $
 *
 ******************************************************************************/

#ifndef TARGET
#include "ffs.cfg"
#endif
#include "board.cfg"

#include "ffs.h"
#include "drv.h"
#include "ffstrace.h"

#if (TARGET == 0)
#include "stdio.h"
#include "sys/types.h"
#include "sys/stat.h"
#include "sys/mman.h"
#include "fcntl.h"
#include "unistd.h"
#else
#include "../Os/nucleus.h"
#endif


// Note that all code notes and comments pertaining to single-bank flash
// drivers are located in the AMD SB driver (amdsbdrv.c). Consider this as
// the reference.


/******************************************************************************
 * Globals
 ******************************************************************************/
#if (BOARD == 34)
  extern const unsigned char FlashImage[];  // image of the file system - 16 kB
#endif

#if (TARGET == 1)

// NOTE: This is the size in bytes of the single-bank driver code that is
// copied to RAM. The only way to determine the amount of memory needed is
// to look into the linker output file (.map) or the assembler output of
// both amdsbdrv.obj and intelsbdrv.obj files.
#define FFSDRV_CODE_SIZE     (0x200)

uint8 ffsdrv_code[FFSDRV_CODE_SIZE];

#endif

struct dev_s dev;
struct ffsdrv_s ffsdrv;

uint32 int_disable(void);
void int_enable(uint32 tmp);

/******************************************************************************
 * Macros
 ******************************************************************************/

#define addr2offset(address) ( (int) (address) - (int) dev.base )


/******************************************************************************
 * Generic Driver Functions
 ******************************************************************************/

void ffsdrv_generic_write(void *dst, const void *src, uint16 size)
{
    uint8 *mydst = dst;
    const uint8 *mysrc = src;

    if (size > 0)
    {
        if ((unsigned int) mydst & 1) {
            ffsdrv_write_byte(mydst++, *mysrc++);
            size--;
        }
        while (size >= 2) {
            ffsdrv.write_halfword((uint16 *) mydst,
                                  mysrc[0] | (mysrc[1] << 8));
            size -= 2;
            mysrc += 2;
            mydst += 2;
        }
        if (size == 1)
            ffsdrv_write_byte(mydst++, *mysrc++);
    }
}


/******************************************************************************
 * AMD Single Bank Driver Functions
 ******************************************************************************/

#if (TARGET == 1)

// Forward declaration of functions in file amdsbdrv.c
void ffsdrv_ram_amd_sb_write_halfword(volatile uint16 *addr, uint16 value);
void ffsdrv_ram_amd_sb_erase(uint8 block);

#else // (TARGET == 0)

// On PC these functions are empty
void ffsdrv_ram_amd_sb_write_halfword(volatile uint16 *addr, uint16 value) {}
void ffsdrv_ram_amd_sb_erase(uint8 block) {}

#endif // (TARGET == 1)


/******************************************************************************
 * AMD Pseudo Single Bank Driver Functions
 ******************************************************************************/

// This is a pseudo single-bank flash driver. It simulates a single-bank
// flash device on a dual-bank device.

#if (TARGET == 1)

void ffsdrv_amd_pseudo_sb_write_halfword(volatile uint16 *addr, uint16 value)
{
    volatile char *flash = dev.base;
    uint32 cpsr, i, x;

    ttw(ttr(TTrDrvWrite, "wh(%x,%x)" NL, addr, value));

    if (~*addr & value) {
        ttw(ttr(TTrFatal, "wh(%x,%x->%x) fatal" NL, addr, *addr, value));
        return;
    }

    cpsr = int_disable();
    tlw(led_on(LED_WRITE));

    flash[0xAAAA] = 0xAA; // unlock cycle 1
    flash[0x5555] = 0x55; // unlock cycle 2
    flash[0xAAAA] = 0xA0;
    *addr         = value;

    while ((*dev.addr ^ dev.data) & 0x80)
        ;

    tlw(led_off(LED_WRITE));
    int_enable(cpsr);
}

// This VERY simple way of erase suspending 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_amd_pseudo_sb_erase(uint8 block)
{
    volatile char *flash = dev.base;
    volatile char *addr;
    uint32 cpsr;
    uint16 flashpoll;

    addr = block2addr(block);

    ttw(ttr(TTrDrvErase, "e(%d)" NL, block));

    cpsr = int_disable();
    tlw(led_on(LED_ERASE));

    flash[0xAAAA] = 0xAA; // unlock cycle 1
    flash[0x5555] = 0x55; // unlock cycle 2
    flash[0xAAAA] = 0x80; 
    flash[0xAAAA] = 0xAA; // unlock cycle 1
    flash[0x5555] = 0x55; // 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));
            int_enable(cpsr);

            // Other interrupts and tasks run now...

            cpsr = 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));
    int_enable(cpsr);
}

#else // (TARGET == 0)

void ffsdrv_amd_pseudo_sb_write_halfword(volatile uint16 *addr, uint16 value) {}
void ffsdrv_amd_pseudo_sb_erase(uint8 block) {}

#endif // (TARGET == 1)


/******************************************************************************
 * AMD Dual/Multi Bank Driver Functions
 ******************************************************************************/

// All erase and write operations are performed atomically (interrupts
// disabled). Otherwise we cannot trust the value of dev.state and we cannot
// determine exactly how many of the command words have already been
// written.

// in ffs_end() when we resume an erasure that was previously suspended, how
// does that affect multiple tasks doing that simultaneously?

void ffsdrv_amd_write_end(void);
void ffsdrv_amd_erase_end(void);

void ffsdrv_amd_write_halfword(volatile uint16 *addr, uint16 value)
{
    volatile char *flash = dev.base;
    uint32 cpsr;

    tlw(led_on(LED_WRITE));
    ttw(ttr(TTrDrvWrite, "wh(%x,%x)" NL, addr, value));

    dev.addr = addr;
    dev.data = value;

    if (~*addr & value) {
        ttw(ttr(TTrFatal, "wh(%x,%x->%x) fatal" NL, addr, *addr, value));
        return;
    }

    cpsr = int_disable();
    tlw(led_toggle(LED_WRITE_SUSPEND));
    dev.state = DEV_WRITE;
    flash[0xAAAA] = 0xAA; // unlock cycle 1
    flash[0x5555] = 0x55; // unlock cycle 2
    flash[0xAAAA] = 0xA0;
    *addr         = value;
    int_enable(cpsr);
    tlw(led_toggle(LED_WRITE_SUSPEND));

    ffsdrv_amd_write_end();
}

void ffsdrv_amd_write(void *dst, const void *src, uint16 size)
{
    uint8 *mydst = dst;
    const uint8 *mysrc = src;

    if (size > 0)
    {
        if ((unsigned int) mydst & 1) {
            ffsdrv_write_byte(mydst++, *mysrc++);
            size--;
        }
        while (size >= 2) {
            ffsdrv_amd_write_halfword((uint16 *) mydst,
                                      mysrc[0] | (mysrc[1] << 8));
            size -= 2;
            mysrc += 2;
            mydst += 2;
        }
        if (size == 1)
            ffsdrv_write_byte(mydst++, *mysrc++);
    }
}

void ffsdrv_amd_write_end(void)
{
    while ((*dev.addr ^ dev.data) & 0x80)
        tlw(led_toggle(LED_WRITE_SUSPEND));

    dev.state = DEV_READ;

    tlw(led_off(LED_WRITE));
}

void ffsdrv_amd_erase(uint8 block)
{
    volatile char *flash = dev.base;
    uint32 cpsr;

    tlw(led_on(LED_ERASE));
    ttw(ttr(TTrDrvErase, "e(%d)" NL, block));

    dev.addr = (uint16 *) block2addr(block);

    cpsr = int_disable();
    dev.state = DEV_ERASE;
    flash[0xAAAA] = 0xAA; // unlock cycle 1
    flash[0x5555] = 0x55; // unlock cycle 2
    flash[0xAAAA] = 0x80; 
    flash[0xAAAA] = 0xAA; // unlock cycle 1
    flash[0x5555] = 0x55; // unlock cycle 2
    *dev.addr = 0x30; // AMD erase sector command
    int_enable(cpsr);

    ffsdrv_amd_erase_end();
}

void ffsdrv_amd_erase_end(void)
{
    while ((*dev.addr & 0x80) == 0)
        ;

    dev.state = DEV_READ;

    tlw(led_off(LED_ERASE));
}

void ffsdrv_amd_erase_suspend(void)
{
    uint32 cpsr;

    tlw(led_on(LED_ERASE_SUSPEND));
    ttw(str(TTrDrvErase, "es" NL));

    // if erase has finished then all is ok
    if (*dev.addr & 0x80) {
        ffsdrv_amd_erase_end();
        tlw(led_off(LED_ERASE_SUSPEND));
        return;
    }

    // NOTEME: As there is no way to be absolutely certain that erase
    // doesn't finish between last poll and the following erase suspend
    // command, we assume that the erase suspend is safe even though the
    // erase IS actually already finished.

    cpsr = int_disable();
    dev.state = DEV_ERASE_SUSPEND;
    *dev.addr = 0xB0;

    // Wait for erase suspend to finish
    while ((*dev.addr & 0x80) == 0)
        ;

    int_enable(cpsr);
}

void ffsdrv_amd_erase_resume(void)
{
    uint32 cpsr;

    ttw(str(TTrDrvErase, "er" NL));

    // NOTEME: See note in erase_suspend()... We assume that the erase
    // resume is safe even though the erase IS actually already finished.
    cpsr = int_disable();
    dev.state = DEV_ERASE;
    *dev.addr = 0x30;
    int_enable(cpsr);

    tlw(led_off(LED_ERASE_SUSPEND));
}


/******************************************************************************
 * SST Dual/Multi Bank Driver Functions
 ******************************************************************************/

// SST flashes use almost same command set as AMD flashes. Only the command
// addresses (4 more bits) and erase command data (0x50 instead of 0x30) are
// different. SST flashes have no erase suspend/resume commands because they
// are so fast at erasing!

void ffsdrv_sst_write_end(void);
void ffsdrv_sst_erase_end(void);

void ffsdrv_sst_write(void *dst, const void *src, uint16 size)
{
    uint8 *mydst = dst;
    const uint8 *mysrc = src;

    if (size > 0)
    {
        if ((unsigned int) mydst & 1) {
            ffsdrv_write_byte(mydst++, *mysrc++);
            size--;
        }
        while (size >= 2) {
            ffsdrv_amd_write_halfword((uint16 *) mydst,
                                      mysrc[0] | (mysrc[1] << 8));
            size -= 2;
            mysrc += 2;
            mydst += 2;
        }
        if (size == 1)
            ffsdrv_write_byte(mydst++, *mysrc++);
    }
}

// Note that SST flashes have smaller sectors than other flash families.
// Fortunately they support erasure of several of these sectors in a logical
// unit called a "block".
void ffsdrv_sst_erase(uint8 block)
{
    volatile char *flash = dev.base;
    uint32 cpsr;

    tlw(led_on(LED_ERASE));
    ttw(ttr(TTrDrvErase, "e(%d)" NL, block));

    dev.addr = (uint16 *) block2addr(block);

    cpsr = int_disable();
    dev.state = DEV_ERASE;
    flash[0xAAAA] = 0xAA; // unlock cycle 1
    flash[0x5555] = 0x55; // unlock cycle 2
    flash[0xAAAA] = 0x80; 
    flash[0xAAAA] = 0xAA; // unlock cycle 1
    flash[0x5555] = 0x55; // unlock cycle 2
    *dev.addr = 0x50; // SST erase block command
    int_enable(cpsr);

    ffsdrv_sst_erase_end();
}

void ffsdrv_sst_erase_end(void)
{
    // Wait for erase end
    while ((*dev.addr & 0x80) == 0)
        ;

    dev.state = DEV_READ;

    tlw(led_off(LED_ERASE));
}

// Erase suspend/resume commands do not exist for SST flashes, so we just
// poll for the end of the erase operation...

void ffsdrv_sst_erase_suspend(void)
{
    ttw(str(TTrDrvErase, "es" NL));

    ffsdrv_sst_erase_end();
}


/******************************************************************************
 * Intel Single Bank Driver Functions
 ******************************************************************************/

#if (TARGET == 1)

// Forward declaration of functions in file intelsbdrv.c
int  ffsdrv_ram_intel_sb_init(void);
void ffsdrv_ram_intel_sb_write_halfword(volatile uint16 *addr, uint16 value);
void ffsdrv_ram_intel_sb_erase(uint8 block);

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -