Part Number: SN65DSI84
Other Parts Discussed in Thread: DSI-TUNER
Hi, I'm trying to write linux driver for SN65DSI84. I use this files as example.
DSI:
lanes = 4,
format = RGB888,
clock = 280 MHz
display-timings (from device tree):
timing0: timing0 {
clock-frequency = <70000000>;
hactive = <1024>;
vactive = <768>;
hback-porch = <160>;
hfront-porch = <24>;
vback-porch = <29>;
vfront-porch = <3>;
hsync-len = <136>;
vsync-len = <6>;
hsync-active = <0>;
vsync-active = <0>;
de-active = <0>;
pixelclk-active = <0>;
};
I set DSI_CLK_DIVIDER to divide by 4 (LVDS clock = 70 MHz)
Test pattern work fine, but for real DSI signal I have an errors. Register 0xE5 bit2 and bit3 (CHA_SOT_BIT_ERR, CHA_LLP_ERR).
#include "sn65dsi84_i2c.h"
static int sn65dsi84_config(struct i2c_client *client)
{
u8 val;
const uint32_t mipi_dsi_freq = 280000; // KHz
const uint8_t dsi_clock_div = 4;
struct sn65dsi84_i2c_data *data = i2c_get_clientdata(client);
s32 i2c_read;
dev_dbg(&client->dev, "sn65dsi84_config()\n");
if(data == NULL) {
dev_dbg(&client->dev, "sn65dsi84_config() data=NULL\n");
return -ENXIO;
}
// Soft reset and disable PLL (init seq 5)
i2c_smbus_write_byte_data(client, DSI85_PLL_EN, 0x00);
mdelay(10);
i2c_smbus_write_byte_data(client, DSI85_SOFT_RESET, 0x01);
mdelay(10);
val = 0;
#if LVDS_CLK_FROM_DSI_CLK
val = 0x1;
#endif
// data->timings.pixel_clock = 70000
// user external clock reference with no muliplier
if (data->timings.pixel_clock <= 37500)
{
// Do nothing.
}
else if (data->timings.pixel_clock <= 62500) {
val |= (0x01 << 1);
}
else if (data->timings.pixel_clock <= 87500)
{
val |= (0x02 << 1);
}
else if (data->timings.pixel_clock <= 112500)
{
val |= (0x03 << 1);
}
else if (data->timings.pixel_clock <= 137500)
{
val |= (0x04 << 1);
}
else
{
val |= (0x05 << 1);
}
i2c_smbus_write_byte_data(client, DSI85_CORE_PLL, val);
#if LVDS_CLK_FROM_DSI_CLK
//i2c_smbus_write_byte_data(client, DSI85_PLL_DIV, 0x10); // Divide DSI_CLK by 3.
val = (dsi_clock_div - 1) << 3; // Divide DSI_CLK by 4.
i2c_smbus_write_byte_data(client, DSI85_PLL_DIV, val);
#else
i2c_smbus_write_byte_data(client, DSI85_PLL_DIV, 0x00); // Multiply REFCLK by 1.
#endif
// four DSI lanes with single channel
i2c_smbus_write_byte_data(client, DSI85_DSI_CFG, 0x00);
//i2c_smbus_write_byte_data(client, DSI85_DSI_CFG, 0x01); // no SoT bit errors are tolerated
i2c_smbus_write_byte_data(client, DSI85_DSI_EQ, 0x00);
// set DSI clock range
//i2c_smbus_write_byte_data(client, DSI85_CHA_DSI_CLK_RNG, (data->timings.pixel_clock * 4 / 5000));
i2c_smbus_write_byte_data(client, DSI85_CHA_DSI_CLK_RNG, (mipi_dsi_freq / 5000));
// set LVDS for single channel, 24 bit mode, HS/VS low, DE high
i2c_smbus_write_byte_data(client, DSI85_LVDS_MODE, 0x7A);
// set LVDS 200 Ohm termination and max differential swing voltage
i2c_smbus_write_byte_data(client, DSI85_LVDS_SIGN, 0x00);
i2c_smbus_write_byte_data(client, DSI85_LVDS_TERM, 0x00);
// x resolution high/low for channel A
i2c_smbus_write_byte_data(client, DSI85_CHA_LINE_LEN_LO, ((data->timings.x_res) & 0x00FF));
i2c_smbus_write_byte_data(client, DSI85_CHA_LINE_LEN_HI, ((data->timings.x_res) & 0x0F00)>>8); // 12 bit value
// y resolution high/low for channel A
i2c_smbus_write_byte_data(client, DSI85_CHA_VERT_LINES_LO, (data->timings.y_res & 0x00FF));
i2c_smbus_write_byte_data(client, DSI85_CHA_VERT_LINES_HI, (data->timings.y_res & 0x0F00)>>8); // 12 bit value
// SYNC delay high/low for channel A
i2c_smbus_write_byte_data(client, DSI85_CHA_SYNC_DELAY_LO, 0x00);
i2c_smbus_write_byte_data(client, DSI85_CHA_SYNC_DELAY_HI, 0x02);
// HSYNC width high/low for channel A
i2c_smbus_write_byte_data(client, DSI85_CHA_HSYNC_WIDTH_LO, (data->timings.hsw & 0x00FF));
i2c_smbus_write_byte_data(client, DSI85_CHA_HSYNC_WIDTH_HI, (data->timings.hsw & 0x0300)>>8); // 10 bit value
// VSYNC width high/low for channel A
i2c_smbus_write_byte_data(client, DSI85_CHA_VSYNC_WIDTH_LO, (data->timings.vsw & 0x00FF));
i2c_smbus_write_byte_data(client, DSI85_CHA_VSYNC_WIDTH_HI, (data->timings.vsw & 0x0300)>>8); // 10 bit value
// Horizontal BackPorch for channel A
i2c_smbus_write_byte_data(client, DSI85_CHA_HORZ_BACKPORCH, (data->timings.hbp & 0x00FF));
// Vertical BackPorch for channel A
i2c_smbus_write_byte_data(client, DSI85_CHA_VERT_BACKPORCH, (data->timings.vbp & 0x00FF));
// Horizontal FrontPorch for channel A
i2c_smbus_write_byte_data(client, DSI85_CHA_HORZ_FRONTPORCH, (data->timings.hfp & 0x00FF));
// Vertical FrontPorch for channel A
i2c_smbus_write_byte_data(client, DSI85_CHA_VERT_FRONTPORCH, (data->timings.vbp & 0x00FF));
// debug
//i2c_smbus_write_byte_data(client, DSI85_CHA_TEST_PATTERN, 0x10);
// Soft reset and enable PLL
//i2c_smbus_write_byte_data(client, DSI85_SOFT_RESET, 0x01);
//i2c_smbus_write_byte_data(client, DSI85_PLL_EN, 0x01);
i2c_smbus_write_byte_data(client, DSI85_PLL_EN, 0x01); // init seq 6
mdelay(10);
i2c_smbus_write_byte_data(client, DSI85_SOFT_RESET, 0x01); // init seq 7
mdelay(10);
// clear errors
i2c_smbus_write_byte_data(client, DSI85_ERRORS, 0xFF); // init seq 10
mdelay(10);
i2c_read = i2c_smbus_read_byte_data(client, DSI85_ERRORS); // init seq 11
if(i2c_read < 0) {
dev_err(&client->dev, "sn65dsi84_config() fun i2c_smbus_read_byte_data return %d\n", i2c_read);
return i2c_read;
}
dev_dbg(&client->dev, "sn65dsi84_config() errors = %d\n", i2c_read);
return 0;
}


