void mdss_dsi_phy_disable(struct mdss_dsi_ctrl_pdata *ctrl)
{
	struct mdss_dsi_ctrl_pdata *other_ctrl;
	if (ctrl == NULL) {
		pr_err("%s: Invalid input data\n", __func__);
		return;
	}

	ctrl->shared_ctrl_data->phy_disable_refcount++;

	/*
	 * In dual-dsi configuration, the phy should be disabled for the
	 * first controller only when the second controller is disabled.
	 * This is true regardless of whether broadcast mode is enabled.
	 */
	if (!mdss_dsi_split_display_enabled() ||
			ctrl->shared_ctrl_data->phy_disable_refcount == 2) {

		other_ctrl = mdss_dsi_get_other_ctrl(ctrl);
		if (other_ctrl)
			MIPI_OUTP(other_ctrl->phy_io.base +
				MDSS_DSI_DSIPHY_CTRL_0, 0x000);

		MIPI_OUTP(ctrl->phy_io.base + MDSS_DSI_DSIPHY_CTRL_0, 0x000);

		mdss_dsi_phy_regulator_disable(ctrl);

		/*
		* Wait for the registers writes to complete in order to
		* ensure that the phy is completely disabled
		*/
		wmb();
		ctrl->shared_ctrl_data->phy_disable_refcount = 0;
	}
}
Exemple #2
0
/*
 * 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)
{
    int ret = 0;
    struct mdss_dsi_ctrl_pdata *mctrl = NULL;

    /*
     * 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.
     */

    if (mdss_dsi_sync_wait_enable(ctrl)) {
        if (mdss_dsi_sync_wait_trigger(ctrl)) {
            mctrl = mdss_dsi_get_other_ctrl(ctrl);
            if (!mctrl) {
                pr_warn("%s: sync_wait, NULL at other control\n",
                        __func__);
                goto do_send;
            }

            mctrl->cmd_cfg_restore =
                __mdss_dsi_cmd_mode_config(mctrl, 1);
        } else if (!ctrl->do_unicast) {
            /* broadcast cmds, let cmd_trigger do it */
            return 0;

        }
    }

    pr_debug("%s: ctrl=%d do_unicast=%d\n", __func__,
             ctrl->ndx, ctrl->do_unicast);

do_send:
    ctrl->cmd_cfg_restore = __mdss_dsi_cmd_mode_config(ctrl, 1);

    ret = mdss_dsi_cmds2buf_tx(ctrl, cmds, cnt);
    if (IS_ERR_VALUE(ret)) {
        pr_err("%s: failed to call\n", __func__);
        cnt = -EINVAL;
    }

    if (!ctrl->do_unicast) {
        if (mctrl && mctrl->cmd_cfg_restore) {
            __mdss_dsi_cmd_mode_config(mctrl, 0);
            mctrl->cmd_cfg_restore = false;
        }

        if (ctrl->cmd_cfg_restore) {
            __mdss_dsi_cmd_mode_config(ctrl, 0);
            ctrl->cmd_cfg_restore = false;
        }
    }

    return cnt;
}
int mdss_dsi_clk_ctrl(struct mdss_dsi_ctrl_pdata *ctrl,
	u8 clk_type, int enable)
{
	int rc = 0;
	int link_changed = 0, bus_changed = 0;
	int m_link_changed = 0, m_bus_changed = 0;
	struct mdss_dsi_ctrl_pdata *mctrl = NULL;

	if (!ctrl) {
		pr_err("%s: Invalid arg\n", __func__);
		return -EINVAL;
	}

	/*
	 * In sync_wait_broadcast mode, we need to enable clocks
	 * for the other controller as well when enabling clocks
	 * for the trigger controller.
	 *
	 * If sync wait_broadcase mode is not enabled, but if split display
	 * mode is enabled where both DSI controller's branch clocks are
	 * sourced out of a single PLL, then we need to ensure that the
	 * controller associated with that PLL also has it's clocks turned
	 * on. This is required to make sure that if that controller's PLL/PHY
	 * are clamped then they can be removed.
	 */
	if (mdss_dsi_sync_wait_trigger(ctrl)) {
		mctrl = mdss_dsi_get_other_ctrl(ctrl);
		if (!mctrl)
			pr_warn("%s: Unable to get other control\n", __func__);
	} else if (mdss_dsi_is_ctrl_clk_slave(ctrl)) {
		mctrl = mdss_dsi_get_ctrl_clk_master();
		if (!mctrl)
			pr_warn("%s: Unable to get clk master control\n",
				__func__);
	}

	pr_debug("%s++: ndx=%d clk_type=%d bus_clk_cnt=%d link_clk_cnt=%d\n",
		__func__, ctrl->ndx, clk_type, ctrl->bus_clk_cnt,
		ctrl->link_clk_cnt);
	pr_debug("%s++: mctrl=%s m_bus_clk_cnt=%d m_link_clk_cnt=%d, enable=%d\n",
		__func__, mctrl ? "yes" : "no", mctrl ? mctrl->bus_clk_cnt : -1,
		mctrl ? mctrl->link_clk_cnt : -1, enable);

	mutex_lock(&dsi_clk_lock);

	if (clk_type & DSI_BUS_CLKS) {
		bus_changed = __mdss_dsi_update_clk_cnt(&ctrl->bus_clk_cnt,
			enable);
		if (bus_changed && mctrl)
			m_bus_changed = __mdss_dsi_update_clk_cnt(
				&mctrl->bus_clk_cnt, enable);
	}

	if (clk_type & DSI_LINK_CLKS) {
		link_changed = __mdss_dsi_update_clk_cnt(&ctrl->link_clk_cnt,
			enable);
		if (link_changed && mctrl)
			m_link_changed = __mdss_dsi_update_clk_cnt(
				&mctrl->link_clk_cnt, enable);
	}

	if (!link_changed && !bus_changed)
		goto no_error; /* clk cnts updated, nothing else needed */

	/*
	 * If updating link clock, need to make sure that the bus
	 * clocks are enabled
	 */
	if (link_changed && (!bus_changed && !ctrl->bus_clk_cnt)) {
		pr_err("%s: Trying to enable link clks w/o enabling bus clks for ctrl%d",
			__func__, ctrl->ndx);
		goto error_mctrl_bus_start;
	}

	if (m_link_changed && (!m_bus_changed && !mctrl->bus_clk_cnt)) {
		pr_err("%s: Trying to enable link clks w/o enabling bus clks for ctrl%d",
			__func__, ctrl->ndx);
		goto error_mctrl_bus_start;
	}

	if (enable && m_bus_changed) {
		rc = mdss_dsi_clk_ctrl_sub(mctrl, DSI_BUS_CLKS, 1);
		if (rc) {
			pr_err("Failed to start mctrl bus clocks rc=%d\n", rc);
			goto error_mctrl_bus_start;
		}
	}
	if (enable && bus_changed) {
		rc = mdss_dsi_clk_ctrl_sub(ctrl, DSI_BUS_CLKS, 1);
		if (rc) {
			pr_err("Failed to start ctrl bus clocks rc=%d\n", rc);
			goto error_ctrl_bus_start;
		}
	}

	if (m_link_changed) {
		rc = mdss_dsi_clk_ctrl_sub(mctrl, DSI_LINK_CLKS, enable);
		if (rc) {
			pr_err("Failed to %s mctrl clocks. rc=%d\n",
			(enable ? "start" : "stop"), rc);
			goto error_mctrl_link_change;
		}
	}
	if (link_changed) {
		rc = mdss_dsi_clk_ctrl_sub(ctrl, DSI_LINK_CLKS, enable);
		if (rc) {
			pr_err("Failed to %s ctrl clocks. rc=%d\n",
			(enable ? "start" : "stop"), rc);
			goto error_ctrl_link_change;
		}
	}

	if (!enable && m_bus_changed) {
		rc = mdss_dsi_clk_ctrl_sub(mctrl, DSI_BUS_CLKS, 0);
		if (rc) {
			pr_err("Failed to stop mctrl bus clocks rc=%d\n", rc);
			goto error_mctrl_bus_stop;
		}
	}
	if (!enable && bus_changed) {
		rc = mdss_dsi_clk_ctrl_sub(ctrl, DSI_BUS_CLKS, 0);
		if (rc) {
			pr_err("Failed to stop ctrl bus clocks\n rc=%d", rc);
			goto error_ctrl_bus_stop;
		}
	}

	goto no_error;

error_ctrl_bus_stop:
	if (m_bus_changed)
		mdss_dsi_clk_ctrl_sub(mctrl, DSI_BUS_CLKS, 1);
error_mctrl_bus_stop:
	if (link_changed)
		mdss_dsi_clk_ctrl_sub(ctrl, DSI_LINK_CLKS, enable ? 0 : 1);
error_ctrl_link_change:
	if (m_link_changed)
		mdss_dsi_clk_ctrl_sub(mctrl, DSI_LINK_CLKS, enable ? 0 : 1);
error_mctrl_link_change:
	if (bus_changed && enable)
		mdss_dsi_clk_ctrl_sub(ctrl, DSI_BUS_CLKS, 0);
error_ctrl_bus_start:
	if (m_bus_changed && enable)
		mdss_dsi_clk_ctrl_sub(mctrl, DSI_BUS_CLKS, 0);
error_mctrl_bus_start:
	if (clk_type & DSI_BUS_CLKS) {
		if (mctrl)
			__mdss_dsi_update_clk_cnt(&mctrl->bus_clk_cnt,
				enable ? 0 : 1);
		__mdss_dsi_update_clk_cnt(&ctrl->bus_clk_cnt, enable ? 0 : 1);
	}
	if (clk_type & DSI_LINK_CLKS) {
		if (mctrl)
			__mdss_dsi_update_clk_cnt(&mctrl->link_clk_cnt,
				enable ? 0 : 1);
		__mdss_dsi_update_clk_cnt(&ctrl->link_clk_cnt, enable ? 0 : 1);
	}

no_error:
	mutex_unlock(&dsi_clk_lock);
	pr_debug("%s--: ndx=%d clk_type=%d bus_clk_cnt=%d link_clk_cnt=%d changed=%d\n",
		__func__, ctrl->ndx, clk_type, ctrl->bus_clk_cnt,
		ctrl->link_clk_cnt, link_changed && bus_changed);
	pr_debug("%s--: mctrl=%s m_bus_clk_cnt=%d m_link_clk_cnt=%d, m_changed=%d, enable=%d\n",
		__func__, mctrl ? "yes" : "no", mctrl ? mctrl->bus_clk_cnt : -1,
		mctrl ? mctrl->link_clk_cnt : -1,
		m_link_changed && m_bus_changed, enable);

	return rc;
}
Exemple #4
0
/*
 * 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;
    struct mdss_dsi_ctrl_pdata *mctrl = NULL;


    /*
     * 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.
     */
    if (mdss_dsi_sync_wait_enable(ctrl)) {
        if (mdss_dsi_sync_wait_trigger(ctrl)) {
            mctrl = mdss_dsi_get_other_ctrl(ctrl);
            if (!mctrl) {
                pr_warn("%s: sync_wait, NULL at other control\n",
                        __func__);
                goto do_send;
            }

            mctrl->cmd_cfg_restore =
                __mdss_dsi_cmd_mode_config(mctrl, 1);
        } else {
            /* skip cmds, let cmd_trigger do it */
            return 0;

        }
    }

do_send:
    ctrl->cmd_cfg_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 && mctrl->cmd_cfg_restore) {
        __mdss_dsi_cmd_mode_config(mctrl, 0);
        mctrl->cmd_cfg_restore = false;
    }

    if (ctrl->cmd_cfg_restore) {
        __mdss_dsi_cmd_mode_config(ctrl, 0);
        ctrl->cmd_cfg_restore = false;
    }

    return rp->len;
}
Exemple #5
0
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;
    struct mdss_dsi_ctrl_pdata *mctrl = NULL;

    bp = tp->data;

    len = ALIGN(tp->len, 4);
    ctrl->dma_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,
                                              ctrl->dma_size, SZ_4K, 0, &(ctrl->dma_addr));
        if (IS_ERR_VALUE(ret)) {
            pr_err("unable to map dma memory to iommu(%d)\n", ret);
            return -ENOMEM;
        }
    } else {
        ctrl->dma_addr = tp->dmap;
    }

    INIT_COMPLETION(ctrl->dma_comp);

    if (mdss_dsi_sync_wait_trigger(ctrl)) {
        /* broadcast same cmd to other panel */
        mctrl = mdss_dsi_get_other_ctrl(ctrl);
        if (mctrl && mctrl->dma_addr == 0) {
            MIPI_OUTP(mctrl->ctrl_base + 0x048, ctrl->dma_addr);
            MIPI_OUTP(mctrl->ctrl_base + 0x04c, len);
            MIPI_OUTP(mctrl->ctrl_base + 0x090, 0x01); /* trigger */
        }
    }

    /* send cmd to its panel */
    MIPI_OUTP((ctrl->ctrl_base) + 0x048, ctrl->dma_addr);
    MIPI_OUTP((ctrl->ctrl_base) + 0x04c, len);
    wmb();

    MIPI_OUTP((ctrl->ctrl_base) + 0x090, 0x01);
    wmb();

    if (ctrl->do_unicast) {
        /* let cmd_trigger to kickoff later */
        pr_debug("%s: SKIP, ndx=%d do_unicast=%d\n", __func__,
                 ctrl->ndx, ctrl->do_unicast);
        ret = tp->len;
        goto end;
    }

    ret = wait_for_completion_timeout(&ctrl->dma_comp,
                                      msecs_to_jiffies(DMA_TX_TIMEOUT));
    if (ret == 0)
        ret = -ETIMEDOUT;
    else
        ret = tp->len;

    if (mctrl && mctrl->dma_addr) {
        if (is_mdss_iommu_attached()) {
            msm_iommu_unmap_contig_buffer(mctrl->dma_addr,
                                          mdss_get_iommu_domain(domain), 0, mctrl->dma_size);
        }
        mctrl->dma_addr = 0;
        mctrl->dma_size = 0;
    }

    if (is_mdss_iommu_attached()) {
        msm_iommu_unmap_contig_buffer(ctrl->dma_addr,
                                      mdss_get_iommu_domain(domain), 0, ctrl->dma_size);
    }

    ctrl->dma_addr = 0;
    ctrl->dma_size = 0;
end:
    return ret;
}