Ejemplo n.º 1
0
/* read chip mfr and id
 * return 0 if they match board config
 * return 1 if not
 */
int nand_chip()
{
	int mfr, id;

 	NAND_ENABLE_CE();

 	if (NanD_Command(NAND_CMD_RESET)) {
 		printf("Err: RESET\n");
 		NAND_DISABLE_CE();   
		return 1;
	}
 
 	if (NanD_Command(NAND_CMD_READID)) {
 		printf("Err: READID\n");
 		NAND_DISABLE_CE();
		return 1;
 	}
 
 	NanD_Address(ADDR_COLUMN, 0);

 	mfr = READ_NAND(NAND_ADDR);
	id = READ_NAND(NAND_ADDR);

	NAND_DISABLE_CE();

  	return (mfr != K9F5616_MFR || id != K9F5616_ID);
}
Ejemplo n.º 2
0
static PSNandInitInfo AT91F_NandReadID(void)
{
    unsigned int uChipID;

    unsigned char bManufacturerID, bDeviceID;

    /*
     * Enable chipset 
     */
    NAND_ENABLE_CE();

    /*
     * Ask the Nand its IDs 
     */
    WRITE_NAND_COMMAND(CMD_READID);
    WRITE_NAND_ADDRESS(0x00);

    /*
     * Read answer 
     */
    bManufacturerID = READ_NAND();
    bDeviceID = READ_NAND();

    /*
     * Disable chipset before returning 
     */
    NAND_DISABLE_CE();

    uChipID = (bManufacturerID << 8) | bDeviceID;

    return AT91F_GetNandInitInfo(uChipID);
}
Ejemplo n.º 3
0
bool onfi_ebidetect(uintptr_t cmdaddr, uintptr_t addraddr,
                    uintptr_t dataaddr)
{
  uint32_t timer;
  uint8_t rc;
  bool found = false;
  uint8_t ids[4];
  uint8_t i;

  finfo("cmdaddr=%08x addraddr=%08x dataaddr=%08x\n",
        (int)cmdaddr, (int)addraddr, (int)dataaddr);

  /* Send Reset command */

  WRITE_NAND_COMMAND(NAND_CMD_RESET, cmdaddr);

  /* If a Nandflash is connected, it should answer to a read status command */

  for (timer = 0; timer < 60; timer++)
    {
      rc = onfi_readstatus(cmdaddr, dataaddr);
      if (rc == OK)
        {
          WRITE_NAND_COMMAND(NAND_CMD_READID, cmdaddr);
          WRITE_NAND_ADDRESS(0, addraddr);

          ids[0] = READ_NAND(dataaddr);
          ids[1] = READ_NAND(dataaddr);
          ids[2] = READ_NAND(dataaddr);
          ids[3] = READ_NAND(dataaddr);

          for (i = 0; i < NAND_NMODELS ; i++)
            {
              if (g_nandmodels[i].devid == ids[1])
                {
                  found = true;
                  break;
                }
            }

          break;
        }
    }

  if (!found)
    {
      if (onfi_compatible(cmdaddr, addraddr, dataaddr))
        {
          /* Report true if it is an ONFI device that is not in device
           * list (perhaps it is a new device that is ONFI campatible
           */

          found = true;
       }
    }

  return found;
}
Ejemplo n.º 4
0
/* read a page with ECC */
static int nand_read_page(u_char *buf, ulong page_addr)
{
 	u_char ecc_code[6];
	u_char ecc_calc[3];
 	u_char oob_buf[16];
	u_char *p;
	u16 val;
	int cntr;

	NAND_ENABLE_CE();   
	NanD_Command(NAND_CMD_READ0);
	NanD_Address(ADDR_COLUMN_PAGE, page_addr>>1);

	NAND_WAIT_READY();
 	p = buf;
	for (cntr = 0; cntr < 256; cntr++){
		val = READ_NAND(NAND_ADDR);
		*p++ = val & 0xff;
		*p++ = val >> 8;
 	}

	p = oob_buf;
	for (cntr = 0; cntr < 8; cntr++){
 		val = READ_NAND(NAND_ADDR);
		*p++ = val & 0xff;
		*p++ = val >> 8;
 	}
 	NAND_DISABLE_CE();  /* set pin high */

 	/* Pick the ECC bytes out of the oob data */
	for (cntr = 0; cntr < 6; cntr++)
		ecc_code[cntr] =  oob_buf[ecc_pos[cntr]];


	if ((oob_buf[eccvalid_pos] & 0x0f) != 0x0f) {
 		nand_calculate_ecc (buf, &ecc_calc[0]);
		if (nand_correct_data (buf, &ecc_code[0], &ecc_calc[0]) == -1) {
 			printf ("ECC Failed, page 0x%08x\n", page_addr);
  			return 1;
 		}
	}
	
	if ((oob_buf[eccvalid_pos] & 0xf0) != 0xf0) {
 		nand_calculate_ecc (buf + 256, &ecc_calc[0]);
		if (nand_correct_data (buf + 256, &ecc_code[3], &ecc_calc[0]) == -1) {
 			printf ("ECC Failed, page 0x%08x\n", page_addr+0x100);
  			return 1;
 		}
	}

	return 0;
}
Ejemplo n.º 5
0
static u_char upmnand_read_byte(struct mtd_info *mtdinfo)
{
	struct nand_chip *this = mtdinfo->priv;
	ulong base = (ulong) (this->IO_ADDR_W + chipsel * CONFIG_SYS_NAND_CS_DIST);

	return READ_NAND(base);
}
Ejemplo n.º 6
0
bool onfi_compatible(uintptr_t cmdaddr, uintptr_t addraddr,
                     uintptr_t dataaddr)
{
  uint8_t parmtab[ONFI_PARAM_TABLE_SIZE];

  /* Check if the Nandflash is ONFI compliant */

  WRITE_NAND_COMMAND(NAND_CMD_READID, cmdaddr);
  WRITE_NAND_ADDRESS(0x20, addraddr);

  parmtab[0] = READ_NAND(dataaddr);
  parmtab[1] = READ_NAND(dataaddr);
  parmtab[2] = READ_NAND(dataaddr);
  parmtab[3] = READ_NAND(dataaddr);

  return
   (parmtab[0] == 'O' && parmtab[1] == 'N' &&
    parmtab[2] == 'F' && parmtab[3] == 'I');
}
Ejemplo n.º 7
0
/**
 * \brief This function retrieves the data structure that describes the target¡®s 
 * organization, features, timings and other behavioral parameters.
 * \param pOnfiPageParameter Pointer to a PmeccDescriptor instance.
 * \return  0: ONFI not compliant or not supported.
            1: ONFI compliant
*/
uint8_t NandGetOnfiPageParam (OnfiPageParam *pOnfiPageParameter)
{
    uint8_t i;
    uint8_t rc;
    uint8_t onfi_param_table[ONFI_PARAM_TABLE_SIZE];

    if (NandIsOnficompatible()) {
        pCurrentOnfiPageParam = pOnfiPageParameter;
        pOnfiPageParameter->onfiCompatiable = 1;
        for (i = 0; i < ONFI_PARAM_TABLE_SIZE; i++) {
            onfi_param_table[i] = 0xFF;
        }
        /* Perform Read Parameter Page command */
        WRITE_NAND_COMMAND(NAND_CMD_READ_PARAM_PAGE, EBI_NF_ADDR);
        WRITE_NAND_ADDRESS(0x0, EBI_NF_ADDR);

        /* Wait NF ready */
        _NandReadStatus();
        /* Re-enable data output mode required after Read Status command */
        WRITE_NAND_COMMAND(NAND_CMD_READ0, EBI_NF_ADDR);

        /* Read the parameter table */
        for (i = 0; i < ONFI_PARAM_TABLE_SIZE; i++) {
            onfi_param_table[i] = READ_NAND(EBI_NF_ADDR);
        }
        for (i = 0; i < ONFI_PARAM_TABLE_SIZE; i++) {
            if ( onfi_param_table[i] != 0xFF ) break;
        }
        if ( i == ONFI_PARAM_TABLE_SIZE) {
            pOnfiPageParameter->onfiCompatiable = 0;
            return 0;
        }
        /* JEDEC manufacturer ID */
        pOnfiPageParameter->manufacturerId = *(uint8_t *)(onfi_param_table + 64);
        /* Bus width */
        pOnfiPageParameter->onfiBusWidth = (*(uint8_t *)(onfi_param_table + 6)) & 0x01;
        /* Get number of data bytes per page (bytes 80-83 in the param table) */
        pOnfiPageParameter->onfiPageSize =  *(uint32_t *)(void*)(onfi_param_table + 80);
        /* Get number of spare bytes per page (bytes 84-85 in the param table) */
        pOnfiPageParameter->onfiSpareSize =  *(uint16_t *)(void*)(onfi_param_table + 84);
        /* Number of pages per block. */
        pOnfiPageParameter->onfiPagesPerBlock = *(uint32_t *)(void*)(onfi_param_table + 92);
        /* Number of blocks per logical unit (LUN). */
        pOnfiPageParameter->onfiBlocksPerLun = *(uint32_t *)(void*)(onfi_param_table + 96);
        /* Number of logical units. */
        pOnfiPageParameter->onfiLogicalUnits = *(uint8_t *)(onfi_param_table + 100);
        /* Number of bits of ECC correction */
        pOnfiPageParameter->onfiEccCorrectability = *(uint8_t *)(onfi_param_table + 112);
        /* Device model */
        pOnfiPageParameter->onfiDeviceModel= *(uint8_t *)(onfi_param_table + 49);
        return 1;
    }
    return 0;
}
Ejemplo n.º 8
0
/**
 * \brief This function read an the ONFI signature at address of 20h to detect
 * if the device is ONFI compatiable.
 * \return  0: ONFI not compliant or not supported.
            1: ONFI compliant
*/
uint8_t NandIsOnficompatible (void)
{
    uint8_t onfi_param_table[ONFI_PARAM_TABLE_SIZE];

    // Check if the Nandflash is ONFI compliant

    WRITE_NAND_COMMAND(NAND_CMD_READID, EBI_NF_ADDR);
    WRITE_NAND_ADDRESS(0x20, EBI_NF_ADDR);

    onfi_param_table[0] = READ_NAND(EBI_NF_ADDR);
    onfi_param_table[1] = READ_NAND(EBI_NF_ADDR);
    onfi_param_table[2] = READ_NAND(EBI_NF_ADDR);
    onfi_param_table[3] = READ_NAND(EBI_NF_ADDR);

    if ((onfi_param_table[0] == 'O') &&
        (onfi_param_table[1] == 'N') &&
        (onfi_param_table[2] == 'F') &&
        (onfi_param_table[3] == 'I')) {
        return 1;
    }
    else {
        return 0;
    }
}
Ejemplo n.º 9
0
/* NanD_Command: Send a flash command to the flash chip */
static int NanD_Command(unsigned char command)
{
 	NAND_CTL_SETCLE(NAND_ADDR);
 	WRITE_NAND_COMMAND(command, NAND_ADDR);
 	NAND_CTL_CLRCLE(NAND_ADDR);

  	if(command == NAND_CMD_RESET){
		unsigned char ret_val;
		NanD_Command(NAND_CMD_STATUS);
		do{
			ret_val = READ_NAND(NAND_ADDR);/* wait till ready */
  		} while((ret_val & 0x40) != 0x40);
 	}
 	
 	NAND_WAIT_READY();
	return 0;
}
Ejemplo n.º 10
0
/* read from the 16 bytes of oob data that correspond to a 512 byte page.
 */
static int nand_read_oob(u_char *buf, ulong page_addr)
{
	u16 val;
	int cntr;
    	
  	NAND_ENABLE_CE();  /* set pin low */
	NanD_Command(NAND_CMD_READOOB);
 	NanD_Address(ADDR_COLUMN_PAGE, page_addr>>1);
	NAND_WAIT_READY();

	for (cntr = 0; cntr < 8; cntr++){
		val = READ_NAND(NAND_ADDR);
		*buf++ = val & 0xff;
		*buf++ = val >> 8;
  	}

	NAND_WAIT_READY();
	NAND_DISABLE_CE();  /* set pin high */

	return 0;
}
Ejemplo n.º 11
0
static int onfi_readstatus(uintptr_t cmdaddr, uintptr_t dataaddr)
{
  uint32_t timeout;
  uint8_t status;

  /* Issue command */

  WRITE_NAND_COMMAND(NAND_CMD_STATUS, cmdaddr);
  timeout = 0;

  while (timeout < MAX_READ_STATUS_COUNT)
    {
      /* Read status byte */

      status = READ_NAND(dataaddr);

      /* Check status. If status bit 6 = 1 device is ready */

      if ((status & STATUS_BIT_6) == STATUS_BIT_6)
        {
          /* If status bit 0 = 0 the last operation was successful */

          if ((status & STATUS_BIT_0) == 0)
            {
              return OK;
            }
          else
            {
              return -EIO;
            }
        }

      timeout++;
    }

  return -ETIMEDOUT;
}
Ejemplo n.º 12
0
/**
 * \brief This function Reads the status register of the NAND device by 
 * issuing a 0x70 command.
 * \return  NAND_IO_RC_PASS     =0 : The function completes operation successfully.
            NAND_IO_RC_FAIL     =1 : The function does not complete operation successfully.
            NAND_IO_RC_TIMEOUT  =2 : The function times out before operation completes.
*/
static uint32_t _NandReadStatus(void)
{
    uint32_t nReadStatusCount;
    uint8_t ucStatus;

    /* Issue command */
    WRITE_NAND_COMMAND(NAND_CMD_STATUS, EBI_NF_ADDR);
    nReadStatusCount = 0;

    while (nReadStatusCount < MAX_READ_STATUS_COUNT) {
        /* Read status byte */
        ucStatus = READ_NAND(EBI_NF_ADDR);
        /* Check status */
        /* If status bit 6 = 1 device is ready */
        if ((ucStatus & STATUS_BIT_6) == STATUS_BIT_6) {
            if ((ucStatus & STATUS_BIT_0) == 0)  /* If status bit 0 = 0 the last operation was succesful */
                return NAND_IO_RC_PASS;
            else
                return NAND_IO_RC_FAIL;
        }
        nReadStatusCount++;
    }
    return NAND_IO_RC_TIMEOUT;
}
Ejemplo n.º 13
0
uint8_t NandEbiDetect(void)
{
    uint32_t timer;
    uint8_t rc;
    uint8_t chip_found = 0;
    uint8_t ids[4];
    uint8_t i;
    
    *ADDR_CCFG_EBICSA |= EBICSA_EBI_DBPDC;
    /* Try to detect a bootable Nand connected on D16 */
    *ADDR_CCFG_EBICSA |= (EBICSA_NAND_D0_ON_D16 );
 
    /* Send Reset command */
    WRITE_NAND_COMMAND(NAND_CMD_RESET, EBI_NF_ADDR);
    /* If a Nandflash is connected, it should answer to a read status command */
    for (timer = 0; timer < 60; timer++) {
        rc = _NandReadStatus();
        if (rc == NAND_IO_RC_PASS) {
            WRITE_NAND_COMMAND(NAND_CMD_READID, EBI_NF_ADDR);
            WRITE_NAND_ADDRESS(0, EBI_NF_ADDR);
            ids[0] = READ_NAND(EBI_NF_ADDR);
            ids[1] = READ_NAND(EBI_NF_ADDR);
            ids[2] = READ_NAND(EBI_NF_ADDR);
            ids[3] = READ_NAND(EBI_NF_ADDR);
            for(i = 0; i< NandFlashModelList_SIZE ; i++) {
                if(nandFlashModelList[i].deviceId == ids[1]) {
                    chip_found = 1;
                    break;
                }
            }
            break;
        }
    }
    if (chip_found == 0) {

        /* Then try Nand connected on D0 */
        *ADDR_CCFG_EBICSA &= (uint32_t)(~ EBICSA_NAND_D0_ON_D16 );

        /* Send Reset command */
        WRITE_NAND_COMMAND(NAND_CMD_RESET, EBI_NF_ADDR);

        /* If a Nandflash is connected, it should answer to a read status command */
        for (timer = 0; timer < 60; timer++) {
            rc = _NandReadStatus();
            if (rc == NAND_IO_RC_PASS) {
                WRITE_NAND_COMMAND(NAND_CMD_READID, EBI_NF_ADDR);
                WRITE_NAND_ADDRESS(0, EBI_NF_ADDR);
                ids[0] = READ_NAND(EBI_NF_ADDR);
                ids[1] = READ_NAND(EBI_NF_ADDR);
                ids[2] = READ_NAND(EBI_NF_ADDR);
                ids[3] = READ_NAND(EBI_NF_ADDR);
                for( i = 0; i< NandFlashModelList_SIZE ; i++) {
                    if(nandFlashModelList[i].deviceId == ids[1]) {
                        chip_found = 1;
                        break;
                    }
                }
            }
            break;
        }
    }
    return chip_found;
}
Ejemplo n.º 14
0
int onfi_read(uintptr_t cmdaddr, uintptr_t addraddr, uintptr_t dataaddr,
              FAR struct onfi_pgparam_s *onfi)
{
  uint8_t parmtab[ONFI_PARAM_TABLE_SIZE];
  int i;

  finfo("cmdaddr=%08x addraddr=%08x dataaddr=%08x\n",
        (int)cmdaddr, (int)addraddr, (int)dataaddr);

  if (!onfi_compatible(cmdaddr, addraddr, dataaddr))
    {
      ferr("ERROR: No ONFI compatible device detected\n");
      return -ENODEV;
    }

  /* Initialize the ONFI parameter table */

  memset(parmtab, 0xff, ONFI_PARAM_TABLE_SIZE);

  /* Perform Read Parameter Page command */

  WRITE_NAND_COMMAND(NAND_CMD_READ_PARAM_PAGE, cmdaddr);
  WRITE_NAND_ADDRESS(0x0, addraddr);

  /* Wait NF ready */

  onfi_readstatus(cmdaddr, dataaddr);

  /* Re-enable data output mode required after Read Status command */

  WRITE_NAND_COMMAND(NAND_CMD_READ0, cmdaddr);

  /* Read the parameter table */

  for (i = 0; i < ONFI_PARAM_TABLE_SIZE; i++)
    {
      parmtab[i] = READ_NAND(dataaddr);
    }

  for (i = 0; i < ONFI_PARAM_TABLE_SIZE; i++)
    {
      if (parmtab[i] != 0xff)
        {
          break;
        }
    }

  if (i == ONFI_PARAM_TABLE_SIZE)
    {
      ferr("ERROR: Failed to read ONFI parameter table\n");
      return -EIO;
   }

  /* JEDEC manufacturer ID */

  onfi->manufacturer = *(FAR uint8_t *)(parmtab + 64);

  /* Bus width */

  onfi->buswidth = (*(FAR uint8_t *)(parmtab + 6)) & 0x01;

  /* Get number of data bytes per page (bytes 80-83 in the param table) */

  onfi->pagesize =  *(FAR uint32_t *)(FAR void *)(parmtab + 80);

  /* Get number of spare bytes per page (bytes 84-85 in the param table) */

  onfi->sparesize =  *(FAR uint16_t *)(FAR void *)(parmtab + 84);

  /* Number of pages per block. */

  onfi->pagesperblock = *(FAR uint32_t *)(FAR void *)(parmtab + 92);

  /* Number of blocks per logical unit (LUN). */

  onfi->blocksperlun = *(FAR uint32_t *)(FAR void *)(parmtab + 96);

  /* Number of logical units. */

  onfi->luns = *(FAR uint8_t *)(parmtab + 100);

  /* Number of bits of ECC correction */

  onfi->eccsize = *(FAR uint8_t *)(parmtab + 112);

  /* Device model */

  onfi->model = *(FAR uint8_t *)(parmtab + 49);

  finfo("Returning:\n");
  finfo("  manufacturer:  0x%02x\n", onfi->manufacturer);
  finfo("  buswidth:      %d\n",     onfi->buswidth);
  finfo("  luns:          %d\n",     onfi->luns);
  finfo("  eccsize:       %d\n",     onfi->eccsize);
  finfo("  model:         0x%02s\n", onfi->model);
  finfo("  sparesize:     %d\n",     onfi->sparesize);
  finfo("  pagesperblock: %d\n",     onfi->pagesperblock);
  finfo("  blocksperlun:  %d\n",     onfi->blocksperlun);
  finfo("  pagesize:      %d\n",     onfi->pagesize);
  return OK;
}
Ejemplo n.º 15
0
//-----------------------------------------------------------------------------
HANDLE 
NAND_Initialize(
    LPCTSTR szContext,
    PCI_REG_INFO *pRegIn,
    PCI_REG_INFO *pRegOut
    )
{
    DWORD chipSelect = BSPGetNandCS();
    const NAND_INFO *  pBSPNandInfo;
    HANDLE hDevice = NULL;
    UINT ffPrefetchMode = 0;
    UINT8 manufacturer, device;
    NandDevice_t *pDevice = &s_Device;
#ifndef BOOT_MODE    
    DWORD dwKernelRet;
#endif

    UNREFERENCED_PARAMETER(pRegOut);
    UNREFERENCED_PARAMETER(szContext);
    // initialize structure
    memset(pDevice, 0, sizeof(NandDevice_t));

#ifdef BOOT_MODE    
    pDevice->pGpmcRegs = (OMAP_GPMC_REGS*)OALPAtoUA(SOCGetGPMCAddress(0));
    pDevice->pFifo = (NANDREG*)OALPAtoUA(pRegIn->MemBase.Reg[0]);

    /* Get ECC mode from BootCfg */
    pDevice->ECCtype = g_ecctype;
    if((pDevice->ECCtype > BCH8bit) || (pDevice->ECCtype < Hamming1bit))
    	{
            pDevice->ECCtype = Hamming1bit;
            RETAILMSG(TRUE, (L"Incorrect ECC type setting\r\n"));			
    	}
#else    
    if (szContext != NULL)
	{
        if (InitializePointers(szContext, pDevice) == FALSE) goto cleanUp;
	}
    else
	{
        PHYSICAL_ADDRESS pa;
        
        // if there's not context string then use global macros

        pa.QuadPart = pRegIn->MemBase.Reg[0];
        pDevice->memLen[0] = pRegIn->MemLen.Reg[0];
        pDevice->pGpmcRegs = MmMapIoSpace(pa, pDevice->memLen[0], FALSE);
        if (pDevice->pGpmcRegs == NULL) goto cleanUp;

        pa.QuadPart = pRegIn->MemBase.Reg[1];
        pDevice->memLen[1] = pRegIn->MemLen.Reg[1];
        pDevice->pFifo = MmMapIoSpace(pa, pDevice->memLen[1], FALSE);
        if (pDevice->pGpmcRegs == NULL) goto cleanUp;

	}

	if (!KernelIoControl(IOCTL_HAL_GET_ECC_TYPE, NULL, 0, &pDevice->ECCtype, sizeof(DWORD), &dwKernelRet))
	{
		RETAILMSG( TRUE,(TEXT("Failed to read Ecc type\r\n")));
		pDevice->ECCtype = Hamming1bit;
	}   
	
	RETAILMSG(TRUE, (L"ECC TYPE is %s\r\n", (pDevice->ECCtype==Hamming1bit)? L"Hamming 1 bit" :
									(pDevice->ECCtype==BCH4bit)? L"BCH 4 bit" : L"BCH 8 bit"));
	
#endif

    pDevice->pNandCmd = (NANDREG*)((UINT32)pDevice->pGpmcRegs + offset(OMAP_GPMC_REGS, GPMC_NAND_COMMAND_0) + (0x30 * chipSelect));
    pDevice->pNandAddress= (NANDREG*)((UINT32)pDevice->pGpmcRegs + offset(OMAP_GPMC_REGS, GPMC_NAND_ADDRESS_0) + (0x30 * chipSelect));
    pDevice->pNandData= (NANDREG*)((UINT32)pDevice->pGpmcRegs + offset(OMAP_GPMC_REGS, GPMC_NAND_DATA_0) + (0x30 * chipSelect));
    // Enable GPMC wait-to-nowait edge detection mechanism on NAND R/B pin
    NAND_Enable(pDevice, TRUE);

    // Write RESET command
    // (a reset aborts any current READ, WRITE (PROGRAM) or ERASE operation)
    NAND_SendCommand(pDevice, NAND_CMD_RESET);

    // Wait for NAND
    while ((NAND_GetStatus(pDevice) & NAND_STATUS_READY) == 0);

    // Send Read ID Command
    NAND_SendCommand(pDevice, NAND_CMD_READID);

    // Send Address 00h
    WRITE_NAND(pDevice->pNandAddress, 0);

    // Read the manufacturer ID & device code
    manufacturer = (UINT8)READ_NAND(pDevice->pNandData);
    device = (UINT8)READ_NAND(pDevice->pNandData);

 
    if ((pBSPNandInfo = BSPGetNandInfo(manufacturer,device))==NULL)
    {                
        goto cleanUp;
    }
    if ((pBSPNandInfo->sectorSize != 2048) && (pBSPNandInfo->wordData != 2))
    {
        ERRORMSG(1,(TEXT("FMD driver supports only 16bits large page (2KB) devices\r\n")));
        goto cleanUp;
    }
    pDevice->nandInfo = *pBSPNandInfo;

    pDevice->IrqWait = BSPGetNandIrqWait();

    /* ECCCfg: 16bit bus width, cs0, 4 - 512 bytes blocks per page */
    pDevice->ECCCfg = (GPMC_ECC_CONFIG_16BIT | (chipSelect << 1) | (0x3<<4)); 
    pDevice->ECCsize = (pDevice->ECCtype == Hamming1bit ) ? ECC_BYTES_HAMMING : 
		                      (pDevice->ECCtype == BCH4bit ) ? ECC_BYTES_BCH4 : ECC_BYTES_BCH8; 
							  
    //  Enable and reset ECC engine (workaround for engine giving 0s first time)
    ECC_Init(pDevice->pGpmcRegs, pDevice->ECCCfg, pDevice->ECCtype, NAND_ECC_READ);
    ECC_Reset(pDevice->pGpmcRegs);

    //  Only enable during NAND read/write/erase operations
    NAND_Enable(pDevice, FALSE);

    // configure the prefetch engine
    pDevice->prefetchMode = kPrefetchOff;
    OUTREG32(&pDevice->pGpmcRegs->GPMC_PREFETCH_CONTROL, 0);

    // set prefetch mask
    ffPrefetchMode = GPMC_PREFETCH_CONFIG_SYNCHROMODE |
                     GPMC_PREFETCH_CONFIG_PFPWENROUNDROBIN |
                     GPMC_PREFETCH_CONFIG_ENABLEOPTIMIZEDACCESS |
                     GPMC_PREFETCH_CONFIG_WAITPINSELECTOR(chipSelect) |
                     GPMC_PREFETCH_CONFIG_FIFOTHRESHOLD(FIFO_THRESHOLD) |
                     GPMC_PREFETCH_CONFIG_ENGINECSSELECTOR(chipSelect);

    OUTREG32(&pDevice->pGpmcRegs->GPMC_PREFETCH_CONFIG1, ffPrefetchMode);

    // configure prefetch engine
    OUTREG32(&pDevice->pGpmcRegs->GPMC_PREFETCH_CONFIG2, 
        pBSPNandInfo->sectorSize
        );
        
    SETREG32(&pDevice->pGpmcRegs->GPMC_PREFETCH_CONFIG1, 
        GPMC_PREFETCH_CONFIG_ENABLEENGINE
        );

    // We are done
    hDevice = pDevice;

cleanUp:
    return hDevice;
}