Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
120 changes: 96 additions & 24 deletions os/arch/arm/src/amebasmart/amebasmart_mipi.c
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,9 @@ static uint8_t *rx_data_ptr = NULL;
static uint32_t rx_data_len = 0;
static sem_t g_send_cmd_done;
static sem_t g_read_cmd_done;
static spinlock_t g_tx_lock = SP_UNLOCKED;
static spinlock_t g_rx_lock = SP_UNLOCKED;

#define MIPI_TRANSFER_TIMEOUT 1 /*one second timeout for mipi transfer*/
struct amebasmart_mipi_dsi_host_s {
struct mipi_dsi_host dsi_host;
Expand Down Expand Up @@ -193,7 +196,9 @@ static void amebasmart_mipidsi_send_cmd(MIPI_TypeDef *MIPIx, u8 cmd, u8 payload_
u32 word0, word1, addr, idx;
u8 cmd_addr[128];
if (MIPI_LPTX_IS_READ(cmd_type)) {
spin_lock(&g_rx_lock);
receive_cmd_done = 0;
spin_unlock(&g_rx_lock);
}
if (payload_len == 0) {
MIPI_DSI_CMD_Send(MIPIx, cmd_type, cmd, 0);
Expand Down Expand Up @@ -264,10 +269,12 @@ static void amebasmart_mipidsi_rcmd_decode(MIPI_TypeDef *MIPIx, u8 rcmd_idx)
}
rx_data_rdy = TRUE;
}
spin_lock(&g_rx_lock);
if (receive_cmd_done == 0) {
receive_cmd_done = 1;
sem_post(&g_read_cmd_done);
}
spin_unlock(&g_rx_lock);
}

static void amebasmart_mipi_reset_trx_helper(MIPI_TypeDef *MIPIx)
Expand All @@ -279,10 +286,10 @@ static void amebasmart_mipi_reset_trx_helper(MIPI_TypeDef *MIPIx)
MIPIx->MIPI_MAIN_CTRL = (MIPIx->MIPI_MAIN_CTRL & ~MIPI_BIT_DSI_MODE) | MIPI_BIT_LPTX_RST | MIPI_BIT_LPRX_RST;
DelayUs(1);
MIPIx->MIPI_MAIN_CTRL = (MIPIx->MIPI_MAIN_CTRL & ~MIPI_BIT_DSI_MODE) & ~MIPI_BIT_LPTX_RST & ~MIPI_BIT_LPRX_RST;

if (rx_data_ptr && rx_data_len > 0 && rx_data_rdy) {
memset(rx_data_ptr, 0, rx_data_len);
}
spin_lock(&g_rx_lock);
rx_data_ptr = NULL;
rx_data_len = 0;
spin_unlock(&g_rx_lock);
}

static void amebasmart_mipidsi_isr(void)
Expand All @@ -297,10 +304,16 @@ static void amebasmart_mipidsi_isr(void)
MIPI_DSI_INTS_ACPU_Clr(MIPIx, reg_val2);
if (reg_val & MIPI_BIT_CMD_TXDONE) {
reg_val &= ~MIPI_BIT_CMD_TXDONE;
spin_lock(&g_tx_lock);
if (send_cmd_done == 0) {
send_cmd_done = 1;
sem_post(&g_send_cmd_done);
} else {
/* Already done - ignore delayed TX IRQ */
spin_unlock(&g_tx_lock);
return;
}
spin_unlock(&g_tx_lock);
}
if (reg_val & MIPI_BIT_RCMD1) {
amebasmart_mipidsi_rcmd_decode(MIPIx, 0);
Expand Down Expand Up @@ -451,10 +464,12 @@ static int amebasmart_mipi_transfer(FAR struct mipi_dsi_host *dsi_host, FAR cons
struct mipi_dsi_packet packet;
struct timespec abstime;
irqstate_t flags;
bool is_read_operation = false;
/*When underflow happens, mipi's irq will be registered to rtl8730e_mipidsi_underflowreset callback to handle video mode frame done interrupt.
only one type of interrupt can be enabled at any one time, either cmd mode interrupt or video mode interrupt, so we need to re-register mipi's
irq cmd mode callback here
*/
MIPI_DSI_INT_Config(priv->MIPIx, DISABLE, ENABLE, FALSE);
#ifdef CONFIG_SMP
spin_lock(&g_rtl8730e_config_dev_s_underflow);
#endif
Expand Down Expand Up @@ -484,12 +499,23 @@ static int amebasmart_mipi_transfer(FAR struct mipi_dsi_host *dsi_host, FAR cons
#endif
return ret;
}
is_read_operation = MIPI_LPTX_IS_READ(msg->type);
/* Initialize state for new transfer */
spin_lock(&g_tx_lock);
send_cmd_done = 0;
spin_unlock(&g_tx_lock);
spin_lock(&g_rx_lock);
receive_cmd_done = 1;
rx_data_rdy = FALSE;
if (msg->rx_buf) {
if (msg->rx_buf && is_read_operation) {
rx_data_ptr = msg->rx_buf;
rx_data_len = msg->rx_len;
} else {
rx_data_ptr = NULL;
rx_data_len = 0;
}
spin_unlock(&g_rx_lock);
/* Send the command */
if (mipi_dsi_packet_format_is_short(msg->type)) {
if (packet.header[1] == 0) {
amebasmart_mipidsi_send_cmd(priv->MIPIx, packet.header[0], 0, NULL, msg->type);
Expand All @@ -500,36 +526,82 @@ static int amebasmart_mipi_transfer(FAR struct mipi_dsi_host *dsi_host, FAR cons
amebasmart_mipidsi_send_cmd(priv->MIPIx, packet.header[0], packet.payload_length, packet.payload, msg->type);
}
flags = enter_critical_section();
/* Wait for TX completion */
(void)clock_gettime(CLOCK_REALTIME, &abstime);
abstime.tv_sec += MIPI_TRANSFER_TIMEOUT;
ret = sem_timedwait(&g_send_cmd_done, &abstime);
if (!receive_cmd_done) {
ret = sem_timedwait(&g_read_cmd_done, &abstime);

int wait_result;
while ((wait_result = sem_timedwait(&g_send_cmd_done, &abstime)) != OK) {
if (errno == EINTR) {
continue;
} else {
/* Timeout occurred */
spin_lock(&g_tx_lock);
if (send_cmd_done == 0) {
send_cmd_done = 1;
receive_cmd_done = 1;
spin_unlock(&g_tx_lock);
/* Clean up RX state on timeout */
spin_lock(&g_rx_lock);
rx_data_ptr = NULL;
rx_data_len = 0;
spin_unlock(&g_rx_lock);
ret = -ETIMEDOUT;
goto cleanup;
}
spin_unlock(&g_tx_lock);
break;
}
}
leave_critical_section(flags);
if (send_cmd_done != 1 || receive_cmd_done != 1) {
#ifdef CONFIG_PM
bsp_pm_domain_control(BSP_MIPI_DRV, 0);
#endif
#ifdef CONFIG_SMP
spin_unlock(&g_rtl8730e_config_dev_s_underflow);
#endif
if (msg->rx_buf && msg->rx_len > 0) {
memset(msg->rx_buf, 0, msg->rx_len);

/* If TX succeeded and it's a read operation, wait for RX completion */
if (is_read_operation) {
(void)clock_gettime(CLOCK_REALTIME, &abstime);
abstime.tv_sec += MIPI_TRANSFER_TIMEOUT;
while ((wait_result = sem_timedwait(&g_read_cmd_done, &abstime)) != OK) {
if (errno == EINTR) {
continue;
} else {
/* RX timeout occurred */
spin_lock(&g_rx_lock);
if (receive_cmd_done == 0) {
receive_cmd_done = 1;
if (msg->rx_buf && msg->rx_len > 0) {
rx_data_ptr = NULL;
rx_data_len = 0;
}
spin_unlock(&g_rx_lock);
ret = -ETIMEDOUT;
goto cleanup;
}
spin_unlock(&g_rx_lock);
break;
}
}
return FAIL;
}

ret = OK;

cleanup:
leave_critical_section(flags);
/* Reset state for next transfer */
spin_lock(&g_tx_lock);
send_cmd_done = 1;
spin_unlock(&g_tx_lock);
spin_lock(&g_rx_lock);
receive_cmd_done = 1;
if (rx_data_rdy) {
rx_data_ptr = NULL;
rx_data_len = 0;
}
spin_unlock(&g_rx_lock);
#ifdef CONFIG_SMP
spin_unlock(&g_rtl8730e_config_dev_s_underflow);
#endif
#ifdef CONFIG_PM
bsp_pm_domain_control(BSP_MIPI_DRV, 0);
#endif
if (rx_data_rdy) {
rx_data_ptr = NULL;
rx_data_len = 0;
}
return OK;
return ret;
}

#ifdef CONFIG_PM
Expand Down