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

📄 flashhw.c

📁 呵呵
💻 C
字号:
/***********************************************************************/
/*  This file is part of the ARM Toolchain package                     */
/*  Copyright KEIL ELEKTRONIK GmbH 2003 - 2007                         */
/***********************************************************************/
/*                                                                     */
/*  FlashHW.C:   Hardware Layer of NAND Flash Programming Functions    */
/*               adapted for the Samsung S3C2410 Controller            */
/***********************************************************************/

#include "NAND_Error.h"                     // Error definitions

// Register and bit definitions
#define NFCONF                 (*(volatile unsigned *) (0x4E000000))
#define NFCMMD                 (*(volatile unsigned *) (0x4E000004))
#define NFADDR                 (*(volatile unsigned *) (0x4E000008))
#define NFDATA                 (*(volatile unsigned *) (0x4E00000C))
#define NFSTAT                 (*(volatile unsigned *) (0x4E000010))      //NAND Flash operation status
#define NFECC                  (*(volatile unsigned *) (0x4E000014))      //NAND Flash ECC
#define NFECC0                 (*(volatile UINT8T   *) (0x4E000014))
#define NFECC1                 (*(volatile UINT8T   *) (0x4E000015))
#define NFECC2                 (*(volatile UINT8T   *) (0x4E000016))

#define CLKCON                 (*(volatile unsigned long *) (0x4C00000C))
#define CLKSLOW                (*(volatile unsigned long *) (0x4C000010))
#define CLKDIVN                (*(volatile unsigned long *) (0x4C000014))

#define INTMSK                 (*(volatile unsigned long *) (0x4A000008))

#define GPACON                 (*(volatile unsigned long *) (0x56000000))
#define GPADAT                 (*(volatile unsigned long *) (0x56000004))

#define GPBCON                 (*(volatile unsigned long *) (0x56000010))
#define GPBDAT                 (*(volatile unsigned long *) (0x56000014))
#define GPBUP                  (*(volatile unsigned long *) (0x56000018))

// NAND Flash Commands
#define NAND_CMD_READ0         0x00         // Read mode (1) command
#define NAND_CMD_READ1         0x01         // Read mode (2) command
#define NAND_CMD_PAGEPROG      0x10         // Auto program command
#define NAND_CMD_READSTART     0x30         // Read start command
#define NAND_CMD_READ2         0x50         // Read mode (3) command
#define NAND_CMD_ERASE1ST      0x60         // Auto block erase 1-st command
#define NAND_CMD_STATUS        0x70         // Status read (1) command
#define NAND_CMD_STATUS_MULTI  0x71         // Status read (2) command
#define NAND_CMD_SDIN          0x80         // Serial data input command
#define NAND_CMD_READID        0x90         // ID read (1) command
#define NAND_CMD_ERASE2ND      0xD0         // Auto block erase 2-nd command
#define NAND_CMD_RESET         0xFF         // Reset command

// Enumerated type names definitions
enum PAGE_TYPE {SMALL_PAGE = 0, LARGE_PAGE};
enum BOOL_TYPE {     FALSE = 0,       TRUE};

// Global variables that describe interface
static volatile unsigned char bus_width_hw; // Bus width
static volatile unsigned char adr_cycles_hw;// Address word count
static volatile unsigned char page_type_hw; // Page type (small or large)

// Buffer for spare area reading or writing
unsigned char spare_buf[16];

// Module's local functions prototypes
static int SetAddress_HW      (unsigned long adr);
static int SetBlockAddress_HW (unsigned long adr);


/************************* Module Exported Functions ***************************/

/*- InitFlashController_HW (...) -----------------------------------------------
 *
 *  Initialize Flash Controller
 *    Parameter:  bus_width:  Bus Width (8, 16 bit)
 *               adr_cycles:  Addressing Cycles (3, 4, 5)
 *                page_type:  Page Type (0 - Small Page, 1 - Large Page)
 *                      clk:  Clock Frequency (Hz)
 *    Return Value:           NAND_ERROR
 */

int InitFlashController_HW (unsigned char *bus_width, unsigned char *adr_cycles, unsigned char *page_type, unsigned long clk) {

  // Normal   NAND Flash (Small Page)
  *bus_width   = 8;
  *page_type   = SMALL_PAGE;
  *adr_cycles  = 4;

  // Remember parameters locally
  bus_width_hw   = *bus_width;
  adr_cycles_hw  = *adr_cycles;
  page_type_hw   = *page_type;

  // Set important registers to reset values as hardware reset is not functional 
  // through JTAG reset pin
  INTMSK  = 0xFFFFFFFF;
  CLKCON  = 0x0007FFF0;
  GPACON  = 0xFFFFFFFF;

  // Disable Write Protect, drive nFWP pin high
  GPBUP  |= 0x0080;
  GPBCON |= 0x4000;
  GPBDAT |= 0x0080;

  // Initialize ECC encoder/decoder, NAND flash controller enable
  // Set: TACLS = 3, TWRPH0 = 7, TWRPH1 = 7
  NFCONF  = (1<<15) | (1<<12) | (0<<11) | (7 << 8) | (7 << 4) | (7 << 0);

  while (!(NFSTAT & 0x01));             // Wait while controller busy
  NFCMMD  = NAND_CMD_RESET;              // Reset NAND flash
  while (!(NFSTAT & 0x01));             // Wait while controller busy

  return (NAND_OK);
}


/*- EraseBlock_HW (...) --------------------------------------------------------
 *
 *  Erase whole Block
 *    Parameter:      adr:  Block Start Address
 *    Return Value:   NAND_ERROR
 */

int EraseBlock_HW (unsigned long adr) {

  while (!(NFSTAT & 0x01));             // Wait while controller busy
  NFCMMD  = NAND_CMD_ERASE1ST;
  SetBlockAddress_HW(adr);
  NFCMMD  = NAND_CMD_ERASE2ND;
  while (!(NFSTAT & 0x01));             // Wait while controller busy

  return (NAND_OK);
}


/*- ReadPage_HW (...) ----------------------------------------------------------
 *
 *  Initialize Flash Programming Functions
 *    Parameter:      adr:  Page Start Address
 *                     sz:  Page Size
 *                    buf:  Page Data
 *    Return Value:         NAND_ERROR
 */

int ReadPage_HW (unsigned long adr, unsigned long sz, unsigned char *buf) {
  int i;
  unsigned char *ptr_ul = buf;

  if (page_type_hw == SMALL_PAGE)  {    // Small Page Device
    while (!(NFSTAT & 0x01));           // Wait while controller busy
    NFCMMD = NAND_CMD_READ0;
    SetAddress_HW(adr);
    while (!(NFSTAT & 0x01));           // Wait while controller busy
    for (i = 0; i < sz; i++) { // Read requested number of bytes
      *ptr_ul++ = NFDATA;
    }
    while (i < 528) {              // Read remaining bytes to the end of page
      NFDATA;
      i++;
    }
    while (!(NFSTAT & 0x01));           // Wait while controller busy
  }  
  else  {                               // Large Page Device
    return (NAND_NOT_IMPLEMENTED_ERROR);
  }

  return (NAND_OK);
}


/*- ProgramPage_HW (...) -------------------------------------------------------
 *
 *  Initialize Flash Programming Functions
 *    Parameter:      adr:  Page Start Address
 *                     sz:  Page Size
 *                    buf:  Page Data
 *    Return Value:         NAND_ERROR
 */

int ProgramPage_HW (unsigned long adr, unsigned long sz, unsigned char *buf) {
  int i;
  unsigned char *ptr_ul = buf;

  if (page_type_hw == SMALL_PAGE)  {    // Small Page Device
    while (!(NFSTAT & 0x01));           // Wait while controller busy
    NFCMMD = NAND_CMD_SDIN;
    SetAddress_HW(adr);
    for (i = 0; i < sz; i++) { // Write requested number of bytes
      NFDATA = *ptr_ul++;
    }
    NFCMMD = NAND_CMD_PAGEPROG;
    while (!(NFSTAT & 0x01));           // Wait while controller busy
  }  
  else  {                               // Large Page Device
    return (NAND_NOT_IMPLEMENTED_ERROR);
  }

  return (NAND_OK);
}


/*- CheckBlock_HW (...) --------------------------------------------------------
 *
 *  Check if block at requested address is valid
 *    Parameter:      adr:  Block Start Address
 *    Return Value:         NAND_ERROR
 */

int CheckBlock_HW (unsigned long adr) {
  int i;
  unsigned char *ptr_ul = spare_buf;

  if (page_type_hw == SMALL_PAGE)  {    // Small Page Device
    while (!(NFSTAT & 0x01));           // Wait while controller busy
    NFCMMD = NAND_CMD_READ2;
    SetAddress_HW(adr);
    while (!(NFSTAT & 0x01));           // Wait while controller busy
    for (i = 0; i < 16; i++) {   // Read 16 spare area bytes
      *ptr_ul++ = NFDATA;
    }
    while (!(NFSTAT & 0x01));           // Wait while controller busy
    NFCMMD = NAND_CMD_READ0;
    while (!(NFSTAT & 0x01));           // Wait while controller busy

    // If 6-th byte in spare area is != 0xFF then the block is bad
    if (spare_buf[5] != 0xFF)          return (NAND_BAD_BLOCK_ERROR);
  }  
  else  {                               // Large Page Device
    return (NAND_NOT_IMPLEMENTED_ERROR);
  }
    
  return (NAND_OK);
}


/*- MarkBlockBad_HW (...) ------------------------------------------------------
 *
 *  Mark the block as being bad
 *    Parameter:      adr:  Block Start Address
 *    Return Value:         NAND_ERROR
 */

int MarkBlockBad_HW (unsigned long adr) {
  int i;
  unsigned char *ptr_ul = spare_buf;

  if (page_type_hw == SMALL_PAGE)  {    // Small Page Device
    while (!(NFSTAT & 0x01));           // Wait while controller busy
    // Marking Block 0 bad is forbidden
    if (adr == 0) return (NAND_NOT_ALLOWED_ERROR);

    // Prepare buffer for spare area data
    for (i=0; i<16; i++) spare_buf[i]=0xFF;
    spare_buf[5] = 0x00;                // Bad block marker in spare area

    // Erase bad block
    EraseBlock_HW(adr);

    // Write Spare Data
    NFCMMD = NAND_CMD_READ2;
    NFCMMD = NAND_CMD_SDIN;
    SetAddress_HW(adr);
    for (i = 0; i < 16; i++) {     // Write 16 spare area bytes
      NFDATA = *ptr_ul++;
    }
    NFCMMD = NAND_CMD_PAGEPROG;

    while (!(NFSTAT & 0x01));           // Wait while controller busy
    NFCMMD = NAND_CMD_READ0;
    while (!(NFSTAT & 0x01));           // Wait while controller busy
  }  
  else  {                               // Large Page Device
    return (NAND_NOT_IMPLEMENTED_ERROR);
  }

  return (NAND_OK);
}


/**************************** Auxiliary Functions ******************************/

/*- SetAddress_HW (...) --------------------------------------------------------
 *
 *  Set the address according to address word count
 *    Parameter:      adr:  Address Requested for Setting
 *               adr_type:  Address Word Count
 *              page_type:  Size of Page
 *    Return Value:         NAND_ERROR
 */

static int SetAddress_HW (unsigned long adr) {

  NFADDR    = adr & 0xFF;               // Address word 1st
  SetBlockAddress_HW(adr);

  return (NAND_OK);
}


/*- SetBlockAddress_HW (...) --------------------------------------------------------
 *
 *  Set the block address according to address word count
 *    Parameter:      adr:  Address Requested for Setting
 *               adr_type:  Address Word Count
 *              page_type:  Size of Page
 *    Return Value:         NAND_ERROR
 */

static int SetBlockAddress_HW (unsigned long adr) {

  if (page_type_hw == SMALL_PAGE)  {    // Small Page Device
    NFADDR    = (adr >>  9) & 0xFF;     // Address word 1st
    NFADDR    = (adr >> 17) & 0xFF;     // Address word 2rd
    if (adr_cycles_hw > 3)
      NFADDR  = (adr >> 25) & 0xFF;     // Address word 3th
  } 
  else  {                               // Large Page Device
    NFADDR    = (adr >> 12) & 0xFF;     // Address word 1st
    if (adr_cycles_hw > 3)
      NFADDR  = (adr >> 20) & 0xFF;     // Address word 2th
    if (adr_cycles_hw > 4)
      NFADDR  = (adr >> 28) & 0xFF;     // Address word 3th
  }

  return (NAND_OK);
}


/*******************************************************************************/

⌨️ 快捷键说明

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