/* * (C) Copyright 2017 Fuzhou Rockchip Electronics Co., Ltd * Seth Liu 2017.03.01 * * SPDX-License-Identifier: GPL-2.0+ */ #include "RKDevice.h" const char* szManufName[] = { "SAMSUNG", "TOSHIBA", "HYNIX", "INFINEON", "MICRON", "RENESAS", "ST", "INTEL" }; void CRKDevice::SetVendorID(USHORT value) { m_vid = value; } void CRKDevice::SetProductID(USHORT value) { m_pid = value; } void CRKDevice::SetDeviceType(ENUM_RKDEVICE_TYPE value) { m_device = value; } void CRKDevice::SetOsType(ENUM_OS_TYPE value) { m_os = value; } void CRKDevice::SetUsbType(ENUM_RKUSB_TYPE value) { m_usb = value; } void CRKDevice::SetBcdUsb(USHORT value) { m_bcdUsb = value; } void CRKDevice::SetLayerName(char *value) { strcpy(m_layerName,value); } void CRKDevice::SetLocationID(DWORD value) { m_locationID = value; } void CRKDevice::SetCallBackPointer(ProgressPromptCB value) { if (value) { m_callBackProc = value; } } CRKLog* CRKDevice::GetLogObjectPointer() { return m_pLog; } CRKComm* CRKDevice::GetCommObjectPointer() { return m_pComm; } USHORT CRKDevice::GetVendorID() { return m_vid; } USHORT CRKDevice::GetProductID() { return m_pid; } ENUM_RKDEVICE_TYPE CRKDevice::GetDeviceType() { return m_device; } ENUM_OS_TYPE CRKDevice::GetOsType() { return m_os; } ENUM_RKUSB_TYPE CRKDevice::GetUsbType() { return m_usb; } USHORT CRKDevice::GetBcdUsb() { return m_bcdUsb; } DWORD CRKDevice::GetLocationID() { return m_locationID; } char* CRKDevice::GetLayerName() { return m_layerName; } string CRKDevice::GetLayerString(DWORD dwLocationID) { char szLocation[32] = "\0"; sprintf(szLocation, "%d-%d", dwLocationID >> 8, dwLocationID & 0xff); return szLocation; } CRKDevice::CRKDevice(STRUCT_RKDEVICE_DESC &device) { VendorID.setContainer(this); VendorID.getter(&CRKDevice::GetVendorID); VendorID.setter(&CRKDevice::SetVendorID); ProductID.setContainer(this); ProductID.getter(&CRKDevice::GetProductID); ProductID.setter(&CRKDevice::SetProductID); DeviceType.setContainer(this); DeviceType.getter(&CRKDevice::GetDeviceType); DeviceType.setter(&CRKDevice::SetDeviceType); UsbType.setContainer(this); UsbType.getter(&CRKDevice::GetUsbType); UsbType.setter(&CRKDevice::SetUsbType); LayerName.setContainer(this); LayerName.getter(&CRKDevice::GetLayerName); LayerName.setter(&CRKDevice::SetLayerName); BcdUsb.setContainer(this); BcdUsb.getter(&CRKDevice::GetBcdUsb); BcdUsb.setter(&CRKDevice::SetBcdUsb); LocationID.setContainer(this); LocationID.getter(&CRKDevice::GetLocationID); LocationID.setter(&CRKDevice::SetLocationID); OsType.setContainer(this); OsType.getter(&CRKDevice::GetOsType); OsType.setter(&CRKDevice::SetOsType); LogObjectPointer.setContainer(this); LogObjectPointer.getter(&CRKDevice::GetLogObjectPointer); CommObjectPointer.setContainer(this); CommObjectPointer.getter(&CRKDevice::GetCommObjectPointer); CallBackPointer.setContainer(this); CallBackPointer.setter(&CRKDevice::SetCallBackPointer); m_vid = device.usVid; m_pid = device.usPid; m_usb = device.emUsbType; m_device = device.emDeviceType; m_bcdUsb = device.usbcdUsb; m_locationID = device.uiLocationID; strcpy(m_layerName, GetLayerString(m_locationID).c_str()); memset(m_flashInfo.blockState, 0, IDBLOCK_TOP); m_flashInfo.usPhyBlokcPerIDB = 1; m_flashInfo.uiSecNumPerIDB = 0; m_callBackProc = NULL; m_chipData = NULL; m_pImage = NULL; m_pLog = NULL; m_pComm = NULL; m_pFlashInfoData = NULL; m_usFlashInfoDataLen = 0; m_usFlashInfoDataOffset = 0; m_bEmmc = false; } CRKDevice::~CRKDevice() { if (m_pComm) { delete m_pComm; m_pComm = NULL; } if (m_chipData) { delete []m_chipData; m_chipData = NULL; } if (m_pFlashInfoData) { delete []m_pFlashInfoData; m_pFlashInfoData = NULL; } } bool CRKDevice::SetObject(CRKImage *pImage, CRKComm *pComm, CRKLog *pLog) { if (!pComm) { return false; } m_pImage = pImage; m_pComm = pComm; m_pLog = pLog; if (m_pImage) { m_os = m_pImage->OsType; } else m_os = RK_OS; return true; } int CRKDevice::EraseEmmcBlock(UCHAR ucFlashCS, DWORD dwPos, DWORD dwCount) { int sectorOffset,nWrittenBlcok,iRet; BYTE emptyData[4 * (SECTOR_SIZE+SPARE_SIZE)]; memset(emptyData, 0xff, 4 * (SECTOR_SIZE + SPARE_SIZE)); nWrittenBlcok = 0; while (dwCount > 0) { sectorOffset = (ucFlashCS * m_flashInfo.uiBlockNum + dwPos + nWrittenBlcok) * m_flashInfo.uiSectorPerBlock; iRet = m_pComm->RKU_WriteSector(sectorOffset, 4, emptyData); if ((iRet != ERR_SUCCESS) && (iRet != ERR_FOUND_BAD_BLOCK)) { if (m_pLog) { m_pLog->Record(" ERROR:EraseEmmcBlock-->RKU_WriteSector failed, RetCode(%d)", m_layerName, iRet); } return iRet; } dwCount--; nWrittenBlcok++; } return ERR_SUCCESS; } int CRKDevice::EraseEmmcByWriteLBA(DWORD dwSectorPos, DWORD dwCount) { int nWritten,iRet; BYTE emptyData[32 * SECTOR_SIZE]; memset(emptyData, 0xff, 32 * SECTOR_SIZE); while (dwCount > 0) { nWritten = (dwCount < 32) ? dwCount : 32; iRet = m_pComm->RKU_WriteLBA(dwSectorPos, nWritten, emptyData); if (iRet != ERR_SUCCESS) { if (m_pLog) { m_pLog->Record(" ERROR:EraseEmmcByWriteLBA-->RKU_WriteLBA failed, RetCode(%d)", m_layerName, iRet); } return iRet; } dwCount -= nWritten; dwSectorPos += nWritten; } return ERR_SUCCESS; } bool CRKDevice::EraseEmmc() { UINT uiCount, uiEraseCount, uiSectorOffset; int iRet = ERR_SUCCESS, iLoopTimes = 0; uiCount = m_flashInfo.uiFlashSize; DWORD dwLayerID; dwLayerID = m_locationID; ENUM_CALL_STEP emCallStep = CALL_FIRST; uiEraseCount = 4; while (uiEraseCount < uiCount) { uiSectorOffset = uiEraseCount * 2048; if (uiEraseCount>8) { iRet = EraseEmmcByWriteLBA(uiSectorOffset, 32); } else iRet = EraseEmmcByWriteLBA(uiSectorOffset, 2048); if (iRet != ERR_SUCCESS) { if (m_pLog) { m_pLog->Record(" ERROR:EraseEmmc-->EraseEmmcByWriteLBA failed, RetCode(%d)", m_layerName, iRet); } return false; } uiEraseCount++; iLoopTimes++; if (iLoopTimes%8 == 0) { if (m_callBackProc) { m_callBackProc(dwLayerID, ERASEFLASH_PROGRESS, uiCount, uiEraseCount, emCallStep); emCallStep = CALL_MIDDLE; } } } if (m_callBackProc) { emCallStep = CALL_LAST; m_callBackProc(dwLayerID, ERASEFLASH_PROGRESS, uiCount, uiCount, emCallStep); } return true; } bool CRKDevice::GetFlashInfo() { STRUCT_FLASHINFO_CMD info; BYTE flashID[5]; int iRet; UINT uiRead; iRet = m_pComm->RKU_ReadFlashInfo((PBYTE)&info, &uiRead); if( ERR_SUCCESS == iRet ) { if ((info.usBlockSize == 0) || (info.bPageSize == 0)) { if (m_pLog) { m_pLog->Record(" ERROR:GetFlashInfo-->RKU_ReadFlashInfo failed,pagesize or blocksize is zero", m_layerName); } return false; } if (info.bManufCode <= 7) { strcpy(m_flashInfo.szManufacturerName, szManufName[info.bManufCode]); } else { strcpy(m_flashInfo.szManufacturerName, "UNKNOWN"); } m_flashInfo.uiFlashSize = info.uiFlashSize / 2 / 1024; m_flashInfo.uiPageSize = info.bPageSize / 2; m_flashInfo.usBlockSize = info.usBlockSize / 2; m_flashInfo.bECCBits = info.bECCBits; m_flashInfo.bAccessTime = info.bAccessTime; m_flashInfo.uiBlockNum = m_flashInfo.uiFlashSize * 1024 / m_flashInfo.usBlockSize; m_flashInfo.uiSectorPerBlock = info.usBlockSize; m_flashInfo.bFlashCS = info.bFlashCS; m_flashInfo.usValidSecPerBlock = (info.usBlockSize / info.bPageSize) * 4; if (m_pFlashInfoData) { delete []m_pFlashInfoData; m_pFlashInfoData = NULL; } m_usFlashInfoDataLen = BYTE2SECTOR(uiRead); m_pFlashInfoData = new BYTE[SECTOR_SIZE * m_usFlashInfoDataLen]; memset(m_pFlashInfoData, 0, SECTOR_SIZE * m_usFlashInfoDataLen); memcpy(m_pFlashInfoData, (PBYTE)&info, uiRead); if (m_pLog) { string strFlashInfo; m_pLog->PrintBuffer(strFlashInfo, m_pFlashInfoData, 11); m_pLog->Record(" INFO:FlashInfo:%s", m_layerName, strFlashInfo.c_str()); } } else { if (m_pLog) { m_pLog->Record(" ERROR:GetFlashInfo-->RKU_ReadFlashInfo failed, RetCode(%d)", m_layerName, iRet); } return false; } iRet = m_pComm->RKU_ReadFlashID(flashID); if( ERR_SUCCESS == iRet ) { DWORD *pID = (DWORD *)flashID; if (*pID==0x434d4d45)/*emmc*/ { m_bEmmc = true; } else m_bEmmc = false; } else { if (m_pLog) { m_pLog->Record(" ERROR:GetFlashInfo-->RKU_ReadFlashID failed, RetCode(%d)", m_layerName, iRet); } return false; } return true; } bool CRKDevice::TestDevice() { int iResult, iTryCount; DWORD dwTotal, dwCurrent, dwLayerID; dwLayerID = m_locationID; ENUM_CALL_STEP emCallStep = CALL_FIRST; do { iTryCount = 3; while (iTryCount > 0) { iResult = m_pComm->RKU_TestDeviceReady(&dwTotal, &dwCurrent); if ((iResult == ERR_SUCCESS) || (iResult == ERR_DEVICE_UNREADY)) { break; } if (m_pLog) { m_pLog->Record(" ERROR:TestDevice-->RKU_TestDeviceReady failed, RetCode(%d)", m_layerName, iResult); } iTryCount--; sleep(1); } if (iTryCount <= 0) { return false; } if (iResult == ERR_SUCCESS) { if (emCallStep == CALL_MIDDLE) { if (m_callBackProc) { dwCurrent = dwTotal; emCallStep = CALL_LAST; m_callBackProc(dwLayerID, TESTDEVICE_PROGRESS, dwTotal, dwCurrent, emCallStep); } } break; } if (dwCurrent>dwTotal) { if (m_pLog) { m_pLog->Record(" ERROR:TestDevice-->RKU_TestDeviceReady failed,Total=%d, Current=%d", m_layerName, dwTotal, dwCurrent); } return false; } if (UsbType == RKUSB_LOADER) { if (dwTotal == 0) { if (m_pLog) { m_pLog->Record(" ERROR:TestDevice-->RKU_TestDeviceReady failed, Total is zero", m_layerName); } return false; } } if (m_callBackProc) { m_callBackProc(dwLayerID, TESTDEVICE_PROGRESS, dwTotal, dwCurrent, emCallStep); emCallStep = CALL_MIDDLE; } sleep(1); }while(iResult == ERR_DEVICE_UNREADY); return true; } bool CRKDevice::ResetDevice() { int iRet; iRet = m_pComm->RKU_ResetDevice(); if (iRet == ERR_SUCCESS) { return true; } else { bool bRet = false; if ((iRet == -2) || (iRet == -4)) { bRet = true; } if (m_pLog) { m_pLog->Record(" ERROR:ResetDevice-->RKU_ResetDevice failed, RetCode(%d)", m_layerName, iRet); } return bRet; } } bool CRKDevice::PowerOffDevice() { int iRet; iRet = m_pComm->RKU_ResetDevice(RST_POWEROFF_SUBCODE); if (iRet == ERR_SUCCESS) { return true; } else { if (m_pLog) { m_pLog->Record(" ERROR:PowerOffDevice-->RKU_ResetDevice failed, RetCode(%d)", m_layerName, iRet); } return false; } } bool CRKDevice::CheckChip() { int iRet; BYTE bChipInfo[CHIPINFO_LEN]; ENUM_RKDEVICE_TYPE curDeviceType = RKNONE_DEVICE; memset(bChipInfo, 0, CHIPINFO_LEN); iRet = m_pComm->RKU_ReadChipInfo(bChipInfo); if (iRet == ERR_SUCCESS) { if (!m_chipData) { m_chipData = new BYTE[CHIPINFO_LEN]; } memset(m_chipData, 0, CHIPINFO_LEN); memcpy(m_chipData, bChipInfo, CHIPINFO_LEN); DWORD *pValue; pValue = (DWORD *)(&bChipInfo[0]); if ((ENUM_RKDEVICE_TYPE)(*pValue) == m_device) { return true; } if (*pValue == 0x524B3237) { curDeviceType = RK27_DEVICE; } else if (*pValue == 0x32373341) { curDeviceType = RKCAYMAN_DEVICE; } else if (*pValue == 0x524B3238) { curDeviceType = RK28_DEVICE; } else if (*pValue == 0x32383158) { curDeviceType = RK281X_DEVICE; } else if (*pValue == 0x32383242) { curDeviceType = RKPANDA_DEVICE; } else if (*pValue == 0x32393058) { curDeviceType = RK29_DEVICE; } else if (*pValue == 0x32393258) { curDeviceType = RK292X_DEVICE; } else if (*pValue == 0x33303041) { curDeviceType = RK30_DEVICE; } else if (*pValue == 0x33313041) { curDeviceType = RK30B_DEVICE; } else if (*pValue == 0x33313042) { curDeviceType = RK31_DEVICE; } else if (*pValue == 0x33323041) { curDeviceType = RK32_DEVICE; } else if (*pValue == 0x32363243) { curDeviceType = RKSMART_DEVICE; } else if (*pValue == 0x6E616E6F) { curDeviceType = RKNANO_DEVICE; } else if (*pValue == 0x4E4F5243) { curDeviceType = RKCROWN_DEVICE; } if (curDeviceType == m_device){ return true; } else { if (m_pLog) { m_pLog->Record(" ERROR:CheckChip-->Chip is not match, firmware(0x%x), device(0x%x)", m_layerName, m_device, *pValue); } return false; } } else { if (m_pLog) { m_pLog->Record(" ERROR:CheckChip-->RKU_ReadChipInfo failed,RetCode(%d)", m_layerName, iRet); } return false; } } int CRKDevice::DownloadBoot() { UCHAR i; DWORD dwSize, dwDelay; PBYTE pBuffer = NULL; for ( i = 0; i < m_pImage->m_bootObject->Entry471Count; i++ ) { if ( !m_pImage->m_bootObject->GetEntryProperty(ENTRY471, i, dwSize, dwDelay) ) { if (m_pLog) { m_pLog->Record(" ERROR:DownloadBoot-->GetEntry471Property failed,index(%d)", m_layerName, i); } return -2; } if (dwSize>0) { pBuffer = new BYTE[dwSize]; if ( !m_pImage->m_bootObject->GetEntryData(ENTRY471, i, pBuffer) ) { if (m_pLog) { m_pLog->Record(" ERROR:DownloadBoot-->GetEntry471Data failed,index(%d)", m_layerName, i); } delete []pBuffer; return -3; } if ( !Boot_VendorRequest(0x0471,pBuffer,dwSize) ) { if (m_pLog) { m_pLog->Record(" ERROR:DownloadBoot-->Boot_VendorRequest471 failed,index(%d)", m_layerName, i); } delete []pBuffer; return -4; } delete []pBuffer; pBuffer = NULL; if (dwDelay>0) { usleep(dwDelay * 1000); } } } for ( i=0; i < m_pImage->m_bootObject->Entry472Count; i++ ) { if ( !m_pImage->m_bootObject->GetEntryProperty(ENTRY472, i, dwSize, dwDelay) ) { if (m_pLog) { m_pLog->Record(" ERROR:DownloadBoot-->GetEntry472Property failed,index(%d)", m_layerName, i); } return -2; } if (dwSize > 0) { pBuffer = new BYTE[dwSize]; if ( !m_pImage->m_bootObject->GetEntryData(ENTRY472, i, pBuffer) ) { if (m_pLog) { m_pLog->Record(" ERROR:DownloadBoot-->GetEntry472Data failed,index(%d)", m_layerName, i); } delete []pBuffer; return -3; } if ( !Boot_VendorRequest(0x0472, pBuffer, dwSize) ) { if (m_pLog) { m_pLog->Record(" ERROR:DownloadBoot-->Boot_VendorRequest472 failed,index(%d)", m_layerName, i); } delete []pBuffer; return -4; } delete []pBuffer; pBuffer = NULL; if (dwDelay > 0) { usleep(dwDelay * 1000); } } } sleep(1); return 0; } bool CRKDevice::Boot_VendorRequest( DWORD requestCode, PBYTE pBuffer, DWORD dwDataSize) { int iRet; iRet = m_pComm->RKU_DeviceRequest(requestCode, pBuffer, dwDataSize); return (iRet == ERR_SUCCESS) ? true : false; } int CRKDevice::EraseAllBlocks() { int i; UINT uiBlockCount; int iRet = ERR_SUCCESS, iErasePos = 0, iEraseBlockNum = 0, iEraseTimes = 0, iCSIndex = 0; BYTE bCSCount = 0; for (i = 0; i < 8; i++) { if ( m_flashInfo.bFlashCS & (1 << i) ) { bCSCount++; } } DWORD dwLayerID; dwLayerID = LocationID; ENUM_CALL_STEP emCallStep = CALL_FIRST; if (m_bEmmc) { iRet = EraseEmmcBlock(0, 0, IDBLOCK_TOP); if (iRet != ERR_SUCCESS) { if (m_pLog) { m_pLog->Record(" ERROR:EraseAllBlocks-->EraseEmmcBlock failed,RetCode(%d)", m_layerName, iRet); } return -1; } if (!EraseEmmc()) { if (m_pLog) { m_pLog->Record(" ERROR:EraseAllBlocks-->EraseEmmc failed", m_layerName); } return -1; } return 0; } for (i = 0; i < 8; i++) { if ( m_flashInfo.bFlashCS & (1 << i) ) { uiBlockCount = m_flashInfo.uiBlockNum; iErasePos = 0; iEraseTimes = 0; while (uiBlockCount > 0) { iEraseBlockNum = (uiBlockCount < MAX_ERASE_BLOCKS) ? uiBlockCount : MAX_ERASE_BLOCKS; iRet = m_pComm->RKU_EraseBlock(i, iErasePos, iEraseBlockNum, ERASE_FORCE); if ((iRet != ERR_SUCCESS) && (iRet != ERR_FOUND_BAD_BLOCK)) { if (m_pLog) { m_pLog->Record(" ERROR:EraseAllBlocks-->RKU_EraseBlock failed,RetCode(%d)", m_layerName, iRet); } return -1; } iErasePos += iEraseBlockNum; uiBlockCount -= iEraseBlockNum; iEraseTimes++; if (iEraseTimes % 8 == 0) { if (m_callBackProc) { m_callBackProc(dwLayerID, ERASEFLASH_PROGRESS, m_flashInfo.uiBlockNum * bCSCount, iCSIndex * m_flashInfo.uiBlockNum + iErasePos, emCallStep); emCallStep = CALL_MIDDLE; } } } iCSIndex++; } } if (m_callBackProc) { emCallStep = CALL_LAST; m_callBackProc(dwLayerID, ERASEFLASH_PROGRESS, m_flashInfo.uiBlockNum * bCSCount, iCSIndex * m_flashInfo.uiBlockNum, emCallStep); } return 0; }