/* mbed Microcontroller Library ******************************************************************************* * Copyright (c) 2014, Realtek Semiconductor Corp. * All rights reserved. * * This module is a confidential and proprietary property of RealTek and * possession or use of this module requires written permission of RealTek. ******************************************************************************* */ #include "objects.h" #include "PinNames.h" #include "pinmap.h" #include "rtl8195a.h" #include "hal_spi_flash.h" #include "hal_platform.h" #include "rtl8195a_spi_flash.h" #include "hal_api.h" #include "flash_api.h" extern u32 ConfigDebugInfo; extern SPIC_INIT_PARA SpicInitParaAllClk[3][CPU_CLK_TYPE_NO]; _LONG_CALL_ extern VOID SpicWaitBusyDoneRtl8195A(VOID); static int isinit = 0; static flash_t flashobj; static void flash_init(flash_t * obj); static void flash_turnon(void); /** * global data structure */ //flash_t flash; /** * @brief Control the flash chip write protect enable/disable * @param protect: 1/0: protect/unprotect * @retval none */ void flash_write_protect(flash_t *obj, uint32_t protect) { flash_turnon(); if(isinit == 0) flash_init(&flashobj); SpicWriteProtectFlashRtl8195A(protect); SpicDisableRtl8195A(); } /** * @brief Init Flash * @param obj: address of the flash object * @retval none */ void flash_init(flash_t *obj) { //SPIC_INIT_PARA spic_init_para; // Init SPI Flash Controller // DBG_8195A("Initial Spi Flash Controller\n"); //SPI_FLASH_PIN_FCTRL(ON); if (!SpicFlashInitRtl8195A(SpicOneBitMode)){ DBG_8195A("SPI Init Fail!!!!!!\n"); HAL_WRITE32(SYSTEM_CTRL_BASE, REG_SYS_DSTBY_INFO3, HAL_READ32(SYSTEM_CTRL_BASE, REG_SYS_DSTBY_INFO3)|0xf); } else { isinit = 1; } flashobj.SpicInitPara.flashtype = SpicInitParaAllClk[0][0].flashtype; //DBG_8195A("Flash ID is = %x %x %x \n",SpicInitParaAllClk[0][0].id[0],SpicInitParaAllClk[0][0].id[1],SpicInitParaAllClk[0][0].id[2]); } /** * @brief Get flash ID (command: 0x9F). * @param obj: Flash object define in application software. * @param buf: Pointer to a byte array to save the readback ID. * @param len: Specifies the length of the buf. It should be 3. * @retval -1: Fail. */ int flash_read_id(flash_t *obj, uint8_t *buf, uint8_t len) { int index = 0; flash_turnon(); if(isinit == 0) flash_init(&flashobj); if (len < 3) { DBG_8195A("ID length should be >= 3\n"); return -1; } SpicReadIDRtl8195A(); for (index = 0; index < 3; index++) { buf[index] = SpicInitParaAllClk[0][0].id[index]; } if ((buf[0] == 0x0) || (buf[0] == 0xFF)) { DBG_8195A("Invalid ID\n"); return -1; } len = 3; return len; } /** * @brief This function is only for Winbond flash to get unique ID (command: 0x4B). * @param obj: Flash object define in application software. * @param buf: Pointer to a byte array to save the readback unique ID. * @param len: Specifies the length of the buf. It should be 8. * @retval -1: Fail. */ int flash_read_unique_id(flash_t *obj, uint8_t *buf, uint8_t len) { int index = 0; flash_turnon(); if(isinit == 0) flash_init(&flashobj); if (len < 8) { DBG_8195A("Unique ID length should be >= 8.\n"); return -1; } if (FLASH_WINBOND != flashobj.SpicInitPara.flashtype) { DBG_8195A("Only Winbond flash supports this function.\n"); return -1; } SpicReadUniqueIDRtl8195A(buf, len); //for (index = 0; index < len; index++) { //DBG_8195A("buf[%d] = %x\n",index,buf[index]); //} len = 8; return len; } void flash_turnon(void) { SPI_FLASH_PIN_FCTRL(ON); SpicWaitBusyDoneRtl8195A(); } /** * @brief Erase flash sector * @param address: Specifies the starting address to be erased. * @retval none */ void flash_erase_sector(flash_t *obj, uint32_t address) { flash_turnon(); if(isinit == 0) flash_init(&flashobj); SpicSectorEraseFlashRtl8195A(SPI_FLASH_BASE + address); SpicDisableRtl8195A(); } void flash_erase_block(flash_t *obj, uint32_t address) { flash_turnon(); if(isinit == 0) flash_init(&flashobj); SpicBlockEraseFlashRtl8195A(SPI_FLASH_BASE + address); SpicDisableRtl8195A(); } /** * @brief Read a word from specified address * @param obj: Specifies the parameter of flash object. * @param address: Specifies the address to be read. * @param data: Specified the address to save the readback data. * @retval status: Success:1 or Failure: Others. */ int flash_read_word(flash_t *obj, uint32_t address, uint32_t * data) { flash_turnon(); if(isinit == 0) flash_init(&flashobj); // Wait flash busy done (wip=0) SpicWaitWipDoneRefinedRtl8195A(flashobj.SpicInitPara); * data = HAL_READ32(SPI_FLASH_BASE, address); SpicDisableRtl8195A(); return 1; } /** * @brief Write a word to specified address * @param obj: Specifies the parameter of flash object. * @param address: Specifies the address to be programmed. * @param data: Specified the data to be programmed. * @retval status: Success:1 or Failure: Others. */ int flash_write_word(flash_t *obj, uint32_t address, uint32_t data) { u8 flashtype = 0; flash_turnon(); if(isinit == 0) flash_init(&flashobj); flashtype = flashobj.SpicInitPara.flashtype; //Write word HAL_WRITE32(SPI_FLASH_BASE, address, data); // Wait spic busy done SpicWaitBusyDoneRtl8195A(); // Wait flash busy done (wip=0) if(flashtype == FLASH_MICRON){ SpicWaitOperationDoneRtl8195A(flashobj.SpicInitPara); } else SpicWaitWipDoneRefinedRtl8195A(flashobj.SpicInitPara); SpicDisableRtl8195A(); return 1; } /** * @brief Read a stream of data from specified address * @param obj: Specifies the parameter of flash object. * @param address: Specifies the address to be read. * @param len: Specifies the length of the data to read. * @param data: Specified the address to save the readback data. * @retval status: Success:1 or Failure: Others. */ int flash_stream_read(flash_t *obj, uint32_t address, uint32_t len, uint8_t * data) { u32 offset_to_align; u32 i; u32 read_word; uint8_t *ptr; uint8_t *pbuf; flash_turnon(); if(isinit == 0) flash_init(&flashobj); // Wait flash busy done (wip=0) SpicWaitWipDoneRefinedRtl8195A(flashobj.SpicInitPara); offset_to_align = address & 0x03; pbuf = data; if (offset_to_align != 0) { // the start address is not 4-bytes aligned read_word = HAL_READ32(SPI_FLASH_BASE, (address - offset_to_align)); ptr = (uint8_t*)&read_word + offset_to_align; offset_to_align = 4 - offset_to_align; for (i=0;i> 2) + 1) << 2; // address = next 4-bytes aligned ptr = (uint8_t*)&read_word; if ((u32)pbuf & 0x03) { while (len >= 4) { read_word = HAL_READ32(SPI_FLASH_BASE, address); for (i=0;i<4;i++) { *pbuf = *(ptr+i); pbuf++; } address += 4; len -= 4; } } else { while (len >= 4) { *((u32 *)pbuf) = HAL_READ32(SPI_FLASH_BASE, address); pbuf += 4; address += 4; len -= 4; } } if (len > 0) { read_word = HAL_READ32(SPI_FLASH_BASE, address); for (i=0;i> 2) + 1) << 2; // address = next 4-bytes aligned if ((u32)pbuf & 0x03) { while (len >= 4) { write_word = (u32)(*pbuf) | ((u32)(*(pbuf+1)) << 8) | ((u32)(*(pbuf+2)) << 16) | ((u32)(*(pbuf+3)) << 24); //Write word HAL_WRITE32(SPI_FLASH_BASE, address, write_word); // Wait spic busy done SpicWaitBusyDoneRtl8195A(); // Wait flash busy done (wip=0) if(flashtype == FLASH_MICRON){ SpicWaitOperationDoneRtl8195A(flashobj.SpicInitPara); } else SpicWaitWipDoneRefinedRtl8195A(flashobj.SpicInitPara); pbuf += 4; address += 4; len -= 4; } } else { while (len >= 4) { //Write word HAL_WRITE32(SPI_FLASH_BASE, address, (u32)*((u32 *)pbuf)); // Wait spic busy done SpicWaitBusyDoneRtl8195A(); // Wait flash busy done (wip=0) if(flashtype == FLASH_MICRON){ SpicWaitOperationDoneRtl8195A(flashobj.SpicInitPara); } else SpicWaitWipDoneRefinedRtl8195A(flashobj.SpicInitPara); pbuf += 4; address += 4; len -= 4; } } if (len > 0) { write_word = HAL_READ32(SPI_FLASH_BASE, address); ptr = (uint8_t*)&write_word; for (i=0;i= PageSize) ||((Length + OccuSize) >= PageSize)) ProgramSize = PageSize - OccuSize; else ProgramSize = Length; flashobj.Length = Length; while(Length > 0){ if(OccuSize){ SpicUserProgramRtl8195A(data, flashobj.SpicInitPara, address, &(flashobj.Length)); // Wait spic busy done SpicWaitBusyDoneRtl8195A(); // Wait flash busy done (wip=0) if(flashtype == FLASH_MICRON){ SpicWaitOperationDoneRtl8195A(flashobj.SpicInitPara); } else SpicWaitWipDoneRefinedRtl8195A(flashobj.SpicInitPara); address += ProgramSize; data+= ProgramSize; Length -= ProgramSize; OccuSize = 0; } else{ while((flashobj.Length) >= PageSize){ SpicUserProgramRtl8195A(data, flashobj.SpicInitPara, address, &(flashobj.Length)); // Wait spic busy done SpicWaitBusyDoneRtl8195A(); // Wait flash busy done (wip=0) if(flashtype == FLASH_MICRON){ SpicWaitOperationDoneRtl8195A(flashobj.SpicInitPara); } else SpicWaitWipDoneRefinedRtl8195A(flashobj.SpicInitPara); address += PageSize; data+=PageSize; Length -= PageSize; } flashobj.Length = Length; if((flashobj.Length) > 0){ SpicUserProgramRtl8195A(data, flashobj.SpicInitPara, address, &(flashobj.Length)); // Wait spic busy done SpicWaitBusyDoneRtl8195A(); // Wait flash busy done (wip=0) if(flashtype == FLASH_MICRON){ SpicWaitOperationDoneRtl8195A(flashobj.SpicInitPara); } else SpicWaitWipDoneRefinedRtl8195A(flashobj.SpicInitPara); break; } } flashobj.Length = Length; } SpicDisableRtl8195A(); return 1; } /** * @brief Read a stream of data from specified address * @param obj: Specifies the parameter of flash object. * @param address: Specifies the address to be read. * @param len: Specifies the length of the data to read. * @param data: Specified the address to save the readback data. * @retval status: Success:1 or Failure: Others. */ int flash_burst_read(flash_t *obj, uint32_t address, uint32_t Length, uint8_t * data) { flash_turnon(); if(isinit == 0) flash_init(&flashobj); // Wait flash busy done (wip=0) SpicWaitWipDoneRefinedRtl8195A(flashobj.SpicInitPara); SpicUserReadRtl8195A(Length, address, data,SpicOneBitMode); SpicDisableRtl8195A(); return 1; } int flash_get_status(flash_t *obj) { u8 Status = 0; flash_turnon(); if(isinit == 0) flash_init(&flashobj); Status = SpicGetFlashStatusRefinedRtl8195A(flashobj.SpicInitPara); SpicDisableRtl8195A(); return Status; } /* Function Description: Please refer to the datatsheet of flash for more details of the content of status register. The block protected area and the corresponding control bits are provided in the flash datasheet. * @brief Set Status register to enable desired operation * @param obj: Specifies the parameter of flash object. * @param data: Specifies which bit users like to set ex: if users want to set the third bit, data = 0x8. */ int flash_set_status(flash_t *obj, uint32_t data) { flash_turnon(); if(isinit == 0) flash_init(&flashobj); SpicSetFlashStatusRefinedRtl8195A(data, flashobj.SpicInitPara); SpicWaitWipDoneRefinedRtl8195A(flashobj.SpicInitPara); DBG_8195A("Status Register After Setting= %x\n", flash_get_status(&flashobj)); SpicDisableRtl8195A(); return 1; } /* Function Description: This function aims to reset the status register, please make sure the operation is appropriate. */ void flash_reset_status(flash_t *obj) { flash_turnon(); if(isinit == 0) flash_init(&flashobj); SpicSetFlashStatusRefinedRtl8195A(0, flashobj.SpicInitPara); SpicWaitWipDoneRefinedRtl8195A(flashobj.SpicInitPara); SpicDisableRtl8195A(); } /* Function Description: This function is only for Micron 512Mbit flash to access beyond 128Mbit by switching between four 128 Mbit area. Please refer to flash datasheet for more information about memory mapping. */ int flash_set_extend_addr(flash_t *obj, uint32_t data) { flash_turnon(); if(isinit == 0) flash_init(&flashobj); SpicSetExtendAddrRtl8195A(data, flashobj.SpicInitPara); SpicWaitWipDoneRefinedRtl8195A(flashobj.SpicInitPara); DBG_8195A("Extended Address Register After Setting= %x\n", flash_get_extend_addr(&flashobj)); SpicDisableRtl8195A(); return 1; } int flash_get_extend_addr(flash_t *obj) { u8 Status = 0; flash_turnon(); if(isinit == 0) flash_init(&flashobj); Status = SpicGetExtendAddrRtl8195A(flashobj.SpicInitPara); SpicDisableRtl8195A(); return Status; } /*********************************************************************************** The following functions are compatile with Winbond flash only. But not all Winbond flash supports these functions, plase refer to data sheets of the target flashes. ************************************************************************************/ /* 0: Set status register 1 to enble write protect feature 1: Enable individual sector / block protect feature */ void flash_set_lock_mode(uint32_t mode) { flash_turnon(); if(isinit == 0) flash_init(&flashobj); SpicSetLockModeRtl8195A(mode); SpicDisableRtl8195A(); } /*Lock whole flash chip*/ void flash_global_lock(void) { flash_turnon(); if(isinit == 0) flash_init(&flashobj); SpicLockFlashRtl8195A(); SpicDisableRtl8195A(); } /*Unlock whole flash chip*/ void flash_global_unlock(void) { flash_turnon(); if(isinit == 0) flash_init(&flashobj); SpicUnlockFlashRtl8195A(); SpicDisableRtl8195A(); } /*Lock individual sector or block region, should refer to the datasheet for more details*/ void flash_individual_lock(uint32_t address) { flash_turnon(); if(isinit == 0) flash_init(&flashobj); SpicSingleLockRtl8195A(address); SpicDisableRtl8195A(); } /*Unlock individual sector or block region, should refer to the datasheet for more details*/ void flash_individual_unlock(uint32_t address) { flash_turnon(); if(isinit == 0) flash_init(&flashobj); SpicSingleUnlockRtl8195A(address); SpicDisableRtl8195A(); } /* 1: the target sector/block is locked 0: the target sector/block is not locked */ int flash_read_individual_lock_state(uint32_t address) { flash_turnon(); int state = 0; if(isinit == 0) flash_init(&flashobj); state = SpicReadLockStateRtl8195A(address); SpicDisableRtl8195A(); return state; }