高通SDM450 副屏mipi转EDP的调试基础是在之前主屏mipi转EDP的基础上面实现的,调试难度比主屏mipi转EDP简单一些,本来是也是在BootLoader的阶段对lt8911进行初始化,但是SDM450 BootLoader阶段的I2C2初始化一直有问题,可能是域错了,厂家也没给具体的实现,后来就放弃了在BootLoader阶段初始化lt8911,毕竟副屏是要进入Android才有图像输出,因而选择在kernel阶段初始化lt8911.本次调试副屏mipi转EDP,lt8911exb 的I2C接到SDM450的I2C2接口上,其他硬件接口跟主屏mipi转EDP差不多,只是一些控制上电和复位的管脚不一样,具体的硬件电路不再贴出来,可以参考之前的主屏mipi转EDP的电路
主屏mipi转EDP 调试过程 原文链接:https://blog.csdn.net/u010852497/article/details/115266158
调试过程简要:
1、LT8911硬件部分各个电源电压是否正常,晶振是否起振,I2C电平状态是否正常
2、添加LT8911设备,注意包括电源、复位的控制IO口,挂载在LT8911上屏幕是多少lane的
3、添加LT8911驱动,确保通信正常,可以出彩条
4、添加SDM450副屏部分参数,注意主控跟LT8911连接是几lane的
一、LT8911硬件部分各个电源电压是否正常,晶振是否起振,I2C电平状态是否正常
这部分的调试使用示波器来测量,一定要确保LT8911能够正常工作,由于调试过程没保存好图片,这里不贴出来具体测量过程
二、添加LT8911设备
kernel4.9来说,设备的描述采用dts设备树描述,我们副屏的LT8911是接到SDM450的I2C2,所有可以要将LT8911挂到I2C2上面
kernel/msm-4.9/arch/arm64/boot/dts/qcom/msm8953-mtp.dtsi
&i2c_2 {
lt8911exb@29 {
compatible = "lontium,lt8911exb";
reg = <0x29>;
power-gpio = <&tlmm 25 0x0>;//LCD0_EN
reset-gpio = <&tlmm 87 0x0>;//LT8912_RSTN
//bl-gpio = <&tlmm 44 0x0>;//LCD0_BL_EN
lontium,pclk = <73248000>;//<148000000>;
lontium,hfp = <94>;
lontium,hs = <16>;
lontium,hbp = <50>;
lontium,hact = <1366>;
lontium,vfp = <13>;
lontium,vs = <6>;
lontium,vbp = <13>;
lontium,vact = <768>;
lontium,mipi_lane = <4>;
lontium,lane_cnt = <1>;
lontium,color = <1>; //1//Color Depth 0:6bit 1:8bit
lontium,test = <0>;
};
注意事项:
1、本次调试的地址是0x29,具体的要根据LT8911的硬件决定
2、pclk = (hfp+hs+hbo+hact)*(vfp+vs+vbp+vact)*60 这个具体也是要看驱动的解析
3、mipi_lane 主控和lt8911连接的lane数
4、lane_cnt lt8911和屏幕连接的lane数
5、test 是否开启彩条测试模式
三、添加LT8911的驱动
kernel/msm-4.9/drivers/video/lt8911exb/lt8911exb.c
#include <linux/irq.h>
#include <linux/platform_device.h>
#include <linux/pinctrl/consumer.h>
#include <linux/input/mt.h>
#include <linux/slab.h>
#include "lt8911exb.h"
/*******************************************************
Function:
Write data to the i2c slave device.
Input:
client: i2c device.
buf[0]: write start address.
buf[1~len-1]: data buffer
len: LT8911EXB_ADDR_LENGTH + write bytes count
Output:
numbers of i2c_msgs to transfer:
0: succeed, otherwise: failed
*********************************************************/
int lt8911exb_i2c_write(struct i2c_client *client, u8 *buf, int len)
{
unsigned int pos = 0, transfer_length = 0;
u8 address = buf[0];
unsigned char put_buf[64];
int retry, ret = 0;
struct i2c_msg msg = {
.addr = client->addr,
.flags = !I2C_M_RD,
};
if(likely(len < sizeof(put_buf))) {
/* code optimize,use stack memory*/
msg.buf = &put_buf[0];
} else {
msg.buf = kmalloc(len > I2C_MAX_TRANSFER_SIZE
? I2C_MAX_TRANSFER_SIZE : len, GFP_KERNEL);
if(!msg.buf)
return -ENOMEM;
}
len -= LT8911EXB_ADDR_LENGTH;
while(pos != len) {
if(unlikely(len - pos > I2C_MAX_TRANSFER_SIZE - LT8911EXB_ADDR_LENGTH))
transfer_length = I2C_MAX_TRANSFER_SIZE - LT8911EXB_ADDR_LENGTH;
else
transfer_length = len - pos;
msg.buf[0] = address;
msg.len = transfer_length + LT8911EXB_ADDR_LENGTH;
memcpy(&msg.buf[LT8911EXB_ADDR_LENGTH], &buf[LT8911EXB_ADDR_LENGTH + pos], transfer_length);
for(retry = 0; retry < RETRY_MAX_TIMES; retry++) {
if(likely(i2c_transfer(client->adapter, &msg, 1) == 1)) {
pos += transfer_length;
address += transfer_length;
break;
}
dev_info(&client->dev, "I2C write retry[%d]\n", retry + 1);
udelay(2000);
}
if(unlikely(retry == RETRY_MAX_TIMES)) {
dev_err(&client->dev,
"I2c write failed,dev:%02x,reg:%02x,size:%u\n",
client->addr, address, len);
ret = -EAGAIN;
goto write_exit;
}
}
write_exit:
if(len + LT8911EXB_ADDR_LENGTH >= sizeof(put_buf))
kfree(msg.buf);
return ret;
}
/*******************************************************
Function:
Read data from the i2c slave device.
Input:
client: i2c device.
buf[0]: read start address.
buf[1~len-1]: data buffer
len: LT8911EXB_ADDR_LENGTH + read bytes count
Output:
numbers of i2c_msgs to transfer:
0: succeed, otherwise: failed
*********************************************************/
int lt8911exb_i2c_read(struct i2c_client *client, u8 *buf, int len)
{
unsigned int transfer_length = 0;
unsigned int pos = 0;
u8 address = buf[0];
unsigned char get_buf[64], addr_buf[2];
int retry, ret = 0;
struct i2c_msg msgs[] = {
{
.addr = client->addr,
.flags = !I2C_M_RD,
.buf = &addr_buf[0],
.len = LT8911EXB_ADDR_LENGTH,
}, {
.addr = client->addr,
.flags = I2C_M_RD,
}
};
len -= LT8911EXB_ADDR_LENGTH;
if(likely(len < sizeof(get_buf))) {
/* code optimize, use stack memory */
msgs[1].buf = &get_buf[0];
} else {
msgs[1].buf = kzalloc(len > I2C_MAX_TRANSFER_SIZE
? I2C_MAX_TRANSFER_SIZE : len, GFP_KERNEL);
if(!msgs[1].buf)
return -ENOMEM;
}
while(pos != len) {
if(unlikely(len - pos > I2C_MAX_TRANSFER_SIZE))
transfer_length = I2C_MAX_TRANSFER_SIZE;
else
transfer_length = len - pos;
msgs[0].buf[0] = address;
msgs[1].len = transfer_length;
for(retry = 0; retry < RETRY_MAX_TIMES; retry++) {
if(likely(i2c_transfer(client->adapter, msgs, 2) == 2)) {
memcpy(&buf[LT8911EXB_ADDR_LENGTH + pos], msgs[1].buf, transfer_length);
pos += transfer_length;
address += transfer_length;
break;
}
dev_info(&client->dev, "I2c read retry[%d]:0x%x\n",
retry + 1, address);
udelay(2000);
}
if(unlikely(retry == RETRY_MAX_TIMES)) {
dev_err(&client->dev,

本文详细介绍了如何在SDM450平台上调试副屏MIPi接口转EDP,包括LT8911硬件初始化、设备添加、驱动配置及参数设置,重点在于解决BootLoader阶段问题并调整I2C通信。
1350

被折叠的 条评论
为什么被折叠?



