/* * Copyright (C) 2025, ArtInChip Technology Co., Ltd * * SPDX-License-Identifier: Apache-2.0 */ #include "panel_com.h" #include "panel_dsi.h" #include #ifndef LT9811EXB_RESOLUTION #define LT9811EXB_RESOLUTION 1 #endif #define LT8911_I2C_NAME "i2c0" #define LT8911_I2C_ADDR 0x29 static struct rt_i2c_bus_device *i2c_bus = RT_NULL; #define LT9811_BL_EN "PE.3" #define LT9811_IOVCC18_EN "PE.4" #define LT9811_RESET_EN "PC.1" static struct gpio_desc iovcc18; static struct gpio_desc bl_en; static struct gpio_desc reset; // #define LT8911_UART_DEBUG // #define _Test_Pattern_ // LT8911 output test pattern #define _read_edid_ // read eDP panel EDID // #define _Msa_Active_Only_ #define _link_train_enable_ #ifdef LT8911_UART_DEBUG #define LT8911_DEV_DEBUG printf #else #define LT8911_DEV_DEBUG(fmt, ...) #endif enum { hfp = 0, hs, hbp, hact, htotal, vfp, vs, vbp, vact, vtotal, pclk_10khz }; enum { _Level0_ = 0, // 27.8 mA 0x83/0x00 _Level1_, // 26.2 mA 0x82/0xe0 _Level2_, // 24.6 mA 0x82/0xc0 _Level3_, // 23 mA 0x82/0xa0 _Level4_, // 21.4 mA 0x82/0x80 _Level5_, // 18.2 mA 0x82/0x40 _Level6_, // 16.6 mA 0x82/0x20 _Level7_, // 15mA 0x82/0x00 // level 1 _Level8_, // 12.8mA 0x81/0x00 // level 2 _Level9_, // 11.2mA 0x80/0xe0 // level 3 _Level10_, // 9.6mA 0x80/0xc0 // level 4 _Level11_, // 8mA 0x80/0xa0 // level 5 _Level12_, // 6mA 0x80/0x80 // level 6 }; static u8 Level = _Level7_; // normal static u8 Swing_Setting1[] = { 0x83, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x81, 0x80, 0x80, 0x80, 0x80 }; static u8 Swing_Setting2[] = { 0x00, 0xe0, 0xc0, 0xa0, 0x80, 0x40, 0x20, 0x00, 0x00, 0xe0, 0xc0, 0xa0, 0x80 }; static bool ScrambleMode = 0; #ifdef _read_edid_ static u8 EDID_DATA[128] = { 0 }; static u16 EDID_Timing[11] = { 0 }; static bool EDID_Reply = 0; #endif /*************************** LT8911EXB Config *********************************/ #define _eDP_2G7_ //#define _eDP_1G62_ #if (LT9811EXB_RESOLUTION == 0) #define _1920x1200_eDP_Panel_ #elif (LT9811EXB_RESOLUTION == 1) #define _1080P_eDP_Panel_ #elif (LT9811EXB_RESOLUTION == 2) #define _1366x768_eDP_Panel_ #endif #define _MIPI_Lane_ 4 #define _MIPI_data_PN_Swap_En 0xF0 #define _MIPI_data_PN_Swap_Dis 0x00 #define _MIPI_data_PN_ _MIPI_data_PN_Swap_Dis #define _No_swap_ 0x00 // 3210 default #define _MIPI_data_3210_ 0 // default #define _MIPI_data_0123_ 21 #define _MIPI_data_2103_ 20 #define _MIPI_data_sequence_ _No_swap_ /* * LT8911EXB pin MIPI RX * D3 (37、38) D3 2 3 2 1 1 3 2 3 2 0 0 3 0 3 0 1 1 2 0 2 0 1 1 * D2 (40、41) D2 3 1 1 2 3 2 3 0 0 2 3 0 3 1 1 0 3 0 2 1 1 0 2 * D1 (44、45) D1 1 2 3 3 2 0 1 2 3 3 2 1 1 0 3 3 0 1 1 0 2 2 0 * D0 (47、48) D0 0 0 0 0 0 1 0 1 1 1 1 2 2 2 2 2 2 3 3 3 3 3 3 * * 0xD003 Reg value 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 */ #define _eDP_data_PN_Swap_En 0xF0 // Please refer to the notes below #define _eDP_data_PN_Swap_Dis 0x00 #define _eDP_data_PN_ _eDP_data_PN_Swap_Dis // default disable /* * eDP data P/N polarity swap * bit7 RGD_MLCTRL_LANE3_RVSD_EN * 1 = data of lane3 polarity swap; * 0 = normal. * * bit6 RGD_MLCTRL_LANE2_RVSD_EN * 1 = data of lane2 polarity swap; * 0 = normal. * * bit5 RGD_MLCTRL_LANE1_RVSD_EN * 1 = data of lane1 polarity swap; * 0 = normal. * * bit4 RGD_MLCTRL_LANE0_RVSD_EN * 1 = data of lane0 polarity swap; * 0 = normal. */ #define _Lane0_data_ 0 #define _Lane1_data_ 1 #define _Lane2_data_ 2 #define _Lane3_data_ 3 #define _eDP_data_No_swap_ 0xe4 // default #define _eDP_data3_select_ (_Lane3_data_ << 6) // default; _Lane3_data_select_ is lane3 #define _eDP_data2_select_ (_Lane2_data_ << 4) // default; _Lane2_data_select_ is lane2 #define _eDP_data1_select_ (_Lane1_data_ << 2) // default; _Lane1_data_select_ is lane1 #define _eDP_data0_select_ (_Lane0_data_ << 0) // default; _Lane0_data_select_ is lane0 // example:lane1 and lane0 swap //#define _eDP_data1_select_ (_Lane0_data_ << 2) // default _Lane1_data_select_ is lane0 //#define _eDP_data0_select_ (_Lane1_data_ << 0) // default _Lane0_data_select_ is lane1 /* _eDP_data_sequence_ default _eDP_data_No_swap_ */ #define _eDP_data_sequence_ (_eDP_data3_select_ + _eDP_data2_select_ + _eDP_data1_select_ + _eDP_data0_select_) #define _Nvid 0 // 0: 0x0080,default static int Nvid_Val[] = { 0x0080, 0x0800 }; // #define _6bit_ #define _8bit_ #define PCR_PLL_PREDIV 0x40 #ifdef _1920x1200_eDP_Panel_ #define eDP_lane 2 #endif #ifdef _1080P_eDP_Panel_ #define eDP_lane 2 #endif #ifdef _1366x768_eDP_Panel_ #define eDP_lane 1 #endif static unsigned char lt8911_i2c_reg_read(struct rt_i2c_bus_device *i2c, unsigned char reg) { rt_uint8_t buffer[1]; unsigned char cmd[1]; struct rt_i2c_msg msgs[2]; cmd[0] = reg; msgs[0].addr = LT8911_I2C_ADDR; msgs[0].flags = RT_I2C_WR; msgs[0].buf = cmd; msgs[0].len = 1; msgs[1].addr = LT8911_I2C_ADDR; msgs[1].flags = RT_I2C_RD; msgs[1].buf = buffer; msgs[1].len = 1; if (rt_i2c_transfer(i2c_bus, msgs, 2) == 2) { return buffer[0]; } else { pr_err("i2c read reg 0x%#x fail\n", reg); return 0; } } static void lt8911_i2c_reg_write(struct rt_i2c_bus_device *i2c, unsigned char reg, unsigned char val) { unsigned char buf[2]; struct rt_i2c_msg msgs; buf[0] = reg; buf[1] = val; msgs.addr = LT8911_I2C_ADDR; msgs.flags = RT_I2C_WR; msgs.buf = buf; msgs.len = 2; if (rt_i2c_transfer(i2c, &msgs, 1) == 1) { return; } else { pr_err("i2c write reg %#x fail\n", reg); } } static inline void lt8911exb_i2c_write_byte(unsigned char reg, unsigned char val) { lt8911_i2c_reg_write(i2c_bus, reg, val); } static inline unsigned char lt8911exb_i2c_read_byte(unsigned char reg) { return lt8911_i2c_reg_read(i2c_bus, reg); } static void lt8911_iic_setup(void) { i2c_bus = rt_i2c_bus_device_find(LT8911_I2C_NAME); if (i2c_bus == RT_NULL) { pr_err("can't find %s device\n", LT8911_I2C_NAME); } } void lt8911exb_read_chipid(void) { /* register bank */ lt8911exb_i2c_write_byte(0xff, 0x81); lt8911exb_i2c_write_byte(0x08, 0x7f); #ifdef LT8911_UART_DEBUG /* LT8911EXB Chip ID: 0x17 0x05 0xE0 */ LT8911_DEV_DEBUG("LT8911EXB Chip ID: 0x%x\n", lt8911exb_i2c_read_byte(0x00)); LT8911_DEV_DEBUG("0x%x, \n", lt8911exb_i2c_read_byte(0x01)); LT8911_DEV_DEBUG("0x%x, \n", lt8911exb_i2c_read_byte(0x02)); #endif } void lt8911exb_read_edid(void) { #ifdef _read_edid_ u8 reg, i, j; /* bool aux_reply, aux_ack, aux_nack, aux_defer */ lt8911exb_i2c_write_byte(0xff, 0xac); lt8911exb_i2c_write_byte(0x00, 0x20); //Soft Link train lt8911exb_i2c_write_byte(0xff, 0xa6); lt8911exb_i2c_write_byte(0x2a, 0x01); /* set edid offset addr */ lt8911exb_i2c_write_byte(0x2b, 0x40); //CMD lt8911exb_i2c_write_byte(0x2b, 0x00); //addr[15:8] lt8911exb_i2c_write_byte(0x2b, 0x50); //addr[7:0] lt8911exb_i2c_write_byte(0x2b, 0x00); //data lenth lt8911exb_i2c_write_byte(0x2b, 0x00); //data lenth lt8911exb_i2c_write_byte(0x2c, 0x00); //start Aux read edid #ifdef LT8911_UART_DEBUG LT8911_DEV_DEBUG("\n"); LT8911_DEV_DEBUG("\nRead eDP EDID......"); #endif /* more than 10ms */ aicos_mdelay(20); reg = lt8911exb_i2c_read_byte(0x25); if ((reg & 0x0f) == 0x0c) { for (j = 0; j < 8; j++) { if (j == 7) { lt8911exb_i2c_write_byte(0x2b, 0x10); //MOT } else { lt8911exb_i2c_write_byte(0x2b, 0x50); } lt8911exb_i2c_write_byte(0x2b, 0x00); lt8911exb_i2c_write_byte(0x2b, 0x50); lt8911exb_i2c_write_byte(0x2b, 0x0f); lt8911exb_i2c_write_byte(0x2c, 0x00); //start Aux read edid /* more than 50ms */ aicos_mdelay(50); if (lt8911exb_i2c_read_byte(0x39) == 0x31) { lt8911exb_i2c_read_byte(0x2b); for (i = 0; i < 16; i++) { EDID_DATA[j * 16 + i] = lt8911exb_i2c_read_byte(0x2b); } EDID_Reply = 1; } else { EDID_Reply = 0; #ifdef LT8911_UART_DEBUG LT8911_DEV_DEBUG("\nno_reply"); LT8911_DEV_DEBUG("\n"); #endif return; } } #ifdef LT8911_UART_DEBUG for (i = 0; i < 128; i++) { if ((i % 16) == 0) { LT8911_DEV_DEBUG("\n"); } LT8911_DEV_DEBUG("0x%x, ", EDID_DATA[i]); } LT8911_DEV_DEBUG("\n"); LT8911_DEV_DEBUG("\neDP Timing = { H_FP / H_pluse / H_BP / H_act / H_tol / V_FP / V_pluse / V_BP / V_act / V_tol / D_CLK };"); LT8911_DEV_DEBUG("\neDP Timing = { "); EDID_Timing[hfp] = ((EDID_DATA[0x41] & 0xC0) * 4 + EDID_DATA[0x3e]); LT8911_DEV_DEBUG("%d", (u32)EDID_Timing[hfp]); LT8911_DEV_DEBUG(", "); EDID_Timing[hs] = ((EDID_DATA[0x41] & 0x30) * 16 + EDID_DATA[0x3f]); LT8911_DEV_DEBUG("%d", (u32)EDID_Timing[hs]); LT8911_DEV_DEBUG(", "); EDID_Timing[hbp] = (((EDID_DATA[0x3a] & 0x0f) * 0x100 + EDID_DATA[0x39]) - ((EDID_DATA[0x41] & 0x30) * 16 + EDID_DATA[0x3f]) - ((EDID_DATA[0x41] & 0xC0) * 4 + EDID_DATA[0x3e])); LT8911_DEV_DEBUG("%d", (u32)EDID_Timing[hbp]); LT8911_DEV_DEBUG(", "); EDID_Timing[hact] = ((EDID_DATA[0x3a] & 0xf0) * 16 + EDID_DATA[0x38]); LT8911_DEV_DEBUG("%d", (u32)EDID_Timing[hact]); LT8911_DEV_DEBUG(", "); EDID_Timing[htotal] = ((EDID_DATA[0x3a] & 0xf0) * 16 + EDID_DATA[0x38] + ((EDID_DATA[0x3a] & 0x0f) * 0x100 + EDID_DATA[0x39])); LT8911_DEV_DEBUG("%d", (u32)EDID_Timing[htotal]); LT8911_DEV_DEBUG(", "); EDID_Timing[vfp] = ((EDID_DATA[0x41] & 0x0c) * 4 + (EDID_DATA[0x40] & 0xf0) / 16); LT8911_DEV_DEBUG("%d", (u32)EDID_Timing[vfp]); LT8911_DEV_DEBUG(", "); EDID_Timing[vs] = ((EDID_DATA[0x41] & 0x03) * 16 + (EDID_DATA[0x40] & 0x0f)); LT8911_DEV_DEBUG("%d", (u32)EDID_Timing[vs]); LT8911_DEV_DEBUG(", "); EDID_Timing[vbp] = (((EDID_DATA[0x3d] & 0x03) * 0x100 + EDID_DATA[0x3c]) - ((EDID_DATA[0x41] & 0x03) * 16 + (EDID_DATA[0x40] & 0x0f)) - ((EDID_DATA[0x41] & 0x0c) * 4 + (EDID_DATA[0x40] & 0xf0) / 16)); LT8911_DEV_DEBUG("%d", (u32)EDID_Timing[vbp]); LT8911_DEV_DEBUG(", "); EDID_Timing[vact] = ((EDID_DATA[0x3d] & 0xf0) * 16 + EDID_DATA[0x3b]); LT8911_DEV_DEBUG("%d", (u32)EDID_Timing[vact]); LT8911_DEV_DEBUG(", "); EDID_Timing[vtotal] = ((EDID_DATA[0x3d] & 0xf0) * 16 + EDID_DATA[0x3b] + ((EDID_DATA[0x3d] & 0x03) * 0x100 + EDID_DATA[0x3c])); LT8911_DEV_DEBUG("%d", (u32)EDID_Timing[vtotal]); LT8911_DEV_DEBUG(", "); EDID_Timing[pclk_10khz] = (EDID_DATA[0x37] * 0x100 + EDID_DATA[0x36]); LT8911_DEV_DEBUG("%d", (u32)EDID_Timing[pclk_10khz]); LT8911_DEV_DEBUG(" };"); LT8911_DEV_DEBUG("\n"); #endif } return; #endif } void lt8911exb_mipi_video_timing(const struct display_timing *timing) { u32 hactive = timing->hactive; u32 hfp = timing->hfront_porch; u32 hs = timing->hsync_len; u32 hbp = timing->hback_porch; u32 htotal = hactive + hfp + hs + hbp; u32 vactive = timing->vactive; u32 vfp = timing->vfront_porch; u32 vs = timing->vsync_len; u32 vbp = timing->vback_porch; u32 vtotal = vactive + vfp + vs + vbp; lt8911exb_i2c_write_byte(0xff, 0xd0); lt8911exb_i2c_write_byte(0x0d, (u8)(vtotal / 256)); lt8911exb_i2c_write_byte(0x0e, (u8)(vtotal % 256)); lt8911exb_i2c_write_byte(0x0f, (u8)(vactive / 256)); lt8911exb_i2c_write_byte(0x10, (u8)(vactive % 256)); lt8911exb_i2c_write_byte(0x11, (u8)(htotal / 256)); lt8911exb_i2c_write_byte(0x12, (u8)(htotal % 256)); lt8911exb_i2c_write_byte(0x13, (u8)(hactive / 256)); lt8911exb_i2c_write_byte(0x14, (u8)(hactive % 256)); lt8911exb_i2c_write_byte(0x15, (u8)(vs % 256)); lt8911exb_i2c_write_byte(0x16, (u8)(hs % 256)); lt8911exb_i2c_write_byte(0x17, (u8)(vfp / 256)); lt8911exb_i2c_write_byte(0x18, (u8)(vfp % 256)); lt8911exb_i2c_write_byte(0x19, (u8)(hfp / 256)); lt8911exb_i2c_write_byte(0x1a, (u8)(hfp % 256)); } void lt8911exb_edo_video_cfg(const struct display_timing *timing) { u32 hactive = timing->hactive; u32 hfp = timing->hfront_porch; u32 hs = timing->hsync_len; u32 hbp = timing->hback_porch; u32 htotal = hactive + hfp + hs + hbp; u32 vactive = timing->vactive; u32 vfp = timing->vfront_porch; u32 vs = timing->vsync_len; u32 vbp = timing->vback_porch; u32 vtotal = vactive + vfp + vs + vbp; lt8911exb_i2c_write_byte(0xff, 0xa8); lt8911exb_i2c_write_byte(0x2d, 0x88); // MSA from register #ifdef _Msa_Active_Only_ lt8911exb_i2c_write_byte(0x05, 0x00); lt8911exb_i2c_write_byte(0x06, 0x00); lt8911exb_i2c_write_byte(0x07, 0x00); lt8911exb_i2c_write_byte(0x08, 0x00); lt8911exb_i2c_write_byte(0x09, 0x00); lt8911exb_i2c_write_byte(0x0a, 0x00); lt8911exb_i2c_write_byte(0x0b, (u8)(hactive / 256)); lt8911exb_i2c_write_byte(0x0c, (u8)(hactive % 256)); lt8911exb_i2c_write_byte(0x0d, 0x00); lt8911exb_i2c_write_byte(0x0e, 0x00); lt8911exb_i2c_write_byte(0x11, 0x00); lt8911exb_i2c_write_byte(0x12, 0x00); lt8911exb_i2c_write_byte(0x14, 0x00); lt8911exb_i2c_write_byte(0x15, (u8)(vactive / 256)); lt8911exb_i2c_write_byte(0x16, (u8)(vactive % 256)); #else lt8911exb_i2c_write_byte(0x05, (u8)(htotal / 256)); lt8911exb_i2c_write_byte(0x06, (u8)(htotal % 256)); lt8911exb_i2c_write_byte(0x07, (u8)((hs + hbp) / 256)); lt8911exb_i2c_write_byte(0x08, (u8)((hs + hbp) % 256)); lt8911exb_i2c_write_byte(0x09, (u8)(hs / 256)); lt8911exb_i2c_write_byte(0x0a, (u8)(hs % 256)); lt8911exb_i2c_write_byte(0x0b, (u8)(hactive / 256)); lt8911exb_i2c_write_byte(0x0c, (u8)(hactive % 256)); lt8911exb_i2c_write_byte(0x0d, (u8)(vtotal / 256)); lt8911exb_i2c_write_byte(0x0e, (u8)(vtotal % 256)); lt8911exb_i2c_write_byte(0x11, (u8)((vs + vbp) / 256)); lt8911exb_i2c_write_byte(0x12, (u8)((vs + vbp) % 256)); lt8911exb_i2c_write_byte(0x14, (u8)(vs % 256)); lt8911exb_i2c_write_byte(0x15, (u8)(vactive / 256)); lt8911exb_i2c_write_byte(0x16, (u8)(vactive % 256)); #endif } void lt8911exb_mipi_rx_sot_get() { u8 set0 = 0; u8 set1 = 0; u8 set2 = 0; u8 set3 = 0; u8 sot0 = 0; u8 sot1 = 0; u8 sot2 = 0; u8 sot3 = 0; lt8911exb_i2c_write_byte(0xff,0xd0); set0 = lt8911exb_i2c_read_byte(0x88); set1 = lt8911exb_i2c_read_byte(0x8a); set2 = lt8911exb_i2c_read_byte(0x8c); set3 = lt8911exb_i2c_read_byte(0x8e); sot0 = lt8911exb_i2c_read_byte(0x89); sot1 = lt8911exb_i2c_read_byte(0x8b); sot2 = lt8911exb_i2c_read_byte(0x8d); sot3 = lt8911exb_i2c_read_byte(0x8f); LT8911_DEV_DEBUG("\nSet Num = 0x%x, 0x%x, 0x%x, 0x%x", set0,set1,set2,set3); LT8911_DEV_DEBUG("\nSot Dta = 0x%x, 0x%x, 0x%x, 0x%x", sot0,sot1,sot2,sot3); } void lt8911exb_mipi_rx_hs_settle_set(void) { lt8911exb_i2c_write_byte(0xff,0xd0); if ((lt8911exb_i2c_read_byte(0x88) > 0x10) && (lt8911exb_i2c_read_byte(0x88) < 0x50)) { LT8911_DEV_DEBUG("\n Set Mipi Rx Settle: 0x%x", (lt8911exb_i2c_read_byte(0x88) - 5)); lt8911exb_i2c_write_byte(0xff,0xd0); lt8911exb_i2c_write_byte(0x02,(lt8911exb_i2c_read_byte(0x88) - 5)); } else { LT8911_DEV_DEBUG("\n Set Mipi Rx Settle: 0x08"); //mipi rx cts test need settle 0x0e lt8911exb_i2c_write_byte(0xff,0xd0); lt8911exb_i2c_write_byte(0x02,0x08); } } void lt8911exb_init(struct aic_panel *panel) { const struct display_timing *timing = panel->timings; u16 pclk_10khz = timing->pixelclock / 10000; u8 pcr_pll_postdiv, pcr_m, i; /* init */ lt8911exb_i2c_write_byte(0xff, 0x81); // Change Reg bank lt8911exb_i2c_write_byte(0x08, 0x7f); // i2c over aux issue lt8911exb_i2c_write_byte(0x49, 0xff); // enable 0x87xx lt8911exb_i2c_write_byte(0xff, 0x82); // Change Reg bank lt8911exb_i2c_write_byte(0x5a, 0x0e); // GPIO test output /* for power consumption */ lt8911exb_i2c_write_byte(0xff, 0x81); lt8911exb_i2c_write_byte(0x05, 0x06); lt8911exb_i2c_write_byte(0x43, 0x00); lt8911exb_i2c_write_byte(0x44, 0x1f); lt8911exb_i2c_write_byte(0x45, 0xf7); lt8911exb_i2c_write_byte(0x46, 0xf6); lt8911exb_i2c_write_byte(0x49, 0x7f); lt8911exb_i2c_write_byte(0xff, 0x82); #if (eDP_lane == 2) { lt8911exb_i2c_write_byte(0x12, 0x33); } #elif (eDP_lane == 1) { lt8911exb_i2c_write_byte(0x12, 0x11); } #endif /* mipi Rx analog */ lt8911exb_i2c_write_byte(0xff, 0x82); // Change Reg bank lt8911exb_i2c_write_byte(0x32, 0x51); lt8911exb_i2c_write_byte(0x35, 0x22); //EQ current 0x22/0x42/0x62/0x82/0xA2/0xC2/0xe2 lt8911exb_i2c_write_byte(0x3a, 0x77); //EQ 12.5db lt8911exb_i2c_write_byte(0x3b, 0x77); //EQ 12.5db lt8911exb_i2c_write_byte(0x4c, 0x0c); lt8911exb_i2c_write_byte(0x4d, 0x00); /* dessc_pcr pll analog */ lt8911exb_i2c_write_byte(0xff, 0x82); // Change Reg bank lt8911exb_i2c_write_byte(0x6a, 0x40); lt8911exb_i2c_write_byte(0x6b, PCR_PLL_PREDIV); if (pclk_10khz < 8800) { lt8911exb_i2c_write_byte(0x6e, 0x82); //0x44:pre-div = 2 ,pixel_clk = 44~ 88MHz pcr_pll_postdiv = 0x08; } else if (pclk_10khz < 17600) { lt8911exb_i2c_write_byte(0x6e, 0x81); //0x40:pre-div = 1, pixel_clk = 88~176MHz pcr_pll_postdiv = 0x04; } else { lt8911exb_i2c_write_byte(0x6e, 0x80); //0x40:pre-div = 0, pixel_clk = 176~200MHz pcr_pll_postdiv = 0x02; } pcr_m = (u8)(pclk_10khz * pcr_pll_postdiv / 25 / 100); /* dessc pll digital */ lt8911exb_i2c_write_byte(0xff, 0x85); // Change Reg bank lt8911exb_i2c_write_byte(0xa9, 0x31); lt8911exb_i2c_write_byte(0xaa, 0x17); lt8911exb_i2c_write_byte(0xab, 0xba); lt8911exb_i2c_write_byte(0xac, 0xe1); lt8911exb_i2c_write_byte(0xad, 0x47); lt8911exb_i2c_write_byte(0xae, 0x01); lt8911exb_i2c_write_byte(0xae, 0x11); /* Digital Top */ lt8911exb_i2c_write_byte(0xff, 0x85); // Change Reg bank lt8911exb_i2c_write_byte(0xc0, 0x01); //select mipi Rx #ifdef _6bit_ lt8911exb_i2c_write_byte(0xb0, 0xd0); //enable dither #else lt8911exb_i2c_write_byte(0xb0, 0x00); // disable dither #endif /* mipi Rx Digital */ lt8911exb_i2c_write_byte(0xff, 0xd0); // Change Reg bank lt8911exb_i2c_write_byte(0x00, _MIPI_data_PN_ + _MIPI_Lane_ % 4); // 0: 4 Lane / 1: 1 Lane / 2 : 2 Lane / 3: 3 Lane lt8911exb_mipi_rx_sot_get(); lt8911exb_mipi_rx_hs_settle_set(); // lt8911exb_i2c_write_byte(0x02, 0x08); //settle lt8911exb_i2c_write_byte(0x03, _MIPI_data_sequence_); // default is 0x00 lt8911exb_i2c_write_byte(0x08, 0x00); // lt8911exb_i2c_write_byte(0x0a, 0x12); //pcr mode lt8911exb_i2c_write_byte(0x0c, 0x80); //fifo position lt8911exb_i2c_write_byte(0x1c, 0x80); //fifo position // lt8911exb_i2c_write_byte(0x1e, 0x10); lt8911exb_i2c_write_byte(0x24, 0x70); // 0x30 [3:0] line limit lt8911exb_i2c_write_byte(0x31, 0x0a); /* stage1 hs mode */ lt8911exb_i2c_write_byte(0x25, 0x90); // 0x80 line limit lt8911exb_i2c_write_byte(0x2a, 0x3a); // 0x04 step in limit lt8911exb_i2c_write_byte(0x21, 0x4f); // hs_step lt8911exb_i2c_write_byte(0x22, 0xff); /* stage2 de mode */ lt8911exb_i2c_write_byte(0x0a, 0x02); // de adjust pre line lt8911exb_i2c_write_byte(0x38, 0x02); // de_threshold 1 lt8911exb_i2c_write_byte(0x39, 0x04); // de_threshold 2 lt8911exb_i2c_write_byte(0x3a, 0x08); // de_threshold 3 lt8911exb_i2c_write_byte(0x3b, 0x10); // de_threshold 4 lt8911exb_i2c_write_byte(0x3f, 0x04); // de_step 1 lt8911exb_i2c_write_byte(0x40, 0x08); // de_step 2 lt8911exb_i2c_write_byte(0x41, 0x10); // de_step 3 lt8911exb_i2c_write_byte(0x42, 0x60); // de_step 4 /* stage2 hs mode */ lt8911exb_i2c_write_byte(0x1e, 0x01); // 0x11 lt8911exb_i2c_write_byte(0x23, 0xf0); // 0x80 lt8911exb_i2c_write_byte(0x2b, 0x80); // 0xa0 #ifdef _Test_Pattern_ lt8911exb_i2c_write_byte(0x26, (pcr_m | 0x80)); #else lt8911exb_i2c_write_byte(0x26, pcr_m); // lt8911exb_i2c_write_byte(0x27, Read_0xD095); // lt8911exb_i2c_write_byte(0x28, Read_0xD096); #endif lt8911exb_mipi_video_timing(timing); // defualt setting is 1080P lt8911exb_i2c_write_byte(0xff, 0x81); // Change Reg bank lt8911exb_i2c_write_byte(0x03, 0x7b); // PCR reset lt8911exb_i2c_write_byte(0x03, 0xff); #ifdef _eDP_2G7_ lt8911exb_i2c_write_byte(0xff, 0x87); lt8911exb_i2c_write_byte(0x19, 0x31); // lt8911exb_i2c_write_byte(0x1a, 0x36); // sync m lt8911exb_i2c_write_byte(0x1a, 0x1b); lt8911exb_i2c_write_byte(0x1b, 0x00); // sync_k [7:0] lt8911exb_i2c_write_byte(0x1c, 0x00); // sync_k [13:8] /* txpll Analog */ lt8911exb_i2c_write_byte(0xff, 0x82); lt8911exb_i2c_write_byte(0x09, 0x00); // div hardware mode, for ssc. // lt8911exb_i2c_write_byte(0x01, 0x18); // default : 0x18 lt8911exb_i2c_write_byte(0x02, 0x42); lt8911exb_i2c_write_byte(0x03, 0x00); // txpll en = 0 lt8911exb_i2c_write_byte(0x03, 0x01); // txpll en = 1 // lt8911exb_i2c_write_byte(0x04, 0x3a); // default : 0x3A lt8911exb_i2c_write_byte(0x0a,0x1b); lt8911exb_i2c_write_byte(0x04,0x2a); lt8911exb_i2c_write_byte(0xff, 0x87); lt8911exb_i2c_write_byte(0x0c, 0x10); // cal en = 0 lt8911exb_i2c_write_byte(0xff, 0x81); lt8911exb_i2c_write_byte(0x09, 0xfc); lt8911exb_i2c_write_byte(0x09, 0xfd); lt8911exb_i2c_write_byte(0xff, 0x87); lt8911exb_i2c_write_byte(0x0c, 0x11); // cal en = 1 /* ssc */ lt8911exb_i2c_write_byte(0xff, 0x87); lt8911exb_i2c_write_byte(0x13, 0x83); lt8911exb_i2c_write_byte(0x14, 0x41); lt8911exb_i2c_write_byte(0x16, 0x0a); lt8911exb_i2c_write_byte(0x18, 0x0a); lt8911exb_i2c_write_byte(0x19, 0x33); #endif #ifdef _eDP_1G62_ lt8911exb_i2c_write_byte(0xff, 0x87); lt8911exb_i2c_write_byte(0x19, 0x31); lt8911exb_i2c_write_byte(0x1a, 0x20); // sync m lt8911exb_i2c_write_byte(0x1b, 0x19); // sync_k [7:0] lt8911exb_i2c_write_byte(0x1c, 0x99); // sync_k [13:8] /* txpll Analog */ lt8911exb_i2c_write_byte(0xff, 0x82); lt8911exb_i2c_write_byte(0x09, 0x00); // div hardware mode, for ssc. // lt8911exb_i2c_write_byte(0x01, 0x18); // default : 0x18 lt8911exb_i2c_write_byte(0x02, 0x42); lt8911exb_i2c_write_byte(0x03, 0x00); // txpll en = 0 lt8911exb_i2c_write_byte(0x03, 0x01); // txpll en = 1 // lt8911exb_i2c_write_byte(0x04, 0x3a); // default : 0x3A lt8911exb_i2c_write_byte(0xff, 0x87); lt8911exb_i2c_write_byte(0x0c, 0x10); // cal en = 0 lt8911exb_i2c_write_byte(0xff, 0x81); lt8911exb_i2c_write_byte(0x09, 0xfc); lt8911exb_i2c_write_byte(0x09, 0xfd); lt8911exb_i2c_write_byte(0xff, 0x87); lt8911exb_i2c_write_byte(0x0c, 0x11); // cal en = 1 /* ssc */ lt8911exb_i2c_write_byte(0xff, 0x87); lt8911exb_i2c_write_byte(0x13, 0x83); lt8911exb_i2c_write_byte(0x14, 0x41); lt8911exb_i2c_write_byte(0x16, 0x0a); lt8911exb_i2c_write_byte(0x18, 0x0a); lt8911exb_i2c_write_byte(0x19, 0x33); #endif lt8911exb_i2c_write_byte(0xff, 0x87); for (i = 0; i < 5; i++) { aicos_mdelay(5); if (lt8911exb_i2c_read_byte(0x37) & 0x02) { LT8911_DEV_DEBUG("\nLT8911 tx pll locked\n"); lt8911exb_i2c_write_byte(0xff,0x87); lt8911exb_i2c_write_byte(0x1a,0x36); lt8911exb_i2c_write_byte(0xff,0x82); lt8911exb_i2c_write_byte(0x0a,0x36); lt8911exb_i2c_write_byte(0x04,0x3a); break; } else { LT8911_DEV_DEBUG("LT8911 tx pll unlocked\n"); lt8911exb_i2c_write_byte(0xff, 0x81); lt8911exb_i2c_write_byte(0x09, 0xfc); lt8911exb_i2c_write_byte(0x09, 0xfd); lt8911exb_i2c_write_byte(0xff, 0x87); lt8911exb_i2c_write_byte(0x0c, 0x10); lt8911exb_i2c_write_byte(0x0c, 0x11); } } lt8911exb_i2c_write_byte(0xff, 0xac); // Change Reg bank lt8911exb_i2c_write_byte(0x15, _eDP_data_sequence_); // eDP data swap lt8911exb_i2c_write_byte(0x16, _eDP_data_PN_); // eDP P / N swap /* AUX reset */ lt8911exb_i2c_write_byte(0xff, 0x81); // Change Reg bank lt8911exb_i2c_write_byte(0x07, 0xfe); lt8911exb_i2c_write_byte(0x07, 0xff); lt8911exb_i2c_write_byte(0x0a, 0xfc); lt8911exb_i2c_write_byte(0x0a, 0xfe); /* tx phy */ lt8911exb_i2c_write_byte(0xff, 0x82); // Change Reg bank lt8911exb_i2c_write_byte(0x11, 0x00); lt8911exb_i2c_write_byte(0x13, 0x10); lt8911exb_i2c_write_byte(0x14, 0x0c); lt8911exb_i2c_write_byte(0x14, 0x08); lt8911exb_i2c_write_byte(0x13, 0x20); lt8911exb_i2c_write_byte(0xff, 0x82); // Change Reg bank lt8911exb_i2c_write_byte(0x0e, 0x35); // lt8911exb_i2c_write_byte(0x12, 0xff); // lt8911exb_i2c_write_byte(0xff, 0x80); // lt8911exb_i2c_write_byte(0x40, 0x22); /* eDP Tx Digital */ lt8911exb_i2c_write_byte(0xff, 0xa8); // Change Reg bank #ifdef _Test_Pattern_ lt8911exb_i2c_write_byte(0x24, 0x50); // bit2 ~ bit 0 : test panttern image mode lt8911exb_i2c_write_byte(0x25, 0x70); // bit6 ~ bit 4 : test Pattern color lt8911exb_i2c_write_byte(0x27, 0x50); //0x50:Pattern; 0x10:mipi video // lt8911exb_i2c_write_byte(0x2d, 0x00); // pure color setting // lt8911exb_i2c_write_byte(0x2d, 0x84); // black color lt8911exb_i2c_write_byte(0x2d, 0x88); // block #else lt8911exb_i2c_write_byte(0x27, 0x10); //0x50:Pattern; 0x10:mipi video #endif #ifdef _6bit_ lt8911exb_i2c_write_byte(0x17, 0x00); lt8911exb_i2c_write_byte(0x18, 0x00); #else /* _8bit_ */ lt8911exb_i2c_write_byte(0x17, 0x10); lt8911exb_i2c_write_byte(0x18, 0x20); #endif /* nvid */ lt8911exb_i2c_write_byte(0xff, 0xa0); // Change Reg bank lt8911exb_i2c_write_byte(0x00, (u8)(Nvid_Val[_Nvid] / 256)); // 0x08 lt8911exb_i2c_write_byte(0x01, (u8)(Nvid_Val[_Nvid] % 256)); // 0x00 } void lt8911exb_txswing_preset(void) { lt8911exb_i2c_write_byte(0xFF, 0x82); lt8911exb_i2c_write_byte(0x22, Swing_Setting1[Level]); //lane 0 tap0 lt8911exb_i2c_write_byte(0x23, Swing_Setting2[Level]); lt8911exb_i2c_write_byte(0x24, 0x80); //lane 0 tap1 lt8911exb_i2c_write_byte(0x25, 0x00); #if (eDP_lane == 2) lt8911exb_i2c_write_byte(0x26, Swing_Setting1[Level]); //lane 1 tap0 lt8911exb_i2c_write_byte(0x27, Swing_Setting2[Level]); lt8911exb_i2c_write_byte(0x28, 0x80); //lane 1 tap1 lt8911exb_i2c_write_byte(0x29, 0x00); #endif } void dpcd_write(u32 address, u8 data) { /* * Pay attention to the Big-Endian and Little-Endian! * The default mode is Big-Endian here. */ u8 address_h = 0x0f & (address >> 16); u8 address_m = 0xff & (address >> 8); u8 address_l = 0xff & address; u8 reg; lt8911exb_i2c_write_byte(0xff, 0xa6); lt8911exb_i2c_write_byte(0x2b, (0x80 | address_h)); //CMD lt8911exb_i2c_write_byte(0x2b, address_m); //addr[15:8] lt8911exb_i2c_write_byte(0x2b, address_l); //addr[7:0] lt8911exb_i2c_write_byte(0x2b, 0x00); //data lenth lt8911exb_i2c_write_byte(0x2b, data); //data lt8911exb_i2c_write_byte(0x2c, 0x00); //start Aux /* more than 10ms */ aicos_mdelay(20); reg = lt8911exb_i2c_read_byte(0x25); if ((reg & 0x0f) == 0x0c) { return; } } void lt8911exb_link_train(void) { lt8911exb_i2c_write_byte(0xff, 0x81); lt8911exb_i2c_write_byte(0x06, 0xdf); // rset VID TX lt8911exb_i2c_write_byte(0x06, 0xff); lt8911exb_i2c_write_byte(0xff, 0x85); // lt8911exb_i2c_write_byte(0x17, 0xf0); // turn off scramble if (ScrambleMode) { lt8911exb_i2c_write_byte(0xa1, 0x82); // eDP scramble mode; /* Aux operater init */ lt8911exb_i2c_write_byte(0xff, 0xac); lt8911exb_i2c_write_byte(0x00, 0x20); //Soft Link train lt8911exb_i2c_write_byte(0xff, 0xa6); lt8911exb_i2c_write_byte(0x2a, 0x01); dpcd_write(0x010a, 0x01); aicos_mdelay(10); dpcd_write(0x0102, 0x00); aicos_mdelay(10); dpcd_write(0x010a, 0x01); aicos_mdelay(200); } else { lt8911exb_i2c_write_byte(0xa1, 0x02); // DP scramble mode; } /* Aux setup */ lt8911exb_i2c_write_byte(0xff, 0xac); lt8911exb_i2c_write_byte(0x00, 0x60); //Soft Link train lt8911exb_i2c_write_byte(0xff, 0xa6); lt8911exb_i2c_write_byte(0x2a, 0x00); lt8911exb_i2c_write_byte(0xff, 0x81); lt8911exb_i2c_write_byte(0x07, 0xfe); lt8911exb_i2c_write_byte(0x07, 0xff); lt8911exb_i2c_write_byte(0x0a, 0xfc); lt8911exb_i2c_write_byte(0x0a, 0xfe); /* link train */ lt8911exb_i2c_write_byte(0xff, 0x85); lt8911exb_i2c_write_byte(0x1a, eDP_lane); #ifdef _link_train_enable_ lt8911exb_i2c_write_byte(0xff, 0xac); lt8911exb_i2c_write_byte(0x00, 0x64); lt8911exb_i2c_write_byte(0x01, 0x0a); lt8911exb_i2c_write_byte(0x0c, 0x85); lt8911exb_i2c_write_byte(0x0c, 0xc5); #else lt8911exb_i2c_write_byte(0xff, 0xac); lt8911exb_i2c_write_byte(0x00, 0x00); lt8911exb_i2c_write_byte(0x01, 0x0a); lt8911exb_i2c_write_byte(0x14, 0x80); lt8911exb_i2c_write_byte(0x14, 0x81); aicos_mdelay(50); lt8911exb_i2c_write_byte(0x14, 0x84); aicos_mdelay(50); lt8911exb_i2c_write_byte(0x14, 0xc0); #endif } void lt8911exb_link_train_result_check(void) { #ifdef _link_train_enable_ u8 i, val; lt8911exb_i2c_write_byte(0xff, 0xac); for (i = 0; i < 10; i++) { val = lt8911exb_i2c_read_byte(0x82); if (val & 0x20) { if ((val & 0x1f) == 0x1e) { LT8911_DEV_DEBUG("edp link train successed.\n"); return; } else { LT8911_DEV_DEBUG("edp link train failed.\n"); lt8911exb_i2c_write_byte(0xff, 0xac); lt8911exb_i2c_write_byte(0x00, 0x00); lt8911exb_i2c_write_byte(0x01, 0x0a); lt8911exb_i2c_write_byte(0x14, 0x80); lt8911exb_i2c_write_byte(0x14, 0x81); aicos_mdelay(50); lt8911exb_i2c_write_byte(0x14, 0x84); aicos_mdelay(50); lt8911exb_i2c_write_byte(0x14, 0xc0); } #ifdef LT8911_UART_DEBUG val = lt8911exb_i2c_read_byte(0x83); LT8911_DEV_DEBUG("panel link rate: %d\n", val); val = lt8911exb_i2c_read_byte(0x84); LT8911_DEV_DEBUG("panel link count: %d\n", val); #endif aicos_mdelay(100); } else { LT8911_DEV_DEBUG("link trian on going...\n"); aicos_mdelay(100); } } #endif } /* mipi should be ready before configuring below video check setting */ void lt8911exb_video_check(void) { u32 reg = 0x00; /* mipi byte clk check*/ lt8911exb_i2c_write_byte(0xff, 0x85); // Change Reg bank lt8911exb_i2c_write_byte(0x1d, 0x00); // FM select byte clk lt8911exb_i2c_write_byte(0x40, 0xf7); lt8911exb_i2c_write_byte(0x41, 0x30); if (ScrambleMode) { lt8911exb_i2c_write_byte(0xa1, 0x82); // eDP scramble mode; } else { lt8911exb_i2c_write_byte(0xa1, 0x02); // DP scramble mode; } // lt8911exb_i2c_write_byte(0x17, 0xf0); // 0xf0:Close scramble; 0xD0 : Open scramble lt8911exb_i2c_write_byte(0xff, 0x81); lt8911exb_i2c_write_byte(0x09, 0x7d); lt8911exb_i2c_write_byte(0x09, 0xfd); lt8911exb_i2c_write_byte(0xff, 0x85); aicos_mdelay(200); if (lt8911exb_i2c_read_byte(0x50) == 0x03) { reg = lt8911exb_i2c_read_byte(0x4d); reg = reg * 256 + lt8911exb_i2c_read_byte(0x4e); reg = reg * 256 + lt8911exb_i2c_read_byte(0x4f); LT8911_DEV_DEBUG("video check: mipi byteclk = %d x1000\n", reg); } else { LT8911_DEV_DEBUG("video check: mipi clk unstable\n"); } reg = lt8911exb_i2c_read_byte(0x76); reg = reg * 256 + lt8911exb_i2c_read_byte(0x77); LT8911_DEV_DEBUG("video check: Vtotal = %d\n", reg); lt8911exb_i2c_write_byte(0xff, 0xd0); reg = lt8911exb_i2c_read_byte(0x82); reg = reg * 256 + lt8911exb_i2c_read_byte(0x83); reg = reg / 3; LT8911_DEV_DEBUG("video check: Hact(word counter) = %d\n", reg); reg = lt8911exb_i2c_read_byte(0x85); reg = reg * 256 + lt8911exb_i2c_read_byte(0x86); LT8911_DEV_DEBUG("video check: Vact = %d\n", reg); } void lt8911exb_pcr_clk_status_check(void) { #ifdef LT8911_UART_DEBUG u8 reg; lt8911exb_i2c_write_byte(0xff, 0xd0); reg = lt8911exb_i2c_read_byte(0x87); LT8911_DEV_DEBUG("Reg 0xD087 = 0x%02x\n", reg); if (reg & 0x10) { LT8911_DEV_DEBUG("PCR Clock stable\n"); } else { LT8911_DEV_DEBUG("PCR Clock unstable\n"); } LT8911_DEV_DEBUG("\n"); #endif } static void panel_gpio_init(void) { panel_get_gpio(&iovcc18, LT9811_IOVCC18_EN); panel_get_gpio(&reset, LT9811_RESET_EN); panel_gpio_set_value(&iovcc18, 1); aicos_mdelay(120); panel_gpio_set_value(&reset, 1); aicos_mdelay(120); panel_gpio_set_value(&reset, 0); aicos_mdelay(120); panel_gpio_set_value(&reset, 1); aicos_mdelay(120); } static void panel_bl_enable(void) { panel_get_gpio(&bl_en, LT9811_BL_EN); panel_gpio_set_value(&bl_en, 1); } static int panel_enable(struct aic_panel *panel) { panel_gpio_init(); /* ArtInChip output mipi video single first */ panel_di_enable(panel, 0); panel_dsi_setup_realmode(panel); panel_de_timing_enable(panel, 0); lt8911_iic_setup(); /* read lt8911 chipid to check i2c */ lt8911exb_read_chipid(); lt8911exb_edo_video_cfg(panel->timings); lt8911exb_init(panel); /* read eDP panel edid */ lt8911exb_read_edid(); lt8911exb_txswing_preset(); lt8911exb_link_train(); /* debug eDP Link Train and mipi video signal */ lt8911exb_link_train_result_check(); lt8911exb_video_check(); lt8911exb_pcr_clk_status_check(); panel_bl_enable(); panel_backlight_enable(panel, 0); return 0; } static struct aic_panel_funcs panel_funcs = { .disable = panel_default_disable, .unprepare = panel_default_unprepare, .prepare = panel_default_prepare, .enable = panel_enable, .register_callback = panel_register_callback, }; #ifdef _1920x1200_eDP_Panel_ static struct display_timing lt9811_timing = { .pixelclock = 155 * 1000 * 1000, .hactive = 1920, .hback_porch = 80, .hfront_porch = 48, .hsync_len = 32, .vactive = 1200, .vback_porch = 20, .vfront_porch = 5, .vsync_len = 5, }; #endif #ifdef _1080P_eDP_Panel_ static struct display_timing lt9811_timing = { .pixelclock = 150 * 1000 * 1000, .hactive = 1920, .hback_porch = 148, .hfront_porch = 188, .hsync_len = 44, .vactive = 1080, .vback_porch = 36, .vfront_porch = 4, .vsync_len = 5, }; #endif #ifdef _1366x768_eDP_Panel_ static struct display_timing lt9811_timing = { .pixelclock = 72000000, .hactive = 1366, .hback_porch = 64, .hfront_porch = 14, .hsync_len = 56, .vactive = 768, .vback_porch = 28, .vfront_porch = 1, .vsync_len = 3, }; #endif struct panel_dsi dsi = { .mode = DSI_MOD_VID_EVENT, .format = DSI_FMT_RGB888, .lane_num = 4, }; struct aic_panel dsi_edp_lt9811exb = { .name = "panel-dsi-eDP-lt9811exb", .timings = <9811_timing, .funcs = &panel_funcs, .dsi = &dsi, .connector_type = AIC_MIPI_COM, };