PUBLIC MEMD_ERR_T memd_FlashErase(UINT8 *startFlashAddress, UINT8 *endFlashAddress) { UINT32 status; VOLATILE UINT16 * ptr; VOLATILE UINT16 *BankAddr; UINT32 phy_Start; UINT32 phy_End; UINT32 phys_end_add; UINT32 phys_start_add; MEMD_ERR_T errorcode=MEMD_ERR_NO; BOOL isLocked; UINT16 rdstatus; //hal_HstSendEvent(0x5555); phys_start_add = (UINT32)startFlashAddress; MEMD_ASSERT((phys_start_add & 0xe0000000) == 0, "flash_address is expected to be a byte offset within the flash chip, not an absolute address"); // Check that start & end addresses are aligned if (endFlashAddress == NULL) { memd_FlashGetSectorLimits(phys_start_add, &phy_Start, &phy_End); phys_end_add = phy_End; } else { phys_end_add = (UINT32)endFlashAddress; MEMD_ASSERT((phys_end_add & 0xe0000000) == 0, "flash_address is expected to be a byte offset within the flash chip, not an absolute address") if (phys_end_add != FLASH_SIZE) { memd_FlashGetSectorLimits(phys_end_add , &phy_Start, &phy_End); if (phys_end_add != phy_Start) { return MEMD_ERR_ALIGN; } } } memd_FlashGetSectorLimits(phys_start_add, &phy_Start, &phy_End); if (phys_start_add != phy_Start) { return MEMD_ERR_ALIGN; } hal_EbcFlashWriteEnable(TRUE); BankAddr = NULL; while (phy_Start != phys_end_add) { BankAddr = (VOLATILE UINT16 *)(g_memdFlashBaseAddress + (phy_Start&FLASHBANK_MASK)); // phy_Start should already be aligned to sector boundary, so shouldn't need any more masking ptr = (VOLATILE UINT16 *)(g_memdFlashBaseAddress + phy_Start); memd_FlashGetLockStatus((UINT8*)((UINT32)ptr & MY_MASK),&isLocked); // Re-enable EBC write hal_EbcFlashWriteEnable(TRUE); if(isLocked == TRUE) { memd_BlockLock((UINT8*)((UINT32)ptr & MY_MASK),NULL,FALSE); // while(1){;}; } status = hal_SysEnterCriticalSection(); // Sector Erase command *(BankAddr) = CMD_BLOCK_ERASE_1; *(ptr) = CMD_BLOCK_ERASE_2; hal_SysExitCriticalSection(status); // pooling // Wait for Ready, then check status do{ rdstatus = *BankAddr; }while((rdstatus & SR7) != SR7); // Any address in the bank may be used // Should probably fix this scheme for reporting errors more cleanly. // For now, just prioritize the errors with the most significant error returned // in errorcode (order this list from least to most significant) if ((rdstatus & SR3) != 0) { while(1){;}; // Vpp Invalid Error errorcode=MEMD_ERR_ERASE; } else if (((rdstatus & SR5) != 0) && ((rdstatus & SR4) != 0)) { // Command Sequence Error errorcode=MEMD_ERR_ERASE; while(1){;}; } else if ((rdstatus & SR5) != 0) { // Erase Error errorcode=MEMD_ERR_ERASE; while(1){;}; } else if ((rdstatus & SR1) != 0) { errorcode=MEMD_ERR_PROTECT; while(1){;}; } // Reset to read array mode when every block erase operation is finished. status = hal_SysEnterCriticalSection(); *BankAddr = CMD_READ_ARRAY; hal_SysExitCriticalSection(status); // Clear status register if any error if(errorcode != MEMD_ERR_NO) { while(1){;}; status = hal_SysEnterCriticalSection(); *BankAddr = CMD_CLR_STATUS_REG; hal_SysExitCriticalSection(status); hal_EbcFlashWriteEnable(FALSE); return errorcode; } if (phy_End != FLASH_SIZE) { memd_FlashGetSectorLimits(phy_End, &phy_Start, &phy_End); } else { phy_Start = phy_End; } } if (BankAddr != NULL) { // Return to Read Array mode status = hal_SysEnterCriticalSection(); *BankAddr = CMD_READ_ARRAY; hal_SysExitCriticalSection(status); } // erase done hal_EbcFlashWriteEnable(FALSE); return errorcode; }
// ============================================================================= // memd_FlashWrite // ----------------------------------------------------------------------------- /// This function writes data in the flash. It gets its data from \c buffer, copies /// \c byteSize bytes to the flash location designed by \c flashAddress. \c /// pWrittenbyteSize is filled with the actual number of written bytes (Equal /// to size, or less in case of error). /// /// @param flashAddress The byte offset within the flash chip. (Take care not /// to overwrite the code present at the beginning of the flash) /// @param byteSize Number of bytes to write in flash /// @param pWrittenbyteSize Number of bytes actually written in flash /// @param buffer Buffer where to get the data to write in the flash /// @return #MEMD_ERR_NO, #MEMD_ERR_WRITE or #MEMD_ERR_PROTECT /// whether the operation succeeded or failed. // ============================================================================= PUBLIC MEMD_ERR_T memd_FlashWrite(UINT8 *flashAddress, UINT32 byteSize, UINT32 * pWrittenbyteSize, CONST UINT8* buffer) { VOLATILE UINT16 * BankAddr; VOLATILE UINT16 * ptr; UINT16 data; UINT32 bsize=0; UINT32 wsize=0; UINT32 owsize=0; MEMD_ERR_T errorcode=MEMD_ERR_NO; UINT32 status; UINT32 phys_add; UINT32 phy_SectAddr; UINT32 phy_End; BOOL isLocked; UINT16 rdstatus; *pWrittenbyteSize=0; if (byteSize==0) { return MEMD_ERR_NO; } hal_EbcFlashWriteEnable(TRUE); phys_add = (UINT32)flashAddress; MEMD_ASSERT((phys_add & 0xe0000000) == 0, "flash_address is expected to be a byte offset within the flash chip, not an absolute address") memd_FlashGetSectorLimits((UINT32)flashAddress, &phy_SectAddr, &phy_End); BankAddr = (VOLATILE UINT16 *)(g_memdFlashBaseAddress + (phys_add&FLASHBANK_MASK)); ptr = (VOLATILE UINT16 *)(g_memdFlashBaseAddress + (phys_add&~1)); // Unlock block memd_FlashGetLockStatus((UINT8*)((UINT32)phy_SectAddr & MY_MASK),&isLocked); hal_EbcFlashWriteEnable(TRUE); if(isLocked == TRUE) memd_BlockLock((UINT8*)((UINT32)phy_SectAddr & MY_MASK),NULL,FALSE); if ((phys_add&1) == 1) { data = *(ptr); } else { data = (*buffer) | ~0x00ff; buffer ++; bsize ++; } if (bsize<byteSize) { data = data & (((*buffer) << 8) | 0x00ff); buffer ++; bsize ++; } if (bsize==byteSize) { // last byte data = data & *(ptr); } // first byte is prepared /* 16b data ready write it to flash*/ status = hal_SysEnterCriticalSection(); *(BankAddr) = CMD_PROG; *(ptr)=data; hal_SysExitCriticalSection(status); while(bsize<byteSize) { UINT16 tdata; VOLATILE UINT16 * tptr; // do the next data preparation before the pooling so we are ready to do a new programming just after pooling is OK. tdata = data; tptr = ptr; owsize = wsize; wsize = bsize; ptr+=1; if (bsize<byteSize) { data = (*buffer) | ~0x00ff; buffer ++; bsize ++; } if(bsize<byteSize) { data = data & (((*buffer) << 8) | 0x00ff); buffer ++; bsize ++; } // pooling // do{ rdstatus = *BankAddr; }while((rdstatus & SR7) != SR7); // Should probably fix this scheme for reporting errors more cleanly. // For now, just prioritize the errors with the most significant error returned // in errorcode (order this list from least to most significant) if ((rdstatus & SR4) != 0) { // Some other programming error, should be decoded, but maybe do it later errorcode=MEMD_ERR_WRITE; } else if ((rdstatus & SR1) != 0) { errorcode=MEMD_ERR_PROTECT; } if (errorcode!=MEMD_ERR_NO) break; if(bsize==byteSize) { /* last byte */ *BankAddr = CMD_READ_ARRAY; data = data & *(ptr); } /* 16b data ready write it to flash*/ status = hal_SysEnterCriticalSection(); *(BankAddr) = CMD_PROG; *(ptr)=data; hal_SysExitCriticalSection(status); } if (errorcode!=MEMD_ERR_NO) { wsize = owsize; } else { // last data pooling do{ rdstatus = *BankAddr; }while((rdstatus & SR7) != SR7); if ((rdstatus & SR4) != 0) { // Some other programming error, should be decoded, but maybe do it later errorcode=MEMD_ERR_WRITE; } else if ((rdstatus & SR1) != 0) { errorcode=MEMD_ERR_PROTECT; } wsize = bsize; } *pWrittenbyteSize = wsize; // return to Read Array mode status = hal_SysEnterCriticalSection(); *BankAddr = CMD_READ_ARRAY; hal_SysExitCriticalSection(status); if(errorcode != MEMD_ERR_NO) { status = hal_SysEnterCriticalSection(); *BankAddr = CMD_CLR_STATUS_REG; hal_SysExitCriticalSection(status); } hal_EbcFlashWriteEnable(FALSE); return errorcode; }
// ============================================================================= // memd_BlockLock // ----------------------------------------------------------------------------- /// This Locks or Unlocks a block (sector) or range of blocks. /// Flash Write Enable must already be set. /// /// @param phy_startFlshAddr Start address of the block in flash to start /// locking. This must be aligned on a block. /// @param phy_endFlshAddr End address of the block in flash to stop locking /// (inclusive). This must also be aligned on a block. If this parameter is /// NULL, then only one block (starting at phy_startFlshAddr) will be locked. /// @return MEMD_ERR_T error type (alignment errors only) // ============================================================================= PRIVATE MEMD_ERR_T memd_BlockLock(UINT8 *phy_startFlshAddr, UINT8 *phy_endFlshAddr, BOOL Lock) { UINT32 phy_Start; UINT32 phy_End; UINT32 status; VOLATILE UINT16 * CurBankAddr; VOLATILE UINT16 * PrevBankAddr; // Check that start & end addresses are aligned if (phy_endFlshAddr == NULL) { memd_FlashGetSectorLimits((UINT32)phy_startFlshAddr, &phy_Start, &phy_End); phy_endFlshAddr = (UINT8*)phy_End; } else { if ((UINT32)phy_endFlshAddr != FLASH_SIZE) { memd_FlashGetSectorLimits((UINT32)phy_endFlshAddr , &phy_Start, &phy_End); if ((UINT32)phy_endFlshAddr != phy_Start) { return MEMD_ERR_ALIGN; } } } memd_FlashGetSectorLimits((UINT32)phy_startFlshAddr, &phy_Start, &phy_End); if ((UINT32)phy_startFlshAddr != phy_Start) { return MEMD_ERR_ALIGN; } PrevBankAddr = (VOLATILE UINT16 *)(g_memdFlashBaseAddress + (phy_Start&FLASHBANK_MASK)); while (phy_Start != (UINT32)phy_endFlshAddr) { VOLATILE UINT16 * SectAddr; SectAddr = (VOLATILE UINT16 *)(g_memdFlashBaseAddress + phy_Start); CurBankAddr = (VOLATILE UINT16 *)(g_memdFlashBaseAddress + (phy_Start&FLASHBANK_MASK)); status = hal_SysEnterCriticalSection(); // If Bank Address is the same as previous Bank Address, continue // otherwise, need to put old Bank into Read Array mode and // open new Bank. if (CurBankAddr != PrevBankAddr) { // Close Prev Bank *PrevBankAddr = CMD_READ_ARRAY; PrevBankAddr = CurBankAddr; } // Lock Set/Clr if (Lock) { *SectAddr = CMD_BLOCK_PROT; *SectAddr = CMD_BLOCK_LOCK; } else { *SectAddr = CMD_BLOCK_PROT; *SectAddr = CMD_BLOCK_UNLOCK; } hal_SysExitCriticalSection(status); if (phy_End != FLASH_SIZE) { memd_FlashGetSectorLimits(phy_End, &phy_Start, &phy_End); } else { phy_Start = phy_End; } } // Return to Read Array mode status = hal_SysEnterCriticalSection(); *PrevBankAddr = CMD_READ_ARRAY; hal_SysExitCriticalSection(status); return MEMD_ERR_NO; }
// ============================================================================= // memd_FlashWrite // ----------------------------------------------------------------------------- /// This function writes data in the flash. It gets its data from \c buffer, copies /// \c byteSize bytes to the flash location designed by \c flashAddress. \c /// pWrittenbyteSize is filled with the actual number of written bytes (Equal /// to size, or less in case of error). /// /// @param flashAddress The byte offset within the flash chip. (Take care not /// to overwrite the code present at the beginning of the flash) /// @param byteSize Number of bytes to write in flash /// @param pWrittenbyteSize Number of bytes actually written in flash /// @param buffer Buffer where to get the data to write in the flash /// @return #MEMD_ERR_NO, #MEMD_ERR_WRITE or #MEMD_ERR_PROTECT /// whether the operation succeeded or failed. // ============================================================================= PUBLIC MEMD_ERR_T memd_FlashWrite(UINT8 *flashAddress, UINT32 byteSize, UINT32 * pWrittenbyteSize, CONST UINT8* buffer) { VOLATILE UINT16 * BankAddr; VOLATILE UINT16 * ptr; UINT16 rdstatus, data; UINT32 bsize=0, wsize=0, owsize=0; MEMD_ERR_T errorcode=MEMD_ERR_NO; UINT32 status; UINT32 phys_add; //SXS_TRACE(TSTDOUT,"hal_flash: Flash Write 0x%08x, %d\n", flash_address, bytesize); *pWrittenbyteSize=0; if (byteSize==0) { return MEMD_ERR_NO; } hal_EbcFlashWriteEnable(TRUE); phys_add = (UINT32)flashAddress; MEMD_ASSERT((phys_add & 0xe0000000) == 0, "flash_address is expected to be a byte offset within the flash chip, not an absolute adresse") if (GET_PAGE_PHYS(phys_add) <= 2) { BankAddr = (VOLATILE UINT16 *)(g_memdFlashBaseAddress + (phys_add&FLASHBANK_MASK)); // Start should already be aligned to sector boundary, so shouldn't need any more masking ptr = (VOLATILE UINT16 *)(g_memdFlashBaseAddress + (phys_add&~1)); } else // Page > 2, so remap { // Bank Address needs to be shifted from its current range to between 0x00C0_0000 - 0x00FF_FFFF BankAddr = (VOLATILE UINT16 *)((g_memdFlashBaseAddress + (phys_add&FLASHBANK_MASK)) - ((GET_PAGE_PHYS(phys_add)-3)*0x400000)); ptr = (VOLATILE UINT16 *)((g_memdFlashBaseAddress + (phys_add&~1)) - ((GET_PAGE_PHYS(phys_add)-3)*0x400000)); // Configure Page Register hal_EbcConfigRemap((HAL_EBC_FLSH_PHYSADD_T)phys_add); } //SXS_TRACE(TSTDOUT,"hal_flash: BankAddr 0x%08x \n", BankAddr); if (!g_memdLockOverride) { if (memd_LockCheck(BankAddr, (UINT16*)ptr)) { hal_EbcFlashWriteEnable(FALSE); return MEMD_ERR_PROTECT; } } // Unlock Bypass Entry status = hal_SysEnterCriticalSection(); *(BankAddr+0x555) = 0xaa; *(BankAddr+0x2aa) = 0x55; *(BankAddr+0x555) = 0x20; hal_SysExitCriticalSection(status); //SXS_TRACE(TSTDOUT,"hal_flash: unlock\n"); if ((phys_add&1) == 1) { data = *(ptr); } else { data = (*buffer) | ~0x00ff; buffer ++; bsize ++; } if (bsize<byteSize) { data = data & (((*buffer) << 8) | 0x00ff); buffer ++; bsize ++; } if (bsize==byteSize) { // last byte data = data & *(ptr); } // first byte is prepared /* 16b data ready write it to flash*/ status = hal_SysEnterCriticalSection(); *(BankAddr) = 0xa0; *(ptr)=data; hal_SysExitCriticalSection(status); while(bsize<byteSize) { UINT16 tdata; VOLATILE UINT16 * tptr; // do the next data preparation before the pooling so we are ready to do a new programming just after pooling is OK. tdata = data; tptr = ptr; owsize = wsize; wsize = bsize; ptr+=1; if (bsize<byteSize) { data = (*buffer) | ~0x00ff; buffer ++; bsize ++; } if(bsize<byteSize) { data = data & (((*buffer) << 8) | 0x00ff); buffer ++; bsize ++; } // pooling while(1) { rdstatus = (*tptr); // DQ7 = prog value ? ok done if (((rdstatus ^ tdata) & 0x80) == 0) break; // DQ5 = 1 if ((rdstatus & 0x20) == 0x20) { rdstatus = (*tptr); // DQ7 = prog value ? ok done if (((rdstatus ^ tdata) & 0x80) == 0) break; errorcode=MEMD_ERR_WRITE; break; } } if (errorcode!=MEMD_ERR_NO) break; if(bsize==byteSize) { /* last byte */ data = data & *(ptr); } /* 16b data ready write it to flash*/ status = hal_SysEnterCriticalSection(); *(BankAddr) = 0xa0; *(ptr)=data; hal_SysExitCriticalSection(status); } if (errorcode!=MEMD_ERR_NO) { wsize = owsize; } else { // last data pooling while(1) { rdstatus = (*ptr); // DQ7 = prog value ? ok done if (((rdstatus ^ data) & 0x80) == 0) break; // DQ5 = 1 if ((rdstatus & 0x20) == 0x20) { rdstatus = (*ptr); // DQ7 = prog value ? ok done if (((rdstatus ^ data) & 0x80) == 0) break; errorcode=MEMD_ERR_WRITE; break; } } wsize = bsize; } *pWrittenbyteSize = wsize; // Unlock Bypass Exit status = hal_SysEnterCriticalSection(); *(BankAddr) = 0x90; *(BankAddr) = 0x00; hal_SysExitCriticalSection(status); hal_EbcFlashWriteEnable(FALSE); return errorcode; }
// ============================================================================ // hal_EbcCsOpen // ---------------------------------------------------------------------------- /// Enable a CS other than the one for FLASH. The chip selects for /// FLASH have been set before by calling #hal_EbcFlashOpen. /// The enabling of a CS returns the base address of the configured space. /// The settings are given at the opening of the peripheral on the given /// chip select, and must support the external maximal clock as it has been /// set by the configuring of the CS0 (Flash) chip select. /// /// @param cs Chip Select to Enable. (HAL_EBC_SRAM and CS2 or above) /// @param csConfig Configuration for the chip select. The \c csEn enable bit /// of the mode configuration must be set to 1 there if the chip select /// of the opened peripheral have to be enabled ! /// @return Base address of the configured space // ============================================================================ PUBLIC VOID* HAL_BOOT_FUNC hal_EbcCsOpen(HAL_EBC_CS_T cs, CONST HAL_EBC_CS_CFG_T* csConfig) { union { UINT32 reg; HAL_EBC_TIME_CFG_T bitfield; } timeCfgUnion; // union representing the status bitfield in a 32 bits value // loadable in the register union { UINT32 reg; HAL_EBC_MODE_CFG_T bitfield; } modeCfgUnion; // union representing the status bitfield in a 32 bits value // loadable in the register VOID* retval = NULL; //ENTER CRITICAL UINT32 status = hal_SysEnterCriticalSection(); timeCfgUnion.bitfield = csConfig->time; modeCfgUnion.bitfield = csConfig->mode; // Wait if the lock is locked hal_EbcWaitReady(); switch(cs) { case HAL_EBC_FLASH : EBC_ASSERT(FALSE, "Improper use of the hal_EbcCsOpen function." "It cannot be used to open CS0 ! Use hal_EbcFlashOpen" " to do that."); break; case HAL_EBC_SRAM : // Write the pointer into the table //g_halEbcCsConfigArray[1] = csConfig; hwp_memBridge->CS_Time_Write = timeCfgUnion.reg; hwp_memBridge->CS_Config[1].CS_Mode = modeCfgUnion.reg; // Save the config in the Boot Sector structure, so that // it can be used by the Boot Sector code to configure the // EBC CS RAM mode and timings, it is especially useful // in burst mode. hal_BootSectorSetEbcConfig(timeCfgUnion.reg, modeCfgUnion.reg); retval = (VOID*)hwp_cs1; break; case HAL_EBC_CS2 : // Write the pointer into the table //g_halEbcCsConfigArray[2] = csConfig; hwp_memBridge->CS_Time_Write = timeCfgUnion.reg; hwp_memBridge->CS_Config[2].CS_Mode = modeCfgUnion.reg; retval = (VOID*)hwp_cs2; break; case HAL_EBC_CS3 : //g_halEbcCsConfigArray[3] = csConfig; hwp_memBridge->CS_Time_Write = timeCfgUnion.reg; hwp_memBridge->CS_Config[3].CS_Mode = modeCfgUnion.reg; retval = (VOID*)hwp_cs3; break; case HAL_EBC_CS4: //g_halEbcCsConfigArray[4] = csConfig; hwp_memBridge->CS_Time_Write = timeCfgUnion.reg; hwp_memBridge->CS_Config[4].CS_Mode = modeCfgUnion.reg; retval = (VOID*)hwp_cs4; break; default: break; } //EXIT CRITICAL hal_SysExitCriticalSection(status); return retval; }
// ============================================================================= // memd_FlashErase // ----------------------------------------------------------------------------- /// This function erases contiguous flash sectors. /// Addresses <B> must be aligned on sectors</B>: /// - The \c startFlashAddress is the address of the first sector to erase. /// - The \c endFlashAddress is the address of the first sector NOT to erase. /// If \c endFlashAddress is \c NULL, only one sector will be erased. /// . /// Care must be taken not to erase the code present at the beginning of the flash. /// /// @param start_flashAddress The address of the first sector to erase /// @param end_flashAddress The address of the first sector NOT to erase. /// If \c NULL, only one sector will be erased /// @return #MEMD_ERR_NO, #MEMD_ERR_ERASE, #MEMD_ERR_ALIGN or #MEMD_ERR_PROTECT /// whether the operation succeeded or failed /// // ============================================================================= PUBLIC MEMD_ERR_T memd_FlashErase(UINT8 *startFlashAddress, UINT8 *endFlashAddress) { UINT8 rdstatus, rdstatus_old; UINT32 status; VOLATILE UINT8 * ptr; VOLATILE UINT16 *BankAddr; UINT32 Start, End; UINT32 phys_end_add, phys_start_add; phys_start_add = (UINT32)startFlashAddress; MEMD_ASSERT((phys_start_add & 0xe0000000) == 0, "flash_address is expected to be a byte offset within the flash chip, not an absolute adresse"); // Check that start & end addresses are aligned if (endFlashAddress == NULL) { memd_FlashGetSectorLimits(phys_start_add, &Start, &End); phys_end_add = End; } else { phys_end_add = (UINT32)endFlashAddress; MEMD_ASSERT((phys_end_add & 0xe0000000) == 0, "flash_address is expected to be a byte offset within the flash chip, not an absolute adresse") if (phys_end_add != FLASH_SIZE) { memd_FlashGetSectorLimits(phys_end_add , &Start, &End); if (phys_end_add != Start) { return MEMD_ERR_ALIGN; } } } memd_FlashGetSectorLimits(phys_start_add, &Start, &End); if (phys_start_add != Start) { return MEMD_ERR_ALIGN; } hal_EbcFlashWriteEnable(TRUE); while (Start != phys_end_add) { if (GET_PAGE_PHYS(Start) <= 2) { BankAddr = (VOLATILE UINT16 *)(g_memdFlashBaseAddress + (Start&FLASHBANK_MASK)); // Start should already be aligned to sector boundary, so shouldn't need any more masking ptr = (VOLATILE UINT8 *)(g_memdFlashBaseAddress + Start); } else // Page > 2, so remap { // Bank Address needs to be shifted from its current range to between 0x00C0_0000 - 0x00FF_FFFF BankAddr = (VOLATILE UINT16 *)((g_memdFlashBaseAddress + (Start&FLASHBANK_MASK)) - ((GET_PAGE_PHYS(Start)-3)*0x400000)); ptr = (VOLATILE UINT8 *)((g_memdFlashBaseAddress + Start) - ((GET_PAGE_PHYS(Start)-3)*0x400000)); // Configure Page Register hal_EbcConfigRemap((HAL_EBC_FLSH_PHYSADD_T)Start); } //SXS_TRACE(TSTDOUT,"hal_flash: erase BankAddr 0x%08x, Page %d \n", BankAddr, GET_PAGE_PHYS(Start)); //SXS_TRACE(TSTDOUT,"hal_flash: erase ptr 0x%08x \n", ptr); if (!g_memdLockOverride) { if (memd_LockCheck(BankAddr, (UINT16*)ptr)) { hal_EbcFlashWriteEnable(FALSE); return MEMD_ERR_PROTECT; } } status = hal_SysEnterCriticalSection(); // Sector Erase command *(BankAddr+0x555) = 0xaa; *(BankAddr+0x2aa) = 0x55; *(BankAddr+0x555) = 0x80; *(BankAddr+0x555) = 0xaa; *(BankAddr+0x2aa) = 0x55; *(ptr) = 0x30; hal_SysExitCriticalSection(status); // note the pooling could be done on data == 0xff also // pooling rdstatus = (*ptr); while(1){ rdstatus_old = rdstatus; rdstatus = (*ptr); // DQ6 & DQ2 not toggling? => done if (((rdstatus ^ rdstatus_old) & 0x44) == 0) break; // DQ5 = 1 if ((rdstatus & 0x20) == 0x20) { rdstatus_old = (*ptr); rdstatus = (*ptr); // DQ6 & DQ2 not toggling? => done if (((rdstatus ^ rdstatus_old) & 0x44) == 0) break; // reset (*BankAddr) = 0xf0; hal_EbcFlashWriteEnable(FALSE); return MEMD_ERR_ERASE; } } if (End != FLASH_SIZE) { memd_FlashGetSectorLimits(End, &Start, &End); } else { Start = End; } } // erase done hal_EbcFlashWriteEnable(FALSE); return MEMD_ERR_NO; }
// ============================================================================= // memd_FlashWrite // ----------------------------------------------------------------------------- /// This function writes data in the flash. It gets its data from \c buffer, copies /// \c byteSize bytes to the flash location designed by \c flashAddress. \c /// pWrittenbyteSize is filled with the actual number of written bytes (Equal /// to size, or less in case of error). /// /// @param flashAddress The byte offset within the flash chip. (Take care not /// to overwrite the code present at the beginning of the flash) /// @param byteSize Number of bytes to write in flash /// @param pWrittenbyteSize Number of bytes actually written in flash /// @param buffer Buffer where to get the data to write in the flash /// @return #MEMD_ERR_NO, #MEMD_ERR_WRITE or #MEMD_ERR_PROTECT /// whether the operation succeeded or failed. // ============================================================================= PUBLIC MEMD_ERR_T memd_FlashWrite(UINT8 *flashAddress, UINT32 byteSize, UINT32 * pWrittenbyteSize, CONST UINT8* buffer) { VOLATILE UINT16 * flashaddr; VOLATILE UINT16 * ptr; UINT16 rdstatus, data; UINT32 bsize=0, wsize=0, owsize=0; MEMD_ERR_T errorcode=MEMD_ERR_NO; UINT32 status; UINT32 phys_add; *pWrittenbyteSize=0; if (byteSize==0) { return MEMD_ERR_NO; } hal_EbcFlashWriteEnable(TRUE); phys_add = (UINT32)flashAddress; hal_HstSendEvent(0x555500); hal_HstSendEvent(phys_add); MEMD_ASSERT((phys_add & 0xe0000000) == 0, "flash_address is expected to be a byte offset within the flash chip, not an absolute adresse") flashaddr = (VOLATILE UINT16 *)(g_memdFlashBaseAddress + (phys_add&FLASHBANK_MASK)); if (!g_memdDybOverride) { ptr = (VOLATILE UINT16 *)(g_memdFlashBaseAddress + (phys_add&~0xfff)); if (memd_DYBCheck(flashaddr, (UINT16*)ptr)) { hal_EbcFlashWriteEnable(FALSE); return MEMD_ERR_PROTECT; } } ptr = (VOLATILE UINT16 *)(g_memdFlashBaseAddress + (phys_add&~1)); // Unlock Bypass Entry status = hal_SysEnterCriticalSection(); *(flashaddr+0x555) = 0xaa; *(flashaddr+0x2aa) = 0x55; *(flashaddr+0x555) = 0x20; hal_SysExitCriticalSection(status); if ((phys_add&1) == 1) { data = *(ptr); } else { data = (*buffer) | ~0x00ff; buffer ++; bsize ++; } if (bsize<byteSize) { data = data & (((*buffer) << 8) | 0x00ff); buffer ++; bsize ++; } if (bsize==byteSize) { // last byte data = data & *(ptr); } // first byte is prepared /* 16b data ready write it to flash*/ status = hal_SysEnterCriticalSection(); *(flashaddr) = 0xa0; *(ptr)=data; hal_SysExitCriticalSection(status); while(bsize<byteSize) { UINT16 tdata; VOLATILE UINT16 * tptr; // do the next data preparation before the pooling so we are ready to do a new programming just after pooling is OK. tdata = data; tptr = ptr; owsize = wsize; wsize = bsize; ptr+=1; if (bsize<byteSize) { data = (*buffer) | ~0x00ff; buffer ++; bsize ++; } if(bsize<byteSize) { data = data & (((*buffer) << 8) | 0x00ff); buffer ++; bsize ++; } // pooling while(1) { rdstatus = (*tptr); // DQ7 = prog value ? ok done if (((rdstatus ^ tdata) & 0x80) == 0) break; // DQ5 = 1 if ((rdstatus & 0x20) == 0x20) { rdstatus = (*tptr); // DQ7 = prog value ? ok done if (((rdstatus ^ tdata) & 0x80) == 0) break; errorcode=MEMD_ERR_WRITE; break; } } if (errorcode!=MEMD_ERR_NO) break; if(bsize==byteSize) { /* last byte */ data = data & *(ptr); } /* 16b data ready write it to flash*/ status = hal_SysEnterCriticalSection(); *(flashaddr) = 0xa0; *(ptr)=data; hal_SysExitCriticalSection(status); } if (errorcode!=MEMD_ERR_NO) { wsize = owsize; } else { // last data pooling while(1) { rdstatus = (*ptr); // DQ7 = prog value ? ok done if (((rdstatus ^ data) & 0x80) == 0) break; // DQ5 = 1 if ((rdstatus & 0x20) == 0x20) { rdstatus = (*ptr); // DQ7 = prog value ? ok done if (((rdstatus ^ data) & 0x80) == 0) break; errorcode=MEMD_ERR_WRITE; break; } } wsize = bsize; } *pWrittenbyteSize = wsize; // Unlock Bypass Exit status = hal_SysEnterCriticalSection(); *(flashaddr) = 0x90; *(flashaddr) = 0x00; hal_SysExitCriticalSection(status); hal_EbcFlashWriteEnable(FALSE); hal_HstSendEvent(0x555504); return errorcode; }
// ============================================================================= // memd_FlashErase // ----------------------------------------------------------------------------- /// This function erases contiguous flash sectors. /// Addresses <B> must be aligned on sectors</B>: /// - The \c startFlashAddress is the address of the first sector to erase. /// - The \c endFlashAddress is the address of the first sector NOT to erase. /// If \c endFlashAddress is \c NULL, only one sector will be erased. /// . /// Care must be taken not to erase the code present at the beginning of the flash. /// /// @param start_flashAddress The address of the first sector to erase /// @param end_flashAddress The address of the first sector NOT to erase. /// If \c NULL, only one sector will be erased /// @return #MEMD_ERR_NO, #MEMD_ERR_ERASE, #MEMD_ERR_ALIGN or #MEMD_ERR_PROTECT /// whether the operation succeeded or failed /// // ============================================================================= PUBLIC MEMD_ERR_T memd_FlashErase(UINT8 *startFlashAddress, UINT8 *endFlashAddress) { UINT8 rdstatus, rdstatus_old; UINT32 status; VOLATILE UINT8 * ptr; VOLATILE UINT16 *flashaddr; UINT32 Start, End; UINT32 phys_end_add, phys_start_add; phys_start_add = (UINT32)startFlashAddress; MEMD_ASSERT((phys_start_add & 0xe0000000) == 0, "flash_address is expected to be a byte offset within the flash chip, not an absolute adresse"); hal_HstSendEvent(0x654300); hal_HstSendEvent(phys_start_add); hal_HstSendEvent(0x654301); // Check that start & end addresses are aligned if (endFlashAddress == NULL) { memd_FlashGetSectorLimits(phys_start_add, &Start, &End); phys_end_add = End; } else { phys_end_add = (UINT32)endFlashAddress; MEMD_ASSERT((phys_end_add & 0xe0000000) == 0, "flash_address is expected to be a byte offset within the flash chip, not an absolute adresse") if (phys_end_add != FLASH_SIZE) { memd_FlashGetSectorLimits(phys_end_add , &Start, &End); if (phys_end_add != Start) { return MEMD_ERR_ALIGN; } } } memd_FlashGetSectorLimits(phys_start_add, &Start, &End); if (phys_start_add != Start) { return MEMD_ERR_ALIGN; } hal_HstSendEvent(0x654311); hal_EbcFlashWriteEnable(TRUE); while (Start != phys_end_add) { flashaddr = (VOLATILE UINT16 *)(g_memdFlashBaseAddress + (Start&FLASHBANK_MASK)); ptr = (VOLATILE UINT8 *)(g_memdFlashBaseAddress + (Start&~0xfff)); if (!g_memdDybOverride) { if (memd_DYBCheck(flashaddr, (UINT16*)ptr)) { hal_EbcFlashWriteEnable(FALSE);hal_HstSendEvent(0x654314); return MEMD_ERR_PROTECT; } } status = hal_SysEnterCriticalSection(); // Sector Erase command *(flashaddr+0x555) = 0xaa; *(flashaddr+0x2aa) = 0x55; *(flashaddr+0x555) = 0x80; *(flashaddr+0x555) = 0xaa; *(flashaddr+0x2aa) = 0x55; *(ptr) = 0x30; hal_SysExitCriticalSection(status); // note the pooling could be done on data == 0xff also // pooling rdstatus = (*ptr); while(1){ rdstatus_old = rdstatus; rdstatus = (*ptr); // DQ6 & DQ2 not toggling? => done if (((rdstatus ^ rdstatus_old) & 0x44) == 0) break; // DQ5 = 1 if ((rdstatus & 0x20) == 0x20) { rdstatus_old = (*ptr); rdstatus = (*ptr); // DQ6 & DQ2 not toggling? => done if (((rdstatus ^ rdstatus_old) & 0x44) == 0) break; // reset (*flashaddr) = 0xf0; hal_EbcFlashWriteEnable(FALSE);hal_HstSendEvent(0x654312); return MEMD_ERR_ERASE; } } if (End != FLASH_SIZE) { memd_FlashGetSectorLimits(End, &Start, &End); } else { Start = End; } } // erase done hal_EbcFlashWriteEnable(FALSE); hal_HstSendEvent(0x654399); return MEMD_ERR_NO; }
PUBLIC MEMD_ERR_T memd_FlashErase_Continue(UINT8 *startFlashAddress, UINT8 *endFlashAddress,UINT32 time) { UINT8 rdstatus, rdstatus_old; UINT32 status; VOLATILE UINT8 * ptr; VOLATILE UINT16 *flashaddr; UINT32 Start, End; UINT32 phys_end_add, phys_start_add; UINT32 suspend_time = 0,max_time = 0; max_time = time MILLI_SECONDS; UINT32 now = hal_TimGetUpTime(); phys_start_add = (UINT32)startFlashAddress; MEMD_ASSERT((phys_start_add & 0xe0000000) == 0, "flash_address is expected to be a byte offset within the flash chip, not an absolute adresse"); // Check that start & end addresses are aligned if (endFlashAddress == NULL) { memd_FlashGetSectorLimits(phys_start_add, &Start, &End); phys_end_add = End; } else { phys_end_add = (UINT32)endFlashAddress; MEMD_ASSERT((phys_end_add & 0xe0000000) == 0, "flash_address is expected to be a byte offset within the flash chip, not an absolute adresse") if (phys_end_add != FLASH_SIZE) { memd_FlashGetSectorLimits(phys_end_add , &Start, &End); if (phys_end_add != Start) { return MEMD_ERR_ALIGN; } } } memd_FlashGetSectorLimits(phys_start_add, &Start, &End); if (phys_start_add != Start) { return MEMD_ERR_ALIGN; } hal_EbcFlashWriteEnable(TRUE); while (Start != phys_end_add) { flashaddr = (VOLATILE UINT16 *)(g_memdFlashBaseAddress + (Start&FLASHBANK_MASK)); ptr = (VOLATILE UINT8 *)(g_memdFlashBaseAddress + (Start&~0xfff)); if (!g_memdDybOverride) { if (memd_DYBCheck(flashaddr, (UINT16*)ptr)) { hal_EbcFlashWriteEnable(FALSE);hal_HstSendEvent(0x654314); return MEMD_ERR_PROTECT; } } status = hal_SysEnterCriticalSection(); *(ptr) = 0x30; hal_SysExitCriticalSection(status); // note the pooling could be done on data == 0xff also // pooling rdstatus = (*ptr); while(1){ suspend_time = hal_TimGetUpTime(); if (suspend_time - now > max_time) { status = hal_SysEnterCriticalSection(); *(ptr) = 0xb0; hal_SysExitCriticalSection(status); do { rdstatus_old = (*ptr); rdstatus = (*ptr); rdstatus_old &= 0x80; rdstatus &= 0x80; }while (!(rdstatus_old == 0x80 && rdstatus == 0x80)); // Wait for suspend active (*flashaddr) = 0xf0; hal_EbcFlashWriteEnable(FALSE); return MEMD_ERR_SUSPEND; } rdstatus_old = rdstatus; rdstatus = (*ptr); // DQ6 & DQ2 not toggling? => done if (((rdstatus ^ rdstatus_old) & 0x44) == 0) break; // DQ5 = 1 if ((rdstatus & 0x20) == 0x20) { rdstatus_old = (*ptr); rdstatus = (*ptr); // DQ6 & DQ2 not toggling? => done if (((rdstatus ^ rdstatus_old) & 0x44) == 0) break; // reset (*flashaddr) = 0xf0; hal_EbcFlashWriteEnable(FALSE);hal_HstSendEvent(0x654312); return MEMD_ERR_ERASE; } } if (End != FLASH_SIZE) { memd_FlashGetSectorLimits(End, &Start, &End); } else { Start = End; } } // erase done hal_EbcFlashWriteEnable(FALSE); hal_HstSendEvent(0x653333); return MEMD_ERR_NO; }
// ============================================================================= // hal_DmaStopStd // ----------------------------------------------------------------------------- /// Stop a standard transfer in progress. If the remaining size to transfer is /// less than the defined threshold, that function waits for the end of the /// transfert. This behaviour is expected by both the FCS and GEA transfert, /// as those transfers are blocking functions. /// /// It has previously been tested that the transfer is currently a standard one. /// @param xferState Pointer where the state of the transfer will be stored /// for a later resume. // ============================================================================= PRIVATE VOID hal_DmaStopStd(HAL_DMA_CFG_T* xferState) { UINT32 status; UINT32 remainingSize = 0; status = hal_SysEnterCriticalSection(); remainingSize = hwp_dma->xfer_size; if (remainingSize > HAL_DMA_PREEMPT_THSLD) { // Preempt - stop hwp_dma->control |= DMA_STOP_TRANSFER; // Wait for the end while (!hal_DmaDone()); // Really needed ? if (hwp_dma->xfer_size == 0) { // the transfer has finished // If an IT was programmed, it will be triggered // once we go out of critical section. hal_SysExitCriticalSection(status); // Remaining size is used by the calling function to // know if there is a transfer to resume. xferState->transferSize = 0; } else { // Stopping the transfer has triggered the IT // We must clear IT as this IRQ is meant to // happen once the stopped transfer is fully // completed (ie NOT now) // --> Done automatically by clearing the command // register xferState->srcAddr =(CONST UINT8*) hwp_dma->src_addr; xferState->dstAddr = (UINT8*) hwp_dma->dst_addr; xferState->alterDstAddr = (UINT8*) hwp_dma->sd_dst_addr; xferState->pattern = hwp_dma->pattern; xferState->transferSize =(UINT16) hwp_dma->xfer_size; xferState->mode = g_halDmaMode; xferState->userHandler = g_halDmaRegistry; g_halDmaRegistry = NULL; hwp_dma->control = 0; //clear it and prog of the stopped transfer hal_SysExitCriticalSection(status); } } else { // Too few bytes to transfer, we wait hal_SysExitCriticalSection(status); // Remaining size is used by the calling function to // know if there is a transfer to resume. xferState->transferSize = 0; // Fill other fields for coherency ? xferState->srcAddr = (CONST UINT8*)0; xferState->dstAddr = (UINT8*)0; xferState->alterDstAddr = (UINT8*)0; xferState->pattern = 0; xferState->mode = 0; xferState->userHandler = NULL; while (!hal_DmaDone()); } g_halDmaUserId = HAL_DMA_NONE; }