/* * mdss_dsi_cmds_rx() - dcs read from panel * @ctrl: dsi controller * @cmds: read command descriptor * @len: number of bytes to read back * * controller have 4 registers can hold 16 bytes of rxed data * dcs packet: 4 bytes header + payload + 2 bytes crc * 2 padding bytes add to payload to have payload length is mutipled by 4 * 1st read: 4 bytes header + 8 bytes payload + 2 padding + 2 crc * 2nd read: 12 bytes payload + 2 padding + 2 crc * 3rd read: 12 bytes payload + 2 padding + 2 crc * */ int mdss_dsi_cmds_rx(struct mdss_dsi_ctrl_pdata *ctrl, struct dsi_cmd_desc *cmds, int rlen) { int data_byte, rx_byte, dlen, end; int short_response, diff, pkt_size, ret = 0; struct dsi_buf *tp, *rp; char cmd; bool ctrl_restore = false, mctrl_restore = false; struct mdss_dsi_ctrl_pdata *mctrl = NULL; /* * In broadcast mode, the configuration for master controller * would be done when the slave controller is configured */ if (mdss_dsi_is_master_ctrl(ctrl)) { pr_debug("%s: Broadcast mode enabled. skipping config for ctrl%d\n", __func__, ctrl->ndx); return 0; } /* * Turn on cmd mode in order to transmit the commands. * For video mode, do not send cmds more than one pixel line, * since it only transmit it during BLLP. * Ensure that for slave controller, master is also configured */ if (mdss_dsi_is_slave_ctrl(ctrl)) { mctrl = mdss_dsi_get_master_ctrl(); if (!mctrl) pr_warn("%s: Unable to get master control\n", __func__); else mctrl_restore = __mdss_dsi_cmd_mode_config(mctrl, 1); } ctrl_restore = __mdss_dsi_cmd_mode_config(ctrl, 1); if (rlen <= 2) { short_response = 1; pkt_size = rlen; rx_byte = 4; } else { short_response = 0; data_byte = 8; /* first read */ /* * add extra 2 padding bytes to have overall * packet size is multipe by 4. This also make * sure 4 bytes dcs headerlocates within a * 32 bits register after shift in. */ pkt_size = data_byte + 2; rx_byte = data_byte + 8; /* 4 header + 2 crc + 2 padding*/ } tp = &ctrl->tx_buf; rp = &ctrl->rx_buf; end = 0; mdss_dsi_buf_init(rp); while (!end) { pr_debug("%s: rlen=%d pkt_size=%d rx_byte=%d\n", __func__, rlen, pkt_size, rx_byte); max_pktsize[0] = pkt_size; mdss_dsi_buf_init(tp); ret = mdss_dsi_cmd_dma_add(tp, &pkt_size_cmd); if (!ret) { pr_err("%s: failed to add max_pkt_size\n", __func__); rp->len = 0; goto end; } mdss_dsi_wait4video_eng_busy(ctrl); mdss_dsi_enable_irq(ctrl, DSI_CMD_TERM); ret = mdss_dsi_cmd_dma_tx(ctrl, tp); if (IS_ERR_VALUE(ret)) { mdss_dsi_disable_irq(ctrl, DSI_CMD_TERM); pr_err("%s: failed to tx max_pkt_size\n", __func__); rp->len = 0; goto end; } pr_debug("%s: max_pkt_size=%d sent\n", __func__, pkt_size); mdss_dsi_buf_init(tp); ret = mdss_dsi_cmd_dma_add(tp, cmds); if (!ret) { pr_err("%s: failed to add cmd = 0x%x\n", __func__, cmds->payload[0]); rp->len = 0; goto end; } mdss_dsi_wait4video_eng_busy(ctrl); /* video mode only */ mdss_dsi_enable_irq(ctrl, DSI_CMD_TERM); /* transmit read comamnd to client */ ret = mdss_dsi_cmd_dma_tx(ctrl, tp); if (IS_ERR_VALUE(ret)) { mdss_dsi_disable_irq(ctrl, DSI_CMD_TERM); pr_err("%s: failed to tx cmd = 0x%x\n", __func__, cmds->payload[0]); rp->len = 0; goto end; } /* * once cmd_dma_done interrupt received, * return data from client is ready and stored * at RDBK_DATA register already * since rx fifo is 16 bytes, dcs header is kept at first loop, * after that dcs header lost during shift into registers */ dlen = mdss_dsi_cmd_dma_rx(ctrl, rp, rx_byte); if (short_response) break; if (rlen <= data_byte) { diff = data_byte - rlen; end = 1; } else { diff = 0; rlen -= data_byte; } dlen -= 2; /* 2 padding bytes */ dlen -= 2; /* 2 crc */ dlen -= diff; rp->data += dlen; /* next start position */ rp->len += dlen; data_byte = 12; /* NOT first read */ pkt_size += data_byte; pr_debug("%s: rp data=%x len=%d dlen=%d diff=%d\n", __func__, (int)rp->data, rp->len, dlen, diff); } rp->data = rp->start; /* move back to start position */ cmd = rp->data[0]; switch (cmd) { case DTYPE_ACK_ERR_RESP: pr_debug("%s: rx ACK_ERR_PACLAGE\n", __func__); rp->len = 0; case DTYPE_GEN_READ1_RESP: case DTYPE_DCS_READ1_RESP: mdss_dsi_short_read1_resp(rp); break; case DTYPE_GEN_READ2_RESP: case DTYPE_DCS_READ2_RESP: mdss_dsi_short_read2_resp(rp); break; case DTYPE_GEN_LREAD_RESP: case DTYPE_DCS_LREAD_RESP: mdss_dsi_long_read_resp(rp); break; default: pr_warning("%s:Invalid response cmd\n", __func__); rp->len = 0; } end: if (mctrl_restore) __mdss_dsi_cmd_mode_config(mctrl, 0); if (ctrl_restore) __mdss_dsi_cmd_mode_config(ctrl, 0); return rp->len; }
static int mdss_dsi_cmds2buf_tx(struct mdss_dsi_ctrl_pdata *ctrl, struct dsi_cmd_desc *cmds, int cnt) { struct dsi_buf *tp; struct dsi_cmd_desc *cm; struct dsi_ctrl_hdr *dchdr; int len, wait, tot = 0; #ifdef CONFIG_OLED_SUPPORT #ifdef LGE_HRTIMER_OLED_PATCH #else struct timeval tv_start, tv_end; long tv_diff; int delay_count; #endif #endif tp = &ctrl->tx_buf; mdss_dsi_buf_init(tp); cm = cmds; len = 0; while (cnt--) { dchdr = &cm->dchdr; mdss_dsi_buf_reserve(tp, len); len = mdss_dsi_cmd_dma_add(tp, cm); if (!len) { pr_err("%s: failed to add cmd = 0x%x\n", __func__, cm->payload[0]); return -EINVAL; } tot += len; if (dchdr->last) { tp->data = tp->start; /* begin of buf */ wait = mdss_dsi_wait4video_eng_busy(ctrl); mdss_dsi_enable_irq(ctrl, DSI_CMD_TERM); len = mdss_dsi_cmd_dma_tx(ctrl, tp); if (IS_ERR_VALUE(len)) { mdss_dsi_disable_irq(ctrl, DSI_CMD_TERM); pr_err("%s: failed to call cmd_dma_tx for cmd = 0x%x\n", __func__, cmds->payload[0]); return -EINVAL; } #ifdef CONFIG_OLED_SUPPORT #ifdef LGE_HRTIMER_OLED_PATCH if (!wait || dchdr->wait/* > VSYNC_PERIOD*/) { pr_info("[Zee][OLED] mipi_dsi_tx(0x%X) start (target delay=%dms)\n", cm->payload[0], (int)dchdr->wait); if (dchdr->wait > 5) oled_hrtimer_delay(dchdr->wait); else mdelay(dchdr->wait); pr_info("[Zee][OLED] mipi_dsi_tx(0x%X) finish (target delay=%dms)\n", cm->payload[0], (int)dchdr->wait); } #else if (!wait || dchdr->wait/* > VSYNC_PERIOD*/) { delay_count = 0; do_gettimeofday(&tv_start); do { mdelay(1); do_gettimeofday(&tv_end); tv_diff = ((tv_end.tv_sec - tv_start.tv_sec) * 1000000) /* sec */ + (tv_end.tv_usec - tv_start.tv_usec); /* usec */ delay_count++; } while (dchdr->wait * 1000 > tv_diff); pr_info("%s: 0x%X needs %d(ms) delay and real delay is %ld(us), delay_count(%d).\n", __func__, cm->payload[0], (int)dchdr->wait, tv_diff, delay_count); } #endif #else if (!wait || dchdr->wait > VSYNC_PERIOD) usleep(dchdr->wait * 1000); #endif mdss_dsi_buf_init(tp); len = 0; } cm++; } return tot; }
/* * mdss_dsi_cmds_rx() - dcs read from panel * @ctrl: dsi controller * @cmds: read command descriptor * @len: number of bytes to read back * * controller have 4 registers can hold 16 bytes of rxed data * dcs packet: 4 bytes header + payload + 2 bytes crc * 2 padding bytes add to payload to have payload length is mutipled by 4 * 1st read: 4 bytes header + 8 bytes payload + 2 padding + 2 crc * 2nd read: 12 bytes payload + 2 padding + 2 crc * 3rd read: 12 bytes payload + 2 padding + 2 crc * */ int mdss_dsi_cmds_rx(struct mdss_dsi_ctrl_pdata *ctrl, struct dsi_cmd_desc *cmds, int rlen) { int data_byte, rx_byte, dlen, end; int short_response, diff, pkt_size, ret = 0; struct dsi_buf *tp, *rp; char cmd; u32 dsi_ctrl, data; int video_mode; u32 left_dsi_ctrl = 0; bool left_ctrl_restore = false; if (ctrl->shared_pdata.broadcast_enable) { if (ctrl->ndx == DSI_CTRL_0) { pr_debug("%s: Broadcast mode. 1st ctrl\n", __func__); return 0; } } if (ctrl->shared_pdata.broadcast_enable) { if ((ctrl->ndx == DSI_CTRL_1) && (left_ctrl_pdata != NULL)) { left_dsi_ctrl = MIPI_INP(left_ctrl_pdata->ctrl_base + 0x0004); video_mode = left_dsi_ctrl & 0x02; /* VIDEO_MODE_EN */ if (video_mode) { data = left_dsi_ctrl | 0x04; /* CMD_MODE_EN */ MIPI_OUTP(left_ctrl_pdata->ctrl_base + 0x0004, data); left_ctrl_restore = true; } } } /* turn on cmd mode * for video mode, do not send cmds more than * one pixel line, since it only transmit it * during BLLP. */ dsi_ctrl = MIPI_INP((ctrl->ctrl_base) + 0x0004); video_mode = dsi_ctrl & 0x02; /* VIDEO_MODE_EN */ if (video_mode) { data = dsi_ctrl | 0x04; /* CMD_MODE_EN */ MIPI_OUTP((ctrl->ctrl_base) + 0x0004, data); } if (rlen == 0) { short_response = 1; rx_byte = 4; } else { short_response = 0; data_byte = 8; /* first read */ /* * add extra 2 padding bytes to have overall * packet size is multipe by 4. This also make * sure 4 bytes dcs headerlocates within a * 32 bits register after shift in. */ pkt_size = data_byte + 2; rx_byte = data_byte + 8; /* 4 header + 2 crc + 2 padding*/ } tp = &ctrl->tx_buf; rp = &ctrl->rx_buf; end = 0; mdss_dsi_buf_init(rp); while (!end) { pr_debug("%s: rlen=%d pkt_size=%d rx_byte=%d\n", __func__, rlen, pkt_size, rx_byte); if (!short_response) { max_pktsize[0] = pkt_size; mdss_dsi_buf_init(tp); ret = mdss_dsi_cmd_dma_add(tp, &pkt_size_cmd); if (!ret) { pr_err("%s: failed to add max_pkt_size\n", __func__); rp->len = 0; goto end; } mdss_dsi_wait4video_eng_busy(ctrl); mdss_dsi_enable_irq(ctrl, DSI_CMD_TERM); ret = mdss_dsi_cmd_dma_tx(ctrl, tp); if (IS_ERR_VALUE(ret)) { mdss_dsi_disable_irq(ctrl, DSI_CMD_TERM); pr_err("%s: failed to tx max_pkt_size\n", __func__); rp->len = 0; goto end; } pr_debug("%s: max_pkt_size=%d sent\n", __func__, pkt_size); } mdss_dsi_buf_init(tp); ret = mdss_dsi_cmd_dma_add(tp, cmds); if (!ret) { pr_err("%s: failed to add cmd = 0x%x\n", __func__, cmds->payload[0]); rp->len = 0; goto end; } mdss_dsi_wait4video_eng_busy(ctrl); /* video mode only */ mdss_dsi_enable_irq(ctrl, DSI_CMD_TERM); /* transmit read comamnd to client */ ret = mdss_dsi_cmd_dma_tx(ctrl, tp); if (IS_ERR_VALUE(ret)) { mdss_dsi_disable_irq(ctrl, DSI_CMD_TERM); pr_err("%s: failed to tx cmd = 0x%x\n", __func__, cmds->payload[0]); rp->len = 0; goto end; } /* * once cmd_dma_done interrupt received, * return data from client is ready and stored * at RDBK_DATA register already * since rx fifo is 16 bytes, dcs header is kept at first loop, * after that dcs header lost during shift into registers */ dlen = mdss_dsi_cmd_dma_rx(ctrl, rp, rx_byte); if (short_response) break; if (rlen <= data_byte) { diff = data_byte - rlen; end = 1; } else { diff = 0; rlen -= data_byte; } dlen -= 2; /* 2 padding bytes */ dlen -= 2; /* 2 crc */ dlen -= diff; rp->data += dlen; /* next start position */ rp->len += dlen; data_byte = 12; /* NOT first read */ pkt_size += data_byte; pr_debug("%s: rp data=%x len=%d dlen=%d diff=%d\n", __func__, (int)rp->data, rp->len, dlen, diff); } rp->data = rp->start; /* move back to start position */ cmd = rp->data[0]; switch (cmd) { case DTYPE_ACK_ERR_RESP: pr_debug("%s: rx ACK_ERR_PACLAGE\n", __func__); rp->len = 0; case DTYPE_GEN_READ1_RESP: case DTYPE_DCS_READ1_RESP: mdss_dsi_short_read1_resp(rp); break; case DTYPE_GEN_READ2_RESP: case DTYPE_DCS_READ2_RESP: mdss_dsi_short_read2_resp(rp); break; case DTYPE_GEN_LREAD_RESP: case DTYPE_DCS_LREAD_RESP: mdss_dsi_long_read_resp(rp); break; default: pr_warning("%s:Invalid response cmd\n", __func__); rp->len = 0; } end: if (left_ctrl_restore) MIPI_OUTP(left_ctrl_pdata->ctrl_base + 0x0004, left_dsi_ctrl); /*restore */ if (video_mode) MIPI_OUTP((ctrl->ctrl_base) + 0x0004, dsi_ctrl); /* restore */ return rp->len; }
int mdss_dsi_cmds_rx(struct mdss_dsi_ctrl_pdata *ctrl, struct dsi_cmd_desc *cmds, int rlen) { int cnt, len, diff, pkt_size, ret = 0; struct dsi_buf *tp, *rp; int no_max_pkt_size; char cmd; u32 dsi_ctrl, data; int video_mode; u32 left_dsi_ctrl = 0; bool left_ctrl_restore = false; int rx_flags = 0; bool long_rd_rsp_chk = false; if (ctrl->shared_pdata.broadcast_enable) { if (ctrl->ndx == DSI_CTRL_0) { pr_debug("%s: Broadcast mode. 1st ctrl\n", __func__); return 0; } } if (ctrl->shared_pdata.broadcast_enable) { if ((ctrl->ndx == DSI_CTRL_1) && (left_ctrl_pdata != NULL)) { left_dsi_ctrl = MIPI_INP(left_ctrl_pdata->ctrl_base + 0x0004); video_mode = left_dsi_ctrl & 0x02; /* VIDEO_MODE_EN */ if (video_mode) { data = left_dsi_ctrl | 0x04; /* CMD_MODE_EN */ MIPI_OUTP(left_ctrl_pdata->ctrl_base + 0x0004, data); left_ctrl_restore = true; } } } /* turn on cmd mode * for video mode, do not send cmds more than * one pixel line, since it only transmit it * during BLLP. */ dsi_ctrl = MIPI_INP((ctrl->ctrl_base) + 0x0004); video_mode = dsi_ctrl & 0x02; /* VIDEO_MODE_EN */ if (video_mode) { data = dsi_ctrl | 0x04; /* CMD_MODE_EN */ MIPI_OUTP((ctrl->ctrl_base) + 0x0004, data); } no_max_pkt_size = rx_flags & CMD_REQ_NO_MAX_PKT_SIZE; if (no_max_pkt_size) rlen = ALIGN(rlen, 4); /* Only support rlen = 4*n */ len = rlen; diff = 0; if (len < 2) cnt = 4; /* short read */ else if (len == 2) { /* Response could be a short or long read */ cnt = 8; long_rd_rsp_chk = true; } else { if (len > MDSS_DSI_LEN) len = MDSS_DSI_LEN; /* 8 bytes at most */ len = ALIGN(len, 4); /* len 4 bytes align */ diff = len - rlen; /* * add extra 2 bytes to len to have overall * packet size is multipe by 4. This also make * sure 4 bytes dcs headerlocates within a * 32 bits register after shift in. * after all, len should be either 6 or 10. */ len += 2; cnt = len + 6; /* 4 bytes header + 2 bytes crc */ } tp = &ctrl->tx_buf; rp = &ctrl->rx_buf; if (!no_max_pkt_size) { /* packet size need to be set at every read */ pkt_size = len; max_pktsize[0] = pkt_size; mdss_dsi_buf_init(tp); ret = mdss_dsi_cmd_dma_add(tp, &pkt_size_cmd); if (!ret) { pr_err("%s: failed to call\n", __func__); rp->len = 0; goto end; } mdss_dsi_wait4video_eng_busy(ctrl); mdss_dsi_enable_irq(ctrl, DSI_CMD_TERM); ret = mdss_dsi_cmd_dma_tx(ctrl, tp); if (IS_ERR_VALUE(ret)) { mdss_dsi_disable_irq(ctrl, DSI_CMD_TERM); pr_err("%s: failed to call\n", __func__); rp->len = 0; goto end; } pr_debug("%s: Max packet size sent\n", __func__); } mdss_dsi_buf_init(tp); ret = mdss_dsi_cmd_dma_add(tp, cmds); if (!ret) { pr_err("%s: failed to call cmd_dma_add for cmd = 0x%x\n", __func__, cmds->payload[0]); rp->len = 0; goto end; } mdss_dsi_wait4video_eng_busy(ctrl); mdss_dsi_enable_irq(ctrl, DSI_CMD_TERM); /* transmit read comamnd to client */ ret = mdss_dsi_cmd_dma_tx(ctrl, tp); if (IS_ERR_VALUE(ret)) { mdss_dsi_disable_irq(ctrl, DSI_CMD_TERM); pr_err("%s: failed to call\n", __func__); rp->len = 0; goto end; } /* * once cmd_dma_done interrupt received, * return data from client is ready and stored * at RDBK_DATA register already */ mdss_dsi_buf_init(rp); if (no_max_pkt_size) { /* * expect rlen = n * 4 * short alignement for start addr */ rp->data += 2; } mdss_dsi_cmd_dma_rx(ctrl, rp, cnt); if (no_max_pkt_size) { /* * remove extra 2 bytes from previous * rx transaction at shift register * which was inserted during copy * shift registers to rx buffer * rx payload start from long alignment addr */ rp->data += 2; } if (long_rd_rsp_chk && rp->data[0] != DTYPE_GEN_LREAD_RESP && rp->data[0] != DTYPE_DCS_LREAD_RESP) rp->data += 4; cmd = rp->data[0]; switch (cmd) { case DTYPE_ACK_ERR_RESP: pr_debug("%s: rx ACK_ERR_PACLAGE\n", __func__); rp->len = 0; case DTYPE_GEN_READ1_RESP: case DTYPE_DCS_READ1_RESP: mdss_dsi_short_read1_resp(rp); break; case DTYPE_GEN_READ2_RESP: case DTYPE_DCS_READ2_RESP: mdss_dsi_short_read2_resp(rp); break; case DTYPE_GEN_LREAD_RESP: case DTYPE_DCS_LREAD_RESP: mdss_dsi_long_read_resp(rp); if (!long_rd_rsp_chk) { rp->len -= 2; /* extra 2 bytes added */ rp->len -= diff; /* align bytes */ } break; default: pr_warning("%s:Invalid response cmd\n", __func__); rp->len = 0; } end: if (left_ctrl_restore) MIPI_OUTP(left_ctrl_pdata->ctrl_base + 0x0004, left_dsi_ctrl); /*restore */ if (video_mode) MIPI_OUTP((ctrl->ctrl_base) + 0x0004, dsi_ctrl); /* restore */ return rp->len; }
int mdss_dsi_cmds_rx(struct mdss_dsi_ctrl_pdata *ctrl, struct dsi_cmd_desc *cmds, int rlen, u32 rx_flags) { int cnt, len, diff, pkt_size; struct dsi_buf *tp, *rp; int no_max_pkt_size; char cmd; u32 dsi_ctrl; u32 data; int video_mode; no_max_pkt_size = rx_flags & CMD_REQ_NO_MAX_PKT_SIZE; if (no_max_pkt_size) rlen = ALIGN(rlen, 4); /* Only support rlen = 4*n */ len = rlen; diff = 0; if (len <= 2) cnt = 4; /* short read */ else { if (len > MDSS_DSI_LEN) len = MDSS_DSI_LEN; /* 8 bytes at most */ len = ALIGN(len, 4); /* len 4 bytes align */ diff = len - rlen; /* * add extra 2 bytes to len to have overall * packet size is multipe by 4. This also make * sure 4 bytes dcs headerlocates within a * 32 bits register after shift in. * after all, len should be either 6 or 10. */ len += 2; cnt = len + 6; /* 4 bytes header + 2 bytes crc */ } dsi_ctrl = MIPI_INP((ctrl->ctrl_base) + 0x0004); video_mode = dsi_ctrl & 0x02; /* VIDEO_MODE_EN */ if (video_mode) { data = dsi_ctrl | 0x04; /* CMD_MODE_EN */ MIPI_OUTP((ctrl->ctrl_base) + 0x0004, data); } tp = &ctrl->tx_buf; rp = &ctrl->rx_buf; if (!no_max_pkt_size) { /* packet size need to be set at every read */ pkt_size = len; max_pktsize[0] = pkt_size; mdss_dsi_enable_irq(ctrl, DSI_CMD_TERM); mdss_dsi_buf_init(tp); mdss_dsi_cmd_dma_add(tp, &pkt_size_cmd); mdss_dsi_cmd_dma_tx(ctrl, tp); pr_debug("%s: Max packet size sent\n", __func__); } mdss_dsi_enable_irq(ctrl, DSI_CMD_TERM); mdss_dsi_buf_init(tp); mdss_dsi_cmd_dma_add(tp, cmds); /* transmit read comamnd to client */ mdss_dsi_cmd_dma_tx(ctrl, tp); /* * once cmd_dma_done interrupt received, * return data from client is ready and stored * at RDBK_DATA register already */ mdss_dsi_buf_init(rp); if (no_max_pkt_size) { /* * expect rlen = n * 4 * short alignement for start addr */ rp->data += 2; } mdss_dsi_cmd_dma_rx(ctrl, rp, cnt); if (video_mode) MIPI_OUTP((ctrl->ctrl_base) + 0x0004, dsi_ctrl); /* restore */ if (no_max_pkt_size) { /* * remove extra 2 bytes from previous * rx transaction at shift register * which was inserted during copy * shift registers to rx buffer * rx payload start from long alignment addr */ rp->data += 2; } cmd = rp->data[0]; switch (cmd) { case DTYPE_ACK_ERR_RESP: pr_debug("%s: rx ACK_ERR_PACLAGE\n", __func__); break; case DTYPE_GEN_READ1_RESP: case DTYPE_DCS_READ1_RESP: mdss_dsi_short_read1_resp(rp); break; case DTYPE_GEN_READ2_RESP: case DTYPE_DCS_READ2_RESP: mdss_dsi_short_read2_resp(rp); break; case DTYPE_GEN_LREAD_RESP: case DTYPE_DCS_LREAD_RESP: mdss_dsi_long_read_resp(rp); rp->len -= 2; /* extra 2 bytes added */ rp->len -= diff; /* align bytes */ break; default: pr_debug("%s: Unknown cmd received\n", __func__); break; } return rp->len; }
/* * mdss_dsi_cmds_tx: * thread context only */ int mdss_dsi_cmds_tx(struct mdss_dsi_ctrl_pdata *ctrl, struct dsi_cmd_desc *cmds, int cnt) { struct dsi_buf *tp; struct dsi_cmd_desc *cm; struct dsi_ctrl_hdr *dchdr; u32 dsi_ctrl, data; int i, video_mode; #ifdef CONFIG_OLED_SUPPORT struct timeval tv_start, tv_end; long tv_diff; int delay_count; #endif if (ctrl->shared_pdata.broadcast_enable) { if (ctrl->ndx == DSI_CTRL_0) { pr_debug("%s: Broadcast mode. 1st ctrl\n", __func__); return 0; } } if (ctrl->shared_pdata.broadcast_enable) { if ((ctrl->ndx == DSI_CTRL_1) && (left_ctrl_pdata != NULL)) { dsi_ctrl = MIPI_INP(left_ctrl_pdata->ctrl_base + 0x0004); video_mode = dsi_ctrl & 0x02; /* VIDEO_MODE_EN */ if (video_mode) { data = dsi_ctrl | 0x04; /* CMD_MODE_EN */ MIPI_OUTP(left_ctrl_pdata->ctrl_base + 0x0004, data); } } } /* turn on cmd mode * for video mode, do not send cmds more than * one pixel line, since it only transmit it * during BLLP. */ dsi_ctrl = MIPI_INP((ctrl->ctrl_base) + 0x0004); video_mode = dsi_ctrl & 0x02; /* VIDEO_MODE_EN */ if (video_mode) { data = dsi_ctrl | 0x04; /* CMD_MODE_EN */ MIPI_OUTP((ctrl->ctrl_base) + 0x0004, data); } tp = &ctrl->tx_buf; cm = cmds; for (i = 0; i < cnt; i++) { mdss_dsi_enable_irq(ctrl, DSI_CMD_TERM); mdss_dsi_buf_init(tp); mdss_dsi_cmd_dma_add(tp, cm); mdss_dsi_cmd_dma_tx(ctrl, tp); dchdr = &cm->dchdr; #ifdef CONFIG_OLED_SUPPORT if(dchdr->wait) { delay_count = 0; do_gettimeofday(&tv_start); do { mdelay(1); do_gettimeofday(&tv_end); tv_diff = ((tv_end.tv_sec - tv_start.tv_sec) * 1000000) // sec + (tv_end.tv_usec - tv_start.tv_usec); // usec delay_count++; } while(dchdr->wait * 1000 > tv_diff); pr_info("%s: 0x%X needs %d(ms) delay and real delay is %ld(us), delay_count(%d).\n", __func__, cm->payload[0], (int)dchdr->wait, tv_diff, delay_count); } #else if (dchdr->wait) usleep(dchdr->wait * 1000); #endif cm++; } if (video_mode) MIPI_OUTP((ctrl->ctrl_base) + 0x0004, dsi_ctrl); /* restore */ return cnt; }
/* * mipi_dsi_cmds_single_tx: * thread context only */ int mdss_dsi_cmds_single_tx(struct mdss_dsi_ctrl_pdata *pdata, struct dsi_cmd_desc *cmds, int cnt) { struct dsi_cmd_desc *cm; unsigned int dsi_ctrl, ctrl; int i, j = 0, k = 0, cmd_len = 0, video_mode; char *cmds_tx; char *bp; struct mdss_dsi_ctrl_pdata *ctrl_pdata = pdata; struct dsi_buf *tp = &ctrl_pdata->tx_buf; pr_debug("%s:++\n",__func__); /*Set Last Bit, only for last packet */ for (i = 0; i < cnt; i++) { if(cmds[i].dchdr.dtype != DTYPE_GEN_LWRITE && cmds[i].dchdr.dtype != DTYPE_DCS_LWRITE ) { pr_err("Single TX expects only Long Packets,"\ "Short packet encountered, return fail\n"); return -1; } cmds[i].dchdr.last = 0; } cmds[cnt-1].dchdr.last = 1; /* turn on cmd mode * for video mode, do not send cmds more than * one pixel line, since it only transmit it * during BLLP. */ if (ctrl_pdata->shared_pdata.broadcast_enable) { if ((ctrl_pdata->ndx == DSI_CTRL_1) && (left_ctrl_pdata != NULL)) { dsi_ctrl = MIPI_INP(left_ctrl_pdata->ctrl_base + 0x0004); video_mode = dsi_ctrl & 0x02; /* VIDEO_MODE_EN */ if (video_mode) { int data = dsi_ctrl | 0x04; /* CMD_MODE_EN */ MIPI_OUTP(left_ctrl_pdata->ctrl_base + 0x0004, data); } } } dsi_ctrl = MIPI_INP((ctrl_pdata->ctrl_base) + 0x0004); video_mode = dsi_ctrl & 0x02; /* VIDEO_MODE_EN */ if (video_mode) { ctrl = dsi_ctrl | 0x04; /* CMD_MODE_EN */ MIPI_OUTP((ctrl_pdata->ctrl_base) + 0x0004, ctrl); } cm = cmds; cmds_tx = kmalloc((1024 + DSI_HOST_HDR_SIZE) * cnt, GFP_KERNEL); mdss_dsi_buf_init(tp); mdss_dsi_enable_irq(pdata, DSI_CMD_TERM); for (i = 0; i < cnt; i++) { mdss_dsi_buf_init(tp); mdss_dsi_cmd_dma_add(tp, cm); bp = tp->data; for (j = 0; j < tp->len; j++) { *(cmds_tx + k) = *bp++; k++; } cmd_len = cmd_len + tp->len; cm++; } tp->data = cmds_tx; tp->len = cmd_len; mdss_dsi_cmd_dma_tx(ctrl_pdata, tp); kfree(cmds_tx); if (video_mode) MIPI_OUTP((ctrl_pdata->ctrl_base) + 0x0004, dsi_ctrl); /* restore */ return cnt; }
/* * mdss_dsi_cmds_rx() - dcs read from panel * @ctrl: dsi controller * @cmds: read command descriptor * @len: number of bytes to read back * * controller have 4 registers can hold 16 bytes of rxed data * dcs packet: 4 bytes header + payload + 2 bytes crc * 2 padding bytes add to payload to have payload length is mutipled by 4 * 1st read: 4 bytes header + 8 bytes payload + 2 padding + 2 crc * 2nd read: 12 bytes payload + 2 padding + 2 crc * 3rd read: 12 bytes payload + 2 padding + 2 crc * */ int mdss_dsi_cmds_rx(struct mdss_dsi_ctrl_pdata *ctrl, struct dsi_cmd_desc *cmds, int rlen) { int data_byte, rx_byte, dlen, end; int short_response, diff, pkt_size, ret = 0; struct dsi_buf *tp, *rp; char cmd; u32 dsi_ctrl, data; int video_mode; u32 left_dsi_ctrl = 0; bool left_ctrl_restore = false; if (ctrl->shared_pdata.broadcast_enable) { if (ctrl->ndx == DSI_CTRL_0) { pr_debug("%s: Broadcast mode. 1st ctrl\n", __func__); return 0; } } if (ctrl->shared_pdata.broadcast_enable) { if ((ctrl->ndx == DSI_CTRL_1) && (left_ctrl_pdata != NULL)) { left_dsi_ctrl = MIPI_INP(left_ctrl_pdata->ctrl_base + 0x0004); video_mode = left_dsi_ctrl & 0x02; /* VIDEO_MODE_EN */ if (video_mode) { data = left_dsi_ctrl | 0x04; /* CMD_MODE_EN */ MIPI_OUTP(left_ctrl_pdata->ctrl_base + 0x0004, data); left_ctrl_restore = true; } } } /* turn on cmd mode * for video mode, do not send cmds more than * one pixel line, since it only transmit it * during BLLP. */ dsi_ctrl = MIPI_INP((ctrl->ctrl_base) + 0x0004); video_mode = dsi_ctrl & 0x02; /* VIDEO_MODE_EN */ if (video_mode) { data = dsi_ctrl | 0x04; /* CMD_MODE_EN */ MIPI_OUTP((ctrl->ctrl_base) + 0x0004, data); } /*fix qcom bug*/ #ifdef CONFIG_HUAWEI_KERNEL if (rlen <= 2) { #else if (rlen == 0) { #endif short_response = 1; rx_byte = 4; } else { short_response = 0; data_byte = 8; /* first read */ /* * add extra 2 padding bytes to have overall * packet size is multipe by 4. This also make * sure 4 bytes dcs headerlocates within a * 32 bits register after shift in. */ pkt_size = data_byte + 2; rx_byte = data_byte + 8; /* 4 header + 2 crc + 2 padding*/ } tp = &ctrl->tx_buf; rp = &ctrl->rx_buf; end = 0; mdss_dsi_buf_init(rp); while (!end) { pr_debug("%s: rlen=%d pkt_size=%d rx_byte=%d\n", __func__, rlen, pkt_size, rx_byte); if (!short_response) { max_pktsize[0] = pkt_size; mdss_dsi_buf_init(tp); ret = mdss_dsi_cmd_dma_add(tp, &pkt_size_cmd); if (!ret) { pr_err("%s: failed to add max_pkt_size\n", __func__); rp->len = 0; goto end; } mdss_dsi_wait4video_eng_busy(ctrl); mdss_dsi_enable_irq(ctrl, DSI_CMD_TERM); ret = mdss_dsi_cmd_dma_tx(ctrl, tp); if (IS_ERR_VALUE(ret)) { mdss_dsi_disable_irq(ctrl, DSI_CMD_TERM); pr_err("%s: failed to tx max_pkt_size\n", __func__); rp->len = 0; goto end; } pr_debug("%s: max_pkt_size=%d sent\n", __func__, pkt_size); } mdss_dsi_buf_init(tp); ret = mdss_dsi_cmd_dma_add(tp, cmds); if (!ret) { pr_err("%s: failed to add cmd = 0x%x\n", __func__, cmds->payload[0]); rp->len = 0; goto end; } mdss_dsi_wait4video_eng_busy(ctrl); /* video mode only */ mdss_dsi_enable_irq(ctrl, DSI_CMD_TERM); /* transmit read comamnd to client */ ret = mdss_dsi_cmd_dma_tx(ctrl, tp); if (IS_ERR_VALUE(ret)) { mdss_dsi_disable_irq(ctrl, DSI_CMD_TERM); pr_err("%s: failed to tx cmd = 0x%x\n", __func__, cmds->payload[0]); rp->len = 0; goto end; } /* * once cmd_dma_done interrupt received, * return data from client is ready and stored * at RDBK_DATA register already * since rx fifo is 16 bytes, dcs header is kept at first loop, * after that dcs header lost during shift into registers */ dlen = mdss_dsi_cmd_dma_rx(ctrl, rp, rx_byte); if (short_response) break; if (rlen <= data_byte) { diff = data_byte - rlen; end = 1; } else { diff = 0; rlen -= data_byte; } dlen -= 2; /* 2 padding bytes */ dlen -= 2; /* 2 crc */ dlen -= diff; rp->data += dlen; /* next start position */ rp->len += dlen; data_byte = 12; /* NOT first read */ pkt_size += data_byte; pr_debug("%s: rp data=%x len=%d dlen=%d diff=%d\n", __func__, (int)rp->data, rp->len, dlen, diff); } rp->data = rp->start; /* move back to start position */ cmd = rp->data[0]; switch (cmd) { case DTYPE_ACK_ERR_RESP: pr_debug("%s: rx ACK_ERR_PACLAGE\n", __func__); rp->len = 0; case DTYPE_GEN_READ1_RESP: case DTYPE_DCS_READ1_RESP: mdss_dsi_short_read1_resp(rp); break; case DTYPE_GEN_READ2_RESP: case DTYPE_DCS_READ2_RESP: mdss_dsi_short_read2_resp(rp); break; case DTYPE_GEN_LREAD_RESP: case DTYPE_DCS_LREAD_RESP: mdss_dsi_long_read_resp(rp); break; default: pr_warning("%s:Invalid response cmd\n", __func__); rp->len = 0; } end: if (left_ctrl_restore) MIPI_OUTP(left_ctrl_pdata->ctrl_base + 0x0004, left_dsi_ctrl); /*restore */ if (video_mode) MIPI_OUTP((ctrl->ctrl_base) + 0x0004, dsi_ctrl); /* restore */ return rp->len; } #define DMA_TX_TIMEOUT 200 static int mdss_dsi_cmd_dma_tx(struct mdss_dsi_ctrl_pdata *ctrl, struct dsi_buf *tp) { int len, ret = 0; int domain = MDSS_IOMMU_DOMAIN_UNSECURE; char *bp; unsigned long size, addr; #ifdef CONFIG_HUAWEI_LCD bool iommu_attached = false; #endif bp = tp->data; len = ALIGN(tp->len, 4); size = ALIGN(tp->len, SZ_4K); if (is_mdss_iommu_attached()) { int ret = msm_iommu_map_contig_buffer(tp->dmap, mdss_get_iommu_domain(domain), 0, size, SZ_4K, 0, &(addr)); if (IS_ERR_VALUE(ret)) { pr_err("unable to map dma memory to iommu(%d)\n", ret); return -ENOMEM; } #ifdef CONFIG_HUAWEI_LCD iommu_attached = true; #endif } else { addr = tp->dmap; #ifdef CONFIG_HUAWEI_LCD iommu_attached = false; #endif } INIT_COMPLETION(ctrl->dma_comp); if (ctrl->shared_pdata.broadcast_enable) if ((ctrl->ndx == DSI_CTRL_1) && (left_ctrl_pdata != NULL)) { MIPI_OUTP(left_ctrl_pdata->ctrl_base + 0x048, addr); MIPI_OUTP(left_ctrl_pdata->ctrl_base + 0x04c, len); } MIPI_OUTP((ctrl->ctrl_base) + 0x048, addr); MIPI_OUTP((ctrl->ctrl_base) + 0x04c, len); wmb(); if (ctrl->shared_pdata.broadcast_enable) if ((ctrl->ndx == DSI_CTRL_1) && (left_ctrl_pdata != NULL)) { MIPI_OUTP(left_ctrl_pdata->ctrl_base + 0x090, 0x01); } MIPI_OUTP((ctrl->ctrl_base) + 0x090, 0x01); /* trigger */ wmb(); ret = wait_for_completion_timeout(&ctrl->dma_comp, msecs_to_jiffies(DMA_TX_TIMEOUT)); if (ret == 0) ret = -ETIMEDOUT; else ret = tp->len; #ifdef CONFIG_HUAWEI_LCD //unmap it when it have been maped at front if (is_mdss_iommu_attached() && iommu_attached) #else if (is_mdss_iommu_attached()) #endif msm_iommu_unmap_contig_buffer(addr, mdss_get_iommu_domain(domain), 0, size); return ret; }
/* * mdss_dsi_cmds_rx() - dcs read from panel * @ctrl: dsi controller * @cmds: read command descriptor * @len: number of bytes to read back * * controller have 4 registers can hold 16 bytes of rxed data * dcs packet: 4 bytes header + payload + 2 bytes crc * 2 padding bytes add to payload to have payload length is mutipled by 4 * 1st read: 4 bytes header + 8 bytes payload + 2 padding + 2 crc * 2nd read: 12 bytes payload + 2 padding + 2 crc * 3rd read: 12 bytes payload + 2 padding + 2 crc * */ int mdss_dsi_cmds_rx(struct mdss_dsi_ctrl_pdata *ctrl, struct dsi_cmd_desc *cmds, int rlen) { int data_byte, rx_byte, dlen, end; int short_response, len, diff, pkt_size, ret = 0; struct dsi_buf *tp, *rp; char cmd; u32 dsi_ctrl, data; int video_mode; u32 left_dsi_ctrl = 0; bool left_ctrl_restore = false; int no_max_pkt_size = ctrl->panel_data.panel_info.mipi.no_max_pkt_size; if (ctrl->shared_pdata.broadcast_enable) { if (ctrl->ndx == DSI_CTRL_0) { pr_debug("%s: Broadcast mode. 1st ctrl\n", __func__); return 0; } } if (ctrl->shared_pdata.broadcast_enable) { if ((ctrl->ndx == DSI_CTRL_1) && (left_ctrl_pdata != NULL)) { left_dsi_ctrl = MIPI_INP(left_ctrl_pdata->ctrl_base + 0x0004); video_mode = left_dsi_ctrl & 0x02; /* VIDEO_MODE_EN */ if (video_mode) { data = left_dsi_ctrl | 0x04; /* CMD_MODE_EN */ MIPI_OUTP(left_ctrl_pdata->ctrl_base + 0x0004, data); left_ctrl_restore = true; } } } /* turn on cmd mode * for video mode, do not send cmds more than * one pixel line, since it only transmit it * during BLLP. */ dsi_ctrl = MIPI_INP((ctrl->ctrl_base) + 0x0004); video_mode = dsi_ctrl & 0x02; /* VIDEO_MODE_EN */ if (video_mode) { data = dsi_ctrl | 0x04; /* CMD_MODE_EN */ MIPI_OUTP((ctrl->ctrl_base) + 0x0004, data); } if (no_max_pkt_size) { /* Only support rlen = 4*n */ rlen = ALIGN(rlen, 4); } tp = &ctrl->tx_buf; rp = &ctrl->rx_buf; len = rlen; diff = 0; end = 0; data_byte = 0; if (len <= 2) { rx_byte = 4; /* short read */ short_response = 1; } else { if (len > MDSS_DSI_LEN) { data_byte = MDSS_DSI_LEN; pkt_size = data_byte + 2;/* 8 bytes +2 padding */ rx_byte = data_byte + 8; /* 4 bytes header + 2 bytes crc + 2 Padding */ } else { len = ALIGN(len, 4); data_byte = len; pkt_size = data_byte; rx_byte = data_byte + 6; /* 4 bytes header + 2 bytes crc*/ } short_response = 0; } mdss_dsi_buf_init(rp); while (!end) { pr_debug("%s: rlen=%d pkt_size=%d rx_byte=%d\n", __func__, len, pkt_size, rx_byte); if (!short_response) { max_pktsize[0] = pkt_size; mdss_dsi_buf_init(tp); ret = mdss_dsi_cmd_dma_add(tp, &pkt_size_cmd); if (!ret) { pr_err("%s: failed to add max_pkt_size\n", __func__); rp->len = 0; goto end; } mdss_dsi_wait4video_eng_busy(ctrl); mdss_dsi_enable_irq(ctrl, DSI_CMD_TERM); /* transmit read comamnd to client */ ret = mdss_dsi_cmd_dma_tx(ctrl, tp); if (IS_ERR_VALUE(ret)) { mdss_dsi_disable_irq(ctrl, DSI_CMD_TERM); pr_err("%s: failed to tx max_pkt_size\n", __func__); rp->len = 0; goto end; } pr_debug("%s: max_pkt_size=%d sent\n", __func__, pkt_size); } mdss_dsi_buf_init(tp); ret = mdss_dsi_cmd_dma_add(tp, cmds); if (!ret) { pr_err("%s: failed to add cmd = 0x%x\n", __func__, cmds->payload[0]); rp->len = 0; goto end; } mdss_dsi_wait4video_eng_busy(ctrl); /* video mode only */ mdss_dsi_enable_irq(ctrl, DSI_CMD_TERM); /* transmit read comamnd to client */ ret = mdss_dsi_cmd_dma_tx(ctrl, tp); if (IS_ERR_VALUE(ret)) { mdss_dsi_disable_irq(ctrl, DSI_CMD_TERM); pr_err("%s: failed to tx cmd = 0x%x\n", __func__, cmds->payload[0]); rp->len = 0; goto end; } /* * once cmd_dma_done interrupt received, * return data from client is ready and stored * at RDBK_DATA register already * since rx fifo is 16 bytes, dcs header is kept at first loop, * after that dcs header lost during shift into registers */ dlen = mdss_dsi_cmd_dma_rx(ctrl, rp, rx_byte); if (short_response) break; if (len <= data_byte) { diff = data_byte - len; end = 1; } else { diff = 0; len -= data_byte; } dlen -= 2; /* 2 padding bytes */ dlen -= 2; /* 2 crc */ dlen -= diff; rp->data += dlen; /* next start position */ rp->len += dlen; data_byte = 12; /* NOT first read */ pkt_size += data_byte; pr_debug("%s: rp data=%x len=%d dlen=%d diff=%d\n", __func__, (int)rp->data, rp->len, dlen, diff); } rp->data = rp->start; if (rlen <= MDSS_DSI_LEN && !no_max_pkt_size && !short_response) { /* * remove extra 2 bytes from previous * rx transaction at shift register * which was inserted during copy * shift registers to rx buffer * rx payload start from long alignment addr */ rp->data += 2; } cmd = rp->data[0]; pr_debug("%s: Read Response:0x%02X\n", __func__, cmd); switch (cmd) { case DTYPE_ACK_ERR_RESP: pr_info("%s: rx ACK_ERR_PACKAGE\n", __func__); rp->len = 0; case DTYPE_GEN_READ1_RESP: case DTYPE_DCS_READ1_RESP: mdss_dsi_short_read1_resp(rp); break; case DTYPE_GEN_READ2_RESP: case DTYPE_DCS_READ2_RESP: mdss_dsi_short_read2_resp(rp); break; case DTYPE_GEN_LREAD_RESP: case DTYPE_DCS_LREAD_RESP: mdss_dsi_long_read_resp(rp); break; default: pr_warning("%s:Invalid response cmd\n", __func__); rp->len = 0; } end: if (left_ctrl_restore) MIPI_OUTP(left_ctrl_pdata->ctrl_base + 0x0004, left_dsi_ctrl); /*restore */ if (video_mode) MIPI_OUTP((ctrl->ctrl_base) + 0x0004, dsi_ctrl); /* restore */ return rp->len; }