[Android5.1][RK3288] LCD Mipi 初始化长包数据规范问题

本文解决了一个关于RK3288平台MipiLCD调试的问题,详细介绍了当出现LP模式被误判为HS模式时的调试过程及原因。通过深入分析代码,发现该问题是由参数拆分不当导致,并解释了正确的参数传递方式。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

先说问题和结论

环境

正在 RK3288 调试 Mipi LCD(540×960)

问题

首先是因为我出现了这样的 Bug:

我的 cmds7 明明填充的是 LP 模式,但是打印中却说是 HS 模式。
我在一个帖子中看到说 cmds 参数 不能为 8 和 16 的情况。
于是错误地将地将两者联系起来,认为参数为 8 或者 16 的情况下,LP 模式会被转换成 HS 模式。
于是希望跟着代码一探究竟。

真相

但是实际上两者是没有关联的。
真相是
其实是可以传递 8 字节 和 16 字节的参数的。

跟踪代码发现打印 LP mode 和 HS mode 这个输出信息的代码是根据 reg[0] 来判断的

MIPI_DBG("%d command sent in %s size:%d\n", __LINE__, regs[0] ? "LP mode" : "HS mode", liTmp);

我出现这种情况的原因,是因为擅自错误地将一个 36 字节的参数 拆分成 28 和 8 。
而后面 8 字节 cmds 的首字节 为 0x00
也就是 reg[0] = 0x00 ,所以会输出 HS mode。

正文

假设我们有 8 个参数,那么 cmds 实际为 { 0x39,0x11,0x22,0x33,0x44,0x55,0x66,0x77,0x88 }
cmd_len = length / sizeof(u32) = 9
在 video/rockchip/screen/lcd_mipi.c 中的 rk_mipi_screen_cmd_init 可以看到是调用
dsi_send_packet 这个函数来进行参数传递

//...
        dcs_cmd = list_entry(screen_pos, struct mipi_dcs_cmd_ctr_list, list);
        len = dcs_cmd->dcs_cmd.cmd_len + 1; // len = 9 + 1 = 10
        for (i = 1; i < len ; i++) {  // 将 dcs_cmd->dcs_cmd.cmds 中的 9 个参数赋值给 cmds
            cmds[i] = dcs_cmd->dcs_cmd.cmds[i-1]; //cmds[1-9] 被 dcs_cmd.cmds[0-8] 赋值
        }
        MIPI_SCREEN_DBG("dcs_cmd.name:%s\n", dcs_cmd->dcs_cmd.name);
        if (dcs_cmd->dcs_cmd.type == LPDT) {
            cmds[0] = LPDT; //cmds[0] 表示传输数据模式的标志 1
            if (dcs_cmd->dcs_cmd.dsi_id == 0) {
                MIPI_SCREEN_DBG("dcs_cmd.dsi_id == 0 line=%d\n", __LINE__);
                //调用这个函数进行 mipi 通信 
                //这里的 cmds 中实际有 10 个字节
                // 0 为 数据类型的标志 1
                // 1-9 为参数 cmds[1] = 0x39 数据类型为长包数据 cmds[2-9] 为屏幕初始化参数
                // len 为 10
                dsi_send_packet(0, cmds, len); 
            } 
//...

跟代码发现在 video/rockchip/transmitter/mipi_dsi.c 中

int dsi_send_dcs_packet(unsigned int id, unsigned char *packet, u32 n) {

    struct mipi_dsi_ops *ops = NULL;
    //printk("dsi_send_dcs_packet-------id=%d\n",id);
    if(id > (MAX_DSI_CHIPS - 1))
        return -EINVAL;
    ops = dsi_ops[id];
    if(!ops)
        return -EINVAL;
    if(ops->dsi_send_dcs_packet)
        ops->dsi_send_dcs_packet(ops->dsi, packet, n);
    return 0;
}
#ifdef CONFIG_MIPI_DSI
EXPORT_SYMBOL(dsi_send_dcs_packet);

ops->dsi_send_dcs_packet 这个实现是在 ops->的 dsi_send_dcs_packet
究其根源的实现是在
kernel/drivers/video/rockchip/transmitter/rk32_mipi_dsi.c
的 rk32_mipi_dsi_send_packet

//arg 是要传输的通道,默认为 0 
//cmds 就是 lcd dtsi 中的 cmds // 这里假设为{ 0x39,0x11,0x22,0x33,0x44,0x55,0x66,0x77,0x88 }
//length 就是 cmds 的长度 // 这里为 10
static int rk32_mipi_dsi_send_packet(void *arg, unsigned char cmds[], u32 length)
{
    struct dsi *dsi = arg;
    unsigned char *regs;
    u32 type, liTmp = 0, i = 0, j = 0, data = 0;

    if (rk32_dsi_get_bits(dsi, gen_cmd_full) == 1) {
        MIPI_TRACE("gen_cmd_full\n");
        return -1;
    }
    regs = kmalloc(0x400, GFP_KERNEL);  
    if (!regs) {
        printk("request regs fail!\n");
        return -ENOMEM;
    }
    memcpy(regs, cmds, length); //regs 现在为 cmds 中的内容了

    liTmp = length - 2;     //liTmp = 10 - 2 = 8
    type = regs[1];         //type = regs[1] = cmds[1] = 0x39 (采用长包模式传输)
    switch (type) { //0x39 即 DTYPE_DCS_LWRITE
        //... 
    case DTYPE_DCS_LWRITE:
        rk32_dsi_set_bits(dsi, regs[0], dcs_lw_tx); // 设置标志位,根据 regs[0] 设置寄存器 dcs_lw_tx 中的标志
        for (i = 0; i < liTmp; i++) { 
            // 0-7 依次给 regs[0]-regs[7] 赋值,这8个值便是屏幕初始化的内容
            // {0x11,0x22,0x33,0x44,0x55.0x66,0x77,0x88}
            regs[i] = regs[i+2];
        }
        for (i = 0; i < liTmp; i++) {
            j = i % 4; //0 1 2 3 0 1 2 3
            data |= regs[i] << (j * 8); 
            //data | (regs[0] << 0)
            //data | (regs[1] << 8)
            //data |  (regs[2] << 16)
            //data | (regs[3] << 24)
            // 8 个字节的内容被组合成两个 data
            // 0x44332211 0x88776655
            if (j == 3 || ((i + 1) == liTmp)) { //每当组成的 data 满了的时候,或者是所有的参数都填充了的时候
                if (rk32_dsi_get_bits(dsi, gen_pld_w_full) == 1) {
                    MIPI_TRACE("gen_pld_w_full :%d\n", i);
                    break;
                }
                rk32_dsi_set_bits(dsi, data, GEN_PLD_DATA);
                MIPI_DBG("write GEN_PLD_DATA:%d, %08x\n", i, data);
                data = 0; //清空 data,开始下个 data 的传输
            }
        }
        data = type;//data = 0x39
        data |= (liTmp & 0xffff) << 8;  //0x0839 //如果是 16 字节的话为 0x1039(16 的16进制是 0x10)
        break;
        //...
        }

    MIPI_DBG("%d command sent in %s size:%d\n", __LINE__, regs[0] ? "LP mode" : "HS mode", liTmp);
    //这里就会打印究竟是什么模式来传输
    //reg[0] 正是代表了 屏幕参数初始化的第一个字节!
    //它的含义是这块屏 IC 的 CMD!
    //0x11 0x22 0x33 0x44... 0x88 表示执行 0x11 这个 CMD,参数为 0x22 到 0x88
    //那为什么  8 个字节就会变成 HS mode 呢,
    //看我所传输的 cmds7 可以发现要传输的第一个参数为 0x00,所以被判别为 HS mode

    MIPI_DBG("write GEN_HDR:%08x\n", data);
    rk32_dsi_set_bits(dsi, data, GEN_HDR);

    i = 10;
    while (!rk32_dsi_get_bits(dsi, gen_cmd_empty) && i--) {
        MIPI_DBG(".");
        udelay(10);
    }
    udelay(10);
    kfree(regs);
    return 0;
}

至此,疑问解决了。
LCD 的 datasheet 也可以发现,像之前所说的,
在 commond mode 的时候,这个参数,
也就是 屏IC 的 CMD,是不会为 0x00 的。
只有在 video mode 下才可能为 0x00。

而参数为 8 字节 和 16 字节 其实都可以,只要不超过 struct dsc_cmd 中定义的大小 400 ,就够了。

本文地址:http://blog.youkuaiyun.com/dearsq/article/details/52369879
欢迎转载,转载请著名出处和作者 Younix~谢谢~

<think>首先,用户的问题是关于在RK3288平台上基于Android 5.1修改LCD横屏和竖屏的代码方法。用户指定了平台是RK3288,系统是Android 5.1。 我需要参考用户提供的引用内容,这些引用似乎是关于RK3288 Android系统的屏幕设置: - 引用[1]:讨论了RK3288支持双屏异显,提到如果两个LCD默认方向不一致,需要修改参数。例子中主屏是MIPI接口。 - 引用[2]:描述了使用LG EDP屏的配置,在dts文件中定义了屏幕参数,括分辨率(2048*1536),并提到将横竖屏对调后显示正常。具体文件是rk3288-rk808.dts和lcd-LP097Qx1.dtsi。 - 引用[3]:Android 5.1中显示方向旋转,讨论了旋转角度(0,90,180,270度),扫描方式(SS和GS),以及开机动画分辨率的调整。 - 引用[4]:关于RK3288 Android 5.1的LVDS配置,括screen-type, lvds-format等参数。 - 引用[5]:RK3288 Android 5.1的HDMI分辨率设置,提到如何查看当前分辨率。 用户的核心需求是修改LCD的横屏和竖屏设置代码。在Android系统中,屏幕方向通常通过设备树(dts文件)和系统属性来控制。 从引用中,我可以提取关键点: - 屏幕方向通常在设备树(dts)文件中定义,如引用[2]中的rk3288-rk808.dts和lcd-LP097Qx1.dtsi。 - 在dts文件中,有参数如screen-type, out-face, clock-frequency, hactive, vactive等。 - 引用[2]提到,将横竖屏对调后显示正常,暗示通过交换hactive和vactive可以改变方向。 - 引用[3]讨论了Android系统阶段的旋转,括设置旋转角度。 所以,修改LCD横屏竖屏设置的方法可能涉及: 1. **修改设备树(dts)文件**:调整屏幕参数,如分辨率的方向。 2. **设置系统属性或旋转角度**:在Android框架中设置屏幕方向。 在Android系统中,屏幕方向由几个层面控制: - **内核层**:通过设备树定义屏幕参数。 - **框架层**:Android的display服务处理旋转。 对于RK3288 Android 5.1,具体步骤可能括: - 编辑dts文件来定义屏幕的分辨率方向。例如,在dts中,hactive和vactive定义了水平和垂直像素数;如果交换它们,可能会改变方向。 - 在Android系统中,设置ro.sf.hwrotation属性来旋转屏幕。 从引用[3]:"进入android系统阶段,可旋转0、90、180、270度",这可以通过设置ro.sf.hwrotation来实现。 在Android源代码中,ro.sf.hwrotation属性用于硬件旋转。 所以,回答的结构应该清晰: 1. **介绍修改方法**:基于引用,总结步骤。 2. **详细步骤**:分步解释如何修改代码。 3. **代码示例**:提供dts文件修改的例子。 4. **注意事项**:提到可能的陷阱,如开机动画分辨率。 最后,生成相关问题。 回答需要使用中文,因为用户指定了"使用中文回答"。 系统级指令要求: - 行内数学表达式用$...$,但这里可能不涉及数学,所以注意如果有变量等。 - 独立公式用$$...$$,但这里可能不需要。 - LaTeX语法正确。 - 添加引用标识,如[^1]。 用户可见层:回答结构清晰,帮助用户逐步解决问题。 步骤: 1. **理解需求**:用户要修改LCD横屏竖屏设置。 2. **参考引用**:结合引用内容,提供具体方法。 3. **步骤分解**: - 修改设备树文件(dts)来定义屏幕方向。 - 设置Android系统属性(如ro.sf.hwrotation)来控制旋转。 - 调整开机动画分辨率(如果需要)。 4. **代码示例**:从引用[2]中提取dts修改例子。 5. **生成相关问题**:在最后添加相关问题。 相关问题示例: - 如何修改Android系统的默认屏幕方向? - RK3288双屏异显如何设置? - 开机动画分辨率不匹配怎么办? 确保回答真实可靠:基于提供的引用和一般知识。</think>### RK3288 Android 5.1 修改LCD横屏竖屏设置代码方法 在RK3288平台上基于Android 5.1修改LCD横屏竖屏设置,主要通过调整设备树(Device Tree Source, DTS)文件和Android系统属性来实现。以下是清晰的步骤指南,基于您提供的引用内容和RK3288 Android 5.1开发经验。修改的核心括**内核层设备树配置**和**Android框架层旋转设置**,确保屏幕方向正确适配。 --- ### 步骤1: 修改设备树(DTS)文件 设备树文件(`.dts`或`.dtsi`)定义了屏幕的硬件参数,如分辨率、扫描方向和接口类型。这是修改屏幕方向的基础。 1. **定位和编辑DTS文件**: - RK3288的DTS文件通常位于Linux内核源码的`arch/arm/boot/dts/`目录下,例如`rk3288-rk808.dts`或自定义屏的DTS文件(如`lcd-LP097Qx1.dtsi`)。 - 关键参数: - `screen-type`: 指定屏幕类型(如`SCREEN_LVDS`、`SCREEN_EDP`)。 - `hactive`和`vactive`: 定义水平(横屏)和垂直(竖屏)像素数。**交换这两个值可改变默认方向**。 - `out-face`: 输出格式(如`OUT_P888`)。 - `clock-frequency`: 屏幕时钟频率。 - **修改示例**(基于引用[2]和[4]): - 假设原始DTS文件定义竖屏(例如`hactive = <1536>; vactive = <2048>;`)。 - 修改为横屏:交换`hactive`和`vactive`值。 ```dts // 文件:lcd-LP097Qx1.dtsi(示例) / { disp_timings: display-timings { native-mode = <&timing0>; timing0: timing0 { screen-type = <SCREEN_EDP>; // 屏幕类型 out-face = <OUT_P666>; // 输出格式 clock-frequency = <205000000>; // 时钟频率 hactive = <2048>; // 修改后:水平像素(横屏) vactive = <1536>; // 修改后:垂直像素(竖屏) // 其他参数(如hfront-porch, hback-porch等)需保持一致 }; }; }; ``` - **注意**:如果屏幕是LVDS接口(如引用[4]),还需检查`lvds-format`和`color-mode`参数是否匹配硬件。 2. **编译和烧录DTS**: - 修改后,重新编译内核并烧录到设备: ```bash make rk3288-rk808.dtb # 生成dtb文件 fastboot flash boot new_kernel.img # 烧录内核 ``` - 验证修改:启动后检查`/sys/class/graphics/fb0/modes`文件,确认分辨率是否更新。 --- ### 步骤2: 设置Android系统旋转属性 在Android框架层,通过系统属性控制屏幕旋转角度。这适用于系统启动后的软件旋转。 1. **修改`ro.sf.hwrotation`属性**: - 该属性定义硬件旋转角度(0, 90, 180, 270度)。在RK3288 Android 5.1中,需编辑`system.prop`文件。 - 文件路径:`/device/rockchip/rk3288/system.prop`(或类似路径)。 - **添加或修改行**: ```properties ro.sf.hwrotation=90 # 设置旋转90度(竖屏转横屏或反之) ``` - **角度选择**: - 0度:默认横屏。 - 90度:竖屏(逆时针旋转)。 - 180度:倒置。 - 270度:竖屏(顺时针旋转)。 - 引用[3]提到,扫描方式(SS和GS)影响旋转效果。常见设置: - SS=1&GS=0时,需旋转270度。 - SS=0&GS=1时,旋转90度即可正常显示[^3]。 2. **调整开机动画分辨率**: - 如果旋转后开机动画显示异常(如只显示部分内容),需修改开机动画分辨率: - 编辑`bootanimation.zip`中的`desc.txt`文件,匹配旋转后的屏幕分辨率。 - **示例**(引用[3]): - 原始竖屏分辨率:720x1280。 - 旋转为横屏后:改为1280x720。 ```plaintext # desc.txt 内容 1280 720 30 # 宽度 高度 帧率 p 1 0 part0 ``` - 将修改后的`bootanimation.zip`推送到`/system/media/`目录。 --- ### 步骤3: 验证和调试 - **检查当前方向**: - 在终端运行: ```bash adb shell cat /sys/class/graphics/fb0/modes # 查看分辨率方向 adb shell getprop ro.sf.hwrotation # 查看旋转角度 ``` - 对于HDMI,可参考引用[5]:`cat /sys/class/display/HDMI/mode`[^5]。 - **常见问题**: - **双屏异显方向不一致**:如引用[1]所述,修改每个屏的DTS参数(`hactive`/`vactive`)来对齐方向[^1]。 - **显示异常**:确保DTS的`screen-type`(如`SCREEN_EDP`或`SCREEN_LVDS`)与实际硬件匹配(引用[2][^2]和[4][^4])。 - **性能问题**:旋转可能增加GPU负载,测试帧率是否稳定。 --- ### 注意事项 - **备份文件**:修改DTS或系统属性前,备份原文件。 - **硬件兼容性**:不同屏幕接口(LVDS, EDP, MIPI)参数不同,参考屏厂数据手册。 - **系统升级**:Android 5.1的代码结构可能因厂商定制而异,建议基于RK3288 SDK操作。 - **引用说明**:本方法基于RK3288 Android 5.1的典型实现,具体细节请参考设备树文档和Rockchip官方指南[^1][^2][^3][^4][^5]。 通过以上步骤,您可以灵活配置横屏或竖屏显示。如果遇到问题,提供更多硬件细节(如屏幕型号和接口)可进一步优化。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值