mirror of
https://github.com/hardkernel/linux.git
synced 2026-06-09 20:32:04 +09:00
edp anx6345: add dpcd&edid read support
This commit is contained in:
File diff suppressed because it is too large
Load Diff
@@ -13,7 +13,7 @@
|
||||
#include <linux/of_gpio.h>
|
||||
#endif
|
||||
#include "anx6345.h"
|
||||
|
||||
#include "dpcd_edid.h"
|
||||
#if defined(CONFIG_DEBUG_FS)
|
||||
#include <linux/fs.h>
|
||||
#include <linux/debugfs.h>
|
||||
@@ -169,8 +169,8 @@ static int get_dp_chip_id(struct i2c_client *client)
|
||||
{
|
||||
char c1,c2;
|
||||
int id;
|
||||
anx6345_i2c_read_p1_reg(client,SP_TX_DEV_IDL_REG,&c1);
|
||||
anx6345_i2c_read_p1_reg(client,SP_TX_DEV_IDH_REG,&c2);
|
||||
anx6345_i2c_read_p1_reg(client,DEV_IDL_REG,&c1);
|
||||
anx6345_i2c_read_p1_reg(client,DEV_IDH_REG,&c2);
|
||||
id = c2;
|
||||
return (id<<8)|c1;
|
||||
}
|
||||
@@ -624,119 +624,459 @@ static int anx980x_init(struct i2c_client *client)
|
||||
return 0;
|
||||
}
|
||||
|
||||
#if 1
|
||||
|
||||
static int anx6345_bist_mode(struct i2c_client *client)
|
||||
{
|
||||
struct edp_anx6345 *anx6345 = i2c_get_clientdata(client);
|
||||
struct rk_screen *screen = &anx6345->screen;
|
||||
u16 x_total ,y_total;
|
||||
u32 total, act_total;
|
||||
u16 x_total ,y_total, x_act;
|
||||
char val = 0x00;
|
||||
//these register are for bist mode
|
||||
x_total = screen->mode.left_margin + screen->mode.right_margin +
|
||||
screen->mode.xres + screen->mode.hsync_len;
|
||||
y_total = screen->mode.upper_margin + screen->mode.lower_margin +
|
||||
screen->mode.yres + screen->mode.vsync_len;
|
||||
total = x_total * y_total;
|
||||
printk("%s>>>>total:0x%08x\n",__func__, total);
|
||||
act_total = screen->mode.xres * screen->mode.yres;
|
||||
x_total >>= 1;
|
||||
x_act = screen->mode.xres >> 1;
|
||||
val = y_total & 0xff;
|
||||
anx6345_i2c_write_p1_reg(client,SP_TX_TOTAL_LINEL_REG,&val);
|
||||
anx6345_i2c_write_p1_reg(client,TOTAL_LINEL_REG,&val);
|
||||
val = (y_total >> 8);
|
||||
anx6345_i2c_write_p1_reg(client,SP_TX_TOTAL_LINEH_REG,&val);
|
||||
anx6345_i2c_write_p1_reg(client,TOTAL_LINEH_REG,&val);
|
||||
val = (screen->mode.yres & 0xff);
|
||||
anx6345_i2c_write_p1_reg(client,SP_TX_ACT_LINEL_REG,&val);
|
||||
anx6345_i2c_write_p1_reg(client,ACT_LINEL_REG,&val);
|
||||
val = (screen->mode.yres >> 8);
|
||||
anx6345_i2c_write_p1_reg(client,SP_TX_ACT_LINEH_REG,&val);
|
||||
anx6345_i2c_write_p1_reg(client,ACT_LINEH_REG,&val);
|
||||
val = screen->mode.lower_margin;
|
||||
anx6345_i2c_write_p1_reg(client,SP_TX_VF_PORCH_REG,&val);
|
||||
anx6345_i2c_write_p1_reg(client,VF_PORCH_REG,&val);
|
||||
val = screen->mode.vsync_len;
|
||||
anx6345_i2c_write_p1_reg(client,SP_TX_VSYNC_CFG_REG,&val);
|
||||
anx6345_i2c_write_p1_reg(client,VSYNC_CFG_REG,&val);
|
||||
val = screen->mode.upper_margin;
|
||||
anx6345_i2c_write_p1_reg(client,SP_TX_VB_PORCH_REG,&val);
|
||||
val = total & 0xff;
|
||||
val = 0x50;
|
||||
anx6345_i2c_write_p1_reg(client,SP_TX_TOTAL_PIXELL_REG,&val);
|
||||
val = total >> 8;
|
||||
val = 0x04;
|
||||
anx6345_i2c_write_p1_reg(client,SP_TX_TOTAL_PIXELH_REG,&val);
|
||||
val = (act_total & 0xff);
|
||||
val = 0x00;
|
||||
anx6345_i2c_write_p1_reg(client,SP_TX_ACT_PIXELL_REG,&val);
|
||||
val = (act_total >> 8);
|
||||
val = 0x04;
|
||||
anx6345_i2c_write_p1_reg(client,SP_TX_ACT_PIXELH_REG,&val);
|
||||
anx6345_i2c_write_p1_reg(client,VB_PORCH_REG,&val);
|
||||
val = x_total & 0xff;
|
||||
anx6345_i2c_write_p1_reg(client,TOTAL_PIXELL_REG,&val);
|
||||
val = x_total >> 8;
|
||||
anx6345_i2c_write_p1_reg(client,TOTAL_PIXELH_REG,&val);
|
||||
val = (x_act & 0xff);
|
||||
anx6345_i2c_write_p1_reg(client,ACT_PIXELL_REG,&val);
|
||||
val = (x_act >> 8);
|
||||
anx6345_i2c_write_p1_reg(client,ACT_PIXELH_REG,&val);
|
||||
val = screen->mode.right_margin & 0xff;
|
||||
anx6345_i2c_write_p1_reg(client,SP_TX_HF_PORCHL_REG,&val);
|
||||
anx6345_i2c_write_p1_reg(client,HF_PORCHL_REG,&val);
|
||||
val = screen->mode.right_margin >> 8;
|
||||
anx6345_i2c_write_p1_reg(client,SP_TX_HF_PORCHH_REG,&val);
|
||||
anx6345_i2c_write_p1_reg(client,HF_PORCHH_REG,&val);
|
||||
val = screen->mode.hsync_len & 0xff;
|
||||
anx6345_i2c_write_p1_reg(client,SP_TX_HSYNC_CFGL_REG,&val);
|
||||
anx6345_i2c_write_p1_reg(client,HSYNC_CFGL_REG,&val);
|
||||
val = screen->mode.hsync_len >> 8;
|
||||
anx6345_i2c_write_p1_reg(client,SP_TX_HSYNC_CFGH_REG,&val);
|
||||
anx6345_i2c_write_p1_reg(client,HSYNC_CFGH_REG,&val);
|
||||
val = screen->mode.left_margin & 0xff;
|
||||
anx6345_i2c_write_p1_reg(client,SP_TX_HB_PORCHL_REG,&val);
|
||||
anx6345_i2c_write_p1_reg(client,HB_PORCHL_REG,&val);
|
||||
val = screen->mode.left_margin >> 8;
|
||||
anx6345_i2c_write_p1_reg(client,SP_TX_HB_PORCHH_REG,&val);
|
||||
anx6345_i2c_write_p1_reg(client,HB_PORCHH_REG,&val);
|
||||
val = 0x13;
|
||||
anx6345_i2c_write_p1_reg(client,SP_TX_VID_CTRL10_REG,&val);
|
||||
anx6345_i2c_write_p1_reg(client,VID_CTRL10_REG,&val);
|
||||
|
||||
|
||||
//enable BIST. In normal mode, don't need to config this reg
|
||||
val = 0x08;
|
||||
anx6345_i2c_write_p1_reg(client, SP_TX_VID_CTRL4_REG, &val);
|
||||
anx6345_i2c_write_p1_reg(client, VID_CTRL4_REG, &val);
|
||||
printk("anx6345 enter bist mode\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
#else
|
||||
static int anx6345_bist_mode(struct i2c_client *client)
|
||||
|
||||
|
||||
int anx6345_start_aux_transaction(struct i2c_client *client)
|
||||
{
|
||||
char val = 0x00;
|
||||
//these register are for bist mode
|
||||
val = 0x2c;
|
||||
anx6345_i2c_write_p1_reg(client,SP_TX_TOTAL_LINEL_REG,&val);
|
||||
val = 0x06;
|
||||
anx6345_i2c_write_p1_reg(client,SP_TX_TOTAL_LINEH_REG,&val);
|
||||
val = 0x00;
|
||||
anx6345_i2c_write_p1_reg(client,SP_TX_ACT_LINEL_REG,&val);
|
||||
val = 0x06;
|
||||
anx6345_i2c_write_p1_reg(client,SP_TX_ACT_LINEH_REG,&val);
|
||||
val = 0x02;
|
||||
anx6345_i2c_write_p1_reg(client,SP_TX_VF_PORCH_REG,&val);
|
||||
val = 0x04;
|
||||
anx6345_i2c_write_p1_reg(client,SP_TX_VSYNC_CFG_REG,&val);
|
||||
val = 0x26;
|
||||
anx6345_i2c_write_p1_reg(client,SP_TX_VB_PORCH_REG,&val);
|
||||
val = 0x50;
|
||||
anx6345_i2c_write_p1_reg(client,SP_TX_TOTAL_PIXELL_REG,&val);
|
||||
val = 0x04;
|
||||
anx6345_i2c_write_p1_reg(client,SP_TX_TOTAL_PIXELH_REG,&val);
|
||||
val = 0x00;
|
||||
anx6345_i2c_write_p1_reg(client,SP_TX_ACT_PIXELL_REG,&val);
|
||||
val = 0x04;
|
||||
anx6345_i2c_write_p1_reg(client,SP_TX_ACT_PIXELH_REG,&val);
|
||||
val = 0x18;
|
||||
anx6345_i2c_write_p1_reg(client,SP_TX_HF_PORCHL_REG,&val);
|
||||
val = 0x00;
|
||||
anx6345_i2c_write_p1_reg(client,SP_TX_HF_PORCHH_REG,&val);
|
||||
val = 0x10;
|
||||
anx6345_i2c_write_p1_reg(client,SP_TX_HSYNC_CFGL_REG,&val);
|
||||
val = 0x00;
|
||||
anx6345_i2c_write_p1_reg(client,SP_TX_HSYNC_CFGH_REG,&val);
|
||||
val = 0x28;
|
||||
anx6345_i2c_write_p1_reg(client,SP_TX_HB_PORCHL_REG,&val);
|
||||
val = 0x13;
|
||||
anx6345_i2c_write_p1_reg(client,SP_TX_VID_CTRL10_REG,&val);
|
||||
//enable BIST. In normal mode, don't need to config this reg
|
||||
val = 0x08;
|
||||
anx6345_i2c_write_p1_reg(client, SP_TX_VID_CTRL4_REG, &val);
|
||||
printk("anx6345 enter bist mode\n");
|
||||
char val;
|
||||
int retval = 0;
|
||||
int timeout_loop = 0;
|
||||
int aux_timeout = 0;
|
||||
|
||||
|
||||
return 0;
|
||||
anx6345_i2c_read_p0_reg(client, DP_AUX_CH_CTL_2, &val);
|
||||
val |= AUX_EN;
|
||||
anx6345_i2c_write_p0_reg(client, DP_AUX_CH_CTL_2, &val);
|
||||
|
||||
anx6345_i2c_read_p0_reg(client, DP_AUX_CH_CTL_2, &val);
|
||||
while (val & AUX_EN) {
|
||||
aux_timeout++;
|
||||
if ((DP_TIMEOUT_LOOP_CNT * 10) < aux_timeout) {
|
||||
dev_err(&client->dev, "AUX CH enable timeout!\n");
|
||||
return -ETIMEDOUT;
|
||||
}
|
||||
anx6345_i2c_read_p0_reg(client, DP_AUX_CH_CTL_2, &val);
|
||||
udelay(100);
|
||||
}
|
||||
|
||||
/* Is AUX CH command redply received? */
|
||||
anx6345_i2c_read_p1_reg(client, DP_INT_STA, &val);
|
||||
while (!(val & RPLY_RECEIV)) {
|
||||
timeout_loop++;
|
||||
if (DP_TIMEOUT_LOOP_CNT < timeout_loop) {
|
||||
dev_err(&client->dev, "AUX CH command redply failed!\n");
|
||||
return -ETIMEDOUT;
|
||||
}
|
||||
anx6345_i2c_read_p1_reg(client, DP_INT_STA, &val);
|
||||
udelay(10);
|
||||
}
|
||||
|
||||
/* Clear interrupt source for AUX CH command redply */
|
||||
anx6345_i2c_write_p1_reg(client, DP_INT_STA, &val);
|
||||
|
||||
/* Check AUX CH error access status */
|
||||
anx6345_i2c_read_p0_reg(client, AUX_CH_STA, &val);
|
||||
if ((val & AUX_STATUS_MASK) != 0) {
|
||||
dev_err(&client->dev, "AUX CH error happens: %d\n\n",
|
||||
val & AUX_STATUS_MASK);
|
||||
return -EREMOTEIO;
|
||||
}
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
#endif
|
||||
int anx6345_dpcd_write_bytes(struct i2c_client *client,
|
||||
unsigned int val_addr,
|
||||
unsigned int count,
|
||||
unsigned char data[])
|
||||
{
|
||||
char val;
|
||||
unsigned int start_offset;
|
||||
unsigned int cur_data_count;
|
||||
unsigned int cur_data_idx;
|
||||
int retval = 0;
|
||||
|
||||
start_offset = 0;
|
||||
while (start_offset < count) {
|
||||
/* Buffer size of AUX CH is 16 * 4bytes */
|
||||
if ((count - start_offset) > 16)
|
||||
cur_data_count = 16;
|
||||
else
|
||||
cur_data_count = count - start_offset;
|
||||
|
||||
val = BUF_CLR;
|
||||
anx6345_i2c_write_p0_reg(client, BUF_DATA_CTL, &val);
|
||||
|
||||
val = AUX_ADDR_7_0(val_addr + start_offset);
|
||||
anx6345_i2c_write_p0_reg(client, DP_AUX_ADDR_7_0, &val);
|
||||
val = AUX_ADDR_15_8(val_addr + start_offset);
|
||||
anx6345_i2c_write_p0_reg(client, DP_AUX_ADDR_15_8, &val);
|
||||
val = AUX_ADDR_19_16(val_addr + start_offset);
|
||||
anx6345_i2c_write_p0_reg(client, DP_AUX_ADDR_19_16, &val);
|
||||
|
||||
for (cur_data_idx = 0; cur_data_idx < cur_data_count;
|
||||
cur_data_idx++) {
|
||||
val = data[start_offset + cur_data_idx];
|
||||
anx6345_i2c_write_p0_reg(client, BUF_DATA_0 + cur_data_idx, &val);
|
||||
}
|
||||
|
||||
/*
|
||||
* Set DisplayPort transaction and write
|
||||
* If bit 3 is 1, DisplayPort transaction.
|
||||
* If Bit 3 is 0, I2C transaction.
|
||||
*/
|
||||
val = AUX_LENGTH(cur_data_count) |
|
||||
AUX_TX_COMM_DP_TRANSACTION | AUX_TX_COMM_WRITE;
|
||||
anx6345_i2c_write_p0_reg(client, DP_AUX_CH_CTL_1, &val);
|
||||
|
||||
/* Start AUX transaction */
|
||||
retval = anx6345_start_aux_transaction(client);
|
||||
if (retval == 0)
|
||||
break;
|
||||
else
|
||||
dev_dbg(&client->dev, "Aux Transaction fail!\n");
|
||||
|
||||
|
||||
start_offset += cur_data_count;
|
||||
}
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
|
||||
int anx6345_dpcd_read_bytes(struct i2c_client *client,
|
||||
unsigned int val_addr,
|
||||
unsigned int count,
|
||||
unsigned char data[])
|
||||
{
|
||||
char val;
|
||||
unsigned int start_offset;
|
||||
unsigned int cur_data_count;
|
||||
unsigned int cur_data_idx;
|
||||
int i;
|
||||
int retval = 0;
|
||||
|
||||
start_offset = 0;
|
||||
while (start_offset < count) {
|
||||
/* Buffer size of AUX CH is 16 * 4bytes */
|
||||
if ((count - start_offset) > 16)
|
||||
cur_data_count = 16;
|
||||
else
|
||||
cur_data_count = count - start_offset;
|
||||
|
||||
/* AUX CH Request Transaction process */
|
||||
for (i = 0; i < 10; i++) {
|
||||
/* Select DPCD device address */
|
||||
val = AUX_ADDR_7_0(val_addr + start_offset);
|
||||
anx6345_i2c_write_p0_reg(client, DP_AUX_ADDR_7_0, &val);
|
||||
val = AUX_ADDR_15_8(val_addr + start_offset);
|
||||
anx6345_i2c_write_p0_reg(client, DP_AUX_ADDR_15_8, &val);
|
||||
val = AUX_ADDR_19_16(val_addr + start_offset);
|
||||
anx6345_i2c_write_p0_reg(client, DP_AUX_ADDR_19_16, &val);
|
||||
|
||||
/*
|
||||
* Set DisplayPort transaction and read
|
||||
* If bit 3 is 1, DisplayPort transaction.
|
||||
* If Bit 3 is 0, I2C transaction.
|
||||
*/
|
||||
val = AUX_LENGTH(cur_data_count) |
|
||||
AUX_TX_COMM_DP_TRANSACTION | AUX_TX_COMM_READ;
|
||||
anx6345_i2c_write_p0_reg(client, DP_AUX_CH_CTL_1, &val);
|
||||
|
||||
val = BUF_CLR;
|
||||
anx6345_i2c_write_p0_reg(client, BUF_DATA_CTL, &val);
|
||||
|
||||
/* Start AUX transaction */
|
||||
retval = anx6345_start_aux_transaction(client);
|
||||
if (retval == 0)
|
||||
break;
|
||||
else
|
||||
dev_dbg(&client->dev, "Aux Transaction fail!\n");
|
||||
}
|
||||
|
||||
for (cur_data_idx = 0; cur_data_idx < cur_data_count;
|
||||
cur_data_idx++) {
|
||||
anx6345_i2c_read_p0_reg(client, BUF_DATA_0 + cur_data_idx, &val);
|
||||
data[start_offset + cur_data_idx] = val;
|
||||
dev_dbg(&client->dev, "0x%05x :0x%02x\n",cur_data_idx, val);
|
||||
}
|
||||
|
||||
start_offset += cur_data_count;
|
||||
}
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
|
||||
int anx6345_select_i2c_device(struct i2c_client *client,
|
||||
unsigned int device_addr,
|
||||
char val_addr)
|
||||
{
|
||||
char val;
|
||||
int retval;
|
||||
|
||||
/* Set normal AUX CH command */
|
||||
anx6345_i2c_read_p0_reg(client, DP_AUX_CH_CTL_2, &val);
|
||||
val &= ~ADDR_ONLY;
|
||||
anx6345_i2c_write_p0_reg(client, DP_AUX_CH_CTL_2, &val);
|
||||
/* Set EDID device address */
|
||||
val = device_addr;
|
||||
anx6345_i2c_write_p0_reg(client, DP_AUX_ADDR_7_0, &val);
|
||||
val = 0;
|
||||
anx6345_i2c_write_p0_reg(client, DP_AUX_ADDR_15_8, &val);
|
||||
anx6345_i2c_write_p0_reg(client, DP_AUX_ADDR_19_16, &val);
|
||||
|
||||
/* Set offset from base address of EDID device */
|
||||
anx6345_i2c_write_p0_reg(client, BUF_DATA_0, &val_addr);
|
||||
|
||||
/*
|
||||
* Set I2C transaction and write address
|
||||
* If bit 3 is 1, DisplayPort transaction.
|
||||
* If Bit 3 is 0, I2C transaction.
|
||||
*/
|
||||
val = AUX_TX_COMM_I2C_TRANSACTION | AUX_TX_COMM_MOT |
|
||||
AUX_TX_COMM_WRITE;
|
||||
anx6345_i2c_write_p0_reg(client, DP_AUX_CH_CTL_1, &val);
|
||||
|
||||
/* Start AUX transaction */
|
||||
retval = anx6345_start_aux_transaction(client);
|
||||
if (retval != 0)
|
||||
dev_dbg(&client->dev, "Aux Transaction fail!\n");
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
int anx6345_edid_read_bytes(struct i2c_client *client,
|
||||
unsigned int device_addr,
|
||||
unsigned int val_addr,
|
||||
unsigned char count,
|
||||
unsigned char edid[])
|
||||
{
|
||||
char val;
|
||||
unsigned int i;
|
||||
unsigned int start_offset;
|
||||
unsigned int cur_data_idx;
|
||||
unsigned int cur_data_cnt;
|
||||
unsigned int defer = 0;
|
||||
int retval = 0;
|
||||
|
||||
for (i = 0; i < count; i += 16) {
|
||||
start_offset = i;
|
||||
if ((count - start_offset) > 16)
|
||||
cur_data_cnt = 16;
|
||||
else
|
||||
cur_data_cnt = count - start_offset;
|
||||
/*
|
||||
* If Rx sends defer, Tx sends only reads
|
||||
* request without sending addres
|
||||
*/
|
||||
if (!defer)
|
||||
retval = anx6345_select_i2c_device(client,
|
||||
device_addr, val_addr + i);
|
||||
else
|
||||
defer = 0;
|
||||
|
||||
/*
|
||||
* Set I2C transaction and write data
|
||||
* If bit 3 is 1, DisplayPort transaction.
|
||||
* If Bit 3 is 0, I2C transaction.
|
||||
*/
|
||||
val = AUX_LENGTH(cur_data_cnt) | AUX_TX_COMM_I2C_TRANSACTION |
|
||||
AUX_TX_COMM_READ;
|
||||
anx6345_i2c_write_p0_reg(client, DP_AUX_CH_CTL_1, &val);
|
||||
|
||||
/* Start AUX transaction */
|
||||
retval = anx6345_start_aux_transaction(client);
|
||||
if (retval < 0)
|
||||
dev_dbg(&client->dev, "Aux Transaction fail!\n");
|
||||
|
||||
/* Check if Rx sends defer */
|
||||
anx6345_i2c_read_p0_reg(client, DP_AUX_RX_COMM, &val);
|
||||
if (val == AUX_RX_COMM_AUX_DEFER ||
|
||||
val == AUX_RX_COMM_I2C_DEFER) {
|
||||
dev_err(&client->dev, "Defer: %d\n\n", val);
|
||||
defer = 1;
|
||||
}
|
||||
|
||||
|
||||
for (cur_data_idx = 0; cur_data_idx < cur_data_cnt; cur_data_idx++) {
|
||||
anx6345_i2c_read_p0_reg(client, BUF_DATA_0 + cur_data_idx, &val);
|
||||
edid[i + cur_data_idx] = val;
|
||||
dev_dbg(&client->dev, "0x%02x : 0x%02x\n", i + cur_data_idx, val);
|
||||
}
|
||||
}
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
static int anx6345_read_edid(struct i2c_client *client)
|
||||
{
|
||||
unsigned char edid[EDID_LENGTH * 2];
|
||||
unsigned char extend_block = 0;
|
||||
unsigned char sum;
|
||||
unsigned char test_vector;
|
||||
int retval;
|
||||
char addr;
|
||||
struct edp_anx6345 *anx6345 = i2c_get_clientdata(client);
|
||||
|
||||
|
||||
/* Read Extension Flag, Number of 128-byte EDID extension blocks */
|
||||
retval = anx6345_edid_read_bytes(client, EDID_ADDR,
|
||||
EDID_EXTENSION_FLAG,1,&extend_block);
|
||||
if (retval < 0) {
|
||||
dev_err(&client->dev, "EDID extension flag failed!\n");
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
if (extend_block > 0) {
|
||||
dev_dbg(&client->dev, "EDID data includes a single extension!\n");
|
||||
|
||||
/* Read EDID data */
|
||||
retval = anx6345_edid_read_bytes(client, EDID_ADDR,
|
||||
EDID_HEADER,
|
||||
EDID_LENGTH,
|
||||
&edid[EDID_HEADER]);
|
||||
if (retval != 0) {
|
||||
dev_err(&client->dev, "EDID Read failed!\n");
|
||||
return -EIO;
|
||||
}
|
||||
sum = edp_calc_edid_check_sum(edid);
|
||||
if (sum != 0) {
|
||||
dev_warn(&client->dev, "EDID bad checksum!\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Read additional EDID data */
|
||||
retval = anx6345_edid_read_bytes(client, EDID_ADDR, EDID_LENGTH,
|
||||
EDID_LENGTH, &edid[EDID_LENGTH]);
|
||||
if (retval != 0) {
|
||||
dev_err(&client->dev, "EDID Read failed!\n");
|
||||
return -EIO;
|
||||
}
|
||||
sum = edp_calc_edid_check_sum(&edid[EDID_LENGTH]);
|
||||
if (sum != 0) {
|
||||
dev_warn(&client->dev, "EDID bad checksum!\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
retval = anx6345_dpcd_read_bytes(client, DPCD_TEST_REQUEST,
|
||||
1, &test_vector);
|
||||
if (retval < 0) {
|
||||
dev_err(&client->dev, "DPCD EDID Read failed!\n");
|
||||
return retval;
|
||||
}
|
||||
|
||||
if (test_vector & DPCD_TEST_EDID_READ) {
|
||||
retval = anx6345_dpcd_write_bytes(client,
|
||||
DPCD_TEST_EDID_CHECKSUM,1,
|
||||
&edid[EDID_LENGTH + EDID_CHECKSUM]);
|
||||
if (retval < 0) {
|
||||
dev_err(&client->dev, "DPCD EDID Write failed!\n");
|
||||
return retval;
|
||||
}
|
||||
|
||||
addr = DPCD_TEST_EDID_CHECKSUM_WRITE;
|
||||
retval = anx6345_dpcd_write_bytes(client,
|
||||
DPCD_TEST_RESPONSE, 1, &addr);
|
||||
if (retval < 0) {
|
||||
dev_err(&client->dev, "DPCD EDID checksum failed!\n");
|
||||
return retval;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
dev_info(&client->dev, "EDID data does not include any extensions.\n");
|
||||
|
||||
/* Read EDID data */
|
||||
retval = anx6345_edid_read_bytes(client, EDID_ADDR, EDID_HEADER,
|
||||
EDID_LENGTH, &edid[EDID_HEADER]);
|
||||
if (retval != 0) {
|
||||
dev_err(&client->dev, "EDID Read failed!\n");
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
sum = edp_calc_edid_check_sum(edid);
|
||||
if (sum != 0) {
|
||||
dev_warn(&client->dev, "EDID bad checksum!\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
retval = anx6345_dpcd_read_bytes(client, DPCD_TEST_REQUEST,
|
||||
1,&test_vector);
|
||||
if (retval < 0) {
|
||||
dev_err(&client->dev, "DPCD EDID Read failed!\n");
|
||||
return retval;
|
||||
}
|
||||
|
||||
if (test_vector & DPCD_TEST_EDID_READ) {
|
||||
retval = anx6345_dpcd_write_bytes(client,
|
||||
DPCD_TEST_EDID_CHECKSUM, 1,
|
||||
&edid[EDID_CHECKSUM]);
|
||||
if (retval < 0) {
|
||||
dev_err(&client->dev, "DPCD EDID Write failed!\n");
|
||||
return retval;
|
||||
}
|
||||
addr = DPCD_TEST_EDID_CHECKSUM_WRITE;
|
||||
retval = anx6345_dpcd_write_bytes(client, DPCD_TEST_RESPONSE,
|
||||
1, &addr);
|
||||
if (retval < 0) {
|
||||
dev_err(&client->dev, "DPCD EDID checksum failed!\n");
|
||||
return retval;
|
||||
}
|
||||
}
|
||||
}
|
||||
fb_edid_to_monspecs(edid, &anx6345->specs);
|
||||
dev_info(&client->dev, "EDID Read success!\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int anx6345_init(struct i2c_client *client)
|
||||
{
|
||||
@@ -744,7 +1084,8 @@ static int anx6345_init(struct i2c_client *client)
|
||||
char i = 0;
|
||||
char lc,bw;
|
||||
char cnt = 50;
|
||||
|
||||
u8 buf[12];
|
||||
|
||||
val = 0x30;
|
||||
anx6345_i2c_write_p1_reg(client,SP_POWERD_CTRL_REG,&val);
|
||||
|
||||
@@ -752,10 +1093,10 @@ static int anx6345_init(struct i2c_client *client)
|
||||
for(i=0;i<50;i++)
|
||||
{
|
||||
|
||||
anx6345_i2c_read_p0_reg(client, SP_TX_SYS_CTRL1_REG, &val);
|
||||
anx6345_i2c_write_p0_reg(client, SP_TX_SYS_CTRL1_REG, &val);
|
||||
anx6345_i2c_read_p0_reg(client, SP_TX_SYS_CTRL1_REG, &val);
|
||||
if((val&SP_TX_SYS_CTRL1_DET_STA)!=0)
|
||||
anx6345_i2c_read_p0_reg(client, SYS_CTRL1_REG, &val);
|
||||
anx6345_i2c_write_p0_reg(client, SYS_CTRL1_REG, &val);
|
||||
anx6345_i2c_read_p0_reg(client, SYS_CTRL1_REG, &val);
|
||||
if((val&SYS_CTRL1_DET_STA)!=0)
|
||||
{
|
||||
break;
|
||||
}
|
||||
@@ -768,10 +1109,10 @@ static int anx6345_init(struct i2c_client *client)
|
||||
//check whether clock is stable
|
||||
for(i=0;i<50;i++)
|
||||
{
|
||||
anx6345_i2c_read_p0_reg(client, SP_TX_SYS_CTRL2_REG, &val);
|
||||
anx6345_i2c_write_p0_reg(client,SP_TX_SYS_CTRL2_REG, &val);
|
||||
anx6345_i2c_read_p0_reg(client, SP_TX_SYS_CTRL2_REG, &val);
|
||||
if((val&SP_TX_SYS_CTRL2_CHA_STA)==0)
|
||||
anx6345_i2c_read_p0_reg(client, SYS_CTRL2_REG, &val);
|
||||
anx6345_i2c_write_p0_reg(client,SYS_CTRL2_REG, &val);
|
||||
anx6345_i2c_read_p0_reg(client, SYS_CTRL2_REG, &val);
|
||||
if((val&SYS_CTRL2_CHA_STA)==0)
|
||||
{
|
||||
break;
|
||||
}
|
||||
@@ -779,49 +1120,52 @@ static int anx6345_init(struct i2c_client *client)
|
||||
}
|
||||
if(i>49)
|
||||
printk("clk is not stable\n");
|
||||
|
||||
anx6345_dpcd_read_bytes(client, DPCD_REV, 12, buf);
|
||||
anx6345_read_edid(client);
|
||||
|
||||
//VESA range, 6bits BPC, RGB
|
||||
val = 0x00;
|
||||
anx6345_i2c_write_p1_reg(client, SP_TX_VID_CTRL2_REG, &val);
|
||||
anx6345_i2c_write_p1_reg(client, VID_CTRL2_REG, &val);
|
||||
|
||||
//ANX6345 chip pll setting
|
||||
val = 0x00;
|
||||
anx6345_i2c_write_p0_reg(client, SP_TX_PLL_CTRL_REG, &val); //UPDATE: FROM 0X07 TO 0X00
|
||||
anx6345_i2c_write_p0_reg(client, PLL_CTRL_REG, &val); //UPDATE: FROM 0X07 TO 0X00
|
||||
|
||||
|
||||
//ANX chip analog setting
|
||||
val = 0x70;
|
||||
anx6345_i2c_write_p1_reg(client, ANALOG_DEBUG_REG1, &val); //UPDATE: FROM 0XF0 TO 0X70
|
||||
val = 0x30;
|
||||
anx6345_i2c_write_p0_reg(client, SP_TX_LINK_DEBUG_REG, &val);
|
||||
anx6345_i2c_write_p0_reg(client, LINK_DEBUG_REG, &val);
|
||||
|
||||
//force HPD
|
||||
//anx6345_i2c_write_p0_reg(client, SP_TX_SYS_CTRL3_REG, &val);
|
||||
//anx6345_i2c_write_p0_reg(client, SYS_CTRL3_REG, &val);
|
||||
|
||||
|
||||
//reset AUX
|
||||
anx6345_i2c_read_p1_reg(client, SP_TX_RST_CTRL2_REG, &val);
|
||||
val |= SP_TX_AUX_RST;
|
||||
anx6345_i2c_write_p1_reg(client, SP_TX_RST_CTRL2_REG, &val);
|
||||
val &= ~SP_TX_AUX_RST;
|
||||
anx6345_i2c_write_p1_reg(client, SP_TX_RST_CTRL2_REG, &val);
|
||||
anx6345_i2c_read_p1_reg(client, RST_CTRL2_REG, &val);
|
||||
val |= AUX_RST;
|
||||
anx6345_i2c_write_p1_reg(client, RST_CTRL2_REG, &val);
|
||||
val &= ~AUX_RST;
|
||||
anx6345_i2c_write_p1_reg(client, RST_CTRL2_REG, &val);
|
||||
|
||||
//Select 2.7G
|
||||
val = 0x0a;
|
||||
anx6345_i2c_write_p0_reg(client, SP_TX_LINK_BW_SET_REG, &val);
|
||||
anx6345_i2c_write_p0_reg(client, LINK_BW_SET_REG, &val);
|
||||
//Select 2 lanes
|
||||
val = 0x02;
|
||||
anx6345_i2c_write_p0_reg(client,SP_TX_LANE_COUNT_SET_REG,&val);
|
||||
anx6345_i2c_write_p0_reg(client,LANE_COUNT_SET_REG,&val);
|
||||
|
||||
val = SP_TX_LINK_TRAINING_CTRL_EN;
|
||||
anx6345_i2c_write_p0_reg(client, SP_TX_LINK_TRAINING_CTRL_REG, &val);
|
||||
val = LINK_TRAINING_CTRL_EN;
|
||||
anx6345_i2c_write_p0_reg(client, LINK_TRAINING_CTRL_REG, &val);
|
||||
mdelay(5);
|
||||
anx6345_i2c_read_p0_reg(client, SP_TX_LINK_TRAINING_CTRL_REG, &val);
|
||||
anx6345_i2c_read_p0_reg(client, LINK_TRAINING_CTRL_REG, &val);
|
||||
while((val&0x80)&&(cnt)) //UPDATE: FROM 0X01 TO 0X80
|
||||
{
|
||||
printk("Waiting...\n");
|
||||
mdelay(5);
|
||||
anx6345_i2c_read_p0_reg(client,SP_TX_LINK_TRAINING_CTRL_REG,&val);
|
||||
anx6345_i2c_read_p0_reg(client,LINK_TRAINING_CTRL_REG,&val);
|
||||
cnt--;
|
||||
}
|
||||
if(cnt <= 0)
|
||||
@@ -842,15 +1186,15 @@ static int anx6345_init(struct i2c_client *client)
|
||||
#else
|
||||
val = 0x81;
|
||||
#endif
|
||||
anx6345_i2c_write_p1_reg(client,SP_TX_VID_CTRL1_REG,&val);
|
||||
anx6345_i2c_write_p1_reg(client,VID_CTRL1_REG,&val);
|
||||
|
||||
anx_video_map_config(client);
|
||||
//force HPD and stream valid
|
||||
val = 0x33;
|
||||
anx6345_i2c_write_p0_reg(client,SP_TX_SYS_CTRL3_REG,&val);
|
||||
anx6345_i2c_write_p0_reg(client,SYS_CTRL3_REG,&val);
|
||||
|
||||
anx6345_i2c_read_p0_reg(client,SP_TX_LANE_COUNT_SET_REG, &lc);
|
||||
anx6345_i2c_read_p0_reg(client,SP_TX_LINK_BW_SET_REG, &bw);
|
||||
anx6345_i2c_read_p0_reg(client,LANE_COUNT_SET_REG, &lc);
|
||||
anx6345_i2c_read_p0_reg(client,LINK_BW_SET_REG, &bw);
|
||||
printk("%s..lc:%d--bw:%d\n",__func__,lc,bw);
|
||||
|
||||
return 0;
|
||||
|
||||
134
drivers/video/rockchip/transmitter/dpcd_edid.h
Normal file
134
drivers/video/rockchip/transmitter/dpcd_edid.h
Normal file
@@ -0,0 +1,134 @@
|
||||
#ifndef __DPCD_EDID_H
|
||||
#define __DPCD_EDID_H
|
||||
#include "../../edid.h"
|
||||
|
||||
#define DPCD_REV 0x00
|
||||
#define DPCD_MAX_LINK_RATE 0x01
|
||||
#define DPCD_MAX_LANE_CNT 0x02
|
||||
|
||||
#define DPCD_MAX_DOWNSPREAD 0x03
|
||||
#define DPCD_NORP 0x04
|
||||
#define DPCD_DOWNSTREAMPORT_PRESENT 0x05
|
||||
|
||||
#define DPCD_RECEIVE_PORT0_CAP_0 0x08
|
||||
#define DPCD_RECEIVE_PORT0_CAP_1 0x09
|
||||
#define DPCD_RECEIVE_PORT0_CAP_2 0x0a
|
||||
#define DPCD_RECEIVE_PORT0_CAP_3 0x0b
|
||||
|
||||
#define DPCD_LINK_BW_SET 0x100
|
||||
#define DPCD_LANE_CNT_SET 0x101
|
||||
#define DPCD_TRAINING_PATTERN_SET 0x102
|
||||
#define DPCD_TRAINING_LANE0_SET 0x103
|
||||
#define DPCD_TRAINING_LANE1_SET 0x104
|
||||
#define DPCD_TRAINING_LANE2_SET 0x105
|
||||
#define DPCD_TRAINING_LANE3_SET 0x106
|
||||
#define DPCD_DOWNSPREAD_CTRL 0x107
|
||||
|
||||
#define DPCD_SINK_COUNT 0x200
|
||||
#define DPCD_DEVICE_SERVICE_IRQ_VECTOR 0x201
|
||||
#define DPCD_LANE0_1_STATUS 0x202
|
||||
#define DPCD_LANE2_3_STATUS 0x203
|
||||
#define DPCD_LANE_ALIGN_STATUS_UPDATED 0x204
|
||||
#define DPCD_SINK_STATUS 0x205
|
||||
#define DPCD_ADJUST_REQUEST_LANE0_1 0x206
|
||||
#define DPCD_ADJUST_REQUEST_LANE2_3 0x207
|
||||
#define DPCD_TRAINING_SCORE_LANE0 0x208
|
||||
#define DPCD_TRAINING_SCORE_LANE1 0x209
|
||||
#define DPCD_TRAINING_SCORE_LANE2 0x20a
|
||||
#define DPCD_TRAINING_SCORE_LANE3 0x20b
|
||||
#define DPCD_SINK_POWER_STATE 0x0600
|
||||
|
||||
/* DPCD_ADDR_MAX_LANE_COUNT */
|
||||
#define DPCD_ENHANCED_FRAME_CAP(x) (((x) >> 7) & 0x1)
|
||||
#define DPCD_MAX_LANE_COUNT(x) ((x) & 0x1f)
|
||||
|
||||
/* DPCD_ADDR_LANE_COUNT_SET */
|
||||
#define DPCD_ENHANCED_FRAME_EN (0x1 << 7)
|
||||
#define DPCD_LANE_COUNT_SET(x) ((x) & 0x1f)
|
||||
|
||||
/* DPCD_ADDR_TRAINING_PATTERN_SET */
|
||||
#define DPCD_SCRAMBLING_DISABLED (0x1 << 5)
|
||||
#define DPCD_SCRAMBLING_ENABLED (0x0 << 5)
|
||||
#define DPCD_TRAINING_PATTERN_2 (0x2 << 0)
|
||||
#define DPCD_TRAINING_PATTERN_1 (0x1 << 0)
|
||||
#define DPCD_TRAINING_PATTERN_DISABLED (0x0 << 0)
|
||||
|
||||
/* DPCD_ADDR_TRAINING_LANE0_SET */
|
||||
#define DPCD_MAX_PRE_EMPHASIS_REACHED (0x1 << 5)
|
||||
#define DPCD_PRE_EMPHASIS_SET(x) (((x) & 0x3) << 3)
|
||||
#define DPCD_PRE_EMPHASIS_GET(x) (((x) >> 3) & 0x3)
|
||||
#define DPCD_PRE_EMPHASIS_PATTERN2_LEVEL0 (0x0 << 3)
|
||||
#define DPCD_MAX_SWING_REACHED (0x1 << 2)
|
||||
#define DPCD_VOLTAGE_SWING_SET(x) (((x) & 0x3) << 0)
|
||||
#define DPCD_VOLTAGE_SWING_GET(x) (((x) >> 0) & 0x3)
|
||||
#define DPCD_VOLTAGE_SWING_PATTERN1_LEVEL0 (0x0 << 0)
|
||||
|
||||
/* DPCD_ADDR_LANE0_1_STATUS */
|
||||
#define DPCD_LANE_SYMBOL_LOCKED (0x1 << 2)
|
||||
#define DPCD_LANE_CHANNEL_EQ_DONE (0x1 << 1)
|
||||
#define DPCD_LANE_CR_DONE (0x1 << 0)
|
||||
#define DPCD_CHANNEL_EQ_BITS (DPCD_LANE_CR_DONE| \
|
||||
DPCD_LANE_CHANNEL_EQ_DONE|\
|
||||
DPCD_LANE_SYMBOL_LOCKED)
|
||||
|
||||
#define DPCD_TEST_REQUEST 0x218
|
||||
#define DPCD_TEST_LINK_RATE 0x219
|
||||
|
||||
#define DPCD_TEST_LANE_COUNT 0x220
|
||||
#define DPCD_TEST_RESPONSE 0x260
|
||||
#define DPCD_TEST_EDID_CHECKSUM 0x261
|
||||
#define TEST_ACK 0x01
|
||||
#define DPCD_TEST_EDID_Checksum_Write 0x04//bit position
|
||||
|
||||
#define DPCD_TEST_EDID_Checksum 0x261
|
||||
|
||||
|
||||
#define DPCD_SPECIFIC_INTERRUPT 0x10
|
||||
#define DPCD_USER_COMM1 0x22//define for downstream HDMI Rx sense detection
|
||||
|
||||
#define AUX_ADDR_7_0(x) (((x) >> 0) & 0xff)
|
||||
#define AUX_ADDR_15_8(x) (((x) >> 8) & 0xff)
|
||||
#define AUX_ADDR_19_16(x) (((x) >> 16) & 0x0f)
|
||||
|
||||
#define AUX_RX_COMM_I2C_DEFER (0x2 << 2)
|
||||
#define AUX_RX_COMM_AUX_DEFER (0x2 << 0)
|
||||
|
||||
/* DPCD_ADDR_LANE_ALIGN__STATUS_UPDATED */
|
||||
#define DPCD_LINK_STATUS_UPDATED (0x1 << 7)
|
||||
#define DPCD_DOWNSTREAM_PORT_STATUS_CHANGED (0x1 << 6)
|
||||
#define DPCD_INTERLANE_ALIGN_DONE (0x1 << 0)
|
||||
|
||||
/* DPCD_ADDR_TEST_REQUEST */
|
||||
#define DPCD_TEST_EDID_READ (0x1 << 2)
|
||||
|
||||
/* DPCD_ADDR_TEST_RESPONSE */
|
||||
#define DPCD_TEST_EDID_CHECKSUM_WRITE (0x1 << 2)
|
||||
|
||||
/* DPCD_ADDR_SINK_POWER_STATE */
|
||||
#define DPCD_SET_POWER_STATE_D0 (0x1 << 0)
|
||||
#define DPCD_SET_POWER_STATE_D4 (0x2 << 0)
|
||||
|
||||
|
||||
/*
|
||||
* EDID device address is 0x50.
|
||||
* However, if necessary, you must have set upper address
|
||||
* into E-EDID in I2C device, 0x30.
|
||||
*/
|
||||
|
||||
#define EDID_ADDR 0x50
|
||||
#define E_EDID_ADDR 0x30
|
||||
#define EDID_EXTENSION_FLAG 0x7e
|
||||
#define EDID_CHECKSUM 0x7f
|
||||
|
||||
static unsigned char edp_calc_edid_check_sum(unsigned char *edid_data)
|
||||
{
|
||||
int i;
|
||||
unsigned char sum = 0;
|
||||
|
||||
for (i = 0; i < EDID_LENGTH; i++)
|
||||
sum = sum + edid_data[i];
|
||||
|
||||
return sum;
|
||||
}
|
||||
|
||||
#endif
|
||||
Reference in New Issue
Block a user