商显板领域板卡中有许多扩展的端子,且这些端子是带mcu并且包含内置固件程序,为了后续的维护通常
需要有升级功能。5450 就是一款扩展芯片,将手机信号转换成DP 信号,主板上的DP转换芯片再将DP信号
转换HDMI 信号最后输入给主板显示出来。下面我们围绕5450 来分享一下升级的流程。
如果是原厂提供的PC 工具端的基本升级流程: 大体就是启动VENDOR_CMD_ENABLE,FLASH_ACCESS_ENABLE,SMBUS_REASE_FLASH,CHECK_BANK,WRITE_BANK,FLASH_ACCESS_DISABLE,SMBUS_ISP_VALIDATION,RESET_TO_FLASH。
其中GET_IC_STATUS 获取芯片状态信息。
详细信息可以查看文档:
https://download.csdn.net/download/kehyuanyu/12629812
int nFd = open(RTL5450_MASTER_DEV, O_RDWR);
if(nFd < 0)
{
printf("[%s][%d] open %s failed !\n", __FUNCTION__,__LINE__,RTL5450_MASTER_DEV);
return FALSE;
}
// 1. enable smbus function
do
{
MAPI_U8 data[5] = {
0x01,0x03,0xDA,0x0B,0x01};
bRet = sendCmdToRtl5450(nFd, data, 5);
if(!bRet)
{
printf("[%s][%d] send cmd <0x01,0x03,0xDA,0x0B,0x01> failed. Count [%d]\n",\
__FUNCTION__,__LINE__,uCount);
break;
}
uCount = 0;
while(uCount++ < 350)
{
usleep(1000);
bRet = recvFeedbackFromRtl5450Sigle(nFd,&u8FeedBuf);
if(bRet && u8FeedBuf == 0x01)
{
bStep1 = MAPI_TRUE;
break;
}
else
{
continue;
}
}
} while (0);
sendCmdToRtl5450 是发送指令给5450
static MAPI_BOOL sendCmdToRtl5450(int nDevFd, MAPI_U8 u8Cmd[], MAPI_U8 u8Size)
{
int nRet = -1;
struct i2c_msg msg;
struct i2c_rdwr_ioctl_data ioctl_data = {
0};
msg.addr = RTL5450_IIC_ADDR;
msg.flags = I2C_SMBUS_WRITE; /* write */
msg.len = u8Size;
msg.buf = u8Cmd;
ioctl_data.msgs = &msg;
ioctl_data.nmsgs = 1;
nRet = ioctl(nDevFd, I2C_RDWR, &ioctl_data);
if( nRet < 0)
{
printf("[%s][%d] ioctl rtl5450 i2c reg[0x%02x] failed! nRet: = %d, errno: %d, error: %s. \n", \
__FUNCTION__,__LINE__,u8Cmd[0],nRet, errno,strerror(errno));
return MAPI_FALSE;
}
return MAPI_TRUE;
}
其中 RTL5450_IIC_ADDR 为typec 7位的设备地址,kernel 会根据上层的操作(读/写)来补全最后一位。
recvFeedbackFromRtl5450Sigle 获取指令执行后,5450 发过来的返回值,使用与所有指令执行后的返回值
// GET_PING_STATUS
static MAPI_BOOL recvFeedbackFromRtl5450Sigle(int nDevFd, MAPI_U8 *pu8FeedBuf)
{
struct i2c_msg msg;
struct i2c_rdwr_ioctl_data data_ioctl;
msg.addr = RTL5450_IIC_ADDR;
msg.flags = I2C_SMBUS_READ;
msg.len = 1;
msg.buf = pu8FeedBuf;
data_ioctl.msgs = &msg;
data_ioctl.nmsgs = 1;
if(ioctl(nDevFd, I2C_RDWR, &data_ioctl) < 0)
{
printf("[%s][%d] read back value failed! \n", __FUNCTION__,__LINE__);
return MAPI_FALSE;
}
return MAPI_TRUE;
}
通过msg.buf 返回上调指令的执行结果。
操作码(亦寄存器)为0x3A,发送三个字节指令"0x00 0x00 0x14"到5450 ,其中主要是操作码,及最后一个0x14(表示将返回0x14 个字节的状态信息)。
// 2. get ic status
do
{
MAPI_U8 data[5] = {
0x3A,0x03,0x00,0x00,0x14};
MAPI_U8 u8CmdCode = 0x00;
MAPI_BOOL bRet = MAPI_FALSE;
bRet = sendCmdToRtl5450(nFd, data, 5);
if(!bRet)
{
printf("[%s][%d] send cmd <0x3A,0x03,0x00,0x00,0x14> failed. Count [%d]\n",\
__FUNCTION__,__LINE__,uCount);
break;
}
uCount = 0;
while(uCount++ < 350)
{
usleep(1000);
u8FeedBuf = 0x00;
bRet = recvFeedbackFromRtl5450Sigle(nFd,&u8FeedBuf);
if(bRet && u8FeedBuf == 0x01)
{
break;
}
else
{
continue;
}
}
uCount = 0;
u8CmdCode = 0x80;
while(uCount++ < 350)
{
usleep(100);
memset(u8FeedBufs, 0x00, sizeof(u8FeedBufs));
recvFeedbackFromRtl5450FromReg(nFd, u8CmdCode, u8FeedBufs, sizeof(u8FeedBufs)/sizeof(u8FeedBufs[0]));
if(bRet && u8FeedBufs[0] == 0x14)
{
bStep2 = MAPI_TRUE;
break;
}
else
{
continue;
}
}
}while(0);
recvFeedbackFromRtl5450Sigle 返回值为0x01 ,表示5450 正常收到请求GET_IC_STATUS的指令,接着通过recvFeedbackFromRtl5450FromReg获取0x14 (20)个的信息
static MAPI_BOOL recvFeedbackFromRtl5450FromReg(int nDevFd, MAPI_U8 u8Cmd, MAPI_U8 *pu8FeedBuf, MAPI_U8 u8FeedSize)
{
struct i2c_msg msg[2];
struct i2c_rdwr_ioctl_data data_ioctl;
MAPI_U8 ucAddr = u8Cmd;
msg[0].addr = RTL5450_IIC_ADDR;
msg[0].flags = I2C_SMBUS_WRITE;
msg[0].len = 1;
msg[0].buf = &ucAddr; // cmd or reg
msg[1].addr = RTL5450_IIC_ADDR;
msg[1].flags = I2C_M_RD;
msg[1].len = u8FeedSize;
msg[1].buf = pu8FeedBuf;
data_ioctl.msgs = msg;
data_ioctl.nmsgs = 2;
if(ioctl(nDevFd, I2C_RDWR, &data_ioctl) < 0)
{
printf("[%s][%d] read back value failed! \n", __FUNCTION__,__LINE__);
return MAPI_FALSE;
}
return MAPI_TRUE;
}
成功之后,解析这个20个bytes,其中byte【1】表示Rom code 还是MCM flash code,而byte【15】为0x10 时表示运行在bank1,其他值则表示运行在bank0,这个会影响写flash的地址。
操作码0x0a, 发送三个字节0xDA,0x0B,0x03 到5450
// 3. falsh enable access
do
{
MAPI_U8 data[5] = {
0x01,0x03,0xDA,0x0B,0x03};
MAPI_BOOL bRet = MAPI_FALSE;
bRet = sendCmdToRtl5450(nFd, data, 5);
if(!bRet)
{
printf("[%s][%d] send cmd <0x01,0x03,0xDA,0x0B,0x03> failed. Count [%d]\n",\
__FUNCTION__,__LINE__,uCount);
break;
}
uCount = 0;
while(uCount++ < 350)
{
u8FeedBuf = 0x00;
bRet = recvFeedbackFromRtl5450Sigle(nFd,&u8FeedBuf);
if(bRet && u8FeedBuf == 0x01)
{
bStep3 = MAPI_TRUE;
break;
}
else
{
continue;
}
usleep(1000);
}
} while (0);
static MAPI_BOOL writeBinTo5450m(MAPI_U8 u8CodeRun, const char* filename, int nFd)
{
MAPI_U8 u8Step4CmdCode1 = 0x00;
MAPI_U8 u8Step4CmdCode2 = 0x00;
char binFile[1024];
MAPI_U8 u8TmpBin[32] = {
0x00};
MAPI_U8 u8WData[34] = {
0x00};
MAPI_U8 u8RUnitLen = 0x1D;
MAPI_BOOL bWRet = MAPI_FALSE;
const MAPI_U8 u8RUnitHeadLen = 5; // cmd, byte count, addr_l, addr_h,wData_count
const MAPI_U32 nBankHalfSize = 65536; // 64K
FILE *pFHandle = NULL;
int nLen = 0;
MAPI_U16 uReadCnt = 0;
MAPI_U32 uWAddr = 0x0000;
MAPI_U16 uWUsdAddr = 0x0000;
MAPI_U32 u32RTotal = 0x0000;
MAPI_U8 u8RItemSize = 29;
MAPI_U8 u8RItem = 1;
MAPI_U8 u8LoopCnt = 0;
if(u8CodeRun == 0x10) // bank1
{
// bank 0 cmd code
u8Step4CmdCode1 = 0x04;
u8Step4CmdCode2 = 0x06;
}
else // bank0
{
// bank 1 cmd code
u8Step4CmdCode1 = 0x13;
u8Step4CmdCode2 = 0x14;
}
printf("[%s][%d] will upgrade %s \n", __FUNCTION__,__LINE__,u8CodeRun ? "bank0" : "bank1");
printf("[%s][%d] cmd code1: 0x%02x , cmd: code2 0x%02x .\n", __FUNCTION__,__LINE__,u8Step4CmdCode1,u8Step4CmdCode2);
memset(binFile,0x00,sizeof(binFile));
memcpy(binFile,filename,strlen(filename));
pFHandle = fopen(binFile, "r");
if(pFHandle == NULL)
{
printf("[%s][%d] open %s failed! \n",__FUNCTION__,__LINE__,binFile);
return MAPI_FALSE;
}
fseek(pFHandle, 0, SEEK_END);
nLen = ftell(pFHandle);
fseek(pFHandle, 0, SEEK_SET);
printf("[%s][%d] file %s size: %d[0x%05x] \n",__FUNCTION__,__LINE__,binFile,nLen,nLen);
while(TRUE)
{
MAPI_BOOL bBackVal = MAPI_FALSE;
u8RItem = (u8RItem % 10) == 0 ? 1 : (u8RItem % 10) ;
if(u8RItem % 9 == 0)
{
u8RItemSize = 24;
}
else
{
u8RItemSize = 29;
}
// init buf
memset(u8TmpBin, 0x00, sizeof(u8TmpBin));
memset(u8WData, 0x00, sizeof(u8WData));
u8RUnitLen = fread(u8TmpBin, sizeof(char), u8RItemSize, pFHandle);
if(u8RUnitLen <= 0)
{
int nCurPosition = ftell(pFHandle);
if(nCurPosition >= nLen)
{
break;
}
}
u32RTotal = u32RTotal + u8RUnitLen;
if(u32RTotal < nBankHalfSize)
{
u8WData[0] = u8Step4CmdCode1;
}
else
{
u8RItem = 1;
u8WData[0] = u8Step4CmdCode2;
}
#if (KERNEL_I2C_DEBUG == 1)
if(u32RTotal % 1024 == 0)
{
printf("[%s][%d] read item ( %d KB) from bin, two banks size: %d KB . \n", \
__FUNCTION__,__LINE__,(u32RTotal/1024),(nLen/1024));
}
#endif
// byte count
u8WData[1] = u8RUnitLen + (u8RUnitHeadLen - 2); // remove 2 byte(cmd , byte count)
uWUsdAddr = uWAddr % nBankHalfSize;
// ADDR_L
u8WData[2] = (MAPI_U8)uWUsdAddr&0x00FF;
// ADDR_H
u8WData[3] = ((MAPI_U8)((uWUsdAddr&0xFF00) >> 8));
// WData_count
u8WData[4] = u8RUnitLen;
// data1 ~ dataN
memcpy(u8WData + u8RUnitHeadLen, u8TmpBin, u8RUnitLen);
bWRet = sendCmdToRtl5450(nFd, u8WData, (u8RUnitLen+u8RUnitHeadLen));
if(!bWRet)
{
printf("[%s][%d] wirte bin data to 5450 failed\n", __FUNCTION__,__LINE__);
break;
}
u8LoopCnt = 0;
while(u8LoopCnt++ < 350)
{
// MAPI_U8 u8CmdCode = u8WData[0];
MAPI_BOOL bRetFeedval = MAPI_FALSE;
MAPI_U8 u8FeedBuf = 0x00;
usleep(1000);
bRetFeedval = recvFeedbackFromRtl5450Sigle(nFd,&u8FeedBuf);
if(bRetFeedval && u8FeedBuf == 0x01)
{
bBackVal = MAPI_TRUE;
break;
}
else
{
continue;
}
}
if(!bBackVal)
{
printf("[%s][%d] get back value failed , when wirte date to 0x%04x\n",\
__FUNCTION__,__LINE__,uWAddr);
break;
}
uReadCnt++;
u8RItem++;
uWAddr = uWAddr + u8RUnitLen;
}
if(feof(pFHandle) != 0 || (ftell(pFHandle) == nLen))
{
printf("[%s][%d] wirte bin file completed .\n", __FUNCTION__,__LINE__);
fclose(pFHandle);
return MAPI_TRUE;
}
printf("[%s][%d] write %d bytes to dev [addr: 0x%04x], [failed] \n",\
__FUNCTION__,__LINE__,u8RUnitLen,uWAddr);
fclose(pFHandle);
return MAPI_FALSE;
}
bank0 : 0~ 128K, bank1: 128K~256K。 根据GET_IC_STATUS获取信息,如果运行在bank1就写bank0,如果运行在bank0 就写bank1.
根据对应操作码,将从bin文件中读取的数据封装成包,写入mcu 的flash中。一个轮回写8次29bytes,接着写1次24bytes,共计256 bytes,如此反复512次即可烧录完128K数据。
do
{
MAPI_U8 data[5] = {
0x01,0x03,0xDA,0x0B,0x01};
MAPI_BOOL bRet = MAPI_FALSE;
memset(u8FeedBufs, 0x00, sizeof(u8FeedBufs));
bRet = sendCmdToRtl5450(nFd, data, 5);
if(!bRet)
{
printf("[%s][%d] send cmd <0x01,0x03,0xDA,0x0B,0x01> failed. Count [%d]\n",\
__FUNCTION__,__LINE__,uCount);
break;
}
uCount = 0;
while(uCount++ < 350)
{
usleep(1000);
u8FeedBuf = 0x00;
bRet = recvFeedbackFromRtl5450Sigle(nFd,&u8FeedBuf);
if(bRet && u8FeedBuf == 0x01)
{
bStep5_1 = MAPI_TRUE;
break;
}
else
{
continue;
}
}
} while (0);
操作码0x01,发送三字节数据0xDA,0x0B,0x01给mcu
// 5. smbus isp validation
do
{
MAPI_U8 data[3] = {
0x16,0x01,0x01};
MAPI_BOOL bRet = MAPI_FALSE;
bRet = sendCmdToRtl5450(nFd, data, 3);
if(!bRet)
{
printf("[%s][%d] send cmd <0x16,0x01,0x01> failed. Count [%d]\n",\
__FUNCTION__,__LINE__,uCount);
break;
}
uCount = 0;
while(uCount++ < 350)
{
usleep(1000);
u8FeedBuf = 0x00;
bRet = recvFeedbackFromRtl5450Sigle(nFd,&u8FeedBuf);
if(bRet && u8FeedBuf == 0x01)
{
bStep5_2 = MAPI_TRUE;
break;
}
else
{
continue;
}
}
} while (0);
do
{
MAPI_U8 data[5] = {
0x05,0x03,0xDA,0x0B,0x01};
MAPI_BOOL bRet = MAPI_FALSE;
bRet = sendCmdToRtl5450(nFd, data, 5);
if(!bRet)
{
printf("[%s][%d] send cmd <0x05,0x03,0xDA,0x0B,0x01> failed. Count [%d]\n",\
__FUNCTION__,__LINE__,uCount);
break;
}
uCount = 0;
while(uCount++ < 350)
{
usleep(1000);
u8FeedBuf = 0x00;
bRet = recvFeedbackFromRtl5450Sigle(nFd,&u8FeedBuf);
if(bRet && u8FeedBuf == 0x01)
{
bStep6 = MAPI_TRUE;
break;
}
else
{
continue;
}
}
} while (0);
至此,整个升级流程完成。