bdk: di: split normal and vblank dsi reads

And also make vblank reads more robust
This commit is contained in:
CTCaer 2022-05-08 04:23:31 +03:00
parent 8f540b2543
commit 0b8cdaf0ea
2 changed files with 125 additions and 52 deletions

View file

@ -57,34 +57,10 @@ static void _display_dsi_send_cmd(u8 cmd, u32 param, u32 wait)
usleep(wait); usleep(wait);
} }
static void _display_dsi_read_rx_fifo(u32 *data) static void _display_dsi_wait_vblank(bool enable)
{ {
u32 fifo_count = DSI(_DSIREG(DSI_STATUS)) & DSI_STATUS_RX_FIFO_SIZE; if (enable)
for (u32 i = 0; i < fifo_count; i++)
{ {
// Read or Drain RX FIFO.
if (data)
data[i] = DSI(_DSIREG(DSI_RD_DATA));
else
(void)DSI(_DSIREG(DSI_RD_DATA));
}
}
int display_dsi_read(u8 cmd, u32 len, void *data, bool video_enabled)
{
int res = 0;
u32 host_control = 0;
u32 cmd_timeout = video_enabled ? 0 : 250000;
u32 fifo[DSI_STATUS_RX_FIFO_SIZE] = {0};
// Drain RX FIFO.
_display_dsi_read_rx_fifo(NULL);
// Save host control and enable host cmd packets during video.
if (video_enabled)
{
host_control = DSI(_DSIREG(DSI_HOST_CONTROL));
// Enable vblank interrupt. // Enable vblank interrupt.
DISPLAY_A(_DIREG(DC_CMD_INT_ENABLE)) = DC_CMD_INT_FRAME_END_INT; DISPLAY_A(_DIREG(DC_CMD_INT_ENABLE)) = DC_CMD_INT_FRAME_END_INT;
@ -96,18 +72,67 @@ int display_dsi_read(u8 cmd, u32 len, void *data, bool video_enabled)
while (!(DISPLAY_A(_DIREG(DC_CMD_INT_STATUS)) & DC_CMD_INT_FRAME_END_INT)) while (!(DISPLAY_A(_DIREG(DC_CMD_INT_STATUS)) & DC_CMD_INT_FRAME_END_INT))
; ;
} }
else
{
// Wait for vblank before reseting sync points.
DISPLAY_A(_DIREG(DC_CMD_INT_STATUS)) = DC_CMD_INT_FRAME_END_INT; // Clear interrupt.
while (!(DISPLAY_A(_DIREG(DC_CMD_INT_STATUS)) & DC_CMD_INT_FRAME_END_INT))
;
usleep(14);
// Reset all states of syncpt block.
DSI(_DSIREG(DSI_INCR_SYNCPT_CNTRL)) = DSI_INCR_SYNCPT_SOFT_RESET;
usleep(300); // Stabilization delay.
// Clear syncpt block reset.
DSI(_DSIREG(DSI_INCR_SYNCPT_CNTRL)) = 0;
usleep(300); // Stabilization delay.
// Restore video mode and host control.
DSI(_DSIREG(DSI_VIDEO_MODE_CONTROL)) = 0;
// Disable and clear vblank interrupt.
DISPLAY_A(_DIREG(DC_CMD_INT_ENABLE)) = 0;
DISPLAY_A(_DIREG(DC_CMD_INT_STATUS)) = DC_CMD_INT_FRAME_END_INT;
}
}
static void _display_dsi_read_rx_fifo(u32 *data)
{
u32 fifo_count = DSI(_DSIREG(DSI_STATUS)) & DSI_STATUS_RX_FIFO_SIZE;
if (fifo_count)
DSI(_DSIREG(DSI_TRIGGER)) = 0;
for (u32 i = 0; i < fifo_count; i++)
{
// Read or Drain RX FIFO.
if (data)
data[i] = DSI(_DSIREG(DSI_RD_DATA));
else
(void)DSI(_DSIREG(DSI_RD_DATA));
}
}
int display_dsi_read(u8 cmd, u32 len, void *data)
{
int res = 0;
u32 fifo[DSI_STATUS_RX_FIFO_SIZE] = {0};
// Drain RX FIFO.
_display_dsi_read_rx_fifo(NULL);
// Set reply size. // Set reply size.
_display_dsi_send_cmd(MIPI_DSI_SET_MAXIMUM_RETURN_PACKET_SIZE, len, 0); _display_dsi_send_cmd(MIPI_DSI_SET_MAXIMUM_RETURN_PACKET_SIZE, len, 0);
_display_dsi_wait(cmd_timeout, _DSIREG(DSI_TRIGGER), DSI_TRIGGER_HOST | DSI_TRIGGER_VIDEO); _display_dsi_wait(250000, _DSIREG(DSI_TRIGGER), DSI_TRIGGER_HOST | DSI_TRIGGER_VIDEO);
// Request register read. // Request register read.
_display_dsi_send_cmd(MIPI_DSI_DCS_READ, cmd, 0); _display_dsi_send_cmd(MIPI_DSI_DCS_READ, cmd, 0);
_display_dsi_wait(cmd_timeout, _DSIREG(DSI_TRIGGER), DSI_TRIGGER_HOST | DSI_TRIGGER_VIDEO); _display_dsi_wait(250000, _DSIREG(DSI_TRIGGER), DSI_TRIGGER_HOST | DSI_TRIGGER_VIDEO);
// Transfer bus control to device for transmitting the reply. // Transfer bus control to device for transmitting the reply.
u32 high_speed = video_enabled ? DSI_HOST_CONTROL_HS : 0; DSI(_DSIREG(DSI_HOST_CONTROL)) |= DSI_HOST_CONTROL_IMM_BTA;
DSI(_DSIREG(DSI_HOST_CONTROL)) = DSI_HOST_CONTROL_TX_TRIG_HOST | DSI_HOST_CONTROL_IMM_BTA | DSI_HOST_CONTROL_CS | DSI_HOST_CONTROL_ECC | high_speed;
// Wait for reply to complete. DSI_HOST_CONTROL_IMM_BTA bit acts as a DSI host read busy.
_display_dsi_wait(150000, _DSIREG(DSI_HOST_CONTROL), DSI_HOST_CONTROL_IMM_BTA); _display_dsi_wait(150000, _DSIREG(DSI_HOST_CONTROL), DSI_HOST_CONTROL_IMM_BTA);
// Wait a bit for the reply. // Wait a bit for the reply.
@ -146,30 +171,77 @@ int display_dsi_read(u8 cmd, u32 len, void *data, bool video_enabled)
else else
res = 1; res = 1;
// Disable host cmd packets during video and restore host control. return res;
if (video_enabled) }
int display_dsi_vblank_read(u8 cmd, u32 len, void *data)
{
int res = 0;
u32 host_control = 0;
u32 fifo[DSI_STATUS_RX_FIFO_SIZE] = {0};
// Drain RX FIFO.
_display_dsi_read_rx_fifo(NULL);
// Save host control and enable host cmd packets during video.
host_control = DSI(_DSIREG(DSI_HOST_CONTROL));
_display_dsi_wait_vblank(true);
// Set reply size.
_display_dsi_send_cmd(MIPI_DSI_SET_MAXIMUM_RETURN_PACKET_SIZE, len, 0);
_display_dsi_wait(0, _DSIREG(DSI_TRIGGER), DSI_TRIGGER_HOST | DSI_TRIGGER_VIDEO);
// Request register read.
_display_dsi_send_cmd(MIPI_DSI_DCS_READ, cmd, 0);
_display_dsi_wait(0, _DSIREG(DSI_TRIGGER), DSI_TRIGGER_HOST | DSI_TRIGGER_VIDEO);
_display_dsi_wait_vblank(false);
// Transfer bus control to device for transmitting the reply.
DSI(_DSIREG(DSI_HOST_CONTROL)) |= DSI_HOST_CONTROL_IMM_BTA;
// Wait for reply to complete. DSI_HOST_CONTROL_IMM_BTA bit acts as a DSI host read busy.
_display_dsi_wait(150000, _DSIREG(DSI_HOST_CONTROL), DSI_HOST_CONTROL_IMM_BTA);
// Wait a bit for the reply.
usleep(5000);
// Read RX FIFO.
_display_dsi_read_rx_fifo(fifo);
// Parse packet and copy over the data.
if ((fifo[0] & 0xFF) == DSI_ESCAPE_CMD)
{ {
// Wait for vblank before reseting sync points. // Act based on reply type.
DISPLAY_A(_DIREG(DC_CMD_INT_STATUS)) = DC_CMD_INT_FRAME_END_INT; // Clear interrupt. switch (fifo[1] & 0xFF)
while (!(DISPLAY_A(_DIREG(DC_CMD_INT_STATUS)) & DC_CMD_INT_FRAME_END_INT)) {
; case GEN_LONG_RD_RES:
case DCS_LONG_RD_RES:
memcpy(data, &fifo[2], MIN((fifo[1] >> 8) & 0xFFFF, len));
break;
// Reset all states of syncpt block. case GEN_1_BYTE_SHORT_RD_RES:
DSI(_DSIREG(DSI_INCR_SYNCPT_CNTRL)) = DSI_INCR_SYNCPT_SOFT_RESET; case DCS_1_BYTE_SHORT_RD_RES:
usleep(300); // Stabilization delay. memcpy(data, &fifo[2], 1);
break;
// Clear syncpt block reset. case GEN_2_BYTE_SHORT_RD_RES:
DSI(_DSIREG(DSI_INCR_SYNCPT_CNTRL)) = 0; case DCS_2_BYTE_SHORT_RD_RES:
usleep(300); // Stabilization delay. memcpy(data, &fifo[2], 2);
break;
// Restore video mode and host control. case ACK_ERROR_RES:
DSI(_DSIREG(DSI_VIDEO_MODE_CONTROL)) = 0; default:
DSI(_DSIREG(DSI_HOST_CONTROL)) = host_control; res = 1;
break;
// Disable and clear vblank interrupt. }
DISPLAY_A(_DIREG(DC_CMD_INT_ENABLE)) = 0;
DISPLAY_A(_DIREG(DC_CMD_INT_STATUS)) = DC_CMD_INT_FRAME_END_INT;
} }
else
res = 1;
// Restore host control.
DSI(_DSIREG(DSI_HOST_CONTROL)) = host_control;
return res; return res;
} }
@ -425,7 +497,7 @@ void display_init()
_display_id = 0xCCCCCC; _display_id = 0xCCCCCC;
for (u32 i = 0; i < 3; i++) for (u32 i = 0; i < 3; i++)
{ {
if (!display_dsi_read(MIPI_DCS_GET_DISPLAY_ID, 3, &_display_id, DSI_VIDEO_DISABLED)) if (!display_dsi_read(MIPI_DCS_GET_DISPLAY_ID, 3, &_display_id))
break; break;
usleep(10000); usleep(10000);

View file

@ -1,6 +1,6 @@
/* /*
* Copyright (c) 2018 naehrwert * Copyright (c) 2018 naehrwert
* Copyright (c) 2018-2021 CTCaer * Copyright (c) 2018-2022 CTCaer
* *
* This program is free software; you can redistribute it and/or modify it * This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License, * under the terms and conditions of the GNU General Public License,
@ -737,7 +737,8 @@ void display_init_cursor(void *crs_fb, u32 size);
void display_set_pos_cursor(u32 x, u32 y); void display_set_pos_cursor(u32 x, u32 y);
void display_deinit_cursor(); void display_deinit_cursor();
int display_dsi_read(u8 cmd, u32 len, void *data);
int display_dsi_vblank_read(u8 cmd, u32 len, void *data);
void display_dsi_write(u8 cmd, u32 len, void *data, bool video_enabled); void display_dsi_write(u8 cmd, u32 len, void *data, bool video_enabled);
int display_dsi_read(u8 cmd, u32 len, void *data, bool video_enabled);
#endif #endif