mirror of
https://gitee.com/Vancouver2017/luban-lite-t3e-pro.git
synced 2025-12-14 18:38:55 +00:00
688 lines
20 KiB
C
688 lines
20 KiB
C
/*
|
|
* Copyright (c) 2024, ArtInChip Technology Co., Ltd
|
|
*
|
|
* SPDX-License-Identifier: Apache-2.0
|
|
*/
|
|
|
|
#include <drivers/i2c.h>
|
|
|
|
#include "panel_com.h"
|
|
|
|
#define LT8911_BLEN "PE.4"
|
|
#define LT8911_RESET "PA.8"
|
|
#define LT8911_I2C_NAME "i2c0"
|
|
#define LT8911_I2C_ADDR 0x29
|
|
|
|
#define _1_Port_ 0x80
|
|
#define _2_Port_ 0x00
|
|
|
|
#define _JEIDA_ 0x40
|
|
#define _VESA_ 0x00
|
|
|
|
#define _Sync_Mode_ 0x00
|
|
#define _DE_Mode_ 0x20
|
|
|
|
#define LT8911_LVDS_PORT _2_Port_
|
|
#define LT8911_LVDS_RX _VESA_
|
|
#define LT8911_LVDS_MODE _DE_Mode_
|
|
|
|
#define _LANE0_DATA_ 0
|
|
#define _LANE1_DATA_ 1
|
|
#define _LANE2_DATA_ 2
|
|
#define _LANE3_DATA_ 3
|
|
|
|
#define _EDP_DATA3_Select_ (_LANE3_DATA_ << 6)
|
|
#define _EDP_DATA2_Select_ (_LANE2_DATA_ << 4)
|
|
|
|
#define _EDP_DATA1_Select_ (_LANE1_DATA_ << 2)
|
|
#define _EDP_DATA0_Select_ (_LANE0_DATA_ << 0)
|
|
|
|
#define LT8911_EDP_DATA_SEQUENCE (_EDP_DATA3_Select_ + _EDP_DATA2_Select_ + \
|
|
_EDP_DATA1_Select_ + _EDP_DATA0_Select_)
|
|
|
|
// #define LT8911_DEBUG
|
|
|
|
#ifdef LT8911_DEBUG
|
|
#define LT8911_DEV_DEBUG pr_info
|
|
#else
|
|
#define LT8911_DEV_DEBUG(fmt, ...)
|
|
#endif
|
|
|
|
static struct gpio_desc lt8911_blen;
|
|
static struct gpio_desc lt8911_reset;
|
|
|
|
struct reg_sequence {
|
|
unsigned int reg;
|
|
unsigned int def;
|
|
};
|
|
|
|
static struct rt_i2c_bus_device *i2c_bus = RT_NULL;
|
|
|
|
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 void
|
|
lt8911_i2c_multi_reg_write(struct rt_i2c_bus_device *i2c,
|
|
const struct reg_sequence *regs, int num_regs)
|
|
{
|
|
int i;
|
|
|
|
for (i = 0; i < num_regs; i++)
|
|
lt8911_i2c_reg_write(i2c, regs[i].reg, regs[i].def);
|
|
|
|
}
|
|
|
|
static void lt8911_check_id(void)
|
|
{
|
|
#ifdef LT8911_DEBUG
|
|
lt8911_i2c_reg_write(i2c_bus, 0xff, 0x81);
|
|
lt8911_i2c_reg_write(i2c_bus, 0x08, 0x7f);
|
|
|
|
LT8911_DEV_DEBUG("LT8911EX chip ID: 0x%x 0x%x 0x%x\n",
|
|
/* 0x17 0x05 0xe0 */
|
|
lt8911_i2c_reg_read(i2c_bus, 0x00),
|
|
lt8911_i2c_reg_read(i2c_bus, 0x01),
|
|
lt8911_i2c_reg_read(i2c_bus, 0x02));
|
|
#endif
|
|
}
|
|
|
|
static void lt8911_edp_video_cfg(struct aic_panel *panel)
|
|
{
|
|
struct display_timing *timing = panel->timings;
|
|
u32 hactive, htotal, hpw, hfp, hbp;
|
|
u32 vactive, vtotal, vpw, vfp, vbp;
|
|
u32 pixelclock, dessc_m;
|
|
|
|
hactive = timing->hactive;
|
|
hfp = timing->hfront_porch;
|
|
hpw = timing->hsync_len;
|
|
hbp = timing->hback_porch;
|
|
htotal = hactive + hfp + hpw + hbp;
|
|
|
|
vactive = timing->vactive;
|
|
vfp = timing->vfront_porch;
|
|
vpw = timing->vsync_len;
|
|
vbp = timing->vback_porch;
|
|
vtotal = vactive + vfp + vpw + vbp;
|
|
|
|
lt8911_i2c_reg_write(i2c_bus, 0xff, 0xa8);
|
|
|
|
lt8911_i2c_reg_write(i2c_bus, 0x2d, 0x04);
|
|
lt8911_i2c_reg_write(i2c_bus, 0x05, htotal / 256);
|
|
lt8911_i2c_reg_write(i2c_bus, 0x06, htotal % 256);
|
|
lt8911_i2c_reg_write(i2c_bus, 0x07, (hpw + hbp) / 256);
|
|
lt8911_i2c_reg_write(i2c_bus, 0x08, (hpw + hbp) % 256);
|
|
lt8911_i2c_reg_write(i2c_bus, 0x09, hpw / 256);
|
|
lt8911_i2c_reg_write(i2c_bus, 0x0a, hpw % 256);
|
|
lt8911_i2c_reg_write(i2c_bus, 0x0b, hactive / 256);
|
|
lt8911_i2c_reg_write(i2c_bus, 0x0c, hactive % 256);
|
|
lt8911_i2c_reg_write(i2c_bus, 0x0d, vtotal / 256);
|
|
lt8911_i2c_reg_write(i2c_bus, 0x0e, vtotal % 256);
|
|
lt8911_i2c_reg_write(i2c_bus, 0x11, (vpw + vbp) / 256);
|
|
lt8911_i2c_reg_write(i2c_bus, 0x12, (vpw + vbp) % 256);
|
|
lt8911_i2c_reg_write(i2c_bus, 0x14, vpw % 256);
|
|
lt8911_i2c_reg_write(i2c_bus, 0x15, vactive / 256);
|
|
lt8911_i2c_reg_write(i2c_bus, 0x16, vactive % 256);
|
|
|
|
/* LVDS de only mode to regenerate h/v sync. */
|
|
lt8911_i2c_reg_write(i2c_bus, 0xff, 0xd8);
|
|
lt8911_i2c_reg_write(i2c_bus, 0x20, hfp / 256);
|
|
lt8911_i2c_reg_write(i2c_bus, 0x21, hfp % 256);
|
|
|
|
lt8911_i2c_reg_write(i2c_bus, 0x22, hpw / 256);
|
|
lt8911_i2c_reg_write(i2c_bus, 0x23, hpw % 256);
|
|
|
|
lt8911_i2c_reg_write(i2c_bus, 0x24, htotal / 256);
|
|
lt8911_i2c_reg_write(i2c_bus, 0x25, htotal % 256);
|
|
|
|
lt8911_i2c_reg_write(i2c_bus, 0x26, vfp % 256);
|
|
lt8911_i2c_reg_write(i2c_bus, 0x27, vpw % 256);
|
|
|
|
pixelclock = timing->pixelclock;
|
|
dessc_m = (pixelclock / 10 * 1000 * 4) / (25 * 100);
|
|
|
|
lt8911_i2c_reg_write(i2c_bus, 0xff, 0x85);
|
|
lt8911_i2c_reg_write(i2c_bus, 0xaa, dessc_m);
|
|
}
|
|
|
|
static void lt8911_init(struct aic_panel *panel)
|
|
{
|
|
int i, val;
|
|
/* init */
|
|
lt8911_i2c_reg_write(i2c_bus, 0xff, 0x81);
|
|
lt8911_i2c_reg_write(i2c_bus, 0x49, 0xff);
|
|
|
|
/* Txpll 2.7G */
|
|
lt8911_i2c_reg_write(i2c_bus, 0xff, 0x87);
|
|
lt8911_i2c_reg_write(i2c_bus, 0x19, 0x31);
|
|
lt8911_i2c_reg_write(i2c_bus, 0x1a, 0x1b);
|
|
lt8911_i2c_reg_write(i2c_bus, 0x1b, 0x00);
|
|
lt8911_i2c_reg_write(i2c_bus, 0x1c, 0x00);
|
|
|
|
/* txpll Analog */
|
|
lt8911_i2c_reg_write(i2c_bus, 0xff, 0x82);
|
|
lt8911_i2c_reg_write(i2c_bus, 0x09, 0x00);
|
|
lt8911_i2c_reg_write(i2c_bus, 0x02, 0x42);
|
|
lt8911_i2c_reg_write(i2c_bus, 0x03, 0x00);
|
|
lt8911_i2c_reg_write(i2c_bus, 0x03, 0x01);
|
|
lt8911_i2c_reg_write(i2c_bus, 0x0a, 0x1b);
|
|
lt8911_i2c_reg_write(i2c_bus, 0x04, 0x2a);
|
|
|
|
lt8911_i2c_reg_write(i2c_bus, 0xff, 0x87);
|
|
lt8911_i2c_reg_write(i2c_bus, 0x0c, 0x10);
|
|
|
|
lt8911_i2c_reg_write(i2c_bus, 0xff, 0x81);
|
|
lt8911_i2c_reg_write(i2c_bus, 0x09, 0xfc);
|
|
lt8911_i2c_reg_write(i2c_bus, 0x09, 0xfd);
|
|
|
|
lt8911_i2c_reg_write(i2c_bus, 0xff, 0x87);
|
|
lt8911_i2c_reg_write(i2c_bus, 0x0c, 0x11);
|
|
|
|
/* ssc */
|
|
lt8911_i2c_reg_write(i2c_bus, 0xff, 0x87);
|
|
lt8911_i2c_reg_write(i2c_bus, 0x13, 0x83);
|
|
lt8911_i2c_reg_write(i2c_bus, 0x14, 0x41);
|
|
lt8911_i2c_reg_write(i2c_bus, 0x16, 0x0a);
|
|
lt8911_i2c_reg_write(i2c_bus, 0x18, 0x0a);
|
|
lt8911_i2c_reg_write(i2c_bus, 0x19, 0x33);
|
|
|
|
lt8911_i2c_reg_write(i2c_bus, 0xff, 0x87);
|
|
|
|
/* Check Tx PLL */
|
|
for (i = 0; i < 5; i++) {
|
|
aic_delay_ms(10);
|
|
val = lt8911_i2c_reg_read(i2c_bus, 0x37);
|
|
if (val & 0x02) {
|
|
LT8911_DEV_DEBUG("LT8911 tx pll locked\n");
|
|
lt8911_i2c_reg_write(i2c_bus, 0xff, 0x87);
|
|
lt8911_i2c_reg_write(i2c_bus, 0x1a, 0x36);
|
|
lt8911_i2c_reg_write(i2c_bus, 0xff, 0x82);
|
|
lt8911_i2c_reg_write(i2c_bus, 0x0a, 0x36);
|
|
lt8911_i2c_reg_write(i2c_bus, 0x04, 0x3a);
|
|
break;
|
|
} else {
|
|
LT8911_DEV_DEBUG("LT8911 tx pll unlocked\n");
|
|
lt8911_i2c_reg_write(i2c_bus, 0xff, 0x81);
|
|
lt8911_i2c_reg_write(i2c_bus, 0x09, 0xfc);
|
|
lt8911_i2c_reg_write(i2c_bus, 0x09, 0xfd);
|
|
|
|
lt8911_i2c_reg_write(i2c_bus, 0xff, 0x87);
|
|
lt8911_i2c_reg_write(i2c_bus, 0x0c, 0x10);
|
|
lt8911_i2c_reg_write(i2c_bus, 0x0c, 0x11);
|
|
}
|
|
}
|
|
|
|
/* LVDS Rx analog */
|
|
lt8911_i2c_reg_write(i2c_bus, 0xff, 0x82);
|
|
lt8911_i2c_reg_write(i2c_bus, 0x3e, 0xa1);
|
|
|
|
/* digital top */
|
|
lt8911_i2c_reg_write(i2c_bus, 0xff, 0x85);
|
|
lt8911_i2c_reg_write(i2c_bus, 0xb0, 0x00);
|
|
|
|
/* lvds digital */
|
|
lt8911_i2c_reg_write(i2c_bus, 0xff, 0x85);
|
|
lt8911_i2c_reg_write(i2c_bus, 0xc3, 0x20);
|
|
|
|
lt8911_i2c_reg_write(i2c_bus, 0xff, 0x81);
|
|
lt8911_i2c_reg_write(i2c_bus, 0x05, 0xae);
|
|
lt8911_i2c_reg_write(i2c_bus, 0x05, 0xfe);
|
|
|
|
/* AUX reset */
|
|
lt8911_i2c_reg_write(i2c_bus, 0xff, 0x81);
|
|
lt8911_i2c_reg_write(i2c_bus, 0x07, 0xfe);
|
|
lt8911_i2c_reg_write(i2c_bus, 0x07, 0xff);
|
|
lt8911_i2c_reg_write(i2c_bus, 0x0a, 0xfc);
|
|
lt8911_i2c_reg_write(i2c_bus, 0x0a, 0xfe);
|
|
|
|
lt8911_i2c_reg_write(i2c_bus, 0xff, 0xd8);
|
|
|
|
lt8911_i2c_reg_write(i2c_bus, 0x10, LT8911_LVDS_PORT);
|
|
lt8911_i2c_reg_write(i2c_bus, 0x11, LT8911_LVDS_RX);
|
|
lt8911_i2c_reg_write(i2c_bus, 0x1f, LT8911_LVDS_MODE);
|
|
|
|
/* eDP out swap config: */
|
|
lt8911_i2c_reg_write(i2c_bus, 0xff, 0xac);
|
|
lt8911_i2c_reg_write(i2c_bus, 0x15, LT8911_EDP_DATA_SEQUENCE);
|
|
lt8911_i2c_reg_write(i2c_bus, 0x16, 0x00);
|
|
|
|
/* tx phy */
|
|
lt8911_i2c_reg_write(i2c_bus, 0xff, 0x82);
|
|
lt8911_i2c_reg_write(i2c_bus, 0x11, 0x00);
|
|
lt8911_i2c_reg_write(i2c_bus, 0x13, 0x10);
|
|
lt8911_i2c_reg_write(i2c_bus, 0x14, 0x0c);
|
|
lt8911_i2c_reg_write(i2c_bus, 0x14, 0x08);
|
|
lt8911_i2c_reg_write(i2c_bus, 0x13, 0x20);
|
|
|
|
lt8911_i2c_reg_write(i2c_bus, 0xff, 0x82);
|
|
lt8911_i2c_reg_write(i2c_bus, 0x0e, 0x35);
|
|
|
|
lt8911_i2c_reg_write(i2c_bus, 0x12, 0x33);
|
|
|
|
/* eDP Tx Digital */
|
|
lt8911_i2c_reg_write(i2c_bus, 0xff, 0xa8);
|
|
lt8911_i2c_reg_write(i2c_bus, 0x27, 0x10);
|
|
|
|
/* _8_bit_eDP_ */
|
|
lt8911_i2c_reg_write(i2c_bus, 0x17, 0x10);
|
|
lt8911_i2c_reg_write(i2c_bus, 0x18, 0x20);
|
|
|
|
/* nvid */
|
|
lt8911_i2c_reg_write(i2c_bus, 0xff, 0xa0);
|
|
lt8911_i2c_reg_write(i2c_bus, 0x00, 0x00);
|
|
lt8911_i2c_reg_write(i2c_bus, 0x01, 0x80);
|
|
|
|
/* gpio init */
|
|
lt8911_i2c_reg_write(i2c_bus, 0xff, 0xd8);
|
|
lt8911_i2c_reg_write(i2c_bus, 0x16, 0x01);
|
|
|
|
lt8911_i2c_reg_write(i2c_bus, 0xff, 0x85);
|
|
lt8911_i2c_reg_write(i2c_bus, 0x1b, 0x05);
|
|
lt8911_i2c_reg_write(i2c_bus, 0xc0, 0x00);
|
|
lt8911_i2c_reg_write(i2c_bus, 0xc1, 0x24);
|
|
|
|
lt8911_i2c_reg_write(i2c_bus, 0xff, 0x82);
|
|
lt8911_i2c_reg_write(i2c_bus, 0x5a, 0x01);
|
|
lt8911_i2c_reg_write(i2c_bus, 0x5b, 0xc0);
|
|
|
|
/* gpio_sync_output */
|
|
lt8911_i2c_reg_write(i2c_bus, 0x60, 0x00);
|
|
lt8911_i2c_reg_write(i2c_bus, 0x61, 0x00);
|
|
}
|
|
|
|
static void lt8911ex_tx_swingpreset(void)
|
|
{
|
|
const struct reg_sequence seq[] = {
|
|
{ 0xFF, 0x82 },
|
|
{ 0x22, 0x82 },
|
|
{ 0x23, 0x00 },
|
|
{ 0x24, 0x80 },
|
|
{ 0x25, 0x00 },
|
|
{ 0x26, 0x82 },
|
|
{ 0x27, 0x00 },
|
|
{ 0x28, 0x80 },
|
|
{ 0x29, 0x00 },
|
|
};
|
|
lt8911_i2c_multi_reg_write(i2c_bus, seq, ARRAY_SIZE(seq));
|
|
}
|
|
|
|
static void lt8911_link_train(void)
|
|
{
|
|
const struct reg_sequence seq[] = {
|
|
{ 0x06, 0xff },
|
|
{ 0xff, 0x85 },
|
|
{ 0xa1, 0x01 },
|
|
|
|
/* Aux setup */
|
|
{ 0xff, 0xac },
|
|
{ 0x00, 0x60 },
|
|
{ 0xff, 0xa6 },
|
|
{ 0x2a, 0x00 },
|
|
{ 0xff, 0x81 },
|
|
{ 0x07, 0xfe },
|
|
{ 0x07, 0xff },
|
|
{ 0x0a, 0xfc },
|
|
{ 0x0a, 0xfe },
|
|
{ 0xff, 0xa8 },
|
|
{ 0x2d, 0x00 },
|
|
{ 0xff, 0xa8 },
|
|
{ 0x2d, 0x00 },
|
|
|
|
/* link train */
|
|
{ 0xff, 0x85 },
|
|
{ 0x1a, 0x02 },
|
|
{ 0xff, 0xac },
|
|
{ 0x00, 0x64 },
|
|
{ 0x01, 0x0a },
|
|
{ 0x0c, 0x85 },
|
|
{ 0x0c, 0xc5 },
|
|
};
|
|
|
|
lt8911_i2c_reg_write(i2c_bus, 0xff, 0x81);
|
|
lt8911_i2c_reg_write(i2c_bus, 0x06, 0xdf);
|
|
aic_delay_ms(10);
|
|
|
|
lt8911_i2c_multi_reg_write(i2c_bus, seq, ARRAY_SIZE(seq));
|
|
}
|
|
|
|
static void lt8911_lvds_clock_check(void)
|
|
{
|
|
#ifdef LT8911_DEBUG
|
|
u32 fm_value;
|
|
|
|
lt8911_i2c_reg_write(i2c_bus, 0xff, 0x85);
|
|
lt8911_i2c_reg_write(i2c_bus, 0x1d, 0x03);
|
|
aic_delay_ms(200);
|
|
fm_value = 0;
|
|
fm_value = lt8911_i2c_reg_read(i2c_bus, 0x4d);
|
|
fm_value = fm_value * 0x100 + lt8911_i2c_reg_read(i2c_bus, 0x4e);
|
|
fm_value = fm_value * 0x100 + lt8911_i2c_reg_read(i2c_bus, 0x4f);
|
|
LT8911_DEV_DEBUG("LVDS portA clock: %d * 10K\n", fm_value);
|
|
|
|
lt8911_i2c_reg_write(i2c_bus, 0x1d, 0x04);
|
|
aic_delay_ms(200);
|
|
fm_value = 0;
|
|
fm_value = lt8911_i2c_reg_read(i2c_bus, 0x4d);
|
|
fm_value = fm_value * 0x100 + lt8911_i2c_reg_read(i2c_bus, 0x4e);
|
|
fm_value = fm_value * 0x100 + lt8911_i2c_reg_read(i2c_bus, 0x4f);
|
|
LT8911_DEV_DEBUG("LVDS portB clock: %d * 10K\n", fm_value);
|
|
|
|
lt8911_i2c_reg_write(i2c_bus, 0x1d, 0x08);
|
|
aic_delay_ms(200);
|
|
fm_value = 0;
|
|
fm_value = lt8911_i2c_reg_read(i2c_bus, 0x4d);
|
|
fm_value = fm_value * 0x100 + lt8911_i2c_reg_read(i2c_bus, 0x4e);
|
|
fm_value = fm_value * 0x100 + lt8911_i2c_reg_read(i2c_bus, 0x4f);
|
|
|
|
LT8911_DEV_DEBUG("LVDS pixel clock: %d * 10K\n", fm_value / 10);
|
|
#endif
|
|
}
|
|
|
|
/* LVDS should be ready before configuring below video check setting */
|
|
static bool lt8911_lvds_signal_check(struct aic_panel *panel)
|
|
{
|
|
#ifdef LT8911_DEBUG
|
|
u16 h_fp, h_sync, h_bp, h_total;
|
|
u16 v_fp, v_sync, v_bp, v_total;
|
|
u8 sync_pol;
|
|
#endif
|
|
struct display_timing *timing = panel->timings;
|
|
u16 h_active, v_active;
|
|
|
|
lt8911_i2c_reg_write(i2c_bus, 0xff, 0x85);
|
|
lt8911_i2c_reg_write(i2c_bus, 0xa1, 0x01);
|
|
|
|
v_active = lt8911_i2c_reg_read(i2c_bus, 0x88);
|
|
v_active = v_active * 0x100 + lt8911_i2c_reg_read(i2c_bus, 0x89);
|
|
|
|
h_active = lt8911_i2c_reg_read(i2c_bus, 0x8a);
|
|
h_active = h_active * 0x100 + lt8911_i2c_reg_read(i2c_bus, 0x8b);
|
|
|
|
#ifdef LT8911_DEBUG
|
|
sync_pol = lt8911_i2c_reg_read(i2c_bus, 0x7a);
|
|
v_sync = lt8911_i2c_reg_read(i2c_bus, 0x7b);
|
|
|
|
h_sync = lt8911_i2c_reg_read(i2c_bus, 0x7c);
|
|
h_sync = h_sync * 0x100 + lt8911_i2c_reg_read(i2c_bus, 0x7d);
|
|
|
|
v_bp = lt8911_i2c_reg_read(i2c_bus, 0x7e);
|
|
v_fp = lt8911_i2c_reg_read(i2c_bus, 0x7f);
|
|
|
|
h_bp = lt8911_i2c_reg_read(i2c_bus, 0x80);
|
|
h_bp = h_bp * 0x100 + lt8911_i2c_reg_read(i2c_bus, 0x81);
|
|
|
|
h_fp = lt8911_i2c_reg_read(i2c_bus, 0x82);
|
|
h_fp = h_fp * 0x100 + lt8911_i2c_reg_read(i2c_bus, 0x83);
|
|
|
|
v_total = lt8911_i2c_reg_read(i2c_bus, 0x84);
|
|
v_total = v_total * 0x100 + lt8911_i2c_reg_read(i2c_bus, 0x85);
|
|
|
|
h_total = lt8911_i2c_reg_read(i2c_bus, 0x86);
|
|
h_total = h_total * 0x100 + lt8911_i2c_reg_read(i2c_bus, 0x87);
|
|
|
|
LT8911_DEV_DEBUG("sync_pol = %x\n", sync_pol);
|
|
|
|
LT8911_DEV_DEBUG("hfp, hs, hbp, hact, htotal = %d, %d, %d, %d, %d\n",
|
|
h_fp, h_sync, h_bp , h_active, h_total);
|
|
|
|
LT8911_DEV_DEBUG("vfp, vs, vbp, vact, vtotal = %d, %d, %d, %d, %d\n",
|
|
v_fp , v_sync, v_bp, v_active ,v_total);
|
|
#endif
|
|
|
|
return (h_active != timing->hactive) || (v_active != timing->vactive);
|
|
}
|
|
|
|
static void lt8911ex_link_train_check(void)
|
|
{
|
|
u8 val, i;
|
|
|
|
lt8911_i2c_reg_write(i2c_bus, 0xff, 0xac);
|
|
for (i = 0; i < 5; i++)
|
|
{
|
|
val = lt8911_i2c_reg_read(i2c_bus, 0x82);
|
|
if (val & 0x20) {
|
|
if ((val & 0x1f) == 0x1e) {
|
|
LT8911_DEV_DEBUG("eDP link train successed: %d\n", val);
|
|
return;
|
|
} else {
|
|
LT8911_DEV_DEBUG("eDP link train failed: %d\n", val);
|
|
|
|
lt8911_i2c_reg_write(i2c_bus, 0xff, 0xac);
|
|
lt8911_i2c_reg_write(i2c_bus, 0x00, 0x00);
|
|
lt8911_i2c_reg_write(i2c_bus, 0x01, 0x0a);
|
|
lt8911_i2c_reg_write(i2c_bus, 0x14, 0x80);
|
|
lt8911_i2c_reg_write(i2c_bus, 0x14, 0x81);
|
|
aic_delay_ms(50);
|
|
lt8911_i2c_reg_write(i2c_bus, 0x14, 0x84);
|
|
aic_delay_ms(50);
|
|
lt8911_i2c_reg_write(i2c_bus, 0x14, 0xc0);
|
|
}
|
|
|
|
val = lt8911_i2c_reg_read(i2c_bus, 0x83);
|
|
LT8911_DEV_DEBUG("panel link rate: %d", val);
|
|
|
|
val = lt8911_i2c_reg_read(i2c_bus, 0x84);
|
|
LT8911_DEV_DEBUG("panel link count: %d", val);
|
|
|
|
aic_delay_ms(100);
|
|
} else {
|
|
aic_delay_ms(100);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
static void lt8911_video_on(struct aic_panel *panel)
|
|
{
|
|
bool lvds_signal_off, txpll_unlock = true;
|
|
int i = 0;
|
|
|
|
lt8911_check_id();
|
|
lt8911_edp_video_cfg(panel);
|
|
lt8911_init(panel);
|
|
|
|
do {
|
|
/* register bank */
|
|
lt8911_i2c_reg_write(i2c_bus, 0xff, 0x85);
|
|
/* clock stable */
|
|
if ((lt8911_i2c_reg_read(i2c_bus, 0x12) & 0xc0) == 0x40) {
|
|
lt8911_i2c_reg_write(i2c_bus, 0xff, 0x87);
|
|
/* pll unlocked */
|
|
if ((lt8911_i2c_reg_read(i2c_bus, 0x37) & 0x04) == 0x00) {
|
|
/* rxpll reset */
|
|
lt8911_i2c_reg_write(i2c_bus, 0xff, 0x81);
|
|
lt8911_i2c_reg_write(i2c_bus, 0x04, 0xfd);
|
|
|
|
aic_delay_ms(10);
|
|
lt8911_i2c_reg_write(i2c_bus, 0x04, 0xff);
|
|
|
|
LT8911_DEV_DEBUG("lvds rxpll unlocked, reset rxpll\n");
|
|
} else {
|
|
LT8911_DEV_DEBUG("lvds rxpll locked\n");
|
|
}
|
|
|
|
lt8911_i2c_reg_write(i2c_bus, 0xff, 0x87);
|
|
/* txpll unlocked */
|
|
if ((lt8911_i2c_reg_read(i2c_bus, 0x37) & 0x02) == 0x00) {
|
|
lt8911_check_id();
|
|
lt8911_edp_video_cfg(panel);
|
|
lt8911_init(panel);
|
|
|
|
txpll_unlock = true;
|
|
LT8911_DEV_DEBUG("lvds txpll unlocked, reset 8911EX\n");
|
|
} else {
|
|
txpll_unlock = false;
|
|
LT8911_DEV_DEBUG("TxPLL locked\n");
|
|
}
|
|
}
|
|
|
|
aic_delay_ms(200);
|
|
lt8911_lvds_clock_check();
|
|
|
|
lvds_signal_off = lt8911_lvds_signal_check(panel);
|
|
if (lvds_signal_off) {
|
|
lt8911_i2c_reg_write(i2c_bus, 0xff, 0x81);
|
|
lt8911_i2c_reg_write(i2c_bus, 0x05, 0xae);
|
|
|
|
aic_delay_ms(10);
|
|
lt8911_i2c_reg_write(i2c_bus, 0x05, 0xfe);
|
|
|
|
LT8911_DEV_DEBUG("No LVDS Signal Input\n");
|
|
}
|
|
|
|
i++;
|
|
} while ((txpll_unlock || lvds_signal_off) && (i < 5));
|
|
|
|
if (i < 5)
|
|
LT8911_DEV_DEBUG("LVDS Signal is OK\n");
|
|
else
|
|
return;
|
|
|
|
lt8911_i2c_reg_write(i2c_bus, 0xff, 0x81);
|
|
lt8911_i2c_reg_write(i2c_bus, 0x06, 0xdf);
|
|
|
|
aic_delay_ms(10);
|
|
lt8911_i2c_reg_write(i2c_bus, 0x06, 0xff);
|
|
|
|
lt8911ex_tx_swingpreset();
|
|
|
|
lt8911_link_train();
|
|
|
|
lt8911ex_link_train_check();
|
|
}
|
|
|
|
static void lt8911_hard_reset(void)
|
|
{
|
|
panel_get_gpio(<8911_reset, LT8911_RESET);
|
|
panel_gpio_set_value(<8911_reset, 0);
|
|
aic_delay_ms(120);
|
|
panel_gpio_set_value(<8911_reset, 1);
|
|
}
|
|
|
|
static void lt8911_video_setup(struct aic_panel *panel)
|
|
{
|
|
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);
|
|
return;
|
|
}
|
|
|
|
lt8911_video_on(panel);
|
|
}
|
|
|
|
static int panel_enable(struct aic_panel *panel)
|
|
{
|
|
lt8911_hard_reset();
|
|
|
|
panel_di_enable(panel, 0);
|
|
panel_de_timing_enable(panel, 0);
|
|
|
|
lt8911_video_setup(panel);
|
|
|
|
panel_get_gpio(<8911_blen, LT8911_BLEN);
|
|
panel_gpio_set_value(<8911_blen, 1);
|
|
panel_backlight_enable(panel, 0);
|
|
return 0;
|
|
}
|
|
|
|
static int panel_disable(struct aic_panel *panel)
|
|
{
|
|
panel_backlight_disable(panel, 0);
|
|
panel_di_disable(panel, 0);
|
|
panel_de_timing_disable(panel, 0);
|
|
|
|
panel_gpio_set_value(<8911_reset, 0);
|
|
return 0;
|
|
}
|
|
|
|
static struct aic_panel_funcs simple_funcs = {
|
|
.prepare = panel_default_prepare,
|
|
.enable = panel_enable,
|
|
.disable = panel_disable,
|
|
.unprepare = panel_default_unprepare,
|
|
.register_callback = panel_register_callback,
|
|
};
|
|
|
|
static struct display_timing panel_timing = {
|
|
.pixelclock = 148 * 1000000,
|
|
|
|
.hactive = 1920,
|
|
.hback_porch = 148,
|
|
.hfront_porch = 88,
|
|
.hsync_len = 44,
|
|
|
|
.vactive = 1080,
|
|
.vback_porch = 36,
|
|
.vfront_porch = 4,
|
|
.vsync_len = 5,
|
|
|
|
.flags = DISPLAY_FLAGS_HSYNC_LOW | DISPLAY_FLAGS_VSYNC_LOW,
|
|
};
|
|
|
|
static struct panel_lvds lvds = {
|
|
.mode = NS,
|
|
.link_mode = DUAL_LINK,
|
|
};
|
|
|
|
struct aic_panel bridge_lt8911 = {
|
|
.name = "panel-bridge-lt8911",
|
|
.timings = &panel_timing,
|
|
.funcs = &simple_funcs,
|
|
.lvds = &lvds,
|
|
.connector_type = AIC_LVDS_COM,
|
|
};
|
|
|