hdmiout 68411升级

7 篇文章 0 订阅
68411 是麦道微代理的一款hdmiout ic, 可以完成主芯片信源通道的扩展功能。 
这里主芯片输出vb1 给68411, 然后68411 输出vb1 及一路hdmi out。该ic 也是一块由I2c控制的芯片但却是非标的i2c,所以我们需要对协议进行调整。

1. 总线配置

关于总线配置,可以参考"mstar 平台内核i2c总线介绍"
这篇博客。

2. 升级流程

novatek 升级流程,主要包含以下几个步骤:
一. ISP 模式设置;
二. 关闭写保护;
三. 擦除novatek 存储分区;
四. 写分区;
五. 校验分区;
六 . 开启写保护,退出ISP模式;

code 如下:

MAPI_BOOL mapi_i2c::doUpgradeNovaTek(const char* filePath)
{
    MAPI_BOOL bRet      = MAPI_FALSE;
    MS_U16 u16Page      = 0x000;
    MAPI_U8 u8CurPage   = 0x00;
    MAPI_BOOL bSkipPage = MAPI_FALSE;
    int nFileFd = open(NOVA_TEK_MASTER_DEV, O_RDWR);

    if(nFileFd < 0)
    {
        return MAPI_FALSE;
    }

    bRet = NovaTekLoadFwBin(filePath);
    if(!bRet)
    {
        goto END;
    }

    configIIcSpeed(nFileFd,50);
    if(!NovaTekEnterIsp(nFileFd))
    {
        bRet = MAPI_FALSE;
        close(nFileFd);
        return bRet;
    }

    configIIcSpeed(nFileFd,100);
    if(DualFwEnable == 1)
    {
        NovaTekEraseIDSector(nFileFd);
    }

    if(!NovaTekTErase(nFileFd))
    {
        bRet = MAPI_FALSE;
        goto END;
    }

    configIIcSpeed(nFileFd,400);

    MaxPages = Flash.Page;
    if(DualFwEnable == 1)
    {
        CodePages   = MaxPages/2 ;
        FlashOffset = MaxPages/2 ;
    }
    else
    {
        CodePages = MaxPages;
        FlashOffset = 0;
    }

    if (McuId == 0xa390 || McuId == 0xA400 || McuId == 0xA450)
    {
        bRet = NovaTek68390ProgramEnable(nFileFd, MAPI_TRUE);
    }

    for(u16Page = FlashOffset; (u16Page<(CodePages+FlashOffset))&&(u16Page<TOTAL_PAGE_SIZE); u16Page++)
    {
        u8CurPage = (u16Page - FlashOffset)%256;
        bRet = NovaTekSetExntend(nFileFd,u16Page);
        if(!bRet)
        {
            goto END;
        }
        else
        {
            g_current_bank  = u16Page>>8;
        }

        SPageSum  = 0;
        bSkipPage = MAPI_TRUE;

        for (int i = 0; i < 512; i++)
        {
            if(BinFilePageBuffer[u16Page-FlashOffset][i] != 0xff)
            {
                bSkipPage = MAPI_FALSE;
            }
            SPageSum += BinFilePageBuffer[u16Page-FlashOffset][i];
        }

        if (NovaTekCheckOverLap(u8CurPage))
        {
            bSkipPage = MAPI_TRUE;
        }

        if(!bSkipPage)   //Bypass program?
        {
            bRet = NovaTekTProgram(nFileFd,u16Page);
            if(!bRet)
            {
                goto END;
            }
        }

        if(!bSkipPage)
        {
            bRet = NovaTekCmdGetCheckSum(nFileFd, u8CurPage);
            if(!bRet)
            {
                goto END;
            }
        }
    }

    if (McuId == 0xa390 || McuId == 0xA400 || McuId == 0xA450)
    {
        bRet = NovaTek68390ProgramEnable(nFileFd, MAPI_FALSE);
    }

    if(DualFwEnable == 1)
    {
        if(!NovaTekUpdateIDSector(nFileFd))
        {
            bRet = MAPI_FALSE;
            goto END;
        }
    }

END:
    NovaTekBlockProtect(nFileFd,1);
    configIIcSpeed(nFileFd,100);
    NovaTekISPOff(nFileFd);
    close(nFileFd);
    if(!bRet)
    {
        printf("[%s][%d] novatek upgrade failed. \n", __FUNCTION__,__LINE__);
    }
    else
    {
        printf("[%s][%d] novatek upgrade successully. \n", __FUNCTION__,__LINE__);
    }
    return bRet;
}

2.1 升级文件加载

novatek 提供的bin 升级文件大小为1M,分成2048 个page,每个page大小为512 Bytes。

static MAPI_BOOL NovaTekLoadFwBin(const char* FwPath)
{
    int nLen = 0;
    FILE *pHandle = NULL;
    char binFile[1024];
    MS_U8  u8RSize     = 0x00;
    MS_U16 u16PageNo   = 0x0000;
    MS_U16 u16PageCnt  = 0x0000;
    MS_U32 u32TotalLen = 0x0000;
    int nCurPosition   = 0;
    MAPI_BOOL bRet     = MAPI_FALSE;
    memset(binFile,0x00,sizeof(binFile));
    memcpy(binFile,FwPath,strlen(FwPath));
    pHandle = fopen(binFile, "r");
    if(pHandle == NULL)
    {
        return MAPI_FALSE;
    }
    fseek(pHandle, 0, SEEK_END);
    nLen = ftell(pHandle);
    if(nLen != 1024*1024)
    {
        fclose(pHandle);
        return MAPI_FALSE;
    }
    u16PageCnt = nLen/512;
    // set to the file head
    fseek(pHandle, 0, SEEK_SET);
    for (u16PageNo = 0; u16PageNo < u16PageCnt; u16PageNo++)
    {
        u8RSize = fread(BinFilePageBuffer[u16PageNo], sizeof(char)*512, 1, pHandle);
        u32TotalLen = u32TotalLen + u8RSize*512; // bytes
        if(u8RSize <= 0)
        {
            bRet = MAPI_FALSE;
            break;
        }
    }
    nCurPosition = ftell(pHandle);
    if(nCurPosition >= nLen)
    {
        bRet = MAPI_TRUE;
    }
    fclose(pHandle);
    return bRet;
}

将升级文件存储在BinFilePageBuffer[2048][512] 的二维结构体中。

2.2 进入ISP mode

在这里插入图片描述
蓝色框框中的byte 序列就是发送给ic 的指令,发送完成之后,就可以通过reply 指令读取mcu id,本款芯片的mcu id 是0xA400。

static MAPI_BOOL NovaTekEnterIsp(int nDevFd)
{
    MAPI_BOOL bStep1 = MAPI_FALSE;
    MAPI_BOOL bStep2 = MAPI_FALSE;
    MAPI_BOOL bStep3 = MAPI_FALSE;
    MAPI_BOOL bStep4 = MAPI_FALSE;
    MAPI_BOOL bStep5 = MAPI_FALSE;

    NOVATEK_DG(printf("[%s][%d] Enter .\n", __FUNCTION__,__LINE__);)

    do
    {
        bStep1 = NovaTekISPOn(nDevFd);
        if(!bStep1)
        {
            printf("[%s][%d] novatek enter isp on mode failed. \n", __FUNCTION__,__LINE__);
            break;
        }

        bStep2 = NovaTekSendSpecialCmd(nDevFd);
        if(!bStep2)
        {
            printf("[%s][%d] send special cmd to novatek failed. \n", __FUNCTION__,__LINE__);
            break;
        }

        bStep3 = NovaTekGetFlashId(nDevFd);
        if(!bStep3)
        {
            printf("[%s][%d] novatek get flash id failed. \n", __FUNCTION__,__LINE__);
            break;
        }

        bStep4 = NovaTekWpEnable(nDevFd);
        if(!bStep4)
        {
            printf("[%s][%d] novatek wp enable failed. \n", __FUNCTION__,__LINE__);
            break;
        }

        bStep5 = NovaTekBlockProtect(nDevFd,0);
        if(!bStep5)
        {
            printf("[%s][%d] novatek block protect failed. \n", __FUNCTION__,__LINE__);
            break;
        }
    }while(0);

    return (bStep5 && bStep4 && bStep3 && bStep2 && bStep1);
}

NovaTekISPOn 是发送enter isp 的指令并通过reply 值校验mcu id。NovaTekSendSpecialCmd 发送一些特殊指令配置芯片烧写前的状态。NovaTekGetFlashId 读取flash id。
NovaTekWpEnable 设置novatek 模组wp 脚。NovaTekBlockProtect 关闭写保护。

2.3 擦除芯片

static MAPI_BOOL NovaTekTErase(int nDevFd)
{
    MAPI_BOOL bRet  = MAPI_FALSE;
    MS_U32 BlkStart = 0x0000;
    MS_U32 BlkEnd   = 0x0000;

    if (McuId == 0xa390 || McuId == 0xA400 || McuId == 0xA450)
    {
        bRet = NovaTek68390ProgramEnable(nDevFd, MAPI_TRUE);
    }
     {
        bRet = NovaTekChipErase(nDevFd);
        //6seconds M25P20 erase time max<6sec
        //5seconds w25x40b erase time max<4sec
        usleep(5*1000*1000);
        bRet = NovaTekChipEraseReply(nDevFd);
        if(!bRet)
        {
            return MAPI_FALSE;
        }
    }

    if (McuId == 0xa390 || McuId == 0xA400 || McuId == 0xA450)
    {
        bRet = NovaTek68390ProgramEnable(nDevFd, MAPI_FALSE);
    }
    return bRet;
}

2.4 升级芯片

    for(u16Page = FlashOffset; (u16Page<(CodePages+FlashOffset))&&(u16Page<TOTAL_PAGE_SIZE); u16Page++)
    {
        u8CurPage = (u16Page - FlashOffset)%256;

        bRet = NovaTekSetExntend(nFileFd,u16Page);
        if(!bRet)
        {
            printf("[%s][%d][error] set bank: 0x%x failed. \n", __FUNCTION__,__LINE__,u16Page>>8);
            goto END;
        }
        else
        {
            g_current_bank  = u16Page>>8;
        }

        printf("\n\n[%s][%d] start upgrade bank[%d], page[%d] \n",__FUNCTION__,__LINE__,g_current_bank,u8CurPage);

        SPageSum  = 0;
        bSkipPage = MAPI_TRUE;

        for (int i = 0; i < 512; i++)
        {
            if(BinFilePageBuffer[u16Page-FlashOffset][i] != 0xff)
            {
                bSkipPage = MAPI_FALSE;
            }
            SPageSum += BinFilePageBuffer[u16Page-FlashOffset][i];
        }

        if (NovaTekCheckOverLap(u8CurPage))
        {
            bSkipPage = MAPI_TRUE;
        }

        printf("\n[%s][%d] bSkipPage: %d, SPageSum: 0x%4x \n",__FUNCTION__,__LINE__,bSkipPage,SPageSum);

        if(!bSkipPage)   //Bypass program?
        {
            bRet = NovaTekTProgram(nFileFd,u16Page);
            if(!bRet)
            {
                printf("[%s][%d][error] T Program failed\n", __FUNCTION__,__LINE__);
                goto END;
            }
        }

        printf("[%s][%d] bank: %d , Page : %d , SPageSum: 0x%4x .\n",__FUNCTION__,__LINE__,g_current_bank, u8CurPage,SPageSum);

        if(!bSkipPage)
        {
            bRet = NovaTekCmdGetCheckSum(nFileFd, u8CurPage);
            if(!bRet)
            {
                printf("[%s][%d][error] cmd get checksum failed\n", __FUNCTION__,__LINE__);
                goto END;
            }
        }

        printf("[%s][%d] upgrade bank[%d], page[%d] completed\n",__FUNCTION__,__LINE__,u16Page>>8,u8CurPage);

    }

将前面保存bin 的二维数组数据写入分区中。NovaTekSetExntend 设置bank(每个bank 256 page), NovaTekTProgram 则是写page

static MAPI_BOOL NovaTekTProgram(int nDevFd, MS_U16 u16BufIndex)
{
    MAPI_BOOL bRet      = MAPI_FALSE;
    MAPI_BOOL bRetReply = MAPI_FALSE;

    bRet = NovaTekWritePgData(nDevFd, u16BufIndex);
    usleep(200*1000);
    bRetReply = NovaTekWritePgDataReply(nDevFd);
    return (bRetReply&&bRet);
}

NovaTekCmdGetCheckSum 则是对每个写入的page 进行校验,通过则继续写下个page 的数据。

2.5 升级完成

升级完成之后,NovaTekBlockProtect打开数据保护,NovaTekISPOff 退出ISP 模式,进入用户模式。

3. 协议客制化

由于novatek 协议主要是ISP ON指令的交互时是非标的,另外一些功能指令交互时的时钟周期不一样。所以我们只需要对这个两部分进行修改即可,没有必要将整个i2c 协议修改。

3.1 i2c 总线周期设置

#define NOVA_TEK__IIC_ADDR   (0x6E >> 1)
static MAPI_BOOL WriteBytesToDev(int nDevFd, MAPI_U8 u8Data[] , MAPI_U16 uDataLen)
{
    int nRet = -1;
    struct i2c_msg msg;
    struct i2c_rdwr_ioctl_data ioctl_data = {0};

    msg.addr          = NOVA_TEK__IIC_ADDR;
    msg.flags         = I2C_SMBUS_WRITE; /* write */
    msg.len           = uDataLen;
    msg.buf           = u8Data;

    ioctl_data.msgs   = &msg;
    ioctl_data.nmsgs  = 1;

    nRet = ioctl(nDevFd, I2C_RDWR, &ioctl_data);
    if( nRet < 0)
    {
        return MAPI_FALSE;
    }

    return MAPI_TRUE;
}

static MAPI_BOOL configIIcSpeed(int nDevFd, MS_U16 u16Spd)
{
    MS_U8 u8SRamPkg[4] = {0x88, 0x00, 0x00, 0x00};
    u8SRamPkg[1] = u16Spd >> 8;
    u8SRamPkg[2] = u16Spd & 0xFF;

    u8SRamPkg[3] = (MS_U8)(0x6E^u8SRamPkg[0]^u8SRamPkg[1]^u8SRamPkg[2]);
    if(WriteBytesToDev(nDevFd, u8SRamPkg, sizeof(u8SRamPkg)/sizeof(u8SRamPkg[0])) == MAPI_FALSE)
    {
        return MAPI_FALSE;
    }
     return MAPI_TRUE;
}

configIIcSpeed 通过 /dev/i2c-2 对应novatek 设备(0x6E)发送指令“0x6E 0x04 0x88 speekH speedL checkSum” 其中speedH 为i2c周期的高8位,speedL为i2c周期的低8位。

在kernel 的master_xfer 回调中会处理i2c 指令,mstar 平台则在vendor\mstar\kernel\linaro\mstar2\drv\iic\mdrv_iic_io.c中
在这里插入图片描述
g_i2c_speed 提取i2c 总线速率。

u16  getCustomerSpeed(void)
{
	return g_i2c_speed;
}

在这里插入图片描述

3.2 ISP ON 指令客制化

int MDrv_SW_IIC_WriteBytesForCustomerIspEnable(u8 u8BusNum, u8 u8SlaveID, u16 u16size, u8* pu8Data, int stop)
{
    int bRet = -EIO;
    u16 u16Retries = g_IICBus[u8BusNum].u16Retries;
    u16 u16size_temp=0;
    u8* pu8Data_temp=(u8*)NULL;

    SWI2C_DBG_FUNC();

    if (u8BusAllocNum == 0)
        return -ENOENT;

    if (IIC_UseBusForCustomer(u8BusNum, getCustomerSpeed())  == FALSE)
    {
        return -ENOENT;
    }

    u16size_temp = u16size;
    pu8Data_temp = (u8*)pu8Data;

    while (u16size_temp)
    {
        u16size_temp--;

		if ( IIC_Start(u8BusNum) == FALSE)
		{
			continue;
		}

        if (IIC_SendByte(u8BusNum, *pu8Data_temp) == FALSE) {
            // goto fail;
        }

        // switch to next byte
        pu8Data_temp++;
    }

    bRet = u16size - u16size_temp;

	iic_delay(u8BusNum);

    if (stop)
    {
        IIC_Stop(u8BusNum);
    }

    return bRet;
}
EXPORT_SYMBOL(MDrv_SW_IIC_WriteBytesForCustomerIspEnable);

至此,整个升级流程我介绍完成,更多指令客制化可以自己根据需求修改。 如果IO足够多也值可以使用IO口来模拟i2c, 这样会减小对原生协议干扰。

参考资料:
https://app.yinxiang.com/Home.action#n=88618994-1419-47ef-923f-79ecaf89d7d0&s=s30&ses=4&sh=5&sds=2&

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值