static ssize_t analogix_dpaux_transfer(struct drm_dp_aux *aux, struct drm_dp_aux_msg *msg) { struct analogix_dp_device *dp = to_dp(aux); return analogix_dp_transfer(dp, msg); }
static void rockchip_dp_drm_encoder_enable(struct drm_encoder *encoder) { struct rockchip_dp_device *dp = to_dp(encoder); int ret; u32 val; ret = drm_of_encoder_active_endpoint_id(dp->dev->of_node, encoder); if (ret < 0) return; if (ret) val = dp->data->lcdsel_lit; else val = dp->data->lcdsel_big; dev_dbg(dp->dev, "vop %s output to dp\n", (ret) ? "LIT" : "BIG"); ret = clk_prepare_enable(dp->grfclk); if (ret < 0) { dev_err(dp->dev, "failed to enable grfclk %d\n", ret); return; } ret = regmap_write(dp->grf, dp->data->lcdsel_grf_reg, val); if (ret != 0) dev_err(dp->dev, "Could not write to GRF: %d\n", ret); clk_disable_unprepare(dp->grfclk); }
static int rockchip_dp_drm_encoder_atomic_check(struct drm_encoder *encoder, struct drm_crtc_state *crtc_state, struct drm_connector_state *conn_state) { struct rockchip_crtc_state *s = to_rockchip_crtc_state(crtc_state); struct rockchip_dp_device *dp = to_dp(encoder); int ret; /* * The hardware IC designed that VOP must output the RGB10 video * format to eDP controller, and if eDP panel only support RGB8, * then eDP controller should cut down the video data, not via VOP * controller, that's why we need to hardcode the VOP output mode * to RGA10 here. */ s->output_mode = ROCKCHIP_OUT_MODE_AAAA; s->output_type = DRM_MODE_CONNECTOR_eDP; if (dp->data->chip_type == RK3399_EDP) { /* * For RK3399, VOP Lit must code the out mode to RGB888, * VOP Big must code the out mode to RGB10. */ ret = drm_of_encoder_active_endpoint_id(dp->dev->of_node, encoder); if (ret > 0) s->output_mode = ROCKCHIP_OUT_MODE_P888; } return 0; }
static int exynos_dp_bridge_attach(struct analogix_dp_plat_data *plat_data, struct drm_bridge *bridge, struct drm_connector *connector) { struct exynos_dp_device *dp = to_dp(plat_data); struct drm_encoder *encoder = &dp->encoder; int ret; drm_connector_register(connector); dp->connector = connector; /* Pre-empt DP connector creation if there's a bridge */ if (dp->ptn_bridge) { bridge->next = dp->ptn_bridge; dp->ptn_bridge->encoder = encoder; ret = drm_bridge_attach(encoder->dev, dp->ptn_bridge); if (ret) { DRM_ERROR("Failed to attach bridge to drm\n"); bridge->next = NULL; return ret; } } return 0; }
static enum drm_connector_status analogix_dp_detect(struct drm_connector *connector, bool force) { struct analogix_dp_device *dp = to_dp(connector); enum drm_connector_status status = connector_status_disconnected; int ret; if (dp->plat_data->panel) return connector_status_connected; ret = analogix_dp_prepare_panel(dp, true, false); if (ret) { DRM_ERROR("Failed to prepare panel (%d)\n", ret); return connector_status_disconnected; } if (!analogix_dp_detect_hpd(dp)) status = connector_status_connected; ret = analogix_dp_prepare_panel(dp, false, false); if (ret) DRM_ERROR("Failed to unprepare panel (%d)\n", ret); return status; }
int analogix_dp_get_modes(struct drm_connector *connector) { struct analogix_dp_device *dp = to_dp(connector); struct edid *edid = (struct edid *)dp->edid; int ret, num_modes = 0; ret = analogix_dp_prepare_panel(dp, true, false); if (ret) { DRM_ERROR("Failed to prepare panel (%d)\n", ret); return 0; } if (analogix_dp_handle_edid(dp) == 0) { drm_mode_connector_update_edid_property(&dp->connector, edid); num_modes += drm_add_edid_modes(&dp->connector, edid); } if (dp->plat_data->panel) num_modes += drm_panel_get_modes(dp->plat_data->panel); if (dp->plat_data->get_modes) num_modes += dp->plat_data->get_modes(dp->plat_data, connector); ret = analogix_dp_prepare_panel(dp, false, false); if (ret) DRM_ERROR("Failed to unprepare panel (%d)\n", ret); return num_modes; }
static void xilinx_drm_dp_dpms(struct drm_encoder *encoder, int dpms) { struct xilinx_drm_dp *dp = to_dp(encoder); void __iomem *iomem = dp->iomem; if (dp->dpms == dpms) return; dp->dpms = dpms; switch (dpms) { case DRM_MODE_DPMS_ON: xilinx_drm_writel(dp->iomem, XILINX_DP_TX_SW_RESET, XILINX_DP_TX_SW_RESET_ALL); if (dp->aud_clk) xilinx_drm_writel(iomem, XILINX_DP_TX_AUDIO_CONTROL, 1); xilinx_drm_writel(iomem, XILINX_DP_TX_PHY_POWER_DOWN, 0); drm_dp_dpcd_writeb(&dp->aux, DP_SET_POWER, DP_SET_POWER_D0); xilinx_drm_dp_train(dp); xilinx_drm_writel(iomem, XILINX_DP_TX_ENABLE_MAIN_STREAM, 1); return; default: xilinx_drm_writel(iomem, XILINX_DP_TX_ENABLE_MAIN_STREAM, 0); drm_dp_dpcd_writeb(&dp->aux, DP_SET_POWER, DP_SET_POWER_D3); xilinx_drm_writel(iomem, XILINX_DP_TX_PHY_POWER_DOWN, XILINX_DP_TX_PHY_POWER_DOWN_ALL); if (dp->aud_clk) xilinx_drm_writel(iomem, XILINX_DP_TX_AUDIO_CONTROL, 0); return; } }
static enum drm_connector_status xilinx_drm_dp_detect(struct drm_encoder *encoder, struct drm_connector *connector) { struct xilinx_drm_dp *dp = to_dp(encoder); struct xilinx_drm_dp_link_config *link_config = &dp->link_config; u32 state; int ret; state = xilinx_drm_readl(dp->iomem, XILINX_DP_TX_INTR_SIGNAL_STATE); if (state & XILINX_DP_TX_INTR_SIGNAL_STATE_HPD) { ret = xilinx_drm_dp_aux_read(dp, 0x0, dp->dpcd, sizeof(dp->dpcd)); if (ret) return connector_status_disconnected; link_config->max_rate = min_t(int, drm_dp_max_link_rate(dp->dpcd), dp->config.max_link_rate); link_config->max_lanes = min_t(u8, drm_dp_max_lane_count(dp->dpcd), dp->config.max_lanes); return connector_status_connected; }
static int exynos_dp_get_modes(struct analogix_dp_plat_data *plat_data) { struct exynos_dp_device *dp = to_dp(plat_data); struct drm_connector *connector = &dp->connector; struct drm_display_mode *mode; int num_modes = 0; if (dp->plat_data.panel) return num_modes; mode = drm_mode_create(connector->dev); if (!mode) { DRM_ERROR("failed to create a new display mode.\n"); return num_modes; } drm_display_mode_from_videomode(&dp->vm, mode); connector->display_info.width_mm = mode->width_mm; connector->display_info.height_mm = mode->height_mm; mode->type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED; drm_mode_set_name(mode); drm_mode_probed_add(connector, mode); return num_modes + 1; }
static void xilinx_drm_dp_dpms(struct drm_encoder *encoder, int dpms) { struct xilinx_drm_dp *dp = to_dp(encoder); void __iomem *iomem = dp->iomem; if (dp->dpms == dpms) return; dp->dpms = dpms; switch (dpms) { case DRM_MODE_DPMS_ON: xilinx_drm_writel(iomem, XILINX_DP_TX_PHY_POWER_DOWN, 0); xilinx_drm_dp_aux_write_byte(dp, DP_SET_POWER, DP_SET_POWER_D0); xilinx_drm_dp_train(dp); xilinx_drm_writel(iomem, XILINX_DP_TX_ENABLE_MAIN_STREAM, 1); return; default: xilinx_drm_writel(iomem, XILINX_DP_TX_ENABLE_MAIN_STREAM, 0); xilinx_drm_dp_aux_write_byte(dp, DP_SET_POWER, DP_SET_POWER_D3); xilinx_drm_writel(iomem, XILINX_DP_TX_PHY_POWER_DOWN, XILINX_DP_TX_PHY_POWER_DOWN_ALL); return; } }
static void xilinx_drm_dp_mode_set(struct drm_encoder *encoder, struct drm_display_mode *mode, struct drm_display_mode *adjusted_mode) { struct xilinx_drm_dp *dp = to_dp(encoder); int bw = 0; unsigned int ret; do { bw = xilinx_drm_dp_mode_configure(dp, adjusted_mode->clock, bw); if (bw < 0) return; xilinx_drm_dp_mode_set_stream(dp, adjusted_mode); xilinx_drm_dp_mode_set_transfer_unit(dp, adjusted_mode); xilinx_drm_writel(dp->iomem, XILINX_DP_TX_PHY_POWER_DOWN, 0); ret = xilinx_drm_dp_train(dp); xilinx_drm_writel(dp->iomem, XILINX_DP_TX_PHY_POWER_DOWN, XILINX_DP_TX_PHY_POWER_DOWN_ALL); if (!ret) return; } while (bw >= DP_LINK_BW_1_62); DRM_ERROR("failed to train the DP link\n"); }
static struct drm_encoder * analogix_dp_best_encoder(struct drm_connector *connector) { struct analogix_dp_device *dp = to_dp(connector); return dp->encoder; }
static int analogix_dp_get_modes(struct drm_connector *connector) { struct analogix_dp_device *dp = to_dp(connector); struct edid *edid; int ret, num_modes = 0; if (dp->plat_data->panel) { num_modes += drm_panel_get_modes(dp->plat_data->panel); } else { ret = analogix_dp_prepare_panel(dp, true, false); if (ret) { DRM_ERROR("Failed to prepare panel (%d)\n", ret); return 0; } edid = drm_get_edid(connector, &dp->aux.ddc); if (edid) { drm_mode_connector_update_edid_property(&dp->connector, edid); num_modes += drm_add_edid_modes(&dp->connector, edid); kfree(edid); } ret = analogix_dp_prepare_panel(dp, false, false); if (ret) DRM_ERROR("Failed to unprepare panel (%d)\n", ret); } if (dp->plat_data->get_modes) num_modes += dp->plat_data->get_modes(dp->plat_data, connector); return num_modes; }
static int rockchip_dp_powerdown(struct analogix_dp_plat_data *plat_data) { struct rockchip_dp_device *dp = to_dp(plat_data); clk_disable_unprepare(dp->pclk); return 0; }
static void xilinx_drm_dp_mode_set(struct drm_encoder *encoder, struct drm_display_mode *mode, struct drm_display_mode *adjusted_mode) { struct xilinx_drm_dp *dp = to_dp(encoder); xilinx_drm_dp_mode_configure(dp, adjusted_mode->clock); xilinx_drm_dp_mode_set_stream(dp, adjusted_mode); xilinx_drm_dp_mode_set_transfer_unit(dp, adjusted_mode); }
int exynos_dp_crtc_clock_enable(struct analogix_dp_plat_data *plat_data, bool enable) { struct exynos_dp_device *dp = to_dp(plat_data); struct drm_encoder *encoder = &dp->encoder; if (!encoder->crtc) return -EPERM; exynos_drm_pipe_clk_enable(to_exynos_crtc(encoder->crtc), enable); return 0; }
int exynos_dp_crtc_clock_enable(struct analogix_dp_plat_data *plat_data, bool enable) { struct exynos_dp_device *dp = to_dp(plat_data); struct drm_encoder *encoder = &dp->encoder; struct exynos_drm_crtc *crtc; if (!encoder) return -1; crtc = to_exynos_crtc(encoder->crtc); if (crtc && crtc->ops && crtc->ops->clock_enable) crtc->ops->clock_enable(crtc, enable); return 0; }
static int xilinx_drm_dp_mode_valid(struct drm_encoder *encoder, struct drm_display_mode *mode) { struct xilinx_drm_dp *dp = to_dp(encoder); u8 max_lanes = dp->link_config.max_lanes; u8 bpp = dp->config.bpp; int max_rate = dp->link_config.max_rate; int rate; if (mode->clock > XILINX_DP_MAX_CLOCK) return MODE_CLOCK_HIGH; rate = xilinx_drm_dp_max_rate(max_rate, max_lanes, bpp); if (mode->clock > rate) return MODE_CLOCK_HIGH; return MODE_OK; }
static int rockchip_dp_poweron(struct analogix_dp_plat_data *plat_data) { struct rockchip_dp_device *dp = to_dp(plat_data); int ret; ret = clk_prepare_enable(dp->pclk); if (ret < 0) { dev_err(dp->dev, "failed to enable pclk %d\n", ret); return ret; } ret = rockchip_dp_pre_init(dp); if (ret < 0) { dev_err(dp->dev, "failed to dp pre init %d\n", ret); return ret; } return 0; }
static void xilinx_drm_dp_dpms(struct drm_encoder *encoder, int dpms) { struct xilinx_drm_dp *dp = to_dp(encoder); void __iomem *iomem = dp->iomem; unsigned int i; int ret; if (dp->dpms == dpms) return; dp->dpms = dpms; switch (dpms) { case DRM_MODE_DPMS_ON: if (dp->aud_clk) xilinx_drm_writel(iomem, XILINX_DP_TX_AUDIO_CONTROL, 1); xilinx_drm_writel(iomem, XILINX_DP_TX_PHY_POWER_DOWN, 0); for (i = 0; i < 3; i++) { ret = drm_dp_dpcd_writeb(&dp->aux, DP_SET_POWER, DP_SET_POWER_D0); if (ret == 1) break; usleep_range(300, 500); } xilinx_drm_dp_train(dp); xilinx_drm_writel(dp->iomem, XILINX_DP_TX_SW_RESET, XILINX_DP_TX_SW_RESET_ALL); xilinx_drm_writel(iomem, XILINX_DP_TX_ENABLE_MAIN_STREAM, 1); return; default: xilinx_drm_writel(iomem, XILINX_DP_TX_ENABLE_MAIN_STREAM, 0); drm_dp_dpcd_writeb(&dp->aux, DP_SET_POWER, DP_SET_POWER_D3); xilinx_drm_writel(iomem, XILINX_DP_TX_PHY_POWER_DOWN, XILINX_DP_TX_PHY_POWER_DOWN_ALL); if (dp->aud_clk) xilinx_drm_writel(iomem, XILINX_DP_TX_AUDIO_CONTROL, 0); return; } }
static void rockchip_dp_drm_encoder_enable(struct drm_encoder *encoder) { struct rockchip_dp_device *dp = to_dp(encoder); int ret; u32 val; ret = drm_of_encoder_active_endpoint_id(dp->dev->of_node, encoder); if (ret < 0) return; if (ret) val = GRF_EDP_SEL_VOP_LIT | (GRF_EDP_LCD_SEL_MASK << 16); else val = GRF_EDP_SEL_VOP_BIG | (GRF_EDP_LCD_SEL_MASK << 16); dev_dbg(dp->dev, "vop %s output to dp\n", (ret) ? "LIT" : "BIG"); ret = regmap_write(dp->grf, GRF_SOC_CON6, val); if (ret != 0) { dev_err(dp->dev, "Could not write to GRF: %d\n", ret); return; } }
static bool xilinx_drm_dp_mode_fixup(struct drm_encoder *encoder, const struct drm_display_mode *mode, struct drm_display_mode *adjusted_mode) { struct xilinx_drm_dp *dp = to_dp(encoder); int diff = mode->htotal - mode->hsync_end; /* * ZynqMP DP requires horizontal backporch to be greater than 12. * This limitation may conflict with the sink device. */ if (dp->dp_sub && diff < XILINX_DP_SUB_TX_MIN_H_BACKPORCH) { int vrefresh = (adjusted_mode->clock * 1000) / (adjusted_mode->vtotal * adjusted_mode->htotal); diff = XILINX_DP_SUB_TX_MIN_H_BACKPORCH - diff; adjusted_mode->htotal += diff; adjusted_mode->clock = adjusted_mode->vtotal * adjusted_mode->htotal * vrefresh / 1000; } return true; }