/* Copyright (c) 2012-2013, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and * only version 2 as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * */ #include #include #include #include #include #include #include #include #include #include #include "dsi_v2.h" #include "dsi_io_v2.h" #include "dsi_host_v2.h" #define DSI_POLL_SLEEP_US 1000 #define DSI_POLL_TIMEOUT_US 16000 #define DSI_ESC_CLK_RATE 19200000 #define DSI_DMA_CMD_TIMEOUT_MS 200 struct dsi_host_v2_private { struct completion dma_comp; int irq_enabled; spinlock_t irq_lock; int irq_no; unsigned char *dsi_base; struct device dis_dev; }; static struct dsi_host_v2_private *dsi_host_private; int msm_dsi_init(void) { if (!dsi_host_private) { dsi_host_private = kzalloc(sizeof(struct dsi_host_v2_private), GFP_KERNEL); if (!dsi_host_private) { pr_err("fail to alloc dsi host private data\n"); return -ENOMEM; } } init_completion(&dsi_host_private->dma_comp); spin_lock_init(&dsi_host_private->irq_lock); return 0; } void msm_dsi_deinit(void) { kfree(dsi_host_private); dsi_host_private = NULL; } void msm_dsi_ack_err_status(unsigned char *ctrl_base) { u32 status; status = MIPI_INP(ctrl_base + DSI_ACK_ERR_STATUS); if (status) { MIPI_OUTP(ctrl_base + DSI_ACK_ERR_STATUS, status); pr_debug("%s: status=%x\n", __func__, status); } } void msm_dsi_timeout_status(unsigned char *ctrl_base) { u32 status; status = MIPI_INP(ctrl_base + DSI_TIMEOUT_STATUS); if (status & 0x0111) { MIPI_OUTP(ctrl_base + DSI_TIMEOUT_STATUS, status); pr_debug("%s: status=%x\n", __func__, status); } } void msm_dsi_dln0_phy_err(unsigned char *ctrl_base) { u32 status; status = MIPI_INP(ctrl_base + DSI_DLN0_PHY_ERR); if (status & 0x011111) { MIPI_OUTP(ctrl_base + DSI_DLN0_PHY_ERR, status); pr_debug("%s: status=%x\n", __func__, status); } } void msm_dsi_fifo_status(unsigned char *ctrl_base) { u32 status; status = MIPI_INP(ctrl_base + DSI_FIFO_STATUS); if (status & 0x44444489) { MIPI_OUTP(ctrl_base + DSI_FIFO_STATUS, status); pr_debug("%s: status=%x\n", __func__, status); } } void msm_dsi_status(unsigned char *ctrl_base) { u32 status; status = MIPI_INP(ctrl_base + DSI_STATUS); if (status & 0x80000000) { MIPI_OUTP(ctrl_base + DSI_STATUS, status); pr_debug("%s: status=%x\n", __func__, status); } } void msm_dsi_error(unsigned char *ctrl_base) { msm_dsi_ack_err_status(ctrl_base); msm_dsi_timeout_status(ctrl_base); msm_dsi_fifo_status(ctrl_base); msm_dsi_status(ctrl_base); msm_dsi_dln0_phy_err(ctrl_base); } void msm_dsi_enable_irq(void) { unsigned long flags; spin_lock_irqsave(&dsi_host_private->irq_lock, flags); dsi_host_private->irq_enabled++; if (dsi_host_private->irq_enabled == 1) enable_irq(dsi_host_private->irq_no); spin_unlock_irqrestore(&dsi_host_private->irq_lock, flags); } void msm_dsi_disable_irq(void) { unsigned long flags; spin_lock_irqsave(&dsi_host_private->irq_lock, flags); dsi_host_private->irq_enabled--; if (dsi_host_private->irq_enabled == 0) disable_irq(dsi_host_private->irq_no); spin_unlock_irqrestore(&dsi_host_private->irq_lock, flags); } void msm_dsi_disable_irq_nosync(void) { spin_lock(&dsi_host_private->irq_lock); dsi_host_private->irq_enabled--; if (dsi_host_private->irq_enabled == 0) disable_irq_nosync(dsi_host_private->irq_no); spin_unlock(&dsi_host_private->irq_lock); } irqreturn_t msm_dsi_isr(int irq, void *ptr) { u32 isr; isr = MIPI_INP(dsi_host_private->dsi_base + DSI_INT_CTRL); MIPI_OUTP(dsi_host_private->dsi_base + DSI_INT_CTRL, isr); if (isr & DSI_INTR_ERROR) msm_dsi_error(dsi_host_private->dsi_base); if (isr & DSI_INTR_CMD_DMA_DONE) complete(&dsi_host_private->dma_comp); return IRQ_HANDLED; } int msm_dsi_irq_init(struct device *dev, int irq_no) { int ret; ret = devm_request_irq(dev, irq_no, msm_dsi_isr, IRQF_DISABLED, "DSI", NULL); if (ret) { pr_err("msm_dsi_irq_init request_irq() failed!\n"); return ret; } dsi_host_private->irq_no = irq_no; disable_irq(irq_no); return 0; } void msm_dsi_host_init(struct mipi_panel_info *pinfo) { u32 dsi_ctrl, intr_ctrl, data; unsigned char *ctrl_base = dsi_host_private->dsi_base; pr_debug("msm_dsi_host_init\n"); pinfo->rgb_swap = DSI_RGB_SWAP_RGB; if (pinfo->mode == DSI_VIDEO_MODE) { data = 0; if (pinfo->pulse_mode_hsa_he) data |= BIT(28); if (pinfo->hfp_power_stop) data |= BIT(24); if (pinfo->hbp_power_stop) data |= BIT(20); if (pinfo->hsa_power_stop) data |= BIT(16); if (pinfo->eof_bllp_power_stop) data |= BIT(15); if (pinfo->bllp_power_stop) data |= BIT(12); data |= ((pinfo->traffic_mode & 0x03) << 8); data |= ((pinfo->dst_format & 0x03) << 4); /* 2 bits */ data |= (pinfo->vc & 0x03); MIPI_OUTP(ctrl_base + DSI_VIDEO_MODE_CTRL, data); data = 0; data |= ((pinfo->rgb_swap & 0x07) << 12); if (pinfo->b_sel) data |= BIT(8); if (pinfo->g_sel) data |= BIT(4); if (pinfo->r_sel) data |= BIT(0); MIPI_OUTP(ctrl_base + DSI_VIDEO_MODE_DATA_CTRL, data); } else if (pinfo->mode == DSI_CMD_MODE) { data = 0; data |= ((pinfo->interleave_max & 0x0f) << 20); data |= ((pinfo->rgb_swap & 0x07) << 16); if (pinfo->b_sel) data |= BIT(12); if (pinfo->g_sel) data |= BIT(8); if (pinfo->r_sel) data |= BIT(4); data |= (pinfo->dst_format & 0x0f); /* 4 bits */ MIPI_OUTP(ctrl_base + DSI_COMMAND_MODE_MDP_CTRL, data); /* DSI_COMMAND_MODE_MDP_DCS_CMD_CTRL */ data = pinfo->wr_mem_continue & 0x0ff; data <<= 8; data |= (pinfo->wr_mem_start & 0x0ff); if (pinfo->insert_dcs_cmd) data |= BIT(16); MIPI_OUTP(ctrl_base + DSI_COMMAND_MODE_MDP_DCS_CMD_CTRL, data); } else pr_err("%s: Unknown DSI mode=%d\n", __func__, pinfo->mode); dsi_ctrl = BIT(8) | BIT(2); /* clock enable & cmd mode */ intr_ctrl = 0; intr_ctrl = (DSI_INTR_CMD_DMA_DONE_MASK | DSI_INTR_CMD_MDP_DONE_MASK); if (pinfo->crc_check) dsi_ctrl |= BIT(24); if (pinfo->ecc_check) dsi_ctrl |= BIT(20); if (pinfo->data_lane3) dsi_ctrl |= BIT(7); if (pinfo->data_lane2) dsi_ctrl |= BIT(6); if (pinfo->data_lane1) dsi_ctrl |= BIT(5); if (pinfo->data_lane0) dsi_ctrl |= BIT(4); /* from frame buffer, low power mode */ /* DSI_COMMAND_MODE_DMA_CTRL */ MIPI_OUTP(ctrl_base + DSI_COMMAND_MODE_DMA_CTRL, 0x14000000); data = 0; if (pinfo->te_sel) data |= BIT(31); data |= pinfo->mdp_trigger << 4;/* cmd mdp trigger */ data |= pinfo->dma_trigger; /* cmd dma trigger */ data |= (pinfo->stream & 0x01) << 8; MIPI_OUTP(ctrl_base + DSI_TRIG_CTRL, data); /* DSI_LAN_SWAP_CTRL */ MIPI_OUTP(ctrl_base + DSI_LANE_SWAP_CTRL, pinfo->dlane_swap); /* clock out ctrl */ data = pinfo->t_clk_post & 0x3f; /* 6 bits */ data <<= 8; data |= pinfo->t_clk_pre & 0x3f; /* 6 bits */ /* DSI_CLKOUT_TIMING_CTRL */ MIPI_OUTP(ctrl_base + DSI_CLKOUT_TIMING_CTRL, data); data = 0; if (pinfo->rx_eot_ignore) data |= BIT(4); if (pinfo->tx_eot_append) data |= BIT(0); MIPI_OUTP(ctrl_base + DSI_EOT_PACKET_CTRL, data); /* allow only ack-err-status to generate interrupt */ /* DSI_ERR_INT_MASK0 */ MIPI_OUTP(ctrl_base + DSI_ERR_INT_MASK0, 0x13ff3fe0); intr_ctrl |= DSI_INTR_ERROR_MASK; MIPI_OUTP(ctrl_base + DSI_INT_CTRL, intr_ctrl); /* turn esc, byte, dsi, pclk, sclk, hclk on */ MIPI_OUTP(ctrl_base + DSI_CLK_CTRL, 0x23f); dsi_ctrl |= BIT(0); /* enable dsi */ MIPI_OUTP(ctrl_base + DSI_CTRL, dsi_ctrl); wmb(); } void msm_dsi_set_tx_power_mode(int mode) { u32 data; unsigned char *ctrl_base = dsi_host_private->dsi_base; data = MIPI_INP(ctrl_base + DSI_COMMAND_MODE_DMA_CTRL); if (mode == 0) data &= ~BIT(26); else data |= BIT(26); MIPI_OUTP(ctrl_base + DSI_COMMAND_MODE_DMA_CTRL, data); } void msm_dsi_sw_reset(void) { u32 dsi_ctrl; unsigned char *ctrl_base = dsi_host_private->dsi_base; pr_debug("msm_dsi_sw_reset\n"); dsi_ctrl = MIPI_INP(ctrl_base + DSI_CTRL); dsi_ctrl &= ~0x01; MIPI_OUTP(ctrl_base + DSI_CTRL, dsi_ctrl); wmb(); /* turn esc, byte, dsi, pclk, sclk, hclk on */ MIPI_OUTP(ctrl_base + DSI_CLK_CTRL, 0x23f); wmb(); MIPI_OUTP(ctrl_base + DSI_SOFT_RESET, 0x01); wmb(); MIPI_OUTP(ctrl_base + DSI_SOFT_RESET, 0x00); wmb(); } void msm_dsi_controller_cfg(int enable) { u32 dsi_ctrl, status; unsigned char *ctrl_base = dsi_host_private->dsi_base; pr_debug("msm_dsi_controller_cfg\n"); /* Check for CMD_MODE_DMA_BUSY */ if (readl_poll_timeout((ctrl_base + DSI_STATUS), status, ((status & 0x02) == 0), DSI_POLL_SLEEP_US, DSI_POLL_TIMEOUT_US)) pr_err("%s: DSI status=%x failed\n", __func__, status); /* Check for x_HS_FIFO_EMPTY */ if (readl_poll_timeout((ctrl_base + DSI_FIFO_STATUS), status, ((status & 0x11111000) == 0x11111000), DSI_POLL_SLEEP_US, DSI_POLL_TIMEOUT_US)) pr_err("%s: FIFO status=%x failed\n", __func__, status); /* Check for VIDEO_MODE_ENGINE_BUSY */ if (readl_poll_timeout((ctrl_base + DSI_STATUS), status, ((status & 0x08) == 0), DSI_POLL_SLEEP_US, DSI_POLL_TIMEOUT_US)) { pr_err("%s: DSI status=%x\n", __func__, status); pr_err("%s: Doing sw reset\n", __func__); msm_dsi_sw_reset(); } dsi_ctrl = MIPI_INP(ctrl_base + DSI_CTRL); if (enable) dsi_ctrl |= 0x01; else dsi_ctrl &= ~0x01; MIPI_OUTP(ctrl_base + DSI_CTRL, dsi_ctrl); wmb(); } void msm_dsi_op_mode_config(int mode, struct mdss_panel_data *pdata) { u32 dsi_ctrl, intr_ctrl; unsigned char *ctrl_base = dsi_host_private->dsi_base; pr_debug("msm_dsi_op_mode_config\n"); dsi_ctrl = MIPI_INP(ctrl_base + DSI_CTRL); /*If Video enabled, Keep Video and Cmd mode ON */ dsi_ctrl &= ~0x06; if (mode == DSI_VIDEO_MODE) { dsi_ctrl |= 0x02; intr_ctrl = DSI_INTR_CMD_DMA_DONE_MASK; } else { /* command mode */ dsi_ctrl |= 0x04; intr_ctrl = DSI_INTR_CMD_DMA_DONE_MASK | DSI_INTR_ERROR_MASK | DSI_INTR_CMD_MDP_DONE_MASK; } pr_debug("%s: dsi_ctrl=%x intr=%x\n", __func__, dsi_ctrl, intr_ctrl); MIPI_OUTP(ctrl_base + DSI_INT_CTRL, intr_ctrl); MIPI_OUTP(ctrl_base + DSI_CTRL, dsi_ctrl); wmb(); } int msm_dsi_cmd_reg_tx(u32 data) { unsigned char *ctrl_base = dsi_host_private->dsi_base; MIPI_OUTP(ctrl_base + DSI_TRIG_CTRL, 0x04);/* sw trigger */ MIPI_OUTP(ctrl_base + DSI_CTRL, 0x135); wmb(); MIPI_OUTP(ctrl_base + DSI_COMMAND_MODE_DMA_CTRL, data); wmb(); MIPI_OUTP(ctrl_base + DSI_CMD_MODE_DMA_SW_TRIGGER, 0x01); wmb(); udelay(300); /*per spec*/ return 0; } int msm_dsi_cmd_dma_tx(struct dsi_buf *tp) { int len, rc; unsigned long size, addr; unsigned char *ctrl_base = dsi_host_private->dsi_base; len = ALIGN(tp->len, 4); size = ALIGN(tp->len, SZ_4K); tp->dmap = dma_map_single(&dsi_host_private->dis_dev, tp->data, size, DMA_TO_DEVICE); if (dma_mapping_error(&dsi_host_private->dis_dev, tp->dmap)) { pr_err("%s: dmap mapp failed\n", __func__); return -ENOMEM; } addr = tp->dmap; INIT_COMPLETION(dsi_host_private->dma_comp); MIPI_OUTP(ctrl_base + DSI_DMA_CMD_OFFSET, addr); MIPI_OUTP(ctrl_base + DSI_DMA_CMD_LENGTH, len); wmb(); MIPI_OUTP(ctrl_base + DSI_CMD_MODE_DMA_SW_TRIGGER, 0x01); wmb(); rc = wait_for_completion_timeout(&dsi_host_private->dma_comp, msecs_to_jiffies(DSI_DMA_CMD_TIMEOUT_MS)); if (rc == 0) { pr_err("DSI command transaction time out\n"); rc = -ETIME; } dma_unmap_single(&dsi_host_private->dis_dev, tp->dmap, size, DMA_TO_DEVICE); tp->dmap = 0; return rc; } int msm_dsi_cmd_dma_rx(struct dsi_buf *rp, int rlen) { u32 *lp, data; int i, off, cnt; unsigned char *ctrl_base = dsi_host_private->dsi_base; lp = (u32 *)rp->data; cnt = rlen; cnt += 3; cnt >>= 2; if (cnt > 4) cnt = 4; /* 4 x 32 bits registers only */ off = DSI_RDBK_DATA0; off += ((cnt - 1) * 4); for (i = 0; i < cnt; i++) { data = (u32)MIPI_INP(ctrl_base + off); *lp++ = ntohl(data); /* to network byte order */ pr_debug("%s: data = 0x%x and ntohl(data) = 0x%x\n", __func__, data, ntohl(data)); off -= 4; rp->len += sizeof(*lp); } return 0; } int msm_dsi_cmds_tx(struct mdss_panel_data *pdata, struct dsi_buf *tp, struct dsi_cmd_desc *cmds, int cnt) { struct dsi_cmd_desc *cm; u32 dsi_ctrl, ctrl; int i, video_mode; unsigned char *ctrl_base = dsi_host_private->dsi_base; /* 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_base + DSI_CTRL); video_mode = dsi_ctrl & 0x02; /* VIDEO_MODE_EN */ if (video_mode) { ctrl = dsi_ctrl | 0x04; /* CMD_MODE_EN */ MIPI_OUTP(ctrl_base + DSI_CTRL, ctrl); } msm_dsi_enable_irq(); cm = cmds; for (i = 0; i < cnt; i++) { dsi_buf_init(tp); dsi_cmd_dma_add(tp, cm); msm_dsi_cmd_dma_tx(tp); if (cm->wait) msleep(cm->wait); cm++; } msm_dsi_disable_irq(); if (video_mode) MIPI_OUTP(ctrl_base + DSI_CTRL, dsi_ctrl); return 0; } /* MDSS_DSI_MRPS, Maximum Return Packet Size */ static char max_pktsize[2] = {0x00, 0x00}; /* LSB tx first, 10 bytes */ static struct dsi_cmd_desc pkt_size_cmd[] = { {DTYPE_MAX_PKTSIZE, 1, 0, 0, 0, sizeof(max_pktsize), max_pktsize} }; /* * DSI panel reply with MAX_RETURN_PACKET_SIZE bytes of data * plus DCS header, ECC and CRC for DCS long read response * mdss_dsi_controller only have 4x32 bits register ( 16 bytes) to * hold data per transaction. * MDSS_DSI_LEN equal to 8 * len should be either 4 or 8 * any return data more than MDSS_DSI_LEN need to be break down * to multiple transactions. * * ov_mutex need to be acquired before call this function. */ int msm_dsi_cmds_rx(struct mdss_panel_data *pdata, struct dsi_buf *tp, struct dsi_buf *rp, struct dsi_cmd_desc *cmds, int rlen) { int cnt, len, diff, pkt_size; char cmd; if (pdata->panel_info.mipi.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 > DSI_LEN) len = 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 */ } msm_dsi_enable_irq(); if (!pdata->panel_info.mipi.no_max_pkt_size) { /* packet size need to be set at every read */ pkt_size = len; max_pktsize[0] = pkt_size; dsi_buf_init(tp); dsi_cmd_dma_add(tp, pkt_size_cmd); msm_dsi_cmd_dma_tx(tp); pr_debug("%s: Max packet size sent\n", __func__); } dsi_buf_init(tp); dsi_cmd_dma_add(tp, cmds); /* transmit read comamnd to client */ msm_dsi_cmd_dma_tx(tp); /* * once cmd_dma_done interrupt received, * return data from client is ready and stored * at RDBK_DATA register already */ dsi_buf_init(rp); if (pdata->panel_info.mipi.no_max_pkt_size) { /* * expect rlen = n * 4 * short alignement for start addr */ rp->data += 2; } msm_dsi_cmd_dma_rx(rp, cnt); msm_dsi_disable_irq(); if (pdata->panel_info.mipi.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: dsi_short_read1_resp(rp); break; case DTYPE_GEN_READ2_RESP: case DTYPE_DCS_READ2_RESP: dsi_short_read2_resp(rp); break; case DTYPE_GEN_LREAD_RESP: case DTYPE_DCS_LREAD_RESP: 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; } static int msm_dsi_cal_clk_rate(struct mdss_panel_data *pdata, u32 *bitclk_rate, u32 *dsiclk_rate, u32 *byteclk_rate, u32 *pclk_rate) { struct mdss_panel_info *pinfo; struct mipi_panel_info *mipi; u32 hbp, hfp, vbp, vfp, hspw, vspw, width, height; int lanes; pinfo = &pdata->panel_info; mipi = &pdata->panel_info.mipi; hbp = pdata->panel_info.lcdc.h_back_porch; hfp = pdata->panel_info.lcdc.h_front_porch; vbp = pdata->panel_info.lcdc.v_back_porch; vfp = pdata->panel_info.lcdc.v_front_porch; hspw = pdata->panel_info.lcdc.h_pulse_width; vspw = pdata->panel_info.lcdc.v_pulse_width; width = pdata->panel_info.xres; height = pdata->panel_info.yres; lanes = 0; if (mipi->data_lane0) lanes++; if (mipi->data_lane1) lanes++; if (mipi->data_lane2) lanes++; if (mipi->data_lane3) lanes++; if (lanes == 0) return -EINVAL; *bitclk_rate = (width + hbp + hfp + hspw) * (height + vbp + vfp + vspw); *bitclk_rate *= mipi->frame_rate; *bitclk_rate *= pdata->panel_info.bpp; *bitclk_rate /= lanes; *byteclk_rate = *bitclk_rate / 8; *dsiclk_rate = *byteclk_rate * lanes; *pclk_rate = *byteclk_rate * lanes * 8 / pdata->panel_info.bpp; pr_debug("dsiclk_rate=%u, byteclk=%u, pck_=%u\n", *dsiclk_rate, *byteclk_rate, *pclk_rate); return 0; } static int msm_dsi_on(struct mdss_panel_data *pdata) { int ret = 0; u32 clk_rate; struct mdss_panel_info *pinfo; struct mipi_panel_info *mipi; u32 hbp, hfp, vbp, vfp, hspw, vspw, width, height; u32 ystride, bpp, data; u32 dummy_xres, dummy_yres; u32 bitclk_rate = 0, byteclk_rate = 0, pclk_rate = 0, dsiclk_rate = 0; unsigned char *ctrl_base = dsi_host_private->dsi_base; pr_debug("msm_dsi_on\n"); pinfo = &pdata->panel_info; ret = msm_dsi_regulator_enable(); if (ret) { pr_err("%s: DSI power on failed\n", __func__); return ret; } msm_dsi_ahb_ctrl(1); msm_dsi_phy_sw_reset(dsi_host_private->dsi_base); msm_dsi_phy_init(dsi_host_private->dsi_base, pdata); msm_dsi_cal_clk_rate(pdata, &bitclk_rate, &dsiclk_rate, &byteclk_rate, &pclk_rate); msm_dsi_clk_set_rate(DSI_ESC_CLK_RATE, dsiclk_rate, byteclk_rate, pclk_rate); msm_dsi_prepare_clocks(); msm_dsi_clk_enable(); clk_rate = pdata->panel_info.clk_rate; clk_rate = min(clk_rate, pdata->panel_info.clk_max); hbp = pdata->panel_info.lcdc.h_back_porch; hfp = pdata->panel_info.lcdc.h_front_porch; vbp = pdata->panel_info.lcdc.v_back_porch; vfp = pdata->panel_info.lcdc.v_front_porch; hspw = pdata->panel_info.lcdc.h_pulse_width; vspw = pdata->panel_info.lcdc.v_pulse_width; width = pdata->panel_info.xres; height = pdata->panel_info.yres; mipi = &pdata->panel_info.mipi; if (pdata->panel_info.type == MIPI_VIDEO_PANEL) { dummy_xres = pdata->panel_info.lcdc.xres_pad; dummy_yres = pdata->panel_info.lcdc.yres_pad; MIPI_OUTP(ctrl_base + DSI_VIDEO_MODE_ACTIVE_H, ((hspw + hbp + width + dummy_xres) << 16 | (hspw + hbp))); MIPI_OUTP(ctrl_base + DSI_VIDEO_MODE_ACTIVE_V, ((vspw + vbp + height + dummy_yres) << 16 | (vspw + vbp))); MIPI_OUTP(ctrl_base + DSI_VIDEO_MODE_TOTAL, (vspw + vbp + height + dummy_yres + vfp - 1) << 16 | (hspw + hbp + width + dummy_xres + hfp - 1)); MIPI_OUTP(ctrl_base + DSI_VIDEO_MODE_HSYNC, (hspw << 16)); MIPI_OUTP(ctrl_base + DSI_VIDEO_MODE_VSYNC, 0); MIPI_OUTP(ctrl_base + DSI_VIDEO_MODE_VSYNC_VPOS, (vspw << 16)); } else { /* command mode */ if (mipi->dst_format == DSI_CMD_DST_FORMAT_RGB888) bpp = 3; else if (mipi->dst_format == DSI_CMD_DST_FORMAT_RGB666) bpp = 3; else if (mipi->dst_format == DSI_CMD_DST_FORMAT_RGB565) bpp = 2; else bpp = 3; /* Default format set to RGB888 */ ystride = width * bpp + 1; data = (ystride << 16) | (mipi->vc << 8) | DTYPE_DCS_LWRITE; MIPI_OUTP(ctrl_base + DSI_COMMAND_MODE_MDP_STREAM0_CTRL, data); MIPI_OUTP(ctrl_base + DSI_COMMAND_MODE_MDP_STREAM1_CTRL, data); data = height << 16 | width; MIPI_OUTP(ctrl_base + DSI_COMMAND_MODE_MDP_STREAM1_TOTAL, data); MIPI_OUTP(ctrl_base + DSI_COMMAND_MODE_MDP_STREAM0_TOTAL, data); } msm_dsi_sw_reset(); msm_dsi_host_init(mipi); if (mipi->force_clk_lane_hs) { u32 tmp; tmp = MIPI_INP(ctrl_base + DSI_LANE_CTRL); tmp |= (1<<28); MIPI_OUTP(ctrl_base + DSI_LANE_CTRL, tmp); wmb(); } msm_dsi_op_mode_config(mipi->mode, pdata); return ret; } static int msm_dsi_off(struct mdss_panel_data *pdata) { int ret = 0; pr_debug("msm_dsi_off\n"); msm_dsi_controller_cfg(0); msm_dsi_clk_set_rate(DSI_ESC_CLK_RATE, 0, 0, 0); msm_dsi_clk_disable(); msm_dsi_unprepare_clocks(); msm_dsi_phy_off(dsi_host_private->dsi_base); msm_dsi_ahb_ctrl(0); ret = msm_dsi_regulator_disable(); if (ret) { pr_err("%s: Panel power off failed\n", __func__); return ret; } return ret; } static int __devinit msm_dsi_probe(struct platform_device *pdev) { struct dsi_interface intf; int rc = 0; pr_debug("%s\n", __func__); rc = msm_dsi_init(); if (rc) return rc; if (pdev->dev.of_node) { struct resource *mdss_dsi_mres; pdev->id = 0; mdss_dsi_mres = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (!mdss_dsi_mres) { pr_err("%s:%d unable to get the MDSS reg resources", __func__, __LINE__); return -ENOMEM; } else { dsi_host_private->dsi_base = ioremap( mdss_dsi_mres->start, resource_size(mdss_dsi_mres)); if (!dsi_host_private->dsi_base) { pr_err("%s:%d unable to remap dsi resources", __func__, __LINE__); return -ENOMEM; } } mdss_dsi_mres = platform_get_resource(pdev, IORESOURCE_IRQ, 0); if (!mdss_dsi_mres || mdss_dsi_mres->start == 0) { pr_err("%s:%d unable to get the MDSS irq resources", __func__, __LINE__); rc = -ENODEV; goto dsi_probe_error; } else { rc = msm_dsi_irq_init(&pdev->dev, mdss_dsi_mres->start); if (rc) { dev_err(&pdev->dev, "%s: failed to init irq, rc=%d\n", __func__, rc); goto dsi_probe_error; } } rc = msm_dsi_io_init(pdev); if (rc) { dev_err(&pdev->dev, "%s: failed to init DSI IO, rc=%d\n", __func__, rc); goto dsi_probe_error; } rc = of_platform_populate(pdev->dev.of_node, NULL, NULL, &pdev->dev); if (rc) { dev_err(&pdev->dev, "%s: failed to add child nodes, rc=%d\n", __func__, rc); goto dsi_probe_error; } } dsi_host_private->dis_dev = pdev->dev; intf.on = msm_dsi_on; intf.off = msm_dsi_off; intf.op_mode_config = msm_dsi_op_mode_config; intf.tx = msm_dsi_cmds_tx; intf.rx = msm_dsi_cmds_rx; intf.index = 0; intf.private = NULL; dsi_register_interface(&intf); pr_debug("%s success\n", __func__); return 0; dsi_probe_error: if (dsi_host_private->dsi_base) { iounmap(dsi_host_private->dsi_base); dsi_host_private->dsi_base = NULL; } msm_dsi_io_deinit(); msm_dsi_deinit(); return rc; } static int __devexit msm_dsi_remove(struct platform_device *pdev) { msm_dsi_disable_irq(); msm_dsi_io_deinit(); iounmap(dsi_host_private->dsi_base); dsi_host_private->dsi_base = NULL; msm_dsi_deinit(); return 0; } static const struct of_device_id msm_dsi_v2_dt_match[] = { {.compatible = "qcom,msm-dsi-v2"}, {} }; MODULE_DEVICE_TABLE(of, msm_dsi_v2_dt_match); static struct platform_driver msm_dsi_v2_driver = { .probe = msm_dsi_probe, .remove = __devexit_p(msm_dsi_remove), .shutdown = NULL, .driver = { .name = "msm_dsi_v2", .of_match_table = msm_dsi_v2_dt_match, }, }; static int msm_dsi_v2_register_driver(void) { return platform_driver_register(&msm_dsi_v2_driver); } static int __init msm_dsi_v2_driver_init(void) { int ret; ret = msm_dsi_v2_register_driver(); if (ret) { pr_err("msm_dsi_v2_register_driver() failed!\n"); return ret; } return ret; } module_init(msm_dsi_v2_driver_init); static void __exit msm_dsi_v2_driver_cleanup(void) { platform_driver_unregister(&msm_dsi_v2_driver); } module_exit(msm_dsi_v2_driver_cleanup);