/** * xilinx_drm_dp_link_train - Train the link * @dp: DisplayPort IP core structure * * Return: 0 if all trains are done successfully, or corresponding error code. */ static int xilinx_drm_dp_train(struct xilinx_drm_dp *dp) { u32 reg; u8 bw_code = dp->mode.bw_code; u8 lane_cnt = dp->mode.lane_cnt; u8 aux_lane_cnt = lane_cnt; bool enhanced; int ret; xilinx_drm_writel(dp->iomem, XILINX_DP_TX_LANE_CNT_SET, lane_cnt); enhanced = drm_dp_enhanced_frame_cap(dp->dpcd); if (enhanced) { xilinx_drm_writel(dp->iomem, XILINX_DP_TX_ENHANCED_FRAME_EN, 1); aux_lane_cnt |= DP_LANE_COUNT_ENHANCED_FRAME_EN; } if (dp->dpcd[3] & 0x1) { xilinx_drm_writel(dp->iomem, XILINX_DP_TX_DOWNSPREAD_CTL, 1); drm_dp_dpcd_writeb(&dp->aux, DP_DOWNSPREAD_CTRL, DP_SPREAD_AMP_0_5); } else { xilinx_drm_writel(dp->iomem, XILINX_DP_TX_DOWNSPREAD_CTL, 0); drm_dp_dpcd_writeb(&dp->aux, DP_DOWNSPREAD_CTRL, 0); } ret = drm_dp_dpcd_writeb(&dp->aux, DP_LANE_COUNT_SET, aux_lane_cnt); if (ret < 0) { DRM_ERROR("failed to set lane count\n"); return ret; } ret = drm_dp_dpcd_writeb(&dp->aux, DP_MAIN_LINK_CHANNEL_CODING_SET, DP_SET_ANSI_8B10B); if (ret < 0) { DRM_ERROR("failed to set ANSI 8B/10B encoding\n"); return ret; } ret = drm_dp_dpcd_writeb(&dp->aux, DP_LINK_BW_SET, bw_code); if (ret < 0) { DRM_ERROR("failed to set DP bandwidth\n"); return ret; } xilinx_drm_writel(dp->iomem, XILINX_DP_TX_LINK_BW_SET, bw_code); switch (bw_code) { case DP_LINK_BW_1_62: reg = XILINX_DP_TX_PHY_CLOCK_FEEDBACK_SETTING_162; break; case DP_LINK_BW_2_7: reg = XILINX_DP_TX_PHY_CLOCK_FEEDBACK_SETTING_270; break; case DP_LINK_BW_5_4: default: reg = XILINX_DP_TX_PHY_CLOCK_FEEDBACK_SETTING_540; break; } xilinx_drm_writel(dp->iomem, XILINX_DP_TX_PHY_CLOCK_FEEDBACK_SETTING, reg); ret = xilinx_drm_dp_phy_ready(dp); if (ret < 0) return ret; xilinx_drm_writel(dp->iomem, XILINX_DP_TX_SCRAMBLING_DISABLE, 1); memset(dp->train_set, 0, 4); ret = xilinx_drm_dp_link_train_cr(dp); if (ret) return ret; ret = xilinx_drm_dp_link_train_ce(dp); if (ret) return ret; xilinx_drm_writel(dp->iomem, XILINX_DP_TX_TRAINING_PATTERN_SET, DP_TRAINING_PATTERN_DISABLE); ret = drm_dp_dpcd_writeb(&dp->aux, DP_TRAINING_PATTERN_SET, DP_TRAINING_PATTERN_DISABLE); if (ret < 0) { DRM_ERROR("failed to disable training pattern\n"); return ret; } xilinx_drm_writel(dp->iomem, XILINX_DP_TX_SCRAMBLING_DISABLE, 0); return 0; }
/** * xilinx_drm_dp_mode_set_stream - Configure the main stream * @dp: DisplayPort IP core structure * @mode: requested display mode * * Configure the main stream based on the requested mode @mode. Calculation is * based on IP core specification. */ static void xilinx_drm_dp_mode_set_stream(struct xilinx_drm_dp *dp, struct drm_display_mode *mode) { u8 lane_cnt = dp->mode.lane_cnt; u32 reg, wpl; xilinx_drm_writel(dp->iomem, XILINX_DP_TX_MAIN_STREAM_HTOTAL, mode->htotal); xilinx_drm_writel(dp->iomem, XILINX_DP_TX_MAIN_STREAM_VTOTAL, mode->vtotal); xilinx_drm_writel(dp->iomem, XILINX_DP_TX_MAIN_STREAM_POLARITY, (!!(mode->flags & DRM_MODE_FLAG_PVSYNC) << XILINX_DP_TX_MAIN_STREAM_POLARITY_VSYNC_SHIFT) | (!!(mode->flags & DRM_MODE_FLAG_PHSYNC) << XILINX_DP_TX_MAIN_STREAM_POLARITY_HSYNC_SHIFT)); xilinx_drm_writel(dp->iomem, XILINX_DP_TX_MAIN_STREAM_HSWIDTH, mode->hsync_end - mode->hsync_start); xilinx_drm_writel(dp->iomem, XILINX_DP_TX_MAIN_STREAM_VSWIDTH, mode->vsync_end - mode->vsync_start); xilinx_drm_writel(dp->iomem, XILINX_DP_TX_MAIN_STREAM_HRES, mode->hdisplay); xilinx_drm_writel(dp->iomem, XILINX_DP_TX_MAIN_STREAM_VRES, mode->vdisplay); xilinx_drm_writel(dp->iomem, XILINX_DP_TX_MAIN_STREAM_HSTART, mode->htotal - mode->hsync_start); xilinx_drm_writel(dp->iomem, XILINX_DP_TX_MAIN_STREAM_VSTART, mode->vtotal - mode->vsync_start); xilinx_drm_writel(dp->iomem, XILINX_DP_TX_MAIN_STREAM_MISC0, dp->config.misc0); xilinx_drm_writel(dp->iomem, XILINX_DP_TX_MAIN_STREAM_MISC1, dp->config.misc1); /* In synchronous mode, set the diviers */ if (dp->config.misc0 & XILINX_DP_TX_MAIN_STREAM_MISC0_SYNC) { reg = drm_dp_bw_code_to_link_rate(dp->mode.bw_code); xilinx_drm_writel(dp->iomem, XILINX_DP_TX_N_VID, reg); xilinx_drm_writel(dp->iomem, XILINX_DP_TX_M_VID, mode->clock); if (dp->aud_clk) { int aud_rate = clk_get_rate(dp->aud_clk) / 512; if (aud_rate != 44100 && aud_rate != 48000) dev_dbg(dp->dev, "Audio rate: %d\n", aud_rate); xilinx_drm_writel(dp->iomem, XILINX_DP_TX_AUDIO_N_AUD, reg); xilinx_drm_writel(dp->iomem, XILINX_DP_TX_AUDIO_M_AUD, aud_rate); } } /* Only 2 channel is supported now */ if (dp->aud_clk) xilinx_drm_writel(dp->iomem, XILINX_DP_TX_AUDIO_CHANNELS, 1); xilinx_drm_writel(dp->iomem, XILINX_DP_TX_USER_PIXEL_WIDTH, 1); /* Translate to the native 16 bit datapath based on IP core spec */ wpl = (mode->hdisplay * dp->config.bpp + 15) / 16; reg = wpl + wpl % lane_cnt - lane_cnt; xilinx_drm_writel(dp->iomem, XILINX_DP_TX_USER_DATA_CNT_PER_LANE, reg); }