int main(int argc, char **argv) { struct _Mailbox *pMailbox = (struct _Mailbox *) argv; /* Communication type with SAM-BA GUI. */ uint8_t comType; uint32_t jedecId; uint32_t bytesToWrite, bytesToRead, bufferAddr, startMemoryOffset, memoryOffset, packetSize; /* index on read/write buffer */ uint8_t *pBuffer; /* Temporary buffer used for non block aligned read/write */ uint32_t tempBufferAddr; /* Offset in destination buffer during buffer copy */ uint32_t bufferOffset; /* INIT */ /* Save communication link type */ comType = pMailbox->argument.inputInit.comType; if (pMailbox->command == APPLET_CMD_INIT) { #if (DYN_TRACES == 1) dwTraceLevel = pMailbox->argument.inputInit.traceLevel; #endif TRACE_INFO("-- SerialFlash AT25/AT26 applet %s --\n\r", SAM_BA_APPLETS_VERSION); TRACE_INFO("-- %s\n\r", BOARD_NAME); TRACE_INFO("-- Compiled: %s %s --\n\r", __DATE__, __TIME__); /* Configure pins */ PIO_Configure(pins, PIO_LISTSIZE(pins)); /* Initialize DMA driver instance with polling mode */ DMAD_Initialize( &dmad, 1 ); /* Initialize the SPI and serial flash */ SPID_Configure(&spid, SPI0, ID_SPI0, &dmad); AT25_Configure(&at25, &spid, SPI_CS, 1); TRACE_INFO("SPI and AT25/AT25 drivers initialized\n\r"); pMailbox->argument.outputInit.bufferAddress = (uint32_t) &_end ; /* Read the JEDEC ID of the device to identify it */ jedecId = AT25D_ReadJedecId(&at25); if (AT25_FindDevice(&at25, jedecId) == 0) { pMailbox->status = APPLET_DEV_UNKNOWN; pMailbox->argument.outputInit.bufferSize = 0; pMailbox->argument.outputInit.memorySize = 0; TRACE_INFO("Device Unknown\n\r"); goto exit; } else { /* Get device parameters */ pMailbox->status = APPLET_SUCCESS; pageSize = AT25_PageSize(&at25); blockSize = AT25_BlockSize(&at25); /* Program page */ if (AT25_ManId(&at25) == SST_SPI_FLASH) { /* SST Flash write is slower, we reduce buffer size to avoid USB timeout */ bufferSize = 10 * pageSize; } else { bufferSize = 4 * blockSize; } /* integer number of pages can be contained in each buffer */ bufferSize -= bufferSize % pageSize; if ( bufferSize < pageSize) { TRACE_INFO("No enought memory to load buffer.\n\r"); goto exit; } pMailbox->argument.outputInit.bufferSize = bufferSize; pMailbox->argument.outputInit.memorySize = AT25_Size(&at25); TRACE_INFO("%s blockSize : 0x%lx bufferAddr : 0x%lx\n\r", at25.pDesc->name, blockSize, pMailbox->argument.outputInit.bufferAddress); } } // ---------------------------------------------------------- // WRITE: // ---------------------------------------------------------- else if (pMailbox->command == APPLET_CMD_WRITE) { startMemoryOffset = pMailbox->argument.inputWrite.memoryOffset; memoryOffset = startMemoryOffset; bufferAddr = pMailbox->argument.inputWrite.bufferAddr; tempBufferAddr = bufferAddr + bufferSize; bytesToWrite = pMailbox->argument.inputWrite.bufferSize; TRACE_INFO("WRITE at offset: 0x%lx buffer at : 0x%lx of: 0x%lx Bytes\n\r", memoryOffset, bufferAddr, bytesToWrite); /* Check word alignment */ if (memoryOffset % 4) { pMailbox->status = APPLET_ALIGN_ERROR; goto exit; } if (AT25D_Unprotect(&at25)) { TRACE_INFO("Can not unprotect the flash\n\r"); pMailbox->status = APPLET_UNPROTECT_FAIL; goto exit; } pBuffer = (uint8_t *) bufferAddr; if ((memoryOffset % pageSize) != 0) { /* We are not page aligned, retrieve first page content to update it*/ if (memoryOffset < writtenAddress) { lastErasedBlock = 0xFFFF; } /* Flush temp buffer */ memset((uint32_t *)tempBufferAddr, 0xFF, pageSize); bufferOffset = (memoryOffset % pageSize); packetSize = pageSize - bufferOffset; memoryOffset -= bufferOffset; /* Read page to be updated*/ AT25D_Read(&at25, (uint8_t *) tempBufferAddr, pageSize, memoryOffset); /* Fill retrieved page with data to be programmed */ memcpy((uint8_t *)(tempBufferAddr + bufferOffset), pBuffer, packetSize); if (((memoryOffset / blockSize) > lastErasedBlock) || (lastErasedBlock == 0xFFFF)) { /* Erase the block to be updated */ AT25D_EraseBlock(&at25, memoryOffset); lastErasedBlock = (memoryOffset / blockSize); } /* Write the page contents */ AT25D_Write(&at25, (uint8_t *) tempBufferAddr, pageSize, memoryOffset); bytesToWrite = (bytesToWrite > packetSize) ? (bytesToWrite - packetSize) : 0; pBuffer += packetSize; memoryOffset += pageSize; writtenAddress = memoryOffset; } /* If it remains more than one page to write */ while (bytesToWrite >= pageSize) { if (memoryOffset < writtenAddress) { lastErasedBlock = 0xFFFF; } if (((memoryOffset / blockSize) > lastErasedBlock) || (lastErasedBlock == 0xFFFF)) { /* Erase the block to be updated */ AT25D_EraseBlock(&at25, memoryOffset); lastErasedBlock = (memoryOffset / blockSize); } /* Write the page contents */ AT25D_Write(&at25, (uint8_t *) pBuffer, pageSize, memoryOffset); pBuffer += pageSize; memoryOffset += pageSize; bytesToWrite -= pageSize; writtenAddress = memoryOffset; } /* Write remaining data */ if (bytesToWrite > 0) { /* Read previous content of page */ AT25D_Read(&at25, (uint8_t *) tempBufferAddr, pageSize, memoryOffset); /* Fill retrieved block with data to be programmed */ memcpy((uint8_t *)tempBufferAddr, pBuffer, bytesToWrite); if (((memoryOffset / blockSize) > lastErasedBlock) || (lastErasedBlock == 0xFFFF)) { /* Erase the block to be updated */ AT25D_EraseBlock(&at25, memoryOffset); lastErasedBlock = (memoryOffset / blockSize); } /* Write the page contents */; AT25D_Write(&at25, (uint8_t *) tempBufferAddr, pageSize, memoryOffset); writtenAddress = memoryOffset + bytesToWrite; /* No more bytes to write */ bytesToWrite = 0; } TRACE_INFO("WRITE return byte written : 0x%lx Bytes\n\r", pMailbox->argument.inputWrite.bufferSize - bytesToWrite); pMailbox->argument.outputWrite.bytesWritten = pMailbox->argument.inputWrite.bufferSize - bytesToWrite; pMailbox->status = APPLET_SUCCESS; } // ---------------------------------------------------------- // READ: // ---------------------------------------------------------- else if (pMailbox->command == APPLET_CMD_READ) { memoryOffset = pMailbox->argument.inputRead.memoryOffset; bufferAddr = pMailbox->argument.inputRead.bufferAddr; bytesToRead = pMailbox->argument.inputRead.bufferSize; TRACE_INFO("READ at offset: 0x%lx buffer at : 0x%lx of: 0x%lx Bytes\n\r", memoryOffset, bufferAddr, bytesToRead); /* Check word alignment */ if (memoryOffset % 4) { pMailbox->status = APPLET_ALIGN_ERROR; goto exit; } pBuffer = (uint8_t *) bufferAddr; /* Read packet after packets */ while (((uint32_t)pBuffer < (bufferAddr + bufferSize)) && (bytesToRead > 0)) { packetSize = min(MAX_COUNT, bytesToRead); AT25D_Read(&at25, pBuffer, packetSize, memoryOffset); pBuffer += packetSize; bytesToRead -= packetSize; memoryOffset += packetSize; } TRACE_INFO("READ return byte read : 0x%lx Bytes\n\r", pMailbox->argument.inputRead.bufferSize - bytesToRead); pMailbox->argument.outputRead.bytesRead = pMailbox->argument.inputRead.bufferSize - bytesToRead; pMailbox->status = APPLET_SUCCESS; } // ---------------------------------------------------------- // FULL ERASE: // ---------------------------------------------------------- else if (pMailbox->command == APPLET_CMD_FULL_ERASE) { TRACE_INFO("FULL ERASE\n\r"); /* Unprotected the flash */ if (AT25D_Unprotect(&at25)) { TRACE_INFO("Can not unprotect the flash\n\r"); pMailbox->status = APPLET_UNPROTECT_FAIL; goto exit; } TRACE_INFO("Flash unprotected\n\r"); /* Erase the chip */ TRACE_INFO("Chip is being erased...\n\r"); if (AT25D_EraseChip(&at25)) { TRACE_INFO("Erasing error\n\r"); pMailbox->status = APPLET_ERASE_FAIL; goto exit; } TRACE_INFO("Full Erase achieved\n\r"); pMailbox->status = APPLET_SUCCESS; } // ---------------------------------------------------------- // BUFFER ERASE: // ---------------------------------------------------------- else if (pMailbox->command == APPLET_CMD_BUFFER_ERASE) { TRACE_INFO("BUFFER ERASE \n\r"); /* Unprotected the flash */ if (AT25D_Unprotect(&at25)) { TRACE_INFO("Can not unprotect the flash\n\r"); pMailbox->status = APPLET_UNPROTECT_FAIL; goto exit; } memoryOffset = pMailbox->argument.inputBufferErase.memoryOffset; if (AT25D_EraseBlock(&at25, memoryOffset)) { pMailbox->status = APPLET_ERASE_FAIL; TRACE_INFO("Block erasing error\n\r"); goto exit; } pMailbox->argument.outputBufferErase.bytesErased = AT25_BlockSize(&at25); TRACE_INFO("Buffer Erase achieved\n\r"); pMailbox->status = APPLET_SUCCESS; } exit: /* Acknowledge the end of command */ TRACE_INFO("\tEnd of applet (command : %lx --- status : %lx)\n\r", pMailbox->command, pMailbox->status); /* Notify the host application of the end of the command processing */ pMailbox->command = ~(pMailbox->command); /* Send ACK character */ if (comType == DBGU_COM_TYPE) { /* Wait for the transmitter to be ready */ while ( (DBGU->DBGU_SR & DBGU_SR_TXEMPTY) == 0 ) ; /* Send character */ DBGU->DBGU_THR= 0x06 ; } return 0; }
int main(int argc, char **argv) { struct _Mailbox *pMailbox = (struct _Mailbox *) argv; const At45Desc *pDesc = 0; uint32_t bytesToWrite, bytesToRead, bufferAddr, memoryOffset, packetSize; /* index on read/write buffer */ uint8_t *pBuffer; /* Temporary buffer used for non block aligned read/write */ uint32_t tempBufferAddr; /* Offset in destination buffer during buffer copy */ uint32_t bufferOffset; /* Configure pins */ PIO_Configure(pins, PIO_LISTSIZE(pins)); if (pMailbox->command == APPLET_CMD_INIT) { /* Save communication link type */ comType = pMailbox->argument.inputInit.comType; #if (DYN_TRACES == 1) dwTraceLevel = pMailbox->argument.inputInit.traceLevel; #endif TRACE_INFO("-- DataFlash AT45 Applet %s --\n\r", SAM_BA_APPLETS_VERSION); TRACE_INFO("-- %s\n\r", BOARD_NAME); TRACE_INFO("-- Compiled: %s %s --\n\r", __DATE__, __TIME__); /* Initialize DMA driver instance with polling mode */ DMAD_Initialize( &dmad, 1 ); /* Initialize the SPI and serial flash */ SPID_Configure(&spid, SPI0, ID_SPI0, &dmad); AT45_Configure(&at45, &spid, SPI_CS, 1); TRACE_INFO("SPI and at45 drivers initialized\n\r"); pMailbox->argument.outputInit.bufferAddress = (uint32_t) &_end ; /* Read the JEDEC ID of the device to identify it */ pDesc = AT45_FindDevice(&at45, AT45D_GetStatus(&at45)); if (!pDesc) { pMailbox->status = APPLET_DEV_UNKNOWN; pMailbox->argument.outputInit.bufferSize = 0; pMailbox->argument.outputInit.memorySize = 0; TRACE_INFO("Device Unknown\n\r"); goto exit; } else { /* Get device parameters */ pMailbox->status = APPLET_SUCCESS; pageSize = AT45_PageSize(&at45); numPages = AT45_PageNumber(&at45); /* Program page */ bufferSize = BUFFER_NB_PAGE * pageSize; pMailbox->argument.outputInit.bufferSize = bufferSize; pMailbox->argument.outputInit.memorySize = numPages * pageSize; TRACE_INFO("%s numPages : 0x%x bufferAddr : 0x%x\n\r", at45.pDesc->name, (unsigned int)numPages, (unsigned int)pMailbox->argument.outputInit.bufferAddress); } } // ---------------------------------------------------------- // WRITE: // ---------------------------------------------------------- else if (pMailbox->command == APPLET_CMD_WRITE) { memoryOffset = pMailbox->argument.inputWrite.memoryOffset; bufferAddr = pMailbox->argument.inputWrite.bufferAddr; bytesToWrite = pMailbox->argument.inputWrite.bufferSize; TRACE_INFO("WRITE at offset: 0x%x buffer at : 0x%x of: 0x%x Bytes\n\r", (unsigned int)memoryOffset, (unsigned int)bufferAddr,(unsigned int) bytesToWrite); pBuffer = (unsigned char *) bufferAddr; tempBufferAddr = bufferAddr + bufferSize; if ((memoryOffset % pageSize) != 0) { /* We are not page aligned, retrieve first page content to update it */ memset((unsigned int *)tempBufferAddr, 0xFF, pageSize); bufferOffset = (memoryOffset % pageSize); if( (bytesToWrite + bufferOffset) < pageSize) { packetSize = bytesToWrite; } else { packetSize = pageSize - bufferOffset; } memoryOffset -= bufferOffset; /* Read page to be updated */ AT45D_Read(&at45, (unsigned char *) tempBufferAddr, pageSize, memoryOffset); /* Fill retrieved page with data to be programmed */ memcpy((unsigned char *)(tempBufferAddr + bufferOffset), pBuffer, packetSize); /* Write the page contents */ AT45D_Write(&at45, (unsigned char *) tempBufferAddr, pageSize, memoryOffset); bytesToWrite -= packetSize; pBuffer += packetSize; memoryOffset += pageSize; } /* If it remains more than one page to write */ while (bytesToWrite >= pageSize) { /* Write the page contents */ AT45D_Write(&at45, pBuffer, pageSize, memoryOffset); pBuffer += pageSize; memoryOffset += pageSize; bytesToWrite -= pageSize; } /* Write remaining data */ if (bytesToWrite > 0) { /* Read previous content of page */ AT45D_Read(&at45, (unsigned char *) tempBufferAddr, pageSize, memoryOffset); /* Fill retrieved block with data to be programmed */ memcpy((unsigned char *)tempBufferAddr, pBuffer, bytesToWrite); /* Write the page contents */ AT45D_Write(&at45, (unsigned char *) tempBufferAddr, pageSize, memoryOffset); /* No more bytes to write */ bytesToWrite = 0; } TRACE_INFO("WRITE return byte written : 0x%x Bytes\n\r", (unsigned int)(pMailbox->argument.inputWrite.bufferSize - bytesToWrite)); pMailbox->argument.outputWrite.bytesWritten = pMailbox->argument.inputWrite.bufferSize - bytesToWrite; pMailbox->status = APPLET_SUCCESS; } // ---------------------------------------------------------- // READ: // ---------------------------------------------------------- else if (pMailbox->command == APPLET_CMD_READ) { memoryOffset = pMailbox->argument.inputRead.memoryOffset; bufferAddr = pMailbox->argument.inputRead.bufferAddr; bytesToRead = pMailbox->argument.inputRead.bufferSize; TRACE_INFO("READ at offset: 0x%x buffer at : 0x%x of: 0x%x Bytes\n\r", (unsigned int)memoryOffset, (unsigned int)bufferAddr, (unsigned int)bytesToRead); pBuffer = (unsigned char *) bufferAddr; /* Read packet after packets */ while (((unsigned int)pBuffer < (bufferAddr + bufferSize)) && (bytesToRead > 0)) { packetSize = min(MAX_COUNT, bytesToRead); AT45D_Read(&at45, pBuffer, packetSize, memoryOffset); pBuffer += packetSize; bytesToRead -= packetSize; memoryOffset += packetSize; } TRACE_INFO("READ return byte read : 0x%x Bytes\n\r", (unsigned int)(pMailbox->argument.inputRead.bufferSize - bytesToRead)); pMailbox->argument.outputRead.bytesRead = pMailbox->argument.inputRead.bufferSize - bytesToRead; pMailbox->status = APPLET_SUCCESS; } // ---------------------------------------------------------- // FULL ERASE: // ---------------------------------------------------------- else if (pMailbox->command == APPLET_CMD_FULL_ERASE) { TRACE_INFO("FULL ERASE command\n\r"); memoryOffset = 0; while (memoryOffset < (pageSize * numPages)) { /* Erase the page */ AT45D_Erase(&at45, memoryOffset); memoryOffset += pageSize; } TRACE_INFO("Full Erase achieved\n\r"); pMailbox->status = APPLET_SUCCESS; } // ---------------------------------------------------------- // BUFFER ERASE: // ---------------------------------------------------------- else if (pMailbox->command == APPLET_CMD_BUFFER_ERASE) { TRACE_INFO("BUFFER ERASE command\n\r"); memoryOffset = pMailbox->argument.inputBufferErase.memoryOffset; while (memoryOffset < (pMailbox->argument.inputBufferErase.memoryOffset + bufferSize)) { /* Erase the page */ AT45D_Erase(&at45, memoryOffset); memoryOffset += pageSize; } TRACE_INFO("Buffer Erase achieved\n\r"); pMailbox->status = APPLET_SUCCESS; } // ---------------------------------------------------------- // CONFIGURE IN BINARY MODE (power of two page size): // ---------------------------------------------------------- else if (pMailbox->command == APPLET_CMD_BINARY_PAGE) { TRACE_INFO("BINARY PAGE SET command\n\r"); /* Configure power-of-2 binary page size. */ AT45D_BinaryPage(&at45); TRACE_INFO("Binary Page achieved\n\r"); pMailbox->status = APPLET_SUCCESS; } exit: /* Acknowledge the end of command */ TRACE_INFO("\tEnd of applet (command : %x --- status : %x)\n\r", (unsigned int)pMailbox->command, (unsigned int)pMailbox->status); /* Notify the host application of the end of the command processing */ pMailbox->command = ~(pMailbox->command); if (comType == DBGU_COM_TYPE) { DBGU_PutChar(0x6); } return 0; }
//------------------------------------------------------------------------------ /// Initializes a Media instance and the associated physical interface /// \param media Pointer to the Media instance to initialize /// \return 1 if success. //------------------------------------------------------------------------------ unsigned char MEDSdusb_Initialize(Media *media, unsigned char mciID) { TRACE_INFO("MEDSdusb init\n\r"); // Initialize SDcard //-------------------------------------------------------------------------- if (!CardIsConnected(mciID)) return 0; // Configure SDcard pins ConfigurePIO(mciID); #if defined(MCI2_INTERFACE) DMAD_Initialize(BOARD_MCI_DMA_CHANNEL, DMAD_NO_DEFAULT_IT); #endif // Initialize the MCI driver if(mciID == 0) { IRQ_ConfigureIT(BOARD_SD_MCI_ID, MCI0_IRQ_PRIORITY, MCI0_IrqHandler); MCI_Init(mciDrv, BOARD_SD_MCI_BASE, BOARD_SD_MCI_ID, BOARD_SD_SLOT, MCI_INTERRUPT_MODE); IRQ_EnableIT(BOARD_SD_MCI_ID); } else { #ifdef BOARD_SD_MCI1_ID IRQ_ConfigureIT(BOARD_SD_MCI1_ID, MCI0_IRQ_PRIORITY, MCI0_IrqHandler); MCI_Init(mciDrv, BOARD_SD_MCI1_BASE, BOARD_SD_MCI1_ID, BOARD_SD_SLOT, MCI_INTERRUPT_MODE); IRQ_EnableIT(BOARD_SD_MCI1_ID); #else TRACE_ERROR("SD/MMC card initialization failed (MCI1 not supported)\n\r"); #endif } #if MCI_BUSY_CHECK_FIX && defined(BOARD_SD_DAT0) MCI_SetBusyFix(mciDrv, &pinSdDAT0); #endif // Initialize the SD card driver if (SD_Init(sdDrv, (SdDriver *)mciDrv)) { TRACE_ERROR("SD/MMC card initialization failed\n\r"); return 0; } else { TRACE_INFO("SD/MMC card initialization successful\n\r"); TRACE_INFO("Card size: %d MB\n\r", (int)(MMC_GetTotalSizeKB(sdDrv)/1024)); } MCI_SetSpeed(mciDrv, sdDrv->transSpeed, sdDrv->transSpeed, BOARD_MCK); // Initialize media fields //-------------------------------------------------------------------------- media->interface = sdDrv; media->write = MEDSdusb_Write; media->read = MEDSdusb_Read; media->lock = 0; media->unlock = 0; media->handler = 0; media->flush = 0; media->blockSize = SD_BLOCK_SIZE; media->baseAddress = 0; media->size = SD_TOTAL_BLOCK(sdDrv); media->mappedRD = 0; media->mappedWR = 0; media->writeProtected = CardIsProtected(mciID); media->removable = 1; media->state = MED_STATE_READY; media->transfer.data = 0; media->transfer.address = 0; media->transfer.length = 0; media->transfer.callback = 0; media->transfer.argument = 0; return 1; }
/** * \brief Applet main entry. This function decodes received command and executes it. * * \param argc always 1 * \param argv Address of the argument area.. */ int main(int argc, char **argv) { struct _Mailbox *pMailbox = (struct _Mailbox *) argv; unsigned int bufferSize, bufferAddr, memoryOffset, bytesToWrite; unsigned int bytesRead = 0; unsigned int nbBadBlocks = 0; unsigned int nbBlocks = 0; /* Temporary buffer used for non block aligned read / write */ unsigned int tempBufferAddr; unsigned short block, page, offset, i; /* Index in source buffer during buffer copy */ unsigned int offsetInSourceBuff; /* Index in destination buffer during buffer copy */ unsigned int offsetInTargetBuff; /* Errors returned by SkipNandFlash functions */ unsigned char error = 0; /* Communication type with SAM-BA GUI. */ unsigned char comType; /* current pmecc parameter header value */ unsigned int currentPmeccHeaderValue; /* Index and value of pmecc command */ unsigned int nIndex, nValue; /* Number of ECC bits required */ unsigned char eccBitReq2TT [5] = {2, 4, 8, 12, 24}; /* Ecc mode to be swtich */ unsigned int eccMode; unsigned int trimPage; /* Save communication link type */ comType = pMailbox->argument.inputInit.comType; /* ---------------------------------------------------------- */ /* INIT: */ /* ---------------------------------------------------------- */ if (pMailbox->command == APPLET_CMD_INIT) { #if (DYN_TRACES == 1) dwTraceLevel = pMailbox->argument.inputInit.traceLevel; #endif TRACE_INFO("-- NandFlash SAM-BA applet %s --\n\r", SAM_BA_APPLETS_VERSION); TRACE_INFO("-- %s\n\r", BOARD_NAME); TRACE_INFO("-- Compiled: %s %s --\n\r", __DATE__, __TIME__); TRACE_INFO("INIT command\n\r"); /* Configure SMC for Nandflash accesses (done each time applet is launched because of old ROM codes) */ BOARD_ConfigureNandFlash(nfBusWidth); PIO_Configure(pPinsNf, PIO_LISTSIZE(pPinsNf)); /* Tries to detect NAND Flash device connected to EBI CS3, with data lines connected to D0-D7, then on NAND Flash connected to D16-D23. */ if (!NandEbiDetect()) { pMailbox->status = APPLET_DEV_UNKNOWN; TRACE_INFO("\tDevice Unknown\n\r"); goto exit; } memset(&skipBlockNf, 0, sizeof(skipBlockNf)); NandGetOnfiPageParam (&OnfiPageParameter); if (SkipBlockNandFlash_Initialize(&skipBlockNf, 0, cmdBytesAddr, addrBytesAddr, dataBytesAddr, nfCePin, nfRbPin)) { pMailbox->status = APPLET_DEV_UNKNOWN; pMailbox->argument.outputInit.bufferSize = 0; pMailbox->argument.outputInit.memorySize = 0; TRACE_INFO("\tDevice Unknown\n\r"); } else { /* Check the data bus width of the NandFlash */ nfBusWidth = NandFlashModel_GetDataBusWidth((struct NandFlashModel *)&skipBlockNf); /* Reconfigure bus width */ if ( nfBusWidth != 8) { SMC->SMC_CS_NUMBER[3].SMC_MODE = SMC_MODE_READ_MODE | SMC_MODE_WRITE_MODE | SMC_MODE_DBW(nfBusWidth/16) | SMC_MODE_TDF_CYCLES(1); } TRACE_INFO("\tNandflash driver initialized\n\r"); pMailbox->argument.outputInit.bufferAddress = (unsigned int) &_end; /* Get device parameters */ memSize = NandFlashModel_GetDeviceSizeInBytes(&skipBlockNf.ecc.raw.model); blockSize = NandFlashModel_GetBlockSizeInBytes(&skipBlockNf.ecc.raw.model); numBlocks = NandFlashModel_GetDeviceSizeInBlocks(&skipBlockNf.ecc.raw.model); pageSize = NandFlashModel_GetPageDataSize(&skipBlockNf.ecc.raw.model); spareSize = NandFlashModel_GetPageSpareSize(&skipBlockNf.ecc.raw.model); numPagesPerBlock = NandFlashModel_GetBlockSizeInPages(&skipBlockNf.ecc.raw.model); pMailbox->status = APPLET_SUCCESS; pMailbox->argument.outputInit.bufferSize = blockSize; pMailbox->argument.outputInit.memorySize = memSize; pMailbox->argument.outputInit.pmeccParamHeader = 0; TRACE_INFO("\tpageSize : 0x%x blockSize : 0x%x blockNb : 0x%x \n\r", pageSize, blockSize, numBlocks); } /* By default, we use pmecc, except MICRON MLC nand with internal ECC controller */ eccOffset = 2; /* By defaut, 2 error bit correction, eccOffset = 2 */ PMECC_Initialize(&pmeccDesc, 0, eccCorrectability, pageSize, spareSize, eccOffset, 0); TRACE_INFO("\tNandflash PMECC initialized\n\r"); DMAD_Initialize( &dmad, POLLING_MODE ); if ( NandFlashConfigureDmaChannels( &dmad )) { pMailbox->status =APPLET_DEV_UNKNOWN; goto exit; } /* Initialize current pmecc parameter header, This 32-bit word is configured below */ currentPmeccHeader.usePmecc = 1; currentPmeccHeader.nbSectorPerPage = pmeccDesc.pageSize >> 8; currentPmeccHeader.spareSize = spareSize; currentPmeccHeader.eccBitReq = pmeccDesc.errBitNbrCapability; currentPmeccHeader.sectorSize = pmeccDesc.sectorSize; currentPmeccHeader.eccOffset = pmeccDesc.eccStartAddr; currentPmeccHeader.reserved = 0; currentPmeccHeader.key = 12; memcpy(&backupPmeccHeader, ¤tPmeccHeader, sizeof(nfParamHeader_t)); memcpy(¤tPmeccHeaderValue, ¤tPmeccHeader, sizeof(nfParamHeader_t)); pMailbox->argument.outputInit.pmeccParamHeader = currentPmeccHeaderValue; /* The Boot Program reads the first page without ECC check, to determine if the NAND parameter header is present. The header is made of 52 times the same 32-bit word (for redundancy reasons) which must contain NAND and PMECC parameters used to correctly perform the read of the rest of the data in the NAND. */ for (i = 0; i< 52; i++) memcpy(&bootNfParamHeader[i], ¤tPmeccHeader, sizeof(nfParamHeader_t)); NandSwitchEcc(ECC_PMECC); pMailbox->status = APPLET_SUCCESS; }
/** * \brief Applet main entry. This function decodes received command and executes it. * * \param argc always 1 * \param argv Address of the argument area.. */ int main(int argc, char **argv) { struct _Mailbox *pMailbox = (struct _Mailbox *) argv; uint32_t bufferSize, bufferAddr, memoryOffset, bytesToWrite; uint16_t pagesToWrite, pagesToRead; uint32_t bytesWritten = 0; uint32_t bytesRead = 0; uint32_t nbBadBlocks = 0; uint32_t nbBlocks = 0; /* Temporary buffer used for non block aligned read / write */ uint32_t tempBufferAddr; uint16_t block, page, offset, i; uint8_t unAlignedPage; /* Index in source buffer during buffer copy */ uint32_t offsetInSourceBuff; /* Index in destination buffer during buffer copy */ uint32_t offsetInTargetBuff; /* Errors returned by SkipNandFlash functions */ uint8_t error = 0; /* Global DMA driver instance for all DMA transfers in application. */ sDmad dmad; /*---------------------------------------------------------- * INIT: *----------------------------------------------------------*/ if (pMailbox->command == APPLET_CMD_INIT) { /* Save info of communication link */ comType = pMailbox->argument.inputInit.comType; /* Re-configurate UART (MCK maybe change in LowLevelInit()) */ UART_Configure(115200, BOARD_MCK); #if (DYN_TRACES == 1) dwTraceLevel = pMailbox->argument.inputInit.traceLevel; #endif TRACE_INFO("-- NandFlash SAM-BA applet %s --\n\r", SAM_BA_APPLETS_VERSION); TRACE_INFO("-- %s\n\r", BOARD_NAME); TRACE_INFO("-- Compiled: %s %s --\n\r", __DATE__, __TIME__); TRACE_INFO("INIT command\n\r"); /* Initialize DMA driver instance with polling mode */ DMAD_Initialize( &dmad, 1 ); if ( NandFlashConfigureDmaChannels( &dmad )) { TRACE_INFO ("-E- Initialize DMA failed !"); } TRACE_INFO ("-I- Initialize DMA done.\n\r"); /* Configure SMC for Nandflash accesses */ BOARD_ConfigureNandFlash(SMC); PIO_PinConfigure(pPinsNf, PIO_LISTSIZE(pPinsNf)); if (pPinsNf->pio == 0) { pMailbox->status = APPLET_NO_DEV; pMailbox->argument.outputInit.bufferSize = 0; pMailbox->argument.outputInit.memorySize = 0; pMailbox->argument.outputInit.bufferAddress = (uint32_t) &end; TRACE_INFO("INIT command: No Nandflash defined for this board\n\r"); } else { memset(&skipBlockNf, 0, sizeof(skipBlockNf)); if (SkipBlockNandFlash_Initialize(&skipBlockNf, 0, cmdBytesAddr, addrBytesAddr, dataBytesAddr, nfCePin, nfRbPin)) { pMailbox->status = APPLET_DEV_UNKNOWN; pMailbox->argument.outputInit.bufferSize = 0; pMailbox->argument.outputInit.memorySize = 0; TRACE_INFO("\tDevice Unknown\n\r"); } else { TRACE_INFO("\tNandflash driver initialized\n\r"); /* Get device parameters */ memSize = NandFlashModel_GetDeviceSizeInBytes(&skipBlockNf.ecc.raw.model); blockSize = NandFlashModel_GetBlockSizeInBytes(&skipBlockNf.ecc.raw.model); numBlocks = NandFlashModel_GetDeviceSizeInBlocks(&skipBlockNf.ecc.raw.model); pageSize = NandFlashModel_GetPageDataSize(&skipBlockNf.ecc.raw.model); numPagesPerBlock = NandFlashModel_GetBlockSizeInPages(&skipBlockNf.ecc.raw.model); latestErasedBlock = 0xFFFF; pMailbox->status = APPLET_SUCCESS; pMailbox->argument.outputInit.bufferAddress = (uint32_t)EBI_SDRAMC_ADDR; pMailbox->argument.outputInit.bufferSize = blockSize; pMailbox->argument.outputInit.memorySize = memSize; TRACE_INFO("\t pageSize : 0x%x blockSize : 0x%x blockNb : 0x%x \n\r", (unsigned int)pageSize, (unsigned int)blockSize, (unsigned int)numBlocks); } } } /*---------------------------------------------------------- * WRITE: *----------------------------------------------------------*/ else if (pMailbox->command == APPLET_CMD_WRITE) { memoryOffset = pMailbox->argument.inputWrite.memoryOffset; bufferAddr = pMailbox->argument.inputWrite.bufferAddr; tempBufferAddr = bufferAddr + blockSize; bytesToWrite = pMailbox->argument.inputWrite.bufferSize; unAlignedPage = 0; TRACE_INFO("WRITE arguments : offset 0x%x, buffer at 0x%x, of 0x%x Bytes\n\r", (unsigned int)memoryOffset, (unsigned int)bufferAddr, (unsigned int)bytesToWrite); pMailbox->argument.outputWrite.bytesWritten = 0; /* Check word alignment */ if (memoryOffset % 4) { pMailbox->status = APPLET_ALIGN_ERROR; goto exit; } /* Retrieve page and block addresses */ if (NandFlashModel_TranslateAccess(&(skipBlockNf.ecc.raw.model), memoryOffset, bytesToWrite, &block, &page, &offset)) { pMailbox->status = APPLET_FAIL; goto exit; } if (block != latestErasedBlock ){ /* Erase target block */ error = SkipBlockNandFlash_EraseBlock(&skipBlockNf, block, NORMAL_ERASE); if (error == NandCommon_ERROR_BADBLOCK) { pMailbox->status = APPLET_BAD_BLOCK; goto exit; } if (error) { pMailbox->status = APPLET_FAIL; goto exit; } latestErasedBlock = block; latestErasedPage = 0xff; } if (page <= ((uint8_t)(latestErasedPage + 1))){ error = SkipBlockNandFlash_EraseBlock(&skipBlockNf, block, NORMAL_ERASE); if (error == NandCommon_ERROR_BADBLOCK) { pMailbox->status = APPLET_BAD_BLOCK; goto exit; } if (error) { pMailbox->status = APPLET_FAIL; goto exit; } latestErasedBlock = block; latestErasedPage = page; } offsetInSourceBuff = 0; TRACE_INFO("WRITE at block 0x%x, page 0x%x, offset 0x%x in page \n\r", (unsigned int)block, (unsigned int)page, (unsigned int)offset); if (offset ) { /* We are not page aligned. */ offsetInTargetBuff = offset; memset((uint32_t *)tempBufferAddr, 0xFF, pageSize); while (offsetInTargetBuff < pageSize) { *(uint32_t *)(tempBufferAddr + offsetInTargetBuff) = *(uint32_t *)(bufferAddr + offsetInSourceBuff); offsetInSourceBuff += 4; offsetInTargetBuff += 4; bytesWritten += 4; } error = SkipBlockNandFlash_WritePage(&skipBlockNf, block, page, ( void *)tempBufferAddr ,0); if (error == NandCommon_ERROR_BADBLOCK) { pMailbox->status = APPLET_BAD_BLOCK; goto exit; } if (error) { pMailbox->status = APPLET_FAIL; goto exit; } unAlignedPage++; } pagesToWrite = (bytesToWrite - bytesWritten) / pageSize; if (bytesToWrite - ((pagesToWrite + unAlignedPage) * pageSize)) { pagesToWrite++; } if ((pagesToWrite + page ) > numPagesPerBlock) { pagesToWrite = numPagesPerBlock - page; } /* Write target block */ error = SkipBlockNandFlash_WriteBlockUnaligned(&skipBlockNf, block, (page + unAlignedPage), pagesToWrite, ( void *)(bufferAddr + offsetInSourceBuff)); bytesWritten += pagesToWrite * pageSize; if (bytesWritten > bytesToWrite) { bytesWritten = bytesToWrite; } if (error == NandCommon_ERROR_BADBLOCK) { pMailbox->status = APPLET_BAD_BLOCK; goto exit; } if (error) { pMailbox->status = APPLET_FAIL; goto exit; } pMailbox->argument.outputWrite.bytesWritten = bytesWritten; pMailbox->status = APPLET_SUCCESS; } /*---------------------------------------------------------- * READ: *----------------------------------------------------------*/ else if (pMailbox->command == APPLET_CMD_READ) { memoryOffset = pMailbox->argument.inputRead.memoryOffset; bufferAddr = pMailbox->argument.inputRead.bufferAddr; tempBufferAddr = bufferAddr + blockSize; bufferSize = pMailbox->argument.inputRead.bufferSize; TRACE_INFO("READ at offset: 0x%x buffer at : 0x%x of: 0x%x Bytes\n\r", (unsigned int)memoryOffset, (unsigned int)bufferAddr, (unsigned int)bufferSize); pMailbox->argument.outputRead.bytesRead = 0; unAlignedPage = 0; /* Check word alignment */ if (memoryOffset % 4) { pMailbox->status = APPLET_ALIGN_ERROR; goto exit; } /* Retrieve page and block addresses */ if (NandFlashModel_TranslateAccess(&(skipBlockNf.ecc.raw.model), memoryOffset, bufferSize, &block, &page, &offset)) { pMailbox->status = APPLET_FAIL; goto exit; } TRACE_INFO("READ at block 0x%x, page 0x%x, offset in page 0x%x\n\r", (unsigned int)block, (unsigned int)page, (unsigned int)offset); offsetInTargetBuff = 0; if (offset) { memset((uint32_t *)tempBufferAddr, 0xFF, pageSize); error = SkipBlockNandFlash_ReadPage(&skipBlockNf, block, page, ( void *)tempBufferAddr ,0); if (error == NandCommon_ERROR_BADBLOCK) { pMailbox->status = APPLET_BAD_BLOCK; goto exit; } if (error) { pMailbox->status = APPLET_FAIL; goto exit; } /* Fill dest buffer with read data */ offsetInSourceBuff = offset; while (offsetInSourceBuff < pageSize) { *(uint32_t *)(bufferAddr + offsetInTargetBuff) = *(uint32_t *)(tempBufferAddr + offsetInSourceBuff); offsetInSourceBuff += 4; offsetInTargetBuff += 4; bytesRead += 4; } unAlignedPage++; } pagesToRead = (bufferSize - bytesRead) / pageSize; if (bufferSize - ((pagesToRead + unAlignedPage)* pageSize)) { pagesToRead++; } if ((pagesToRead + page ) > numPagesPerBlock) { pagesToRead = numPagesPerBlock - page; } /* Read target block */ error = SkipBlockNandFlash_ReadBlockUnaligned(&skipBlockNf, block, (page + unAlignedPage), pagesToRead, ( void *)(bufferAddr + offsetInTargetBuff)); bytesRead += pagesToRead * pageSize; if (bytesRead > bufferSize) { bytesRead = bufferSize; } if (error == NandCommon_ERROR_BADBLOCK) { pMailbox->status = APPLET_BAD_BLOCK; goto exit; } if (error) { pMailbox->status = APPLET_FAIL; goto exit; } pMailbox->argument.outputRead.bytesRead = bytesRead; pMailbox->status = APPLET_SUCCESS; } /*---------------------------------------------------------- * FULL ERASE: *----------------------------------------------------------*/ else if (pMailbox->command == APPLET_CMD_FULL_ERASE) { TRACE_INFO("FULL ERASE command\n\r"); TRACE_INFO("\tForce erase flag: 0x%x\n\r", (unsigned int)pMailbox->argument.inputFullErase.eraseType); for (i = 0; i < numBlocks; i++) { /* Erase the page */ if (SkipBlockNandFlash_EraseBlock(&skipBlockNf, i, pMailbox->argument.inputFullErase.eraseType)) { TRACE_INFO("Found block #%d BAD, skip it\n\r", (unsigned int)i); } } TRACE_INFO("Full Erase achieved\n\r"); pMailbox->status = APPLET_SUCCESS; } /*---------------------------------------------------------- * BATCH FULL ERASE: *----------------------------------------------------------*/ else if (pMailbox->command == APPLET_CMD_BATCH_ERASE) { TRACE_INFO("BATCH ERASE command\n\r"); block = pMailbox->argument.inputBatchErase.batch * (numBlocks / ERASE_BATCH); TRACE_INFO("Erase block from #%d to #%d\n\r", (unsigned int)block, (unsigned int)(block + (numBlocks / ERASE_BATCH))); for (i = block ; i < block + (numBlocks / ERASE_BATCH) ; i++) { /* Erase the block */ if (SkipBlockNandFlash_EraseBlock(&skipBlockNf, i, pMailbox->argument.inputBatchErase.eraseType)) { TRACE_INFO("Found block #%d BAD, skip it\n\r", (unsigned int)i); } } if ((pMailbox->argument.inputBatchErase.batch + 1) == ERASE_BATCH) { TRACE_INFO("Full Erase achieved, erase type is %d\n\r", (unsigned int)pMailbox->argument.inputBatchErase.eraseType); pMailbox->argument.outputBatchErase.nextBatch = 0; } else { pMailbox->argument.outputBatchErase.nextBatch = pMailbox->argument.inputBatchErase.batch + 1; TRACE_INFO("Batch Erase achieved\n\r"); } pMailbox->status = APPLET_SUCCESS; } /*---------------------------------------------------------- * ERASE_BLOCKS: *----------------------------------------------------------*/ else if (pMailbox->command == APPLET_CMD_ERASE_BLOCKS) { TRACE_INFO("BLOCKS ERASE command\n\r"); memoryOffset = pMailbox->argument.inputBlocksErase.memoryOffsetStart; if ((pMailbox->argument.inputBlocksErase.memoryOffsetEnd > memSize) || (pMailbox->argument.inputBlocksErase.memoryOffsetEnd < memoryOffset) ) { TRACE_INFO("Out of memory space\n\r"); pMailbox->status = APPLET_ERASE_FAIL; goto exit; } nbBlocks = ((pMailbox->argument.inputBlocksErase.memoryOffsetEnd- memoryOffset)/ blockSize) + 1; TRACE_INFO("Erase blocks from %d to %d \n\r", (unsigned int)(memoryOffset / blockSize),(unsigned int)((memoryOffset / blockSize)+ nbBlocks) ); /* Erase blocks */ for (i = memoryOffset / blockSize; i < memoryOffset / blockSize + nbBlocks ; i++) { if (SkipBlockNandFlash_EraseBlock(&skipBlockNf, i , NORMAL_ERASE)) { TRACE_INFO("Found block #%d BAD, skip it\n\r", (unsigned int)i); } } TRACE_INFO("Blocks Erase achieved\n\r"); pMailbox->status = APPLET_SUCCESS; } /*---------------------------------------------------------- * LIST BAD BLOCKS: *----------------------------------------------------------*/ else if (pMailbox->command == APPLET_CMD_LIST_BAD_BLOCKS) { TRACE_INFO("LIST BAD BLOCKS command\n\r"); nbBadBlocks = 0; bufferAddr = (uint32_t) &end; pMailbox->argument.outputListBadBlocks.bufferAddress = bufferAddr; for (i = 0; i < numBlocks; i++) { /* Erase the page */ if (SkipBlockNandFlash_CheckBlock(&skipBlockNf, i) == BADBLOCK) { nbBadBlocks++; *((uint32_t *)bufferAddr) = i; bufferAddr += 4; TRACE_INFO("Found block #%d BAD\n\r", i); } } TRACE_INFO("LIST BAD BLOCKS achieved\n\r"); pMailbox->argument.outputListBadBlocks.nbBadBlocks = nbBadBlocks; pMailbox->status = APPLET_SUCCESS; } /*---------------------------------------------------------- * TAG BLOCK: *----------------------------------------------------------*/ else if (pMailbox->command == APPLET_CMD_TAG_BLOCK) { TRACE_INFO("TAG BLOCK command\n\r"); bufferAddr = (uint32_t) &end; block = pMailbox->argument.inputTagBlock.blockId; /* To tag the block as good, just erase it without bad block check */ if ((uint8_t)pMailbox->argument.inputTagBlock.tag == 0xFF) { if (SkipBlockNandFlash_EraseBlock(&skipBlockNf, block, SCRUB_ERASE)) { TRACE_INFO("Cannot erase block %d\n\r", (unsigned int)block); pMailbox->status = APPLET_FAIL; goto exit; } } else { for (i = 0; i < 2; i++) { /* Start by reading the spare */ memset((uint8_t *)bufferAddr, 0xFF, NandCommon_MAXSPAREECCBYTES); TRACE_INFO("Tag to write : 0x%x\n\r", (unsigned int)pMailbox->argument.inputTagBlock.tag); NandSpareScheme_WriteBadBlockMarker((struct NandSpareScheme *)(NandFlashModel_GetScheme((struct NandFlashModel *)(&skipBlockNf))), (uint8_t *)bufferAddr, ((uint8_t)pMailbox->argument.inputTagBlock.tag)); if (RawNandFlash_WritePage((struct RawNandFlash *)(&skipBlockNf), block, i, 0, (uint8_t *)bufferAddr)) { TRACE_ERROR("Failed to write spare data of page %d of block %d\n\r", i, block); pMailbox->status = APPLET_FAIL; goto exit; } } } TRACE_INFO("TAG BLOCK achieved\n\r"); pMailbox->status = APPLET_SUCCESS; } exit : /* Acknowledge the end of command */ TRACE_INFO("\tEnd of applet (command : %x --- status : %x)\n\r", (unsigned int)pMailbox->command, (unsigned int)pMailbox->status); /* Notify the host application of the end of the command processing */ pMailbox->command = ~(pMailbox->command); if (comType == DBGU_COM_TYPE) { UART_PutChar(0x6); } return 0; }