/* * Configure DP in slave mode and wait for video stream. * * param dp pointer to main s5p-dp structure * param video_info pointer to main video_info structure. * return status */ static int s5p_dp_config_video(struct s5p_dp_device *dp, struct video_info *video_info) { int timeout = 0; struct exynos5_dp *base = dp->base; struct mono_time start, current, end; s5p_dp_config_video_slave_mode(dp, video_info); s5p_dp_set_video_color_format(dp, video_info->color_depth, video_info->color_space, video_info->dynamic_range, video_info->ycbcr_coeff); if (s5p_dp_get_pll_lock_status(dp) == PLL_UNLOCKED) { printk(BIOS_DEBUG, "PLL is not locked yet.\n"); return -ERR_PLL_NOT_UNLOCKED; } timer_monotonic_get(&start); end = current = start; mono_time_add_usecs(&end, STREAM_ON_TIMEOUT * USECS_PER_MSEC); do { if (s5p_dp_is_slave_video_stream_clock_on(dp) == 0) { timeout++; break; } timer_monotonic_get(¤t); } while (mono_time_before(¤t, &end)); if (!timeout) { printk(BIOS_ERR, "Video Clock Not ok after %ldus.\n", mono_time_diff_microseconds(&start, &end)); return -ERR_VIDEO_CLOCK_BAD; } /* Set to use the register calculated M/N video */ s5p_dp_set_video_cr_mn(dp, CALCULATED_M, 0, 0); clrbits_le32(&base->video_ctl_10, FORMAT_SEL); /* Disable video mute */ clrbits_le32(&base->video_ctl_1, HDCP_VIDEO_MUTE); /* Configure video slave mode */ s5p_dp_enable_video_master(dp); /* Enable video */ setbits_le32(&base->video_ctl_1, VIDEO_EN); timeout = s5p_dp_is_video_stream_on(dp); if (timeout) { printk(BIOS_DEBUG, "Video Stream Not on\n"); return -ERR_VIDEO_STREAM_BAD; } return 0; }
/* * Configure DP in slave mode and wait for video stream. * * param dp pointer to main s5p-dp structure * param video_info pointer to main video_info structure. * return status */ static int s5p_dp_config_video(struct s5p_dp_device *dp, struct video_info *video_info) { int timeout = 0; struct exynos5_dp *base = dp->base; struct stopwatch sw; s5p_dp_config_video_slave_mode(dp, video_info); s5p_dp_set_video_color_format(dp, video_info->color_depth, video_info->color_space, video_info->dynamic_range, video_info->ycbcr_coeff); if (s5p_dp_get_pll_lock_status(dp) == PLL_UNLOCKED) { printk(BIOS_DEBUG, "PLL is not locked yet.\n"); return -ERR_PLL_NOT_UNLOCKED; } stopwatch_init_msecs_expire(&sw, STREAM_ON_TIMEOUT); do { if (s5p_dp_is_slave_video_stream_clock_on(dp) == 0) { timeout++; break; } } while (!stopwatch_expired(&sw)); if (!timeout) { printk(BIOS_ERR, "Video Clock Not ok after %ldus.\n", stopwatch_duration_usecs(&sw)); return -ERR_VIDEO_CLOCK_BAD; } /* Set to use the register calculated M/N video */ s5p_dp_set_video_cr_mn(dp, CALCULATED_M, 0, 0); clrbits_le32(&base->video_ctl_10, FORMAT_SEL); /* Disable video mute */ clrbits_le32(&base->video_ctl_1, HDCP_VIDEO_MUTE); /* Configure video slave mode */ s5p_dp_enable_video_master(dp); /* Enable video */ setbits_le32(&base->video_ctl_1, VIDEO_EN); timeout = s5p_dp_is_video_stream_on(dp); if (timeout) { printk(BIOS_DEBUG, "Video Stream Not on\n"); return -ERR_VIDEO_STREAM_BAD; } return 0; }
/* * DP H/w Link Training. Set DPCD link rate and bandwidth. * param dp pointer to main s5p-dp structure * param max_lane No of lanes * param max_rate bandwidth * return status */ static int s5p_dp_hw_link_training(struct s5p_dp_device *dp, unsigned int max_lane, unsigned int max_rate) { int pll_is_locked = 0; u32 data; int lane; struct mono_time current, end; struct exynos5_dp *base = dp->base; /* Stop Video */ clrbits_le32(&base->video_ctl_1, VIDEO_EN); timer_monotonic_get(¤t); end = current; mono_time_add_msecs(&end, PLL_LOCK_TIMEOUT); while ((pll_is_locked = s5p_dp_get_pll_lock_status(dp)) == PLL_UNLOCKED) { if (mono_time_after(¤t, &end)) { /* Ignore this error, and try to continue */ printk(BIOS_ERR, "PLL is not locked yet.\n"); break; } timer_monotonic_get(¤t); } printk(BIOS_SPEW, "PLL is %slocked\n", pll_is_locked == PLL_LOCKED ? "": "not "); /* Reset Macro */ setbits_le32(&base->dp_phy_test, MACRO_RST); /* 10 us is the minimum reset time. */ udelay(10); clrbits_le32(&base->dp_phy_test, MACRO_RST); /* Set TX pre-emphasis to minimum */ for (lane = 0; lane < max_lane; lane++) if (s5p_dp_set_lane_lane_pre_emphasis(dp, PRE_EMPHASIS_LEVEL_0, lane)) { printk(BIOS_DEBUG, "Unable to set pre emphasis level\n"); return -ERR_PRE_EMPHASIS_LEVELS; } /* All DP analog module power up */ writel(0x00, &base->dp_phy_pd); /* Initialize by reading RX's DPCD */ s5p_dp_get_max_rx_bandwidth(dp, &dp->link_train.link_rate); s5p_dp_get_max_rx_lane_count(dp, &dp->link_train.lane_count); printk(BIOS_SPEW, "%s: rate 0x%x, lane_count %d\n", __func__, dp->link_train.link_rate, dp->link_train.lane_count); if ((dp->link_train.link_rate != LINK_RATE_1_62GBPS) && (dp->link_train.link_rate != LINK_RATE_2_70GBPS)) { printk(BIOS_DEBUG, "Rx Max Link Rate is abnormal :%x !\n", dp->link_train.link_rate); /* Not Retrying */ return -ERR_LINK_RATE_ABNORMAL; } if (dp->link_train.lane_count == 0) { printk(BIOS_DEBUG, "Rx Max Lane count is abnormal :%x !\n", dp->link_train.lane_count); /* Not retrying */ return -ERR_MAX_LANE_COUNT_ABNORMAL; } /* Setup TX lane count & rate */ if (dp->link_train.lane_count > max_lane) dp->link_train.lane_count = max_lane; if (dp->link_train.link_rate > max_rate) dp->link_train.link_rate = max_rate; /* Set link rate and count as you want to establish*/ writel(dp->link_train.lane_count, &base->lane_count_set); writel(dp->link_train.link_rate, &base->link_bw_set); /* Set sink to D0 (Sink Not Ready) mode. */ s5p_dp_write_byte_to_dpcd(dp, DPCD_ADDR_SINK_POWER_STATE, DPCD_SET_POWER_STATE_D0); /* Start HW link training */ writel(HW_TRAINING_EN, &base->dp_hw_link_training); /* Wait until HW link training done */ s5p_dp_wait_hw_link_training_done(dp); /* Get hardware link training status */ data = readl(&base->dp_hw_link_training); printk(BIOS_SPEW, "hardware link training status: 0x%08x\n", data); if (data != 0) { printk(BIOS_ERR, " H/W link training failure: 0x%x\n", data); return -ERR_LINK_TRAINING_FAILURE; } /* Get Link Bandwidth */ data = readl(&base->link_bw_set); dp->link_train.link_rate = data; data = readl(&base->lane_count_set); dp->link_train.lane_count = data; printk(BIOS_SPEW, "Done training: Link bandwidth: 0x%x, lane_count: %d\n", dp->link_train.link_rate, data); return 0; }
static int s5p_dp_config_video(struct s5p_dp_device *dp, struct video_info *video_info) { int retval = 0; int timeout_loop = 0; int done_count = 0; s5p_dp_config_video_slave_mode(dp, video_info); s5p_dp_set_video_color_format(dp, video_info->color_depth, video_info->color_space, video_info->dynamic_range, video_info->ycbcr_coeff); if (s5p_dp_get_pll_lock_status(dp) == PLL_UNLOCKED) { dev_err(dp->dev, "PLL is not locked yet.\n"); return -EINVAL; } for (;;) { timeout_loop++; if (s5p_dp_is_slave_video_stream_clock_on(dp) == 0) break; if (DP_TIMEOUT_LOOP_COUNT < timeout_loop) { dev_err(dp->dev, "Timeout of video streamclk ok\n"); return -ETIMEDOUT; } usleep_range(1, 1); } /* Set to use the register calculated M/N video */ s5p_dp_set_video_cr_mn(dp, CALCULATED_M, 0, 0); /* For video bist, Video timing must be generated by register */ s5p_dp_set_video_timing_mode(dp, VIDEO_TIMING_FROM_CAPTURE); /* Disable video mute */ s5p_dp_enable_video_mute(dp, 0); /* Configure video slave mode */ s5p_dp_enable_video_master(dp, 0); /* Enable video */ s5p_dp_start_video(dp); timeout_loop = 0; for (;;) { timeout_loop++; if (s5p_dp_is_video_stream_on(dp) == 0) { done_count++; if (done_count > 10) break; } else if (done_count) { done_count = 0; } if (DP_TIMEOUT_LOOP_COUNT < timeout_loop) { dev_err(dp->dev, "Timeout of video streamclk ok\n"); return -ETIMEDOUT; } usleep_range(1000, 1000); } if (retval != 0) dev_err(dp->dev, "Video stream is not detected!\n"); return retval; }
int s5p_dp_psr_exit(struct s5p_dp_device *dp) { struct platform_device *pdev; struct s5p_dp_platdata *pdata; int timeout_loop = 0; u8 data; u32 reg; int ret = 0; pdev = to_platform_device(dp->dev); pdata = pdev->dev.platform_data; mutex_lock(&dp->lock); dev_dbg(dp->dev, "%s +\n", __func__); if (dp->psr_enter_state == PSR_NONE) { dev_info(dp->dev, "%s: Already edP PSR_EXIT state\n", __func__); dp->psr_exit_state = PSR_NONE; mutex_unlock(&dp->lock); return 0; } clk_enable(dp->clock); s5p_dp_exit_psr(dp); s5p_dp_set_fifo_reset(dp); s5p_dp_reset_macro_onoff(dp, 1); s5p_dp_set_analog_power_down(dp, ANALOG_TOTAL, 0); if (s5p_dp_get_pll_lock_status(dp) == PLL_UNLOCKED) { while (s5p_dp_get_pll_lock_status(dp) == PLL_UNLOCKED) { timeout_loop++; if (DP_TIMEOUT_LOOP_COUNT < timeout_loop) { dev_err(dp->dev, "failed to get pll lock status\n"); ret = -ETIMEDOUT; goto err_exit; } udelay(10); } } ndelay(600); s5p_dp_clear_fifo_reset(dp); s5p_dp_reset_macro_onoff(dp, 0); s5p_dp_reset_serdes_fifo(dp); /* Set sink to D0 (Normal operation) mode. */ s5p_dp_write_byte_to_dpcd(dp, DPCD_ADDR_SINK_POWER_STATE, DPCD_SET_POWER_STATE_D0); s5p_dp_set_link_train_for_psr(dp, dp->video_info->lane_count, dp->video_info->link_rate); s5p_dp_set_idle_en(dp); timeout_loop = 0; for (;;) { timeout_loop++; if (s5p_dp_get_psr_status(dp) == PSR_STATUS_INACTIVE) break; if (DP_TIMEOUT_LOOP_COUNT < timeout_loop) { dev_err(dp->dev, "DP: Timeout of PSR inactive\n"); ret = -ETIMEDOUT; goto err_exit; } usleep_range(100, 110); } s5p_dp_set_force_stream_valid(dp); timeout_loop = 0; for (;;) { timeout_loop++; if (s5p_dp_is_video_stream_on(dp) == 0) break; if (DP_TIMEOUT_LOOP_COUNT < timeout_loop) { dev_err(dp->dev, "Timeout of video streamclk ok\n"); ret = -ETIMEDOUT; goto err_exit; } usleep_range(1000, 1100); } timeout_loop = 0; for (;;) { timeout_loop++; s5p_dp_read_byte_from_dpcd(dp, DPCD_ADDR_SINK_PSR_STATUS, &data); if (data == SINK_PSR_INACTIVE_STATE || data == 4) { break; } if (DP_TIMEOUT_LOOP_COUNT < timeout_loop) { dev_err(dp->dev, "LCD: Timeout of Sink PSR inactive\n"); ret = -ETIMEDOUT; goto err_exit; } usleep_range(100, 110); } dp->psr_enter_state = PSR_NONE; dp->psr_exit_state = PSR_EXIT_DONE; dev_dbg(dp->dev, "%s -\n", __func__); mutex_unlock(&dp->lock); return ret; err_exit: dp->psr_exit_state = PSR_NONE; dev_dbg(dp->dev, "%s -\n", __func__); mutex_unlock(&dp->lock); return ret; }