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

📄 flashhw.c

📁 nxp 3250 的nandflash的bootloader
💻 C
字号:
/***********************************************************************/
/*  This file is part of the ARM Toolchain package                     */
/*  Copyright KEIL ELEKTRONIK GmbH 2003 - 2006                         */
/***********************************************************************/
/*                                                                     */
/*  FlashHW.C:   Hardware Layer of Flash Programming Functions         */
/*               adapted for the Philips LPC318x MLC NAND Controller   */
/***********************************************************************/

#include "LPC318x.H"                        // LPC318x definitions
#include "NAND_Error.h"                     // Error definitions

// NAND Controller Buffer Definition
#define MLC_DATA               (*(volatile unsigned long  *)(0x200B0000))
#define MLC_DATAX(x)           (*(volatile unsigned long  *)(0x200A8000+(x<<2)))

// 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[64];

// 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) {
  static unsigned char first_run_f = TRUE;

  bus_width_hw    = bus_width;
  adr_cycles_hw   = adr_cycles;
  page_type_hw    = page_type;

  if (first_run_f == TRUE) {
    first_run_f = FALSE;

    // Enable programming with GPO_19 pin driven high
    PIO_OUTP_SET = (1 << 1) | (1 << 19);

    FLASHCLK_CTRL = 0x00000022;         // Setup NAND Flash Clock Control
    MLC_CEH       = 0;                  // Force nCE assert
    MLC_CMD       = NAND_CMD_RESET;     // Reset NAND Flash

    while (!(MLC_ISR & 0x01));
  }

  // 16 bit bus width is not supported by controller
  if (bus_width_hw != 8) return (NAND_NOT_ALLOWED_ERROR);

  MLC_LOCK_PR     = 0xA25E;             // Unlock access to MLC_ICR register
  MLC_ICR         =  (bus_width_hw  == 16)
                  | ((adr_cycles_hw ==  4) << 1)
                  | ((page_type_hw  ==  1) << 2);

  MLC_LOCK_PR     = 0xA25E;             // Unlock access to MLC_TIME register
  MLC_TIME_REG    = (3 << 24) | (11 << 19) | (4 << 16) | (2 << 12) | (4 << 8) | (3 << 4) | (4 << 0);

  while (!(MLC_ISR & 0x01));

  return (NAND_OK);
}


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

int EraseBlock_HW (unsigned long adr) {

  while (!(MLC_ISR & 0x01));            // Wait for NAND ready
  MLC_CMD  = NAND_CMD_ERASE1ST;
  SetBlockAddress_HW(adr);
  MLC_CMD  = NAND_CMD_ERASE2ND;

  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 long *ptr_ul = (unsigned long *)buf;

  if (page_type_hw == SMALL_PAGE)  {    // Small Page Device
    while (!(MLC_ISR & 0x01));          // Wait for NAND ready
    MLC_CMD = NAND_CMD_READ0;
    SetAddress_HW(adr);
    MLC_ECC_AUTO_DEC_REG = 0x00;        // Auto Decode
    while (!(MLC_ISR & 0x02));          // Wait for controller ready
    while (!(MLC_ISR & 0x04));          // Wait for ECC ready
    if (MLC_ISR & 0x40)
      return (NAND_ECC_ERROR);          // Decode ECC error
    for (i=0; i<((sz+3)>>2); i++) {     // Read requested number of bytes
      *ptr_ul++ = MLC_DATAX(i);
    }
  }  
  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 long *ptr_ul = (unsigned long *)buf;

  if (page_type_hw == SMALL_PAGE)  {    // Small Page Device
    while (!(MLC_ISR & 0x01));          // Wait for NAND ready
    MLC_CMD = NAND_CMD_SDIN;
    SetAddress_HW(adr);
    MLC_ECC_ENC_REG = 0;
    for (i=0;        i<(512>>2); i++)   // Load main area data
      MLC_DATAX(i) = *ptr_ul++;
    for (i=(512>>2); i<(520>>2); i++)   // Load spare area data
      MLC_DATAX(i) = 0xFFFFFFFF;
    MLC_ECC_AUTO_ENC_REG = 0;
    while (!(MLC_ISR & 0x02));          // Wait for controller ready
    MLC_CMD     = NAND_CMD_PAGEPROG;
  }  
  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 long *ptr_ul = (unsigned long *)spare_buf;

  if (page_type_hw == SMALL_PAGE)  {    // Small Page Device
    while (!(MLC_ISR & 0x01));          // Wait for NAND ready
    MLC_CMD = NAND_CMD_READ0;
    SetAddress_HW(adr);
    MLC_ECC_AUTO_DEC_REG = 0x00;        // Auto Decode
    while (!(MLC_ISR & 0x02));          // Wait for controller ready
    while (!(MLC_ISR & 0x04));          // Wait for ECC ready
    if (MLC_ISR & 0x40)                return (NAND_ECC_ERROR);
    for (i=0;        i<(512>>2); i++)   // Load main area data
      MLC_DATAX(i);
    for (i=(512>>2); i<(520>>2); i++)   // Load spare area data
      *ptr_ul++ = MLC_DATAX(i);

    // 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 long *ptr_ul = (unsigned long *)spare_buf;
  
  if (page_type_hw == SMALL_PAGE)  {    // Small Page Device
    while (!(MLC_ISR & 0x01));          // Wait for NAND ready
    // 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
    MLC_CMD = NAND_CMD_SDIN;
    SetAddress_HW(adr);
    MLC_ECC_ENC_REG = 0;
    for (i=0;        i<(512>>2); i++)   // Load main area data
      MLC_DATAX(i) = 0xFFFFFFFF;
    for (i=(512>>2); i<(520>>2); i++)   // Load spare area data
      MLC_DATAX(i) = *ptr_ul++;
    MLC_ECC_AUTO_ENC_REG = 0;
    while (!(MLC_ISR & 0x02));          // Wait for controller ready
    MLC_CMD     = NAND_CMD_PAGEPROG;
  }  
  else  {                               // Large Page Device
    return (NAND_NOT_IMPLEMENTED_ERROR);
  }
  
  return (NAND_OK);
}


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

/*- SwapU32 (...) --------------------------------------------------------------
 *
 *  Swap big <-> little-endian for 32 bit value
 *    Parameter:
 *    Return Value:         swapped value
 *//*

static unsigned long SwapU32(unsigned long to_swap)
{
  const unsigned long mask = 0x00FF00FF;
  unsigned long temp;

  __asm {
    AND temp,    mask,    to_swap
    AND to_swap, mask,    to_swap, ROR #24
    ORR to_swap, to_swap, temp,    ROR #8
  }

  return (to_swap);
} */


/*- 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) {
  if (page_type_hw == SMALL_PAGE)  {    // Small Page Device
    MLC_ADDR    = (0        ) & 0xFF;   // Address word 1st
    MLC_ADDR    = (adr >>  9) & 0xFF;   // Address word 2nd
    MLC_ADDR    = (adr >> 17) & 0xFF;   // Address word 3rd
    if (adr_cycles_hw > 3)
      MLC_ADDR  = (adr >> 25) & 0xFF;   // Address word 4th
  }  
  else  {                               // Large Page Device
    MLC_ADDR    = (0        ) & 0xFF;   // Address word 1st
    MLC_ADDR    = (adr >>  8) & 0x0F;   // Address word 2nd
    MLC_ADDR    = (adr >> 12) & 0xFF;   // Address word 3rd
    if (adr_cycles_hw > 3)
      MLC_ADDR  = (adr >> 20) & 0xFF;   // Address word 4th
    if (adr_cycles_hw > 4)
      MLC_ADDR  = (adr >> 28) & 0xFF;   // Address word 5th
  }
  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
    MLC_ADDR    = (adr >>  9) & 0xFF;   // Address word 1nd
    MLC_ADDR    = (adr >> 17) & 0xFF;   // Address word 2rd
    if (adr_cycles_hw > 3)
      MLC_ADDR  = (adr >> 25) & 0xFF;   // Address word 3th
  }  
  else  {                               // Large Page Device
    MLC_ADDR    = (adr >> 12) & 0xFF;   // Address word 1rd
    if (adr_cycles_hw > 3)
      MLC_ADDR  = (adr >> 20) & 0xFF;   // Address word 2th
    if (adr_cycles_hw > 4)
      MLC_ADDR  = (adr >> 28) & 0xFF;   // Address word 3th
  }
  return (NAND_OK);
}


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

⌨️ 快捷键说明

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