static int edp_ctrl_training(struct edp_ctrl *ctrl) { int ret; /* Do link training only when power is on */ if (!ctrl->power_on) return -EINVAL; train_start: ret = edp_do_link_train(ctrl); if (ret == EDP_TRAIN_RECONFIG) { /* Re-configure main link */ edp_ctrl_irq_enable(ctrl, 0); edp_ctrl_link_enable(ctrl, 0); msm_edp_phy_ctrl(ctrl->phy, 0); /* Make sure link is fully disabled */ wmb(); usleep_range(500, 1000); msm_edp_phy_ctrl(ctrl->phy, 1); edp_ctrl_link_enable(ctrl, 1); edp_ctrl_irq_enable(ctrl, 1); goto train_start; } return ret; }
bool msm_edp_ctrl_panel_connected(struct edp_ctrl *ctrl) { mutex_lock(&ctrl->dev_mutex); DBG("connect status = %d", ctrl->edp_connected); if (ctrl->edp_connected) { mutex_unlock(&ctrl->dev_mutex); return true; } if (!ctrl->power_on) { edp_ctrl_phy_aux_enable(ctrl, 1); edp_ctrl_irq_enable(ctrl, 1); } if (drm_dp_dpcd_read(ctrl->drm_aux, DP_DPCD_REV, ctrl->dpcd, DP_RECEIVER_CAP_SIZE) < DP_RECEIVER_CAP_SIZE) { pr_err("%s: AUX channel is NOT ready\n", __func__); memset(ctrl->dpcd, 0, DP_RECEIVER_CAP_SIZE); } else { ctrl->edp_connected = true; } if (!ctrl->power_on) { edp_ctrl_irq_enable(ctrl, 0); edp_ctrl_phy_aux_enable(ctrl, 0); } DBG("exit: connect status=%d", ctrl->edp_connected); mutex_unlock(&ctrl->dev_mutex); return ctrl->edp_connected; }
int msm_edp_ctrl_get_panel_info(struct edp_ctrl *ctrl, struct drm_connector *connector, struct edid **edid) { int ret = 0; mutex_lock(&ctrl->dev_mutex); if (ctrl->edid) { if (edid) { DBG("Just return edid buffer"); *edid = ctrl->edid; } goto unlock_ret; } if (!ctrl->power_on) { edp_ctrl_phy_aux_enable(ctrl, 1); edp_ctrl_irq_enable(ctrl, 1); } ret = drm_dp_link_probe(ctrl->drm_aux, &ctrl->dp_link); if (ret) { pr_err("%s: read dpcd cap failed, %d\n", __func__, ret); goto disable_ret; } /* Initialize link rate as panel max link rate */ ctrl->link_rate = drm_dp_link_rate_to_bw_code(ctrl->dp_link.rate); ctrl->edid = drm_get_edid(connector, &ctrl->drm_aux->ddc); if (!ctrl->edid) { pr_err("%s: edid read fail\n", __func__); goto disable_ret; } if (edid) *edid = ctrl->edid; disable_ret: if (!ctrl->power_on) { edp_ctrl_irq_enable(ctrl, 0); edp_ctrl_phy_aux_enable(ctrl, 0); } unlock_ret: mutex_unlock(&ctrl->dev_mutex); return ret; }
static void edp_ctrl_on_worker(struct work_struct *work) { struct edp_ctrl *ctrl = container_of( work, struct edp_ctrl, on_work); int ret; mutex_lock(&ctrl->dev_mutex); if (ctrl->power_on) { DBG("already on"); goto unlock_ret; } edp_ctrl_phy_aux_enable(ctrl, 1); edp_ctrl_link_enable(ctrl, 1); edp_ctrl_irq_enable(ctrl, 1); ret = drm_dp_link_power_up(ctrl->drm_aux, &ctrl->dp_link); if (ret) goto fail; ctrl->power_on = true; /* Start link training */ ret = edp_ctrl_training(ctrl); if (ret != EDP_TRAIN_SUCCESS) goto fail; DBG("DONE"); goto unlock_ret; fail: edp_ctrl_irq_enable(ctrl, 0); edp_ctrl_link_enable(ctrl, 0); edp_ctrl_phy_aux_enable(ctrl, 0); ctrl->power_on = false; unlock_ret: mutex_unlock(&ctrl->dev_mutex); }
static void edp_ctrl_off_worker(struct work_struct *work) { struct edp_ctrl *ctrl = container_of( work, struct edp_ctrl, off_work); int ret; mutex_lock(&ctrl->dev_mutex); if (!ctrl->power_on) { DBG("already off"); goto unlock_ret; } reinit_completion(&ctrl->idle_comp); edp_state_ctrl(ctrl, EDP_STATE_CTRL_PUSH_IDLE); ret = wait_for_completion_timeout(&ctrl->idle_comp, msecs_to_jiffies(500)); if (ret <= 0) DBG("%s: idle pattern timedout, %d\n", __func__, ret); edp_state_ctrl(ctrl, 0); drm_dp_link_power_down(ctrl->drm_aux, &ctrl->dp_link); edp_ctrl_irq_enable(ctrl, 0); edp_ctrl_link_enable(ctrl, 0); edp_ctrl_phy_aux_enable(ctrl, 0); ctrl->power_on = false; unlock_ret: mutex_unlock(&ctrl->dev_mutex); }