Hello,
We are trying to make work a 3.5'' display with the following characteristics:
MIPI, video mode
2-lane + clock
320(H) x 480(V) (RGB Stripe)
24-bits (R8, G8, B8)
VP 500 Line
VS 8 Line
VFP 6 Line
VBP 6 Line
VDISP 480 Line
HP 380 clk
HS 16 clk
HFP 12 clk
HBP 12 clk
HDISP 320 clk
fPCLK 10.80 MHz
tPCLK 92.5925935 ns
We have tried to implement the section 15.6.7 of http://focus.ti.com/lit/ug/spruf98g/spruf98g.pdf with the following code:
/* DSI registers */
#define DSI_IRQSTATUS 0x4804FC18
#define DSI_SYSCONFIG 0x4804FC10
#define DSI_SYSSTATUS 0x4804FC14
#define DSI_CLK_CTRL 0x4804FC54
#define DSI_PLL_CONTROL 0x4804FF00
#define DSI_PLL_CONFIGURATION1 0x4804FF0C
#define DSI_PLL_CONFIGURATION2 0x4804FF10
#define DSI_PLL_GO 0x4804FF08
#define DSI_PLL_STATUS 0x4804FF04
#define DSI_IRQENABLE 0x4804FC1C
#define DSI_VC0_CTRL 0x4804FD00
#define DSI_VC0_IRQENABLE 0x4804FD1C
#define DSI_VC0_LONG_PACKET_HEADER 0x4804FD08
#define DSI_VC1_CTRL 0x4804FD20
#define DSI_VC1_IRQENABLE 0x4804FD3C
#define DSI_VC1_SHORT_PACKET_HEADER 0x4804FD30
#define DSI_CTRL 0x4804FC40
#define DSI_COMPLEXIO_CFG1 0x4804FC48
#define DSI_COMPLEXIO_IRQSTATUS 0x4804FC4C
#define DSI_COMPLEXIO_IRQENABLE 0x4804FC50
#define DSI_SYSSTATUS 0x4804FC14
#define DSI_TIMING1 0x4804FC58
#define DSI_TIMING2 0x4804FC5C
#define DSI_VM_TIMING1 0x4804FC60
#define DSI_VM_TIMING2 0x4804FC64
#define DSI_VM_TIMING3 0x4804FC68
#define DSI_VM_TIMING7 0x4804FC90
#define DSI_CLK_TIMING 0x4804FC6C
#define DSI_PHY_CFG0 0x4804FE00
#define DSI_PHY_CFG1 0x4804FE04
#define DSI_PHY_CFG2 0x4804FE08
#define DSI_PHY_CFG5 0x4804FE14
#define DISPC_IRQENABLE 0x4805041C
/* Reset DSI [15.6.7.2.1] */
void dsi_reset(void)
{
dss_write_reg(DSI_IRQSTATUS, 0); /* Reset IRQ status */
dss_write_reg(DSI_SYSCONFIG, 0x2); /* Reset the module */
/* Wait until RESET_DONE != 0 */
printf("[1] DSI module reset in progress...\n");
while((dss_read_reg(DSI_SYSSTATUS) & 0x1) == 0)
;
dss_write_reg(DSI_SYSCONFIG, 0x314); /* Set initial DSI configuration */
}
/* From DSS2 dss/dss.h */
#define FLD_MASK(start, end) (((1 << ((start) - (end) + 1)) - 1) << (end))
#define FLD_VAL(val, start, end) (((val) << (end)) & FLD_MASK(start, end))
#define FLD_GET(val, start, end) (((val) & FLD_MASK(start, end)) >> (end))
#define FLD_MOD(orig, val, start, end) (((orig) & ~FLD_MASK(start, end)) | FLD_VAL(val, start, end))
/* Set up DSI DPLL [15.6.7.2.2] */
void dsi_set_dpll(void)
{
uint l;
/* Touch Book parameters */
unsigned char m4 = 2, m3 = 2, m = 108, n = 19;
unsigned char fint = 4, use_pck = 1, use_hfc = 0;
unsigned int height = 480, width = 320;
unsigned char lck_div = 1, pck_div = 18;
unsigned char hbp = 12, hfp = 12, hsw = 16;
unsigned char vbp = 6, vfp = 6, vsw = 8;
/* Set timings */
l = FLD_MOD(0, hbp - 1, 31, 20); /* HBP */
l = FLD_MOD(l, hfp - 1, 19, 8); /* HFP */
l = FLD_MOD(l, hsw - 1, 7, 0); /* HSW */
dss_write_reg(DISPC_TIMING_H, l);
l = FLD_MOD(0, vbp - 1, 27, 20); /* VBP */
l = FLD_MOD(l, vfp - 1, 15, 8); /* VFP */
l = FLD_MOD(l, vsw - 1, 5, 0); /* VSW */
dss_write_reg(DISPC_TIMING_V, l);
l = FLD_MOD(0, lck_div, 23, 16); /* LCD */
l = FLD_MOD(l, pck_div, 7, 0); /* PCD */
dss_write_reg(DISPC_DIVISOR, l);
l = FLD_MOD(0, height - 1, 26, 16); /* LPP */
l = FLD_MOD(l, width - 1, 10, 0); /* PPL */
dss_write_reg(DISPC_SIZE_LCD, l);
/* Enable PCLKFREE */
l = dss_read_reg(DISPC_CONTROL);
dss_write_reg(DISPC_CONTROL, l | (1 << 27));
/* Turn on PLL and HSDIVIDER */
l = dss_read_reg(DSI_CLK_CTRL) | 0xC0000000;
dss_write_reg(DSI_CLK_CTRL, l);
/* Wait until PLL_PWR_STATUS = 0x2 */
printf("[2] Waiting for PLL power...\n");
while((dss_read_reg(DSI_CLK_CTRL) & 0x20000000) != 0x20000000)
;
/* Set up the PLL */
/* (Part 1) */
l = FLD_MOD(0, 1, 0, 0); /* DSI_PLL_STOPMODE */
l = FLD_MOD(l, n - 1, 7, 1); /* DSI_PLL_REGN */
l = FLD_MOD(l, m, 18, 8); /* DSI_PLL_REGM */
l = FLD_MOD(l, m3 > 0 ? m3 - 1 : 0, 22, 19); /* DSI_CLOCK_DIV */
l = FLD_MOD(l, m4 > 0 ? m4 - 1 : 0, 26, 23); /* DSIPROTO_CLOCK_DIV */
dss_write_reg(DSI_PLL_CONFIGURATION1, l);
/* (Part 2) */
l = FLD_MOD(0, fint, 4, 1); /* DSI_PLL_FREQSEL */
l = FLD_MOD(l, use_pck, 11, 11); /* DSI_PLL_CLKSEL */
l = FLD_MOD(l, use_hfc, 12, 12); /* DSI_PLL_HIGHFREQ */
l = FLD_MOD(l, 1, 13, 13); /* DSI_PLL_REFEN */
l = FLD_MOD(l, 0, 14, 14); /* DSIPHY_CLKINEN */
l = FLD_MOD(l, 1, 20, 20); /* DSIPHY_CLKINEN */
dss_write_reg(DSI_PLL_CONFIGURATION2, l);
/* Request locking */
dss_write_reg(DSI_PLL_CONTROL, 0x0);
dss_write_reg(DSI_PLL_GO, 0x1);
/* Wait for lock... */
printf("[3] Waiting for PLL lock request...\n");
while((dss_read_reg(DSI_PLL_GO) & 0x1) != 0)
;
printf("[4] Waiting for PLL lock...\n");
while((dss_read_reg(DSI_PLL_STATUS) & 0x2) != 0x2)
;
/* Locked -- change the configuration */
l = dss_read_reg(DSI_PLL_CONFIGURATION2);
l = FLD_MOD(l, 0, 0, 0); /* DSI_PLL_IDLE */
l = FLD_MOD(l, 0, 5, 5); /* DSI_PLL_PLLLPMODE */
l = FLD_MOD(l, 0, 6, 6); /* DSI_PLL_LOWCURRSTBY */
l = FLD_MOD(l, 0, 7, 7); /* DSI_PLL_TIGHTPHASELOCK */
l = FLD_MOD(l, 0, 8, 8); /* DSI_PLL_DRIFTGUARDEN */
l = FLD_MOD(l, 0, 10, 9); /* DSI_PLL_LOCKSEL */
l = FLD_MOD(l, 1, 13, 13); /* DSI_PLL_REFEN */
l = FLD_MOD(l, 1, 14, 14); /* DSIPHY_CLKINEN */
l = FLD_MOD(l, 0, 15, 15); /* DSI_BYPASSEN */
l = FLD_MOD(l, 1, 16, 16); /* DSS_CLOCK_EN */
l = FLD_MOD(l, 0, 17, 17); /* DSS_CLOCK_PWDN */
l = FLD_MOD(l, 1, 18, 18); /* DSI_PROTO_CLOCK_EN */
l = FLD_MOD(l, 0, 19, 19); /* DSI_PROTO_CLOCK_PWDN */
l = FLD_MOD(l, 0, 20, 20); /* DSI_HSDIVBYPASS */
dss_write_reg(DSI_PLL_CONFIGURATION2, l);
/* Clock control */
dss_write_reg(DSI_CLK_CTRL, 0x80244008);
}
/* Set up DSI Protocol Engine [15.6.7.2.4] */
void dsi_set_protocol_engine(void)
{
uint l, dsi_ctrl = 0x2EE9C;
/* Touch Book parameters */
unsigned char pos_clock = 2, pos_data1 = 1, pos_data2 = 3;
unsigned char pol_clock = 1, pol_data1 = 1, pol_data2 = 1;
dss_write_reg(DSI_IRQENABLE, 0x40000);
dss_write_reg(DSI_VC0_IRQENABLE, 0x4);
dss_write_reg(DSI_CTRL, dsi_ctrl);
/* Set up CIO */
l = dss_read_reg(DSI_COMPLEXIO_CFG1);
l = FLD_MOD(l, pol_clock, 3, 3); /* CLOCK_POL */
l = FLD_MOD(l, pol_data1, 7, 7); /* DATA1_POL */
l = FLD_MOD(l, pol_data2, 11, 11); /* DATA2_POL */
l = FLD_MOD(l, pos_clock, 2, 0); /* CLOCK_POSITION */
l = FLD_MOD(l, pos_data1, 6, 4); /* DATA1_POSITION */
l = FLD_MOD(l, pos_data2, 10, 8); /* DATA2_POSITION */
dss_write_reg(DSI_COMPLEXIO_CFG1, l);
dss_write_reg(DSI_COMPLEXIO_IRQSTATUS, 0xC3F39CE7);
dss_write_reg(DSI_COMPLEXIO_IRQENABLE, 0x0);
/* A dummy read using the SCP interface to any DSIPHY register is
* required after DSIPHY reset to complete the reset of the DSI complex
* I/O. */
dss_read_reg(DSI_PHY_CFG5);
printf("[5] Waiting for DSIPHY reset...\n");
while((dss_read_reg(DSI_PHY_CFG5) & 0x40000000) != 0x40000000)
;
/* Enable ComplexIO Power */
l = dss_read_reg(DSI_COMPLEXIO_CFG1);
l = FLD_MOD(l, 1, 28, 27);
dss_write_reg(DSI_COMPLEXIO_CFG1, l);
/* Check power status */
printf("[6] Actioning ComplexIO power-up...\n");
while((dss_read_reg(DSI_COMPLEXIO_CFG1) & 0x08000000) == 0)
;
/* Wait until reset done */
printf("[7] Waiting for ComplexIO reset...\n");
while((dss_read_reg(DSI_COMPLEXIO_CFG1) & 0x20000000) == 0)
;
printf("[8] Waiting for ComplexIO power status...\n");
while((dss_read_reg(DSI_COMPLEXIO_CFG1) & 0x06000000) == 0)
;
/* Now, reset I/F */
l = dsi_ctrl;
dss_write_reg(DSI_CTRL, l | 0x1);
dss_write_reg(DSI_CTRL, l & ~0x1);
printf("[9] Waiting for DSI I/F reset...\n");
while((dss_read_reg(DSI_CTRL) & 0x1) != 0x0)
;
/* Enable Low Power clock */
dss_write_reg(DSI_CLK_CTRL, 0x80344008);
printf("[10] Waiting for DSI I/F reset...\n");
while((dss_read_reg(DSI_SYSSTATUS) & 0x1) == 0)
;
/* Set timing registers (FIXME -- these are just the magic values
in the TRM -- do they need to be changed?) */
dss_write_reg(DSI_TIMING1, 0x00000999);
dss_write_reg(DSI_TIMING2, 0x2FD240CD);
dss_write_reg(DSI_VM_TIMING1, 0x0000700A);
dss_write_reg(DSI_VM_TIMING2, 0x04010101);
dss_write_reg(DSI_VM_TIMING3, 0x05BB0280);
dss_write_reg(DSI_VM_TIMING7, 0x0000C00A);
dss_write_reg(DSI_CLK_TIMING, 0x00000F0B);
dss_write_reg(DSI_VC0_CTRL, 0x20800390); /* DSS */
dss_write_reg(DSI_VC1_CTRL, 0x00000380); /* L4 */
}
/* Set up DSI PHY [15.6.7.2.5] */
void dsi_set_phy(void)
{
/* Touch Book parameters */
uint ths_prepare = 22, ths_prepare_ths_zero = 49, ths_trail = 22, ths_exit = 39;
uint tlpx_half = 8, tclk_trail = 19, tclk_zero = 69;
uint tclk_prepare = 18, r;
r = dss_read_reg(DSI_PHY_CFG0);
r = FLD_MOD(r, ths_prepare, 31, 24);
r = FLD_MOD(r, ths_prepare_ths_zero, 23, 16);
r = FLD_MOD(r, ths_trail, 15, 8);
r = FLD_MOD(r, ths_exit, 7, 0);
dss_write_reg(DSI_PHY_CFG0, r);
r = dss_read_reg(DSI_PHY_CFG1);
r = FLD_MOD(r, tlpx_half, 22, 16);
r = FLD_MOD(r, tclk_trail, 15, 8);
r = FLD_MOD(r, tclk_zero, 7, 0);
dss_write_reg(DSI_PHY_CFG1, r);
r = dss_read_reg(DSI_PHY_CFG2);
r = FLD_MOD(r, tclk_prepare, 7, 0);
dss_write_reg(DSI_PHY_CFG2, r);
/* Drive Stop State */
printf("[11] Forcing TX Stop Mode...\n");
dss_write_reg(DSI_TIMING1, dss_read_reg(DSI_TIMING1) | (1 << 15));
while((dss_read_reg(DSI_SYSSTATUS) & (1 << 15)) != 0)
;
/* FIXME: Toggle external controller reset at this point */
}
/* Set up DISPC [15.6.7.4.1] */
void dsi_set_dispc(void)
{
/* Reset DISPC */
uint t = dss_read_reg(DISPC_SYSCONFIG);
dss_write_reg(DISPC_SYSCONFIG, t | (1 << 1));
printf("[12] Waiting for DISPC reset...\n");
while((dss_read_reg(DSI_SYSSTATUS) & 0x1) == 0)
;
/* Turn off standby */
dss_write_reg(DISPC_SYSCONFIG, t | (1 << 12) | (1 << 3));
dss_write_reg(DISPC_IRQENABLE, 0);
/* Configure DISPC_CONTROL */
t = dss_read_reg(DISPC_CONTROL);
t &= ~(1 << 0);
t &= ~(1 << 5);
t &= ~(1 << 11);
t |= (1 << 27) | (1 << 16) | (1 << 15) | (1 << 9) |
(1 << 8) | (1 << 3);
dss_write_reg(DISPC_CONTROL, t);
/* Enable VC0 */
dss_write_reg(DSI_VC0_LONG_PACKET_HEADER, 0x0005A03E);
t = dss_read_reg(DSI_VC0_CTRL);
dss_write_reg(DSI_VC0_CTRL, t | 0x1);
/* Enable VC1, set BTA_SHORT_EN */
t = dss_read_reg(DSI_VC1_CTRL);
dss_write_reg(DSI_VC1_CTRL, t | (1 << 0) | (1 << 2));
t = dss_read_reg(DSI_CTRL);
dss_write_reg(DSI_CTRL, t | 1);
printf("[13] Waiting for DSI to be ready...\n");
while((dss_read_reg(DSI_CTRL) & 0x1) == 0)
;
/* Set up GFX plane */
ai_logo();
t = dss_read_reg(DISPC_CONTROL);
t |= (1 << 5) | (1 << 0);
dss_write_reg(DISPC_CONTROL, t);
printf("[14] Waiting for DISPC to be ready...\n");
while((dss_read_reg(DISPC_CONTROL) & (1 << 5)) != 0)
;
/* Send NOP */
t = 0x05; /* Data type: DCS Short WRITE, 0 parameters */
t |= (0x00) << 8; /* Data byte 1 */
printf("[14] Sending DCS NOP\n");
dss_write_reg(DSI_VC1_SHORT_PACKET_HEADER, t);
while((dss_read_reg(DSI_VC1_CTRL) & (1 << 16)) == 1)
;
/* Try "Read Panel ID" */
t = 0x15; /* Data type: DCS Short WRITE, 1 parameter */
t |= (0xB1) << 8; /* Data byte 1 */
t |= (0x14) << 16; /* Data byte 2 */
printf("[14] Sending DCS Read Panel ID\n");
dss_write_reg(DSI_VC1_SHORT_PACKET_HEADER, t);
while((dss_read_reg(DSI_VC1_CTRL) & (1 << 16)) == 1)
;
/* Block on RX FIFO */
printf("[14] Testing GET ID [waiting to get back data]\n");
while((dss_read_reg(DSI_VC1_CTRL) & (1 << 20)) == 0)
;
/* Send wake-up commands on VC1 */
printf("[14] RX FIFO has data!\n");
printf("[15] Testing Sleep Out\n");
t = 0x05; /* Data type: DCS Short WRITE, 0 parameters */
t |= (0x11) << 8; /* Data byte 1 */
dss_write_reg(DSI_VC1_SHORT_PACKET_HEADER, t);
while((dss_read_reg(DSI_VC1_CTRL) & (1 << 16)) == 1)
;
printf("[16] Testing Display On\n");
t = 0x05; /* Data type: DCS Short WRITE, 0 parameters */
t |= (0x29) << 8; /* Data byte 1 */
dss_write_reg(DSI_VC1_SHORT_PACKET_HEADER, t);
while((dss_read_reg(DSI_VC1_CTRL) & (1 << 16)) == 1)
;
}
and then:
MUX_VAL(CP(DSS_DATA0), (IDIS | PTD | DIS | M1));
MUX_VAL(CP(DSS_DATA1), (IDIS | PTD | DIS | M1));
MUX_VAL(CP(DSS_DATA2), (IDIS | PTD | DIS | M1));
MUX_VAL(CP(DSS_DATA3), (IDIS | PTD | DIS | M1));
MUX_VAL(CP(DSS_DATA4), (IDIS | PTD | DIS | M1));
MUX_VAL(CP(DSS_DATA5), (IDIS | PTD | DIS | M1));
dsi_reset();
dsi_set_dpll();
dsi_set_protocol_engine();
dsi_set_phy();
dsi_set_dispc();
The result is:
[1] DSI module reset in progress...
[2] Waiting for PLL power...
[3] Waiting for PLL lock request...
[4] Waiting for PLL lock...
[5] Waiting for DSIPHY reset...
[6] Actioning ComplexIO power-up...
[7] Waiting for ComplexIO reset...
[8] Waiting for ComplexIO power status...
[9] Waiting for DSI I/F reset...
[10] Waiting for DSI I/F reset...
[11] Forcing TX Stop Mode...
[12] Waiting for DISPC reset...
[13] Waiting for DSI to be ready...
[14] Waiting for DISPC to be ready...
[14] Sending DCS NOP
[14] Sending DCS Read Panel ID
[14] Testing GET ID [waiting to get back data]
The screen doesn't answer the get id request. Hardware wise, everything seems correctly wired.
Any idea? Has anyone (at TI???) done an implementation of section 15.6.7 of spruf98g?
Grégoire