高通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_ENreset-gpio = <&tlmm 87 0x0>;//LT8912_RSTN //bl-gpio = <&tlmm 44 0x0>;//LCD0_BL_ENlontium,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:8bitlontium,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 bufferlen: LT8911EXB_ADDR_LENGTH + write bytes countOutput: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;elsetransfer_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 bufferlen: LT8911EXB_ADDR_LENGTH + read bytes countOutput: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;elsetransfer_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,"I2c read failed,dev:%02x,reg:%02x,size:%u\n",client->addr, address, len);ret = -EAGAIN;goto read_exit;}}read_exit:if(len >= sizeof(get_buf))kfree(msgs[1].buf);return ret;
}int lt8911exb_write(struct i2c_client *client, u8 addr, u8 data)
{u8 buf[2] = {addr, data};int ret = -1;ret = lt8911exb_i2c_write(client, buf, 2);return ret;
}u8 lt8911exb_read(struct i2c_client *client, u8 addr)
{u8 buf[2] = {addr};int ret = -1;ret = lt8911exb_i2c_read(client, buf, 2);if(ret == 0) {return buf[1];} else {return 0;}
}void lt8911exb_reset_guitar(struct i2c_client *client)
{struct lt8911exb_data *lt8911exb = i2c_get_clientdata(client);dev_info(&client->dev, "Guitar reset");if(!gpio_is_valid(lt8911exb->rst_gpio)) {dev_warn(&client->dev, "reset failed no valid reset gpio");return;}gpio_direction_output(lt8911exb->rst_gpio, 1);mdelay(100); //150msgpio_direction_output(lt8911exb->rst_gpio, 0);mdelay(100);gpio_direction_output(lt8911exb->rst_gpio, 1);mdelay(10);//gpio_direction_output(lt8911exb->bl_gpio, 1);}static int lt8911exb_parse_dt(struct device *dev,struct lt8911exb_data *pdata)
{int ret = 0;struct device_node *np = dev->of_node;pdata->pwr_gpio = of_get_named_gpio(np, "power-gpio", 0);if(!gpio_is_valid(pdata->pwr_gpio)) {dev_err(dev, "No valid pwr gpio");return -1;}pdata->rst_gpio = of_get_named_gpio(np, "reset-gpio", 0);if(!gpio_is_valid(pdata->rst_gpio)) {dev_err(dev, "No valid rst gpio");return -1;}pdata->bl_gpio = of_get_named_gpio(np, "bl-gpio", 0);if(!gpio_is_valid(pdata->rst_gpio)) {dev_err(dev, "No valid bl gpio");return -1;}ret = of_property_read_u32(np, "lontium,test", &pdata->test);if (ret) {dev_err(dev, "Parse test failed");return -1;}ret = of_property_read_u32(np, "lontium,mipi_lane", &pdata->mipi_lane);if (ret) {dev_err(dev, "Parse mipi_lane failed");return -1;}ret = of_property_read_u32(np, "lontium,lane_cnt", &pdata->lane_cnt);if (ret) {dev_err(dev, "Parse lane_cnt failed");return -1;}ret = of_property_read_u32(np, "lontium,color", &pdata->color);if (ret) {dev_err(dev, "Parse color failed");return -1;}ret = of_property_read_u32(np, "lontium,lane_cnt", &pdata->lane_cnt);if (ret) {dev_err(dev, "Parse lane_cnt failed");return -1;}ret = of_property_read_u32(np, "lontium,hact", &pdata->hact);if (ret) {dev_err(dev, "Parse hact failed");return -1;}ret = of_property_read_u32(np, "lontium,hact", &pdata->hact);if (ret) {dev_err(dev, "Parse hact failed");return -1;}ret = of_property_read_u32(np, "lontium,vact", &pdata->vact);if (ret) {dev_err(dev, "Parse vact failed");return -1;}ret = of_property_read_u32(np, "lontium,hbp", &pdata->hbp);if (ret) {dev_err(dev, "Parse hbp failed");return -1;}ret = of_property_read_u32(np, "lontium,hfp", &pdata->hfp);if (ret) {dev_err(dev, "Parse hfp failed");return -1;}ret = of_property_read_u32(np, "lontium,hs", &pdata->hs);if (ret) {dev_err(dev, "Parse hs failed");return -1;}ret = of_property_read_u32(np, "lontium,vbp", &pdata->vbp);if (ret) {dev_err(dev, "Parse vbp failed");return -1;}ret = of_property_read_u32(np, "lontium,vfp", &pdata->vfp);if (ret) {dev_err(dev, "Parse vfp failed");return -1;}ret = of_property_read_u32(np, "lontium,vs", &pdata->vs);if (ret) {dev_err(dev, "Parse vs failed");return -1;}ret = of_property_read_u32(np, "lontium,pclk", &pdata->pclk);if (ret) {dev_err(dev, "Parse pclk failed");return -1;} else {pdata->pclk = pdata->pclk/10000; // 10khz}pdata->htotal = pdata->hact + pdata->hbp + pdata->hfp + pdata->hs;pdata->vtotal = pdata->vact + pdata->vbp + pdata->vfp + pdata->vs;return 0;
}static int lt8911exb_request_io_port(struct lt8911exb_data *lt8911exb)
{int ret = 0;if(gpio_is_valid(lt8911exb->pwr_gpio)) {ret = gpio_request(lt8911exb->pwr_gpio, "lt8911exb_pwr");if(ret < 0) {dev_err(&lt8911exb->client->dev,"Failed to request GPIO:%d, ERRNO:%d\n",(s32)lt8911exb->pwr_gpio, ret);return -ENODEV;}gpio_direction_output(lt8911exb->pwr_gpio , 1);dev_info(&lt8911exb->client->dev, "Success request pwr-gpio\n");}if(gpio_is_valid(lt8911exb->rst_gpio)) {ret = gpio_request(lt8911exb->rst_gpio, "lt8911exb_rst");if(ret < 0) {dev_err(&lt8911exb->client->dev,"Failed to request GPIO:%d, ERRNO:%d\n",(s32)lt8911exb->rst_gpio, ret);if(gpio_is_valid(lt8911exb->pwr_gpio))gpio_free(lt8911exb->pwr_gpio);return -ENODEV;}//gpio_direction_input(lt8911exb->rst_gpio);dev_info(&lt8911exb->client->dev,  "Success request rst-gpio\n");}if(gpio_is_valid(lt8911exb->bl_gpio)) {ret = gpio_request(lt8911exb->bl_gpio, "lt8911exb_bl");if(ret < 0) {dev_err(&lt8911exb->client->dev,"Failed to request GPIO:%d, ERRNO:%d\n",(s32)lt8911exb->bl_gpio, ret);if(gpio_is_valid(lt8911exb->pwr_gpio))gpio_free(lt8911exb->pwr_gpio);if(gpio_is_valid(lt8911exb->rst_gpio))gpio_free(lt8911exb->rst_gpio);return -ENODEV;}dev_info(&lt8911exb->client->dev,  "Success request bl-gpio\n");}return 0;
}static int lt8911exb_i2c_test(struct i2c_client *client)
{u8 retry = 0;u8 chip_id_h = 0, chip_id_m = 0, chip_id_l = 0;int ret = -EAGAIN;while(retry++ < 3) {ret = lt8911exb_write(client, 0xff, 0x81);if(ret < 0) {dev_err(&client->dev, "LT8911EXB i2c test write addr:0xff failed\n");continue;}ret = lt8911exb_write(client, 0x08, 0x7f);if(ret < 0) {dev_err(&client->dev, "LT8911EXB i2c test write addr:0x08 failed\n");continue;}chip_id_l = lt8911exb_read(client, 0x00);chip_id_m = lt8911exb_read(client, 0x01);chip_id_h = lt8911exb_read(client, 0x02);// LT8911EXB i2c test success chipid: 0xe0517dev_info(&client->dev, "LT8911EXB i2c test success chipid: 0x%x%x%x\n", chip_id_h, chip_id_m, chip_id_l);//        if (chip_id_h == 0 && chip_id_l == 0) {
//            dev_err(&client->dev, "LT8911EXB i2c test failed time %d\n", retry);
//            continue;
//        }ret = 0;break;}return ret;
}void lt8911exb_dpcd_write(struct i2c_client *client, u32 address, u8 Data)
{u8 address_h = 0x0f & (address >> 16);u8 address_m = 0xff & (address >> 8);u8 address_l = 0xff & address;u8 ret = 0x00;lt8911exb_write(client, 0xff, 0xa6);lt8911exb_write(client, 0x2b, (0x80|address_h));lt8911exb_write(client, 0x2b,address_m); //addr[15:8]lt8911exb_write(client, 0x2b,address_l); //addr[7:0]lt8911exb_write(client, 0x2b,0x00); //data lenthlt8911exb_write(client, 0x2b,Data); //datalt8911exb_write(client, 0x2c,0x00); //start Aux read edidmdelay(20);ret = lt8911exb_read(client, 0x25);if((ret&0x0f)== 0x0c) {return;}
}u8 lt8911exb_dpcd_read(struct i2c_client *client, u32 address)
{u8 read_cnt = 0x03;u8 dpcd_value = 0x00;u8 address_h = 0x0f & (address >> 16);u8 address_m = 0xff & (address >> 8);u8 address_l = 0xff & address;lt8911exb_write(client, 0xff, 0x80);lt8911exb_write(client, 0x62, 0xbd);lt8911exb_write(client, 0x62, 0xbf); //ECO(AUX reset)lt8911exb_write(client, 0x36, 0x00);lt8911exb_write(client, 0x30, 0x8f); //0x91lt8911exb_write(client, 0x33, address_l);lt8911exb_write(client, 0x34, address_m);lt8911exb_write(client, 0x35, address_h);lt8911exb_write(client, 0x36, 0x20);mdelay(2); //The necessaryif(lt8911exb_read(client, 0x39) == 0x01) {dpcd_value = lt8911exb_read(client, 0x38);} else {while((lt8911exb_read(client, 0x39) != 0x01) && (read_cnt > 0)) {lt8911exb_write(client, 0x36, 0x00);lt8911exb_write(client, 0x36, 0x20);read_cnt--;mdelay(2);}if(lt8911exb_read(client, 0x39) == 0x01) {dpcd_value = lt8911exb_read(client, 0x38);}}return dpcd_value;
}void lt8911exb_mipi_video_timing(struct i2c_client *client)
{struct lt8911exb_data *lt8911exb = i2c_get_clientdata(client);lt8911exb_write(client, 0xff, 0xd0);lt8911exb_write(client, 0x0d, (u8)(lt8911exb->vtotal / 256));lt8911exb_write(client, 0x0e, (u8)(lt8911exb->vtotal % 256));    //vtotallt8911exb_write(client, 0x0f, (u8)(lt8911exb->vact / 256));lt8911exb_write(client, 0x10, (u8)(lt8911exb->vact % 256));      //vactivelt8911exb_write(client, 0x11, (u8)(lt8911exb->htotal / 256));lt8911exb_write(client, 0x12, (u8)(lt8911exb->htotal % 256));    //htotallt8911exb_write(client, 0x13, (u8)(lt8911exb->hact / 256));lt8911exb_write(client, 0x14, (u8)(lt8911exb->hact % 256));      //hactivelt8911exb_write(client, 0x15, (u8)(lt8911exb->vs % 256));        //vsalt8911exb_write(client, 0x16, (u8)(lt8911exb->hs % 256));        //hsalt8911exb_write(client, 0x17, (u8)(lt8911exb->vfp / 256));lt8911exb_write(client, 0x18, (u8)(lt8911exb->vfp % 256));       //vfplt8911exb_write(client, 0x19, (u8)(lt8911exb->hfp / 256));lt8911exb_write(client, 0x1a, (u8)(lt8911exb->hfp % 256));       //hfp
}void lt8911exb_edp_video_cfg(struct i2c_client *client)
{struct lt8911exb_data *lt8911exb = i2c_get_clientdata(client);lt8911exb_write(client, 0xff, 0xa8);lt8911exb_write(client, 0x2d, 0x88); // MSA from registerlt8911exb_write(client, 0x05, (u8)(lt8911exb->htotal / 256));lt8911exb_write(client, 0x06, (u8)(lt8911exb->htotal % 256));lt8911exb_write(client, 0x07, (u8)((lt8911exb->hs + lt8911exb->hbp) / 256));lt8911exb_write(client, 0x08, (u8)((lt8911exb->hs + lt8911exb->hbp) % 256));lt8911exb_write(client, 0x09, (u8)(lt8911exb->hs / 256));lt8911exb_write(client, 0x0a, (u8)(lt8911exb->hs % 256));lt8911exb_write(client, 0x0b, (u8)(lt8911exb->hact / 256));lt8911exb_write(client, 0x0c, (u8)(lt8911exb->hact % 256));lt8911exb_write(client, 0x0d, (u8)(lt8911exb->vtotal / 256));lt8911exb_write(client, 0x0e, (u8)(lt8911exb->vtotal % 256));lt8911exb_write(client, 0x11, (u8)((lt8911exb->vs + lt8911exb->vbp) / 256));lt8911exb_write(client, 0x12, (u8)((lt8911exb->vs + lt8911exb->vbp) % 256));lt8911exb_write(client, 0x14, (u8)(lt8911exb->vs % 256));lt8911exb_write(client, 0x15, (u8)(lt8911exb->vact / 256));lt8911exb_write(client, 0x16, (u8)(lt8911exb->vact % 256));
}void lt8911exb_setup(struct i2c_client *client)
{u8 i;u8 pcr_pll_postdiv;u8 pcr_m;u16 temp16;struct lt8911exb_data *lt8911exb = i2c_get_clientdata(client);/* init */lt8911exb_write(client, 0xff, 0x81);lt8911exb_write(client, 0x49, 0xff); //enable 0x87xxlt8911exb_write(client, 0xff, 0x82); //GPIO test outputlt8911exb_write(client, 0x5a, 0x0e);/* mipi Rx analog */lt8911exb_write(client, 0xff, 0x82);lt8911exb_write(client, 0x32, 0x51);lt8911exb_write(client, 0x35, 0x42); //EQ currentlt8911exb_write(client, 0x4c, 0x0c);lt8911exb_write(client, 0x4d, 0x00);lt8911exb_write(client, 0x3a, 0x44); // 11 // 22 / 33 / 55 / 66 / 77lt8911exb_write(client, 0x3b, 0x44); // 11 // 22 / 33 / 55 / 66 / 77/* dessc_pcr  pll analog */lt8911exb_write(client, 0xff, 0x82);lt8911exb_write(client, 0x6a, 0x40);lt8911exb_write(client, 0x6b, 0x40);temp16 = lt8911exb->pclk;if(lt8911exb->pclk < 8800) {lt8911exb_write(client, 0x6e, 0x82); //0x44:pre-div = 2 ,pixel_clk=44~ 88MHzpcr_pll_postdiv = 0x08;} else {lt8911exb_write(client, 0x6e, 0x81); //0x40:pre-div = 1, pixel_clk =88~176MHzpcr_pll_postdiv = 0x04;}pcr_m = (u8)(temp16 * pcr_pll_postdiv / 25 / 100);/* dessc pll digital */lt8911exb_write(client, 0xff, 0x85);lt8911exb_write(client, 0xa9, 0x31);lt8911exb_write(client, 0xaa, 0x17);lt8911exb_write(client, 0xab, 0xba);lt8911exb_write(client, 0xac, 0xe1);lt8911exb_write(client, 0xad, 0x47);lt8911exb_write(client, 0xae, 0x01);lt8911exb_write(client, 0xae, 0x11);/* Digital Top */lt8911exb_write(client, 0xff, 0x85);lt8911exb_write(client, 0xc0, 0x01); //select mipi Rx
#ifdef _6bit_lt8911exb_write(client, 0xb0, 0xd0); //enable dither
#elselt8911exb_write(client, 0xb0, 0x00); // disable dither
#endif/* mipi Rx Digital */lt8911exb_write(client, 0xff, 0xd0);lt8911exb_write(client, 0x00, lt8911exb->mipi_lane % 4); // 0: 4 Lane / 1: 1 Lane / 2 : 2 Lane / 3: 3 Lanelt8911exb_write(client, 0x02, 0x08); //settlelt8911exb_write(client, 0x08, 0x00);lt8911exb_write(client, 0x0a, 0x12); //pcr modelt8911exb_write(client, 0x0c, 0x40);lt8911exb_write(client, 0x1c, 0x3a);//lt8911exb_write(client,0x2d,0x19); //M up limitlt8911exb_write(client, 0x31, 0x0a);
//  lt8911exb_write(client, 0x21, 0x4f );
//  lt8911exb_write(client, 0x22, 0xff );
//  lt8911exb_write(client, 0x2a, 0x08 );lt8911exb_write(client, 0x3f, 0x10);lt8911exb_write(client, 0x40, 0x20);lt8911exb_write(client, 0x41, 0x30);if (lt8911exb->test) {dev_info(&client->dev, "LT8911EXB i2c test \n");lt8911exb_write(client, 0x26, (pcr_m | 0x80));} else {lt8911exb_write(client, 0x26, pcr_m);}lt8911exb_write(client, 0xff, 0x81); //PCR resetlt8911exb_write(client, 0x03, 0x7b);lt8911exb_write(client, 0x03, 0xff);/* Txpll 2.7G*/lt8911exb_write(client, 0xff, 0x87);lt8911exb_write(client, 0x19, 0x31);lt8911exb_write(client, 0xff, 0x82);lt8911exb_write(client, 0x02, 0x42);lt8911exb_write(client, 0x03, 0x00);lt8911exb_write(client, 0x03, 0x01);lt8911exb_write(client, 0xff, 0x81);lt8911exb_write(client, 0x09, 0xfc);lt8911exb_write(client, 0x09, 0xfd);lt8911exb_write(client, 0xff, 0x87);lt8911exb_write(client, 0x0c, 0x11);for(i = 0; i < 5; i++) { //Check Tx PLLmdelay(5);if(lt8911exb_read(client, 0x37) & 0x02) {dev_info(&client->dev,  "LT8911 tx pll locked");break;} else {dev_info(&client->dev,  "LT8911 tx pll unlocked");lt8911exb_write(client, 0xff, 0x81);lt8911exb_write(client, 0x09, 0xfc);lt8911exb_write(client, 0x09, 0xfd);lt8911exb_write(client, 0xff, 0x87);lt8911exb_write(client, 0x0c, 0x10);lt8911exb_write(client, 0x0c, 0x11);}}/* tx phy */lt8911exb_write(client, 0xff, 0x82);lt8911exb_write(client, 0x11, 0x00);lt8911exb_write(client, 0x13, 0x10);lt8911exb_write(client, 0x14, 0x0c);lt8911exb_write(client, 0x14, 0x08);lt8911exb_write(client, 0x13, 0x20);lt8911exb_write(client, 0xff, 0x82);lt8911exb_write(client, 0x0e, 0x25);lt8911exb_write(client, 0x12, 0xff);
//  lt8911exb_write(client, 0xff, 0x80 );
//  lt8911exb_write(client, 0x40, 0x22 );/*eDP Tx Digital */lt8911exb_write(client, 0xff, 0xa8);if (lt8911exb->test) {lt8911exb_write(client, 0x24, 0x50); // bit2 ~ bit 0 : test panttern image modelt8911exb_write(client, 0x25, 0x70); // bit6 ~ bit 4 : test Pattern colorlt8911exb_write(client, 0x27, 0x50); //0x50:Pattern; 0x10:mipi video} else {lt8911exb_write(client, 0x27, 0x10); //0x50:Pattern; 0x10:mipi video}if(lt8911exb->color) {//8bitlt8911exb_write(client, 0x17, 0x10);lt8911exb_write(client, 0x18, 0x20);} else {//6bitlt8911exb_write(client, 0x17, 0x00);lt8911exb_write(client, 0x18, 0x00);}lt8911exb_write(client, 0xff, 0xa0);lt8911exb_write(client, 0x00, 0x08);lt8911exb_write(client, 0x01, 0x00);
}/* mipi should be ready before configuring below video check setting*/
void lt8911exb_video_check(struct i2c_client *client)
{u32 ret = 0x00;/* mipi byte clk check*/lt8911exb_write(client, 0xff, 0x85);lt8911exb_write(client, 0x1d, 0x00); //FM select byte clklt8911exb_write(client, 0x40, 0xf7);lt8911exb_write(client, 0x41, 0x30);lt8911exb_write(client, 0xa1, 0x82); //eDP scramble mode; //video chech from mipi//  lt8911exb_write(client, 0x17, 0xf0 ); //0xf0:Close scramble; 0xD0 : Open scramblelt8911exb_write(client, 0xff, 0x81); //video check rstlt8911exb_write(client, 0x09, 0x7d);lt8911exb_write(client, 0x09, 0xfd);lt8911exb_write(client, 0xff, 0x85);mdelay(30);if(lt8911exb_read(client, 0x50) == 0x03) {ret = lt8911exb_read(client, 0x4d);ret = ret * 256 + lt8911exb_read(client, 0x4e);ret = ret * 256 + lt8911exb_read(client, 0x4f);dev_info(&client->dev,  "video check: mipi clk = %d", ret); //mipi clk = ret * 1000} else {dev_info(&client->dev,  "video check: mipi clk unstable");}/* mipi vtotal check*/ret    = lt8911exb_read(client, 0x76);ret    = ret * 256 + lt8911exb_read(client, 0x77);dev_info(&client->dev,  "video check: Vtotal = %d", ret);/* mipi word count check*/lt8911exb_write(client, 0xff, 0xd0);ret = lt8911exb_read(client, 0x82);ret = ret * 256 + lt8911exb_read(client, 0x83);ret = ret / 3;dev_info(&client->dev,  "video check: Hact(word counter) = %d", ret);/* mipi Vact check*/ret    = lt8911exb_read(client, 0x85);ret    = ret * 256 + lt8911exb_read(client, 0x86);dev_info(&client->dev,  "video check: Vact = %d", ret);
}void lt8911exb_link_train(struct i2c_client *client)
{struct lt8911exb_data *lt8911exb = i2c_get_clientdata(client);lt8911exb_write(client, 0xff, 0x85);lt8911exb_write(client, 0xa1, 0x82);   // eDP scramble mode;/* Aux operater init */lt8911exb_write(client,0xff,0xac);lt8911exb_write(client,0x00,0x20);  //Soft Link trainlt8911exb_write(client,0xff,0xa6);lt8911exb_write(client,0x2a,0x01);lt8911exb_dpcd_write(client, 0x010a, 0x01);mdelay(10);lt8911exb_dpcd_write(client, 0x0102, 0x00);mdelay(10);lt8911exb_dpcd_write(client, 0x010a, 0x01);mdelay(200);/* Aux setup */lt8911exb_write(client, 0xff, 0xac);lt8911exb_write(client, 0x00, 0x60);  //Soft Link trainlt8911exb_write(client, 0xff, 0xa6);lt8911exb_write(client, 0x2a, 0x00);lt8911exb_write(client, 0xff, 0x81);lt8911exb_write(client, 0x07, 0xfe);lt8911exb_write(client, 0x07, 0xff);lt8911exb_write(client, 0x0a, 0xfc);lt8911exb_write(client, 0x0a, 0xfe);/* link train */lt8911exb_write(client, 0xff, 0x85);lt8911exb_write(client, 0x1a, lt8911exb->lane_cnt);// lt8911exb_write(client,0x13,0xd1);lt8911exb_write(client, 0xff, 0xac);lt8911exb_write(client, 0x00, 0x64);lt8911exb_write(client, 0x01, 0x0a);lt8911exb_write(client, 0x0c, 0x85);lt8911exb_write(client, 0x0c, 0xc5);
}void lt8911exb_config(struct i2c_client *client)
{lt8911exb_mipi_video_timing(client); //defualt setting is 1080Plt8911exb_edp_video_cfg(client);lt8911exb_setup(client);lt8911exb_video_check(client); //just for Check MIPI Inputlt8911exb_link_train(client);
}static int lt8911exb_probe(struct i2c_client * client, const struct i2c_device_id * id)
{int ret = -1;struct lt8911exb_data *lt8911exb;/* do NOT remove these logs */dev_info(&client->dev, "LT8911EXB Driver Version: %s\n", LT8911EXB_DRIVER_VERSION);dev_info(&client->dev, "LT8911EXB I2C Address: 0x%02x\n", client->addr);if(!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {dev_err(&client->dev, "Failed check I2C functionality");return -ENODEV;}lt8911exb = devm_kzalloc(&client->dev, sizeof(*lt8911exb), GFP_KERNEL);if(lt8911exb == NULL) {dev_err(&client->dev, "Failed alloc lt8911exb memory");return -ENOMEM;}if(client->dev.of_node) {ret = lt8911exb_parse_dt(&client->dev, lt8911exb);if(ret < 0) {dev_err(&client->dev, "Failed parse dlt8911exb\n");goto exit_free_client_data;}}lt8911exb->client = client;i2c_set_clientdata(client, lt8911exb);ret = lt8911exb_request_io_port(lt8911exb);if(ret < 0) {dev_err(&client->dev, "Failed request IO port\n");goto exit_free_client_data;}lt8911exb_reset_guitar(client);ret = lt8911exb_i2c_test(client);if(ret < 0) {dev_err(&client->dev, "Failed communicate with IC use I2C\n");goto exit_free_io_port;}lt8911exb_config(client);mdelay(200);dev_info(&client->dev, "LT8911EXB setup finish.\n");return 0;exit_free_io_port:if(gpio_is_valid(lt8911exb->rst_gpio))gpio_free(lt8911exb->rst_gpio);if(gpio_is_valid(lt8911exb->pwr_gpio))gpio_free(lt8911exb->pwr_gpio);if(gpio_is_valid(lt8911exb->bl_gpio))gpio_free(lt8911exb->bl_gpio);exit_free_client_data:devm_kfree(&client->dev, lt8911exb);i2c_set_clientdata(client, NULL);return ret;
}static int lt8911exb_remove(struct i2c_client * client)
{struct lt8911exb_data *lt8911exb = i2c_get_clientdata(client);if(gpio_is_valid(lt8911exb->rst_gpio))gpio_free(lt8911exb->rst_gpio);if(gpio_is_valid(lt8911exb->pwr_gpio))gpio_free(lt8911exb->pwr_gpio);if(gpio_is_valid(lt8911exb->bl_gpio))gpio_free(lt8911exb->bl_gpio);dev_info(&client->dev, "goodix lt8911exb driver removed");i2c_set_clientdata(client, NULL);devm_kfree(&client->dev, lt8911exb);return 0;
}static const struct of_device_id lt8911exb_match_table[] = {{.compatible = "lontium,lt8911exb",},{ },
};static const struct i2c_device_id lt8911exb_device_id[] = {{ LT8911EXB_I2C_NAME, 0 },{ }
};static struct i2c_driver lt8911exb_driver = {.probe      = lt8911exb_probe,.remove     = lt8911exb_remove,.id_table   = lt8911exb_device_id,.driver = {.name     = LT8911EXB_I2C_NAME,.owner    = THIS_MODULE,.of_match_table = lt8911exb_match_table,},
};static int __init lt8911exb_init(void)
{s32 ret;pr_info("Lontium LT8911EXB driver installing....\n");ret = i2c_add_driver(&lt8911exb_driver);return ret;
}static void __exit lt8911exb_exit(void)
{pr_info("Lontium LT8911EXB driver exited\n");i2c_del_driver(&lt8911exb_driver);
}fs_initcall(lt8911exb_init);
module_exit(lt8911exb_exit);MODULE_DESCRIPTION("Lontium LT8911EXB Driver");
MODULE_LICENSE("GPL V2");
kernel/msm-4.9/drivers/video/lt8911exb/lt8911exb.h
#include <linux/hrtimer.h>
#include <linux/i2c.h>
#include <linux/input.h>
#include <linux/module.h>
#include <linux/delay.h>
#include <linux/i2c.h>
#include <linux/proc_fs.h>
#include <linux/string.h>
#include <linux/uaccess.h>
#include <linux/vmalloc.h>
#include <linux/interrupt.h>
#include <linux/io.h>
#include <linux/gpio.h>
#include <linux/regulator/consumer.h>
#include <linux/major.h>
#include <linux/kdev_t.h>
#include <linux/of_gpio.h>
#ifdef CONFIG_HAS_EARLYSUSPEND
#include <linux/earlysuspend.h>
#endif
#include <linux/usb.h>
#include <linux/power_supply.h>#define LT8911EXB_I2C_NAME      "lt8911exb"
#define LT8911EXB_DRIVER_VERSION  "1.0.0"#define LT8911EXB_ADDR_LENGTH      1
#define I2C_MAX_TRANSFER_SIZE   255
#define RETRY_MAX_TIMES         3struct lt8911exb_data {struct i2c_client *client;int pwr_gpio;int rst_gpio;int bl_gpio;int hact;int vact;int hbp;int hfp;int hs;int vbp;int vfp;int vs;int pclk;int htotal;int vtotal;int lane_cnt;int mipi_lane;int color; //Color Depth 0:6bit 1:8bitint test;
};#endif /*_LONTIUM_LT8911EXB_H_*/

四、添加SDM450副屏部分参数,注意主控跟LT8911连接是几lane

1、屏幕头文件

kernel/msm-4.9/arch/arm64/boot/dts/qcom/dsi-panel-test-600-video.dtsi
&mdss_mdp {dsi_ydt101ml659hs24a_600_video: qcom,mdss_dsi_ydt101ml659hs24a_600_video {qcom,mdss-dsi-panel-name = "YDT101ML659HS24A 600 video mode dsi panel";//   qcom,mdss-dsi-panel-controller = <&mdss_dsi1>;qcom,mdss-dsi-panel-type = "dsi_video_mode";//  qcom,mdss-dsi-panel-destination = "display_2";qcom,mdss-dsi-panel-framerate = <60>;qcom,mdss-dsi-virtual-channel-id = <0>;qcom,mdss-dsi-stream = <0>;qcom,mdss-dsi-panel-width = <1366>;qcom,mdss-dsi-panel-height = <768>;qcom,mdss-dsi-h-front-porch = <94>;qcom,mdss-dsi-h-back-porch = <50>;qcom,mdss-dsi-h-pulse-width = <16>;qcom,mdss-dsi-h-sync-skew = <0>;qcom,mdss-dsi-v-back-porch = <13>;qcom,mdss-dsi-v-front-porch = <13>;qcom,mdss-dsi-v-pulse-width = <6>;qcom,mdss-dsi-h-left-border = <0>;qcom,mdss-dsi-h-right-border = <0>;qcom,mdss-dsi-v-top-border = <0>;qcom,mdss-dsi-v-bottom-border = <0>;qcom,mdss-dsi-bpp = <24>;qcom,mdss-dsi-color-order = "rgb_swap_rgb";qcom,mdss-dsi-underflow-color = <0xff>;qcom,mdss-dsi-border-color = <0>;qcom,mdss-dsi-on-command = [05 01 00 00 78 00 02 11 0005 01 00 00 32 00 02 29 00];qcom,mdss-dsi-off-command = [05 01 00 00 32 00 02 28 0005 01 00 00 78 00 02 10 00];qcom,mdss-dsi-on-command-state = "dsi_lp_mode";qcom,mdss-dsi-off-command-state = "dsi_hs_mode";qcom,mdss-dsi-h-sync-pulse = <1>;qcom,mdss-dsi-traffic-mode = "burst_mode";qcom,mdss-dsi-lane-map = "lane_map_0123";qcom,mdss-dsi-bllp-eof-power-mode;qcom,mdss-dsi-bllp-power-mode;qcom,mdss-dsi-lane-0-state;qcom,mdss-dsi-lane-1-state;qcom,mdss-dsi-lane-2-state;qcom,mdss-dsi-lane-3-state;qcom,mdss-dsi-panel-timings = [82 1c 12 00 40 42 16 1e 14 03 04 00];qcom,mdss-dsi-t-clk-post = <0x04>;qcom,mdss-dsi-t-clk-pre = <0x27>;qcom,mdss-dsi-bl-min-level = <1>;qcom,mdss-dsi-bl-max-level = <4095>;qcom,mdss-dsi-dma-trigger = "trigger_sw";qcom,mdss-dsi-mdp-trigger = "none";qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_pwm";qcom,mdss-dsi-reset-sequence = <1 20>, <0 30>, <1 30>;qcom,mdss-dsi-panel-timings-phy-v2 = [1e 1b 04 06 02 03 04 a0    /*Data 0*/1e 1b 04 06 02 03 04 a0      /*Data 1*/1e 1b 04 06 02 03 04 a0    /*Data 2*/1e 1b 04 06 02 03 04 a0      /*Data 3*/1e 0e 04 05 02 03 04 a0];   /*CLK lane*/};
};

2、配置双屏显示模式,并使用mdss_dsi1为副屏显示

kernel/msm-4.9/arch/arm64/boot/dts/qcom/msm8953-nopmi-panel-camera.dtsi
&mdss_dsi {hw-config = "dual_dsi"; //"dual_dsi"; //"single_dsi";
};&mdss_dsi1 {status = "ok";qcom,dsi-pref-prim-pan = <&dsi_ydt101ml659hs24a_600_video>;pinctrl-names = "mdss_default", "mdss_sleep";pinctrl-0 = <&mdss_dsi1_active &mdss_te1_active>;pinctrl-1 = <&mdss_dsi1_suspend &mdss_te1_suspend>;qcom,bridge-index = <0>;qcom,pluggable;
};&dsi_ydt101ml659hs24a_600_video {qcom,panel-supply-entries = <&dsi_panel_pwr_supply>;qcom,dba-panel;qcom,bridge-name = "dsi1-bridge";
};

3、配置DEFAULT_VFRMT_TIMING

DEFAULT_VFRMT_TIMING 是高通SDM450副屏必须配置的一个参数

#define DEFAULT_VFRMT_TIMING                           \{DEFAULT_VFRMT, 1366/*active_h*/, 94/*front_porch_h*/, 16/*pulse_width_h*/, 50/*back_porch_h*/, false,  \768/*active_v*/, 13/*front_porch_v*/, 6/*pulse_width_v*/, 13/*back_porch_v*/, false, \73248/*pixel_freq/1000*/, 60000/*refresh_rate/1000*/, false, true, HDMI_RES_AR_16_9, 0}

73248 = (1366+94+16+50)*(768+13+6)*60/1000

如果这个参数不对系统会一直打印,然后不断变得很卡,最后系统会崩溃重启

[   61.361415] __mdss_fb_sync_buf_done_callback: mdp-fence: frame timeout
[   61.470309] mdss_mdp_video_pollwait: vsync poll timed out! rc=-110 status=0x0 mask=0x20000000
[   61.470360] __mdss_fb_sync_buf_done_callback: mdp-fence: frame timeout

五、总结

对于副屏mipi转EDP相对于主屏来说比较简单,只需要注意各个接口和硬件的匹配

高通SDM450 副屏mipi转EDP相关推荐

  1. 高通SDM450 主屏mipi转EDP

    主屏通过lt8911exb 将mipi信号转换成EDP信号输出,调试从大的方向上看,主要是两方面,一个是bootloader阶段的lt8911exb初始化,为了让现实过程更完整,需要在lk的displ ...

  2. [高通SDM450][Android 9.0] 虹软人脸算法WIFI信息变化导致授权失败

    虹软人脸算法WIFI信息变化导致授权失败 开发平台基本信息 补丁下载地址 前言 问题描述 解决方法 开发平台基本信息 芯片: 高通SDM450 版本: Android 9.0 kernel: msm- ...

  3. [高通SDM450][Android9.0]刷机后RTC时钟不生效问题

    文章目录 开发平台基本信息 问题描述 解决方法 1.写入RTC时钟添加增加开机广播 开发平台基本信息 芯片: 高通SDM450 版本: Android 9 kernel: msm-4.19 问题描述 ...

  4. Twitter或面临欧盟更严格内容审核;韩国电商巨头用机器人军团替代仓库工人;高通公司副总裁加盟三星丨每日大事件...

    ‍ ‍数据智能产业创新服务媒体 --聚焦数智 · 改变商业 投融资 辰鳗科技完成新一轮五千万元融资 数字化能源管理服务企业四川辰鳗科技有限公司(以下简称"辰鳗科技")于2月7日宣布 ...

  5. [高通SDM450][Android9.0]屏幕显示DPI可动态配置

    文章目录 开发平台基本信息 问题描述 解决方法 去除默认dpi限制 开发平台基本信息 芯片: 高通SDM450 版本: Android 9.0 kernel: msm-4.9 问题描述 正常我们要修改 ...

  6. [高通SDM450][Android9.0]屏蔽开放WIFi以及WIFI信号有个x导致无法上网

    文章目录 开发平台基本信息 问题描述 解决方法 1.解决WIFI信号有个x的问题 2.屏蔽开放WIFi 开发平台基本信息 芯片: 高通SDM450 版本: Android 9.0 kernel: ms ...

  7. 高通SDM450 Android9上调试RS485接口温湿度传感器调试介绍

    高通SDM450 Android9上调试RS485接口温湿度传感器调试介绍 1.初步确认硬件电路工作正常 2.确认主控端串口可以正常工作 3.调试主控串口经过RS485连接电脑可以正常收发 4.单独调 ...

  8. 高通SDM450平台的LDO 输出与电压调节

    开始之前,首先我们要知道什么是LDO?有什么作用?LDO调试需要调哪些? 什么是LDO,有什么作用? LDO为 低压线性稳压器,高通平台有多路LDO电压输出,以SDM450 为例 共有 LDO1~LD ...

  9. [高通SDM450][Android9.0]双屏异显、双屏异触

    文章目录 开发平台基本信息 问题描述 解决方法 双屏异显 双屏异触 延伸扩展 开发平台基本信息 芯片: SDM450 版本: Android 9.0 kernel: msm-4.9 问题描述 公司有一 ...

最新文章

  1. 甘肃计算机教室中标,大单纷至沓来 甘肃百亿工程浪潮电脑中标8000台
  2. Electron 打包Mac安装包代码签名问题解决方案Could not get code signature for running application
  3. 右)侧固定宽度,右(左)侧宽度自适应 ---清除浮动
  4. 根据开始日期和结束日期获取基金的当天净值,并计算收益率
  5. 只安装mysql的centos_centos6 只安装mysql client(安装包安装和yum安装mysql)
  6. 计算机控制系统由硬件和软件组成部分,计算机控制系统的硬件一般由哪几个主要部分组成,各有何作用?...
  7. js获取USB扫码枪数据
  8. Labview和三菱Q系列PLC通讯
  9. 骨传导耳机是什么,骨传导耳机对耳朵有什么好处吗
  10. HTML5学习01-基础讲解、新特性
  11. mac下安装pyinstaller
  12. chrome浏览器拦截广告_如何禁用Chrome的新广告拦截器(在某些网站或所有网站上)...
  13. 生成Base64编码格式的二维码图片(添加url地址图片logo)
  14. 汇编语言(王爽)-实验
  15. 垃圾邮件的判定标准与识别方法
  16. 基于Python实现的二手车价格预测
  17. iOS 入门开发踩坑实录
  18. 【vue】生成二维码
  19. 美的变频空调保护性停机分析与检修案例
  20. 一张图读懂caffe架构

热门文章

  1. Python学习,约束和异常处理
  2. 听说……国产的领航辅助驾驶系统都很卷?
  3. 智慧园区水电监测系统
  4. 【移动安全技术】_第一站
  5. html5 滚屏效果 插件,jQuery插件fullPage.js实现全屏滚动效果
  6. 华为云电脑怎么玩云顶之弈_云顶之弈怎么玩?云电脑为你介绍沉默熊阵容玩法...
  7. Java多线程Demo
  8. 2018福建省“百越杯”CTF初赛writeup
  9. 又一所新大学,来了!河南工业软件大学
  10. 如何给视频制作添加字幕?