Merge "msm: mdss: dp: fix HBR2 pattern generation"

This commit is contained in:
Linux Build Service Account 2017-01-28 00:46:32 -08:00 committed by Gerrit - the friendly Code Review server
commit 252a3a5bb6
16 changed files with 2318 additions and 562 deletions

View file

@ -1,4 +1,4 @@
/* Copyright (c) 2015-2016, The Linux Foundation. All rights reserved.
/* Copyright (c) 2015-2017, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@ -559,6 +559,7 @@ static int hdcp_lib_txmtr_init_legacy(struct hdcp_lib_handle *handle);
static struct qseecom_handle *hdcp1_handle;
static bool hdcp1_supported = true;
static bool hdcp1_enc_enabled;
static struct mutex hdcp1_ta_cmd_lock;
static const char *hdcp_lib_message_name(int msg_id)
{
@ -805,8 +806,8 @@ static int hdcp_lib_get_version(struct hdcp_lib_handle *handle)
goto exit;
}
if (handle->hdcp_state & HDCP_STATE_APP_LOADED) {
pr_err("library already loaded\n");
if (!(handle->hdcp_state & HDCP_STATE_APP_LOADED)) {
pr_err("library not loaded\n");
return rc;
}
@ -901,8 +902,8 @@ static int hdcp_app_init_legacy(struct hdcp_lib_handle *handle)
goto exit;
}
if (handle->hdcp_state & HDCP_STATE_APP_LOADED) {
pr_err("library already loaded\n");
if (!(handle->hdcp_state & HDCP_STATE_APP_LOADED)) {
pr_err("library not loaded\n");
goto exit;
}
@ -949,8 +950,8 @@ static int hdcp_app_init(struct hdcp_lib_handle *handle)
goto exit;
}
if (handle->hdcp_state & HDCP_STATE_APP_LOADED) {
pr_err("library already loaded\n");
if (!(handle->hdcp_state & HDCP_STATE_APP_LOADED)) {
pr_err("library not loaded\n");
goto exit;
}
@ -1024,6 +1025,7 @@ static int hdcp_lib_library_load(struct hdcp_lib_handle *handle)
goto exit;
}
handle->hdcp_state |= HDCP_STATE_APP_LOADED;
pr_debug("qseecom_start_app success\n");
rc = hdcp_lib_get_version(handle);
@ -1050,8 +1052,6 @@ static int hdcp_lib_library_load(struct hdcp_lib_handle *handle)
pr_err("app init failed\n");
goto exit;
}
handle->hdcp_state |= HDCP_STATE_APP_LOADED;
exit:
return rc;
}
@ -1240,8 +1240,8 @@ static int hdcp_lib_txmtr_init(struct hdcp_lib_handle *handle)
goto exit;
}
if (handle->hdcp_state & HDCP_STATE_TXMTR_INIT) {
pr_err("txmtr already initialized\n");
if (!(handle->hdcp_state & HDCP_STATE_APP_LOADED)) {
pr_err("library not loaded\n");
goto exit;
}
@ -1622,6 +1622,12 @@ static int hdcp_lib_check_valid_state(struct hdcp_lib_handle *handle)
rc = -EBUSY;
goto exit;
}
if (handle->hdcp_state & HDCP_STATE_APP_LOADED) {
pr_debug("library already loaded\n");
rc = -EBUSY;
goto exit;
}
} else {
if (atomic_read(&handle->hdcp_off)) {
pr_debug("hdcp2.2 session tearing down\n");
@ -2212,6 +2218,8 @@ bool hdcp1_check_if_supported_load_app(void)
if (rc) {
pr_err("qseecom_start_app failed %d\n", rc);
hdcp1_supported = false;
} else {
mutex_init(&hdcp1_ta_cmd_lock);
}
}
@ -2276,12 +2284,16 @@ int hdcp1_set_enc(bool enable)
struct hdcp1_set_enc_req *set_enc_req;
struct hdcp1_set_enc_rsp *set_enc_rsp;
if (!hdcp1_supported || !hdcp1_handle)
return -EINVAL;
mutex_lock(&hdcp1_ta_cmd_lock);
if (!hdcp1_supported || !hdcp1_handle) {
rc = -EINVAL;
goto end;
}
if (hdcp1_enc_enabled == enable) {
pr_debug("already %s\n", enable ? "enabled" : "disabled");
return rc;
goto end;
}
/* set keys and request aksv */
@ -2299,18 +2311,21 @@ int hdcp1_set_enc(bool enable)
if (rc < 0) {
pr_err("qseecom cmd failed err=%d\n", rc);
return -EINVAL;
goto end;
}
rc = set_enc_rsp->ret;
if (rc) {
pr_err("enc cmd failed, rsp=%d\n", set_enc_rsp->ret);
return -EINVAL;
rc = -EINVAL;
goto end;
}
hdcp1_enc_enabled = enable;
pr_debug("%s success\n", enable ? "enable" : "disable");
return 0;
end:
mutex_unlock(&hdcp1_ta_cmd_lock);
return rc;
}
int hdcp_library_register(struct hdcp_register_data *data)

File diff suppressed because it is too large Load diff

View file

@ -1,4 +1,4 @@
/* Copyright (c) 2012-2014, 2016 The Linux Foundation. All rights reserved.
/* Copyright (c) 2012-2014, 2016-2017 The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@ -269,6 +269,32 @@ struct dpcd_test_request {
u32 test_link_rate;
u32 test_lane_count;
u32 phy_test_pattern_sel;
u32 test_video_pattern;
u32 test_bit_depth;
u32 test_dyn_range;
u32 test_h_total;
u32 test_v_total;
u32 test_h_start;
u32 test_v_start;
u32 test_hsync_pol;
u32 test_hsync_width;
u32 test_vsync_pol;
u32 test_vsync_width;
u32 test_h_width;
u32 test_v_height;
u32 test_rr_d;
u32 test_rr_n;
u32 test_audio_sampling_rate;
u32 test_audio_channel_count;
u32 test_audio_pattern_type;
u32 test_audio_period_ch_1;
u32 test_audio_period_ch_2;
u32 test_audio_period_ch_3;
u32 test_audio_period_ch_4;
u32 test_audio_period_ch_5;
u32 test_audio_period_ch_6;
u32 test_audio_period_ch_7;
u32 test_audio_period_ch_8;
u32 response;
};
@ -376,6 +402,28 @@ struct dp_hdcp {
bool feature_enabled;
};
struct mdss_dp_event {
struct mdss_dp_drv_pdata *dp;
u32 id;
};
#define MDSS_DP_EVENT_Q_MAX 4
struct mdss_dp_event_data {
wait_queue_head_t event_q;
u32 pndx;
u32 gndx;
struct mdss_dp_event event_list[MDSS_DP_EVENT_Q_MAX];
spinlock_t event_lock;
};
struct mdss_dp_crc_data {
bool en;
u32 r_cr;
u32 g_y;
u32 b_cb;
};
struct mdss_dp_drv_pdata {
/* device driver */
int (*on) (struct mdss_panel_data *pdata);
@ -402,6 +450,7 @@ struct mdss_dp_drv_pdata {
bool sink_info_read;
bool hpd;
bool psm_enabled;
bool audio_test_req;
/* dp specific */
unsigned char *base;
@ -413,8 +462,11 @@ struct mdss_dp_drv_pdata {
struct dss_io_data hdcp_io;
int base_size;
unsigned char *mmss_cc_base;
bool override_config;
u32 mask1;
u32 mask2;
struct mdss_dp_crc_data ctl_crc;
struct mdss_dp_crc_data sink_crc;
struct mdss_panel_data panel_data;
struct mdss_util_intf *mdss_util;
@ -451,7 +503,6 @@ struct mdss_dp_drv_pdata {
/* aux */
struct completion aux_comp;
struct completion train_comp;
struct completion idle_comp;
struct completion video_comp;
struct completion irq_comp;
@ -478,18 +529,15 @@ struct mdss_dp_drv_pdata {
char tu_desired;
char valid_boundary;
char delay_start;
u32 bpp;
struct dp_statistic dp_stat;
bool hpd_irq_on;
bool hpd_irq_toggled;
bool hpd_irq_clients_notified;
u32 hpd_notification_status;
struct mdss_dp_event_data dp_event;
struct task_struct *ev_thread;
/* event */
struct workqueue_struct *workq;
struct work_struct work;
struct delayed_work hdcp_cb_work;
u32 current_event;
spinlock_t event_lock;
spinlock_t lock;
struct switch_dev sdev;
struct kobject *kobj;
@ -512,6 +560,55 @@ enum dp_lane_count {
DP_LANE_COUNT_4 = 4,
};
enum audio_pattern_type {
AUDIO_TEST_PATTERN_OPERATOR_DEFINED = 0x00,
AUDIO_TEST_PATTERN_SAWTOOTH = 0x01,
};
static inline char *mdss_dp_get_audio_test_pattern(u32 pattern)
{
switch (pattern) {
case AUDIO_TEST_PATTERN_OPERATOR_DEFINED:
return DP_ENUM_STR(AUDIO_TEST_PATTERN_OPERATOR_DEFINED);
case AUDIO_TEST_PATTERN_SAWTOOTH:
return DP_ENUM_STR(AUDIO_TEST_PATTERN_SAWTOOTH);
default:
return "unknown";
}
}
enum audio_sample_rate {
AUDIO_SAMPLE_RATE_32_KHZ = 0x00,
AUDIO_SAMPLE_RATE_44_1_KHZ = 0x01,
AUDIO_SAMPLE_RATE_48_KHZ = 0x02,
AUDIO_SAMPLE_RATE_88_2_KHZ = 0x03,
AUDIO_SAMPLE_RATE_96_KHZ = 0x04,
AUDIO_SAMPLE_RATE_176_4_KHZ = 0x05,
AUDIO_SAMPLE_RATE_192_KHZ = 0x06,
};
static inline char *mdss_dp_get_audio_sample_rate(u32 rate)
{
switch (rate) {
case AUDIO_SAMPLE_RATE_32_KHZ:
return DP_ENUM_STR(AUDIO_SAMPLE_RATE_32_KHZ);
case AUDIO_SAMPLE_RATE_44_1_KHZ:
return DP_ENUM_STR(AUDIO_SAMPLE_RATE_44_1_KHZ);
case AUDIO_SAMPLE_RATE_48_KHZ:
return DP_ENUM_STR(AUDIO_SAMPLE_RATE_48_KHZ);
case AUDIO_SAMPLE_RATE_88_2_KHZ:
return DP_ENUM_STR(AUDIO_SAMPLE_RATE_88_2_KHZ);
case AUDIO_SAMPLE_RATE_96_KHZ:
return DP_ENUM_STR(AUDIO_SAMPLE_RATE_96_KHZ);
case AUDIO_SAMPLE_RATE_176_4_KHZ:
return DP_ENUM_STR(AUDIO_SAMPLE_RATE_176_4_KHZ);
case AUDIO_SAMPLE_RATE_192_KHZ:
return DP_ENUM_STR(AUDIO_SAMPLE_RATE_192_KHZ);
default:
return "unknown";
}
}
enum phy_test_pattern {
PHY_TEST_PATTERN_NONE,
PHY_TEST_PATTERN_D10_2_NO_SCRAMBLING,
@ -608,17 +705,22 @@ static inline char *mdss_dp_get_test_response(u32 test_response)
enum test_type {
UNKNOWN_TEST = 0,
TEST_LINK_TRAINING = BIT(0),
PHY_TEST_PATTERN = BIT(3),
TEST_EDID_READ = BIT(2),
TEST_LINK_TRAINING = 0x1,
TEST_VIDEO_PATTERN = 0x2,
PHY_TEST_PATTERN = 0x8,
TEST_EDID_READ = 0x4,
TEST_AUDIO_PATTERN = 32,
TEST_AUDIO_DISABLED_VIDEO = 64,
};
static inline char *mdss_dp_get_test_name(u32 test_requested)
{
switch (test_requested) {
case TEST_LINK_TRAINING: return DP_ENUM_STR(TEST_LINK_TRAINING);
case TEST_VIDEO_PATTERN: return DP_ENUM_STR(TEST_VIDEO_PATTERN);
case PHY_TEST_PATTERN: return DP_ENUM_STR(PHY_TEST_PATTERN);
case TEST_EDID_READ: return DP_ENUM_STR(TEST_EDID_READ);
case TEST_AUDIO_PATTERN: return DP_ENUM_STR(TEST_AUDIO_PATTERN);
default: return "unknown";
}
}
@ -661,11 +763,252 @@ static inline char *mdss_dp_ev_event_to_string(int event)
return DP_ENUM_STR(EV_IDLE_PATTERNS_SENT);
case EV_VIDEO_READY:
return DP_ENUM_STR(EV_VIDEO_READY);
case EV_USBPD_DISCOVER_MODES:
return DP_ENUM_STR(EV_USBPD_DISCOVER_MODES);
case EV_USBPD_ENTER_MODE:
return DP_ENUM_STR(EV_USBPD_ENTER_MODE);
case EV_USBPD_DP_STATUS:
return DP_ENUM_STR(EV_USBPD_DP_STATUS);
case EV_USBPD_DP_CONFIGURE:
return DP_ENUM_STR(EV_USBPD_DP_CONFIGURE);
case EV_USBPD_CC_PIN_POLARITY:
return DP_ENUM_STR(EV_USBPD_CC_PIN_POLARITY);
case EV_USBPD_EXIT_MODE:
return DP_ENUM_STR(EV_USBPD_EXIT_MODE);
case EV_USBPD_ATTENTION:
return DP_ENUM_STR(EV_USBPD_ATTENTION);
default:
return "unknown";
}
}
enum dynamic_range {
DP_DYNAMIC_RANGE_RGB_VESA = 0x00,
DP_DYNAMIC_RANGE_RGB_CEA = 0x01,
DP_DYNAMIC_RANGE_UNKNOWN = 0xFFFFFFFF,
};
static inline char *mdss_dp_dynamic_range_to_string(u32 dr)
{
switch (dr) {
case DP_DYNAMIC_RANGE_RGB_VESA:
return DP_ENUM_STR(DP_DYNAMIC_RANGE_RGB_VESA);
case DP_DYNAMIC_RANGE_RGB_CEA:
return DP_ENUM_STR(DP_DYNAMIC_RANGE_RGB_CEA);
case DP_DYNAMIC_RANGE_UNKNOWN:
default:
return "unknown";
}
}
/**
* mdss_dp_is_dynamic_range_valid() - validates the dynamic range
* @bit_depth: the dynamic range value to be checked
*
* Returns true if the dynamic range value is supported.
*/
static inline bool mdss_dp_is_dynamic_range_valid(u32 dr)
{
switch (dr) {
case DP_DYNAMIC_RANGE_RGB_VESA:
case DP_DYNAMIC_RANGE_RGB_CEA:
return true;
default:
return false;
}
}
enum test_bit_depth {
DP_TEST_BIT_DEPTH_6 = 0x00,
DP_TEST_BIT_DEPTH_8 = 0x01,
DP_TEST_BIT_DEPTH_10 = 0x02,
DP_TEST_BIT_DEPTH_UNKNOWN = 0xFFFFFFFF,
};
static inline char *mdss_dp_test_bit_depth_to_string(u32 tbd)
{
switch (tbd) {
case DP_TEST_BIT_DEPTH_6:
return DP_ENUM_STR(DP_TEST_BIT_DEPTH_6);
case DP_TEST_BIT_DEPTH_8:
return DP_ENUM_STR(DP_TEST_BIT_DEPTH_8);
case DP_TEST_BIT_DEPTH_10:
return DP_ENUM_STR(DP_TEST_BIT_DEPTH_10);
case DP_TEST_BIT_DEPTH_UNKNOWN:
default:
return "unknown";
}
}
/**
* mdss_dp_is_test_bit_depth_valid() - validates the bit depth requested
* @bit_depth: bit depth requested by the sink
*
* Returns true if the requested bit depth is supported.
*/
static inline bool mdss_dp_is_test_bit_depth_valid(u32 tbd)
{
/* DP_TEST_VIDEO_PATTERN_NONE is treated as invalid */
switch (tbd) {
case DP_TEST_BIT_DEPTH_6:
case DP_TEST_BIT_DEPTH_8:
case DP_TEST_BIT_DEPTH_10:
return true;
default:
return false;
}
}
/**
* mdss_dp_test_bit_depth_to_bpp() - convert test bit depth to bpp
* @tbd: test bit depth
*
* Returns the bits per pixel (bpp) to be used corresponding to the
* git bit depth value. This function assumes that bit depth has
* already been validated.
*/
static inline u32 mdss_dp_test_bit_depth_to_bpp(enum test_bit_depth tbd)
{
u32 bpp;
/*
* Few simplistic rules and assumptions made here:
* 1. Bit depth is per color component
* 2. If bit depth is unknown return 0
* 3. Assume 3 color components
*/
switch (tbd) {
case DP_TEST_BIT_DEPTH_6:
bpp = 18;
break;
case DP_TEST_BIT_DEPTH_8:
bpp = 24;
break;
case DP_TEST_BIT_DEPTH_10:
bpp = 30;
break;
case DP_TEST_BIT_DEPTH_UNKNOWN:
default:
bpp = 0;
}
return bpp;
}
/**
* mdss_dp_bpp_to_test_bit_depth() - convert bpp to test bit depth
* &bpp: the bpp to be converted
*
* Return the bit depth per color component to used with the video
* test pattern data based on the bits per pixel value.
*/
static inline u32 mdss_dp_bpp_to_test_bit_depth(u32 bpp)
{
enum test_bit_depth tbd;
/*
* Few simplistic rules and assumptions made here:
* 1. Test bit depth is bit depth per color component
* 2. Assume 3 color components
*/
switch (bpp) {
case 18:
tbd = DP_TEST_BIT_DEPTH_6;
break;
case 24:
tbd = DP_TEST_BIT_DEPTH_8;
break;
case 30:
tbd = DP_TEST_BIT_DEPTH_10;
break;
default:
tbd = DP_TEST_BIT_DEPTH_UNKNOWN;
break;
}
return tbd;
}
enum test_video_pattern {
DP_TEST_VIDEO_PATTERN_NONE = 0x00,
DP_TEST_VIDEO_PATTERN_COLOR_RAMPS = 0x01,
DP_TEST_VIDEO_PATTERN_BW_VERT_LINES = 0x02,
DP_TEST_VIDEO_PATTERN_COLOR_SQUARE = 0x03,
};
static inline char *mdss_dp_test_video_pattern_to_string(u32 test_video_pattern)
{
switch (test_video_pattern) {
case DP_TEST_VIDEO_PATTERN_NONE:
return DP_ENUM_STR(DP_TEST_VIDEO_PATTERN_NONE);
case DP_TEST_VIDEO_PATTERN_COLOR_RAMPS:
return DP_ENUM_STR(DP_TEST_VIDEO_PATTERN_COLOR_RAMPS);
case DP_TEST_VIDEO_PATTERN_BW_VERT_LINES:
return DP_ENUM_STR(DP_TEST_VIDEO_PATTERN_BW_VERT_LINES);
case DP_TEST_VIDEO_PATTERN_COLOR_SQUARE:
return DP_ENUM_STR(DP_TEST_VIDEO_PATTERN_COLOR_SQUARE);
default:
return "unknown";
}
}
/**
* mdss_dp_is_test_video_pattern_valid() - validates the video pattern
* @pattern: video pattern requested by the sink
*
* Returns true if the requested video pattern is supported.
*/
static inline bool mdss_dp_is_test_video_pattern_valid(u32 pattern)
{
switch (pattern) {
case DP_TEST_VIDEO_PATTERN_NONE:
case DP_TEST_VIDEO_PATTERN_COLOR_RAMPS:
case DP_TEST_VIDEO_PATTERN_BW_VERT_LINES:
case DP_TEST_VIDEO_PATTERN_COLOR_SQUARE:
return true;
default:
return false;
}
}
enum notification_status {
NOTIFY_UNKNOWN,
NOTIFY_CONNECT,
NOTIFY_DISCONNECT,
NOTIFY_CONNECT_IRQ_HPD,
NOTIFY_DISCONNECT_IRQ_HPD,
};
static inline char const *mdss_dp_notification_status_to_string(
enum notification_status status)
{
switch (status) {
case NOTIFY_UNKNOWN:
return DP_ENUM_STR(NOTIFY_UNKNOWN);
case NOTIFY_CONNECT:
return DP_ENUM_STR(NOTIFY_CONNECT);
case NOTIFY_DISCONNECT:
return DP_ENUM_STR(NOTIFY_DISCONNECT);
case NOTIFY_CONNECT_IRQ_HPD:
return DP_ENUM_STR(NOTIFY_CONNECT_IRQ_HPD);
case NOTIFY_DISCONNECT_IRQ_HPD:
return DP_ENUM_STR(NOTIFY_DISCONNECT_IRQ_HPD);
default:
return "unknown";
}
}
static inline void mdss_dp_reset_frame_crc_data(struct mdss_dp_crc_data *crc)
{
if (!crc)
return;
crc->r_cr = 0;
crc->g_y = 0;
crc->b_cb = 0;
crc->en = false;
}
void mdss_dp_phy_initialize(struct mdss_dp_drv_pdata *dp);
void mdss_dp_dpcd_cap_read(struct mdss_dp_drv_pdata *dp);
@ -681,7 +1024,7 @@ void mdss_dp_fill_link_cfg(struct mdss_dp_drv_pdata *ep);
void mdss_dp_sink_power_down(struct mdss_dp_drv_pdata *ep);
void mdss_dp_lane_power_ctrl(struct mdss_dp_drv_pdata *ep, int up);
void mdss_dp_config_ctrl(struct mdss_dp_drv_pdata *ep);
char mdss_dp_gen_link_clk(struct mdss_panel_info *pinfo, char lane_cnt);
char mdss_dp_gen_link_clk(struct mdss_dp_drv_pdata *dp);
int mdss_dp_aux_set_sink_power_state(struct mdss_dp_drv_pdata *ep, char state);
int mdss_dp_aux_send_psm_request(struct mdss_dp_drv_pdata *dp, bool enable);
void mdss_dp_aux_send_test_response(struct mdss_dp_drv_pdata *ep);
@ -694,5 +1037,9 @@ bool mdss_dp_aux_is_lane_count_valid(u32 lane_count);
int mdss_dp_aux_link_status_read(struct mdss_dp_drv_pdata *ep, int len);
void mdss_dp_aux_update_voltage_and_pre_emphasis_lvl(
struct mdss_dp_drv_pdata *dp);
int mdss_dp_aux_read_sink_frame_crc(struct mdss_dp_drv_pdata *dp);
int mdss_dp_aux_config_sink_frame_crc(struct mdss_dp_drv_pdata *dp,
bool enable);
int mdss_dp_aux_parse_vx_px(struct mdss_dp_drv_pdata *ep);
#endif /* MDSS_DP_H */

File diff suppressed because it is too large Load diff

View file

@ -1,4 +1,4 @@
/* Copyright (c) 2016, The Linux Foundation. All rights reserved.
/* Copyright (c) 2016-2017, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@ -370,6 +370,8 @@ static void dp_hdcp2p2_auth_failed(struct dp_hdcp2p2_ctrl *ctrl)
dp_hdcp2p2_set_interrupts(ctrl, false);
atomic_set(&ctrl->auth_state, HDCP_STATE_AUTH_FAIL);
/* notify DP about HDCP failure */
ctrl->init_data.notify_status(ctrl->init_data.cb_data,
HDCP_STATE_AUTH_FAIL);
@ -625,6 +627,12 @@ static void dp_hdcp2p2_link_work(struct kthread_work *work)
return;
}
if (atomic_read(&ctrl->auth_state) == HDCP_STATE_AUTH_FAIL ||
atomic_read(&ctrl->auth_state) == HDCP_STATE_INACTIVE) {
pr_err("invalid hdcp state\n");
return;
}
cdata.context = ctrl->lib_ctx;
if (ctrl->sink_rx_status & ctrl->abort_mask) {
@ -685,6 +693,13 @@ static int dp_hdcp2p2_cp_irq(void *input)
return -EINVAL;
}
if (atomic_read(&ctrl->auth_state) == HDCP_STATE_AUTH_FAIL ||
atomic_read(&ctrl->auth_state) == HDCP_STATE_INACTIVE) {
pr_err("invalid hdcp state\n");
rc = -EINVAL;
goto error;
}
ctrl->sink_rx_status = 0;
rc = mdss_dp_aux_read_rx_status(ctrl->init_data.cb_data,
&ctrl->sink_rx_status);

View file

@ -1,4 +1,4 @@
/* Copyright (c) 2016, The Linux Foundation. All rights reserved.
/* Copyright (c) 2016-2017, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@ -202,6 +202,45 @@ void mdss_dp_configuration_ctrl(struct dss_io_data *ctrl_io, u32 data)
writel_relaxed(data, ctrl_io->base + DP_CONFIGURATION_CTRL);
}
void mdss_dp_config_ctl_frame_crc(struct mdss_dp_drv_pdata *dp, bool enable)
{
if (dp->ctl_crc.en == enable) {
pr_debug("CTL crc already %s\n",
enable ? "enabled" : "disabled");
return;
}
writel_relaxed(BIT(8), dp->ctrl_io.base + MMSS_DP_TIMING_ENGINE_EN);
if (!enable)
mdss_dp_reset_frame_crc_data(&dp->ctl_crc);
dp->ctl_crc.en = enable;
pr_debug("CTL crc %s\n", enable ? "enabled" : "disabled");
}
int mdss_dp_read_ctl_frame_crc(struct mdss_dp_drv_pdata *dp)
{
u32 data;
u32 crc_rg = 0;
struct mdss_dp_crc_data *crc = &dp->ctl_crc;
data = readl_relaxed(dp->ctrl_io.base + MMSS_DP_TIMING_ENGINE_EN);
if (!(data & BIT(8))) {
pr_debug("frame CRC calculation not enabled\n");
return -EPERM;
}
crc_rg = readl_relaxed(dp->ctrl_io.base + MMSS_DP_PSR_CRC_RG);
crc->r_cr = crc_rg & 0xFFFF;
crc->g_y = crc_rg >> 16;
crc->b_cb = readl_relaxed(dp->ctrl_io.base + MMSS_DP_PSR_CRC_B);
pr_debug("r_cr=0x%08x\t g_y=0x%08x\t b_cb=0x%08x\n",
crc->r_cr, crc->g_y, crc->b_cb);
return 0;
}
/* DP state controller*/
void mdss_dp_state_ctrl(struct dss_io_data *ctrl_io, u32 data)
{
@ -735,7 +774,9 @@ void mdss_dp_timing_cfg(struct dss_io_data *ctrl_io,
data = pinfo->lcdc.v_pulse_width;
data <<= 16;
data |= (pinfo->lcdc.v_active_low << 31);
data |= pinfo->lcdc.h_pulse_width;
data |= (pinfo->lcdc.h_active_low << 15);
/* DP_HSYNC_VSYNC_WIDTH_POLARITY */
writel_relaxed(data, ctrl_io->base + DP_HSYNC_VSYNC_WIDTH_POLARITY);
@ -765,28 +806,15 @@ void mdss_dp_sw_config_msa(struct dss_io_data *ctrl_io,
writel_relaxed(nvid, ctrl_io->base + DP_SOFTWARE_NVID);
}
void mdss_dp_config_misc_settings(struct dss_io_data *ctrl_io,
struct mdss_panel_info *pinfo)
void mdss_dp_config_misc(struct mdss_dp_drv_pdata *dp, u32 bd, u32 cc)
{
u32 bpp = pinfo->bpp;
u32 misc_val = 0x0;
switch (bpp) {
case 18:
misc_val |= (0x0 << 5);
break;
case 30:
misc_val |= (0x2 << 5);
break;
case 24:
default:
misc_val |= (0x1 << 5);
}
u32 misc_val = cc;
misc_val |= (bd << 5);
misc_val |= BIT(0); /* Configure clock to synchronous mode */
pr_debug("Misc settings = 0x%x\n", misc_val);
writel_relaxed(misc_val, ctrl_io->base + DP_MISC1_MISC0);
writel_relaxed(misc_val, dp->ctrl_io.base + DP_MISC1_MISC0);
}
void mdss_dp_setup_tr_unit(struct dss_io_data *ctrl_io, u8 link_rate,
@ -1113,7 +1141,8 @@ static u8 mdss_dp_calculate_parity_byte(u32 data)
return parityByte;
}
static void mdss_dp_audio_setup_audio_stream_sdp(struct dss_io_data *ctrl_io)
static void mdss_dp_audio_setup_audio_stream_sdp(struct dss_io_data *ctrl_io,
u32 num_of_channels)
{
u32 value = 0;
u32 new_value = 0;
@ -1131,7 +1160,7 @@ static void mdss_dp_audio_setup_audio_stream_sdp(struct dss_io_data *ctrl_io)
/* Config header and parity byte 2 */
value = readl_relaxed(ctrl_io->base + MMSS_DP_AUDIO_STREAM_1);
new_value = 0x0;
new_value = value;
parity_byte = mdss_dp_calculate_parity_byte(new_value);
value |= ((new_value << HEADER_BYTE_2_BIT)
| (parity_byte << PARITY_BYTE_2_BIT));
@ -1141,7 +1170,7 @@ static void mdss_dp_audio_setup_audio_stream_sdp(struct dss_io_data *ctrl_io)
/* Config header and parity byte 3 */
value = readl_relaxed(ctrl_io->base + MMSS_DP_AUDIO_STREAM_1);
new_value = 0x01;
new_value = num_of_channels - 1;
parity_byte = mdss_dp_calculate_parity_byte(new_value);
value |= ((new_value << HEADER_BYTE_3_BIT)
| (parity_byte << PARITY_BYTE_3_BIT));
@ -1179,7 +1208,7 @@ static void mdss_dp_audio_setup_audio_timestamp_sdp(struct dss_io_data *ctrl_io)
/* Config header and parity byte 3 */
value = readl_relaxed(ctrl_io->base + MMSS_DP_AUDIO_TIMESTAMP_1);
new_value = (0x0 | (0x12 << 2));
new_value = (0x0 | (0x11 << 2));
parity_byte = mdss_dp_calculate_parity_byte(new_value);
value |= ((new_value << HEADER_BYTE_3_BIT)
| (parity_byte << PARITY_BYTE_3_BIT));
@ -1216,7 +1245,7 @@ static void mdss_dp_audio_setup_audio_infoframe_sdp(struct dss_io_data *ctrl_io)
/* Config header and parity byte 3 */
value = readl_relaxed(ctrl_io->base + MMSS_DP_AUDIO_INFOFRAME_1);
new_value = (0x0 | (0x12 << 2));
new_value = (0x0 | (0x11 << 2));
parity_byte = mdss_dp_calculate_parity_byte(new_value);
value |= ((new_value << HEADER_BYTE_3_BIT)
| (parity_byte << PARITY_BYTE_3_BIT));
@ -1309,7 +1338,7 @@ static void mdss_dp_audio_setup_isrc_sdp(struct dss_io_data *ctrl_io)
writel_relaxed(0x0, ctrl_io->base + MMSS_DP_AUDIO_ISRC_4);
}
void mdss_dp_audio_setup_sdps(struct dss_io_data *ctrl_io)
void mdss_dp_audio_setup_sdps(struct dss_io_data *ctrl_io, u32 num_of_channels)
{
u32 sdp_cfg = 0;
u32 sdp_cfg2 = 0;
@ -1335,7 +1364,7 @@ void mdss_dp_audio_setup_sdps(struct dss_io_data *ctrl_io)
writel_relaxed(sdp_cfg2, ctrl_io->base + MMSS_DP_SDP_CFG2);
mdss_dp_audio_setup_audio_stream_sdp(ctrl_io);
mdss_dp_audio_setup_audio_stream_sdp(ctrl_io, num_of_channels);
mdss_dp_audio_setup_audio_timestamp_sdp(ctrl_io);
mdss_dp_audio_setup_audio_infoframe_sdp(ctrl_io);
mdss_dp_audio_setup_copy_management_sdp(ctrl_io);
@ -1366,7 +1395,7 @@ void mdss_dp_set_safe_to_exit_level(struct dss_io_data *ctrl_io,
}
mainlink_levels = readl_relaxed(ctrl_io->base + DP_MAINLINK_LEVELS);
mainlink_levels &= 0xFF0;
mainlink_levels &= 0xFE0;
mainlink_levels |= safe_to_exit_level;
pr_debug("mainlink_level = 0x%x, safe_to_exit_level = 0x%x\n",
@ -1406,28 +1435,17 @@ void mdss_dp_phy_send_test_pattern(struct mdss_dp_drv_pdata *dp)
return;
}
/* Disable mainlink */
writel_relaxed(0x0, io->base + DP_MAINLINK_CTRL);
/* Reset mainlink */
mdss_dp_mainlink_reset(io);
/* Enable mainlink */
writel_relaxed(0x0, io->base + DP_MAINLINK_CTRL);
/* Initialize DP state control */
mdss_dp_state_ctrl(io, 0x00);
writel_relaxed(0x0, io->base + DP_STATE_CTRL);
pr_debug("phy_test_pattern_sel = %s\n",
mdss_dp_get_phy_test_pattern(phy_test_pattern_sel));
switch (phy_test_pattern_sel) {
case PHY_TEST_PATTERN_D10_2_NO_SCRAMBLING:
mdss_dp_state_ctrl(io, BIT(0));
writel_relaxed(0x1, io->base + DP_STATE_CTRL);
break;
case PHY_TEST_PATTERN_SYMBOL_ERR_MEASUREMENT_CNT:
value = readl_relaxed(io->base +
DP_HBR2_COMPLIANCE_SCRAMBLER_RESET);
value &= ~(1 << 16);
writel_relaxed(value, io->base +
DP_HBR2_COMPLIANCE_SCRAMBLER_RESET);
@ -1438,7 +1456,7 @@ void mdss_dp_phy_send_test_pattern(struct mdss_dp_drv_pdata *dp)
mdss_dp_state_ctrl(io, BIT(4));
break;
case PHY_TEST_PATTERN_PRBS7:
mdss_dp_state_ctrl(io, BIT(5));
writel_relaxed(0x20, io->base + DP_STATE_CTRL);
break;
case PHY_TEST_PATTERN_80_BIT_CUSTOM_PATTERN:
mdss_dp_state_ctrl(io, BIT(6));
@ -1453,9 +1471,7 @@ void mdss_dp_phy_send_test_pattern(struct mdss_dp_drv_pdata *dp)
DP_TEST_80BIT_CUSTOM_PATTERN_REG2);
break;
case PHY_TEST_PATTERN_HBR2_CTS_EYE_PATTERN:
value = readl_relaxed(io->base +
DP_HBR2_COMPLIANCE_SCRAMBLER_RESET);
value |= BIT(16);
value = BIT(16);
writel_relaxed(value, io->base +
DP_HBR2_COMPLIANCE_SCRAMBLER_RESET);
value |= 0xFC;
@ -1469,4 +1485,8 @@ void mdss_dp_phy_send_test_pattern(struct mdss_dp_drv_pdata *dp)
phy_test_pattern_sel);
return;
}
value = 0x0;
value = readl_relaxed(io->base + DP_MAINLINK_READY);
pr_info("DP_MAINLINK_READY = 0x%x\n", value);
}

View file

@ -1,4 +1,4 @@
/* Copyright (c) 2016, The Linux Foundation. All rights reserved.
/* Copyright (c) 2016-2017, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@ -65,6 +65,7 @@
#define DP_TEST_80BIT_CUSTOM_PATTERN_REG1 (0x000004C4)
#define DP_TEST_80BIT_CUSTOM_PATTERN_REG2 (0x000004C8)
#define MMSS_DP_MISC1_MISC0 (0x0000042C)
#define MMSS_DP_AUDIO_TIMING_GEN (0x00000480)
#define MMSS_DP_AUDIO_TIMING_RBR_32 (0x00000484)
#define MMSS_DP_AUDIO_TIMING_HBR_32 (0x00000488)
@ -73,6 +74,9 @@
#define MMSS_DP_AUDIO_TIMING_RBR_48 (0x00000494)
#define MMSS_DP_AUDIO_TIMING_HBR_48 (0x00000498)
#define MMSS_DP_PSR_CRC_RG (0x00000554)
#define MMSS_DP_PSR_CRC_B (0x00000558)
#define MMSS_DP_AUDIO_CFG (0x00000600)
#define MMSS_DP_AUDIO_STATUS (0x00000604)
#define MMSS_DP_AUDIO_PKT_CTRL (0x00000608)
@ -135,6 +139,8 @@
#define MMSS_DP_GENERIC1_8 (0x00000748)
#define MMSS_DP_GENERIC1_9 (0x0000074C)
#define MMSS_DP_TIMING_ENGINE_EN (0x00000A10)
/*DP PHY Register offsets */
#define DP_PHY_REVISION_ID0 (0x00000000)
#define DP_PHY_REVISION_ID1 (0x00000004)
@ -285,8 +291,7 @@ void mdss_dp_switch_usb3_phy_to_dp_mode(struct dss_io_data *tcsr_reg_io);
void mdss_dp_assert_phy_reset(struct dss_io_data *ctrl_io, bool assert);
void mdss_dp_setup_tr_unit(struct dss_io_data *ctrl_io, u8 link_rate,
u8 ln_cnt, u32 res, struct mdss_panel_info *pinfo);
void mdss_dp_config_misc_settings(struct dss_io_data *ctrl_io,
struct mdss_panel_info *pinfo);
void mdss_dp_config_misc(struct mdss_dp_drv_pdata *dp, u32 bd, u32 cc);
void mdss_dp_phy_aux_setup(struct dss_io_data *phy_io);
void mdss_dp_hpd_configure(struct dss_io_data *ctrl_io, bool enable);
void mdss_dp_aux_ctrl(struct dss_io_data *ctrl_io, bool enable);
@ -312,7 +317,7 @@ void mdss_dp_phy_share_lane_config(struct dss_io_data *phy_io,
u8 orientation, u8 ln_cnt);
void mdss_dp_config_audio_acr_ctrl(struct dss_io_data *ctrl_io,
char link_rate);
void mdss_dp_audio_setup_sdps(struct dss_io_data *ctrl_io);
void mdss_dp_audio_setup_sdps(struct dss_io_data *ctrl_io, u32 num_of_channels);
void mdss_dp_audio_enable(struct dss_io_data *ctrl_io, bool enable);
void mdss_dp_audio_select_core(struct dss_io_data *ctrl_io);
void mdss_dp_audio_set_sample_rate(struct dss_io_data *ctrl_io,
@ -321,5 +326,7 @@ void mdss_dp_set_safe_to_exit_level(struct dss_io_data *ctrl_io,
uint32_t lane_cnt);
int mdss_dp_aux_read_rx_status(struct mdss_dp_drv_pdata *dp, u8 *rx_status);
void mdss_dp_phy_send_test_pattern(struct mdss_dp_drv_pdata *dp);
void mdss_dp_config_ctl_frame_crc(struct mdss_dp_drv_pdata *dp, bool enable);
int mdss_dp_read_ctl_frame_crc(struct mdss_dp_drv_pdata *dp);
#endif /* __DP_UTIL_H__ */

View file

@ -1,4 +1,4 @@
/* Copyright (c) 2010-2016 The Linux Foundation. All rights reserved.
/* Copyright (c) 2010-2017, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@ -643,7 +643,8 @@ static int hdcp_1x_wait_for_hw_ready(struct hdcp_1x *hdcp)
/* Wait for HDCP keys to be checked and validated */
rc = readl_poll_timeout(io->base + reg_set->status, link0_status,
((link0_status >> reg_set->keys_offset) & 0x7)
== HDCP_KEYS_STATE_VALID,
== HDCP_KEYS_STATE_VALID ||
!hdcp_1x_state(HDCP_STATE_AUTHENTICATING),
HDCP_POLL_SLEEP_US, HDCP_POLL_TIMEOUT_US);
if (IS_ERR_VALUE(rc)) {
pr_err("key not ready\n");
@ -658,7 +659,8 @@ static int hdcp_1x_wait_for_hw_ready(struct hdcp_1x *hdcp)
/* Wait for An0 and An1 bit to be ready */
rc = readl_poll_timeout(io->base + reg_set->status, link0_status,
(link0_status & (BIT(8) | BIT(9))),
(link0_status & (BIT(8) | BIT(9))) ||
!hdcp_1x_state(HDCP_STATE_AUTHENTICATING),
HDCP_POLL_SLEEP_US, HDCP_POLL_TIMEOUT_US);
if (IS_ERR_VALUE(rc)) {
pr_err("An not ready\n");
@ -668,6 +670,9 @@ static int hdcp_1x_wait_for_hw_ready(struct hdcp_1x *hdcp)
/* As per hardware recommendations, wait before reading An */
msleep(20);
error:
if (!hdcp_1x_state(HDCP_STATE_AUTHENTICATING))
rc = -EINVAL;
return rc;
}
@ -820,7 +825,8 @@ static int hdcp_1x_verify_r0(struct hdcp_1x *hdcp)
/* Wait for HDCP R0 computation to be completed */
rc = readl_poll_timeout(io->base + reg_set->status, link0_status,
link0_status & BIT(reg_set->r0_offset),
(link0_status & BIT(reg_set->r0_offset)) ||
!hdcp_1x_state(HDCP_STATE_AUTHENTICATING),
HDCP_POLL_SLEEP_US, HDCP_POLL_TIMEOUT_US);
if (IS_ERR_VALUE(rc)) {
pr_err("R0 not ready\n");
@ -862,10 +868,14 @@ static int hdcp_1x_verify_r0(struct hdcp_1x *hdcp)
DSS_REG_W(io, reg_set->data2_0, (((u32)buf[1]) << 8) | buf[0]);
rc = readl_poll_timeout(io->base + reg_set->status,
link0_status, link0_status & BIT(12),
link0_status, (link0_status & BIT(12)) ||
!hdcp_1x_state(HDCP_STATE_AUTHENTICATING),
r0_read_delay_us, r0_read_timeout_us);
} while (rc && --r0_retry);
error:
if (!hdcp_1x_state(HDCP_STATE_AUTHENTICATING))
rc = -EINVAL;
return rc;
}
@ -1092,9 +1102,9 @@ static int hdcp_1x_write_ksv_fifo(struct hdcp_1x *hdcp)
*/
if (i && !((i + 1) % 64)) {
rc = readl_poll_timeout(io->base + reg_set->sha_status,
sha_status, sha_status & BIT(0),
HDCP_POLL_SLEEP_US,
HDCP_POLL_TIMEOUT_US);
sha_status, (sha_status & BIT(0)) ||
!hdcp_1x_state(HDCP_STATE_AUTHENTICATING),
HDCP_POLL_SLEEP_US, HDCP_POLL_TIMEOUT_US);
if (IS_ERR_VALUE(rc)) {
pr_err("block not done\n");
goto error;
@ -1108,7 +1118,8 @@ static int hdcp_1x_write_ksv_fifo(struct hdcp_1x *hdcp)
/* Now wait for HDCP_SHA_COMP_DONE */
rc = readl_poll_timeout(io->base + reg_set->sha_status, sha_status,
sha_status & BIT(4),
(sha_status & BIT(4)) ||
!hdcp_1x_state(HDCP_STATE_AUTHENTICATING),
HDCP_POLL_SLEEP_US, HDCP_POLL_TIMEOUT_US);
if (IS_ERR_VALUE(rc)) {
pr_err("V computation not done\n");
@ -1117,13 +1128,17 @@ static int hdcp_1x_write_ksv_fifo(struct hdcp_1x *hdcp)
/* Wait for V_MATCHES */
rc = readl_poll_timeout(io->base + reg_set->status, status,
status & BIT(reg_set->v_offset),
(status & BIT(reg_set->v_offset)) ||
!hdcp_1x_state(HDCP_STATE_AUTHENTICATING),
HDCP_POLL_SLEEP_US, HDCP_POLL_TIMEOUT_US);
if (IS_ERR_VALUE(rc)) {
pr_err("V mismatch\n");
rc = -EINVAL;
}
error:
if (!hdcp_1x_state(HDCP_STATE_AUTHENTICATING))
rc = -EINVAL;
return rc;
}
@ -1273,8 +1288,6 @@ static void hdcp_1x_update_auth_status(struct hdcp_1x *hdcp)
if (hdcp_1x_state(HDCP_STATE_AUTHENTICATED)) {
hdcp_1x_cache_topology(hdcp);
hdcp_1x_notify_topology(hdcp);
} else {
hdcp1_set_enc(false);
}
if (hdcp->init_data.notify_status &&
@ -1459,9 +1472,6 @@ void hdcp_1x_off(void *input)
return;
}
if (hdcp_1x_state(HDCP_STATE_AUTHENTICATED))
hdcp1_set_enc(false);
/*
* Disable HDCP interrupts.
* Also, need to set the state to inactive here so that any ongoing
@ -1482,11 +1492,13 @@ void hdcp_1x_off(void *input)
* No more reauthentiaction attempts will be scheduled since we
* set the currect state to inactive.
*/
rc = cancel_delayed_work(&hdcp->hdcp_auth_work);
rc = cancel_delayed_work_sync(&hdcp->hdcp_auth_work);
if (rc)
pr_debug("%s: Deleted hdcp auth work\n",
HDCP_STATE_NAME);
hdcp1_set_enc(false);
reg = DSS_REG_R(io, reg_set->reset);
DSS_REG_W(io, reg_set->reset, reg | reg_set->reset_bit);

View file

@ -1,4 +1,4 @@
/* Copyright (c) 2010-2016, The Linux Foundation. All rights reserved.
/* Copyright (c) 2010-2017, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@ -122,13 +122,6 @@ struct hdmi_edid_sink_caps {
bool ind_view_support;
};
struct hdmi_edid_override_data {
int scramble;
int sink_mode;
int format;
int vic;
};
struct hdmi_edid_ctrl {
u8 pt_scan_info;
u8 it_scan_info;
@ -1607,9 +1600,14 @@ static void hdmi_edid_detail_desc(struct hdmi_edid_ctrl *edid_ctrl,
(timing.refresh_rate % 100) / 10,
timing.refresh_rate % 10);
rc = hdmi_get_video_id_code(&timing, NULL);
if (rc < 0)
rc = hdmi_set_resv_timing_info(&timing);
/*
* Always add resolutions parsed from DTD in the reserved
* timing info. This can avoid matching resolutions that have
* a non-integral fps denominators with corresponding
* resolutions that have an integral fps denominator.
* For example - 640x480p@59.94Hz --> 640x480p@60Hz
*/
rc = hdmi_set_resv_timing_info(&timing);
} else {
rc = -EINVAL;
}
@ -1983,7 +1981,6 @@ static void hdmi_edid_get_display_mode(struct hdmi_edid_ctrl *edid_ctrl)
{
u8 i = 0, offset = 0, std_blk = 0;
u32 video_format = HDMI_VFRMT_640x480p60_4_3;
u32 has480p = false;
u8 len = 0;
u8 num_of_cea_blocks;
u8 *data_buf;
@ -2046,9 +2043,6 @@ static void hdmi_edid_get_display_mode(struct hdmi_edid_ctrl *edid_ctrl)
video_format == HDMI_VFRMT_2880x576p50_16_9 ||
video_format == HDMI_VFRMT_1920x1250i50_16_9)
has50hz_mode = true;
if (video_format == HDMI_VFRMT_640x480p60_4_3)
has480p = true;
}
}
@ -2067,9 +2061,6 @@ static void hdmi_edid_get_display_mode(struct hdmi_edid_ctrl *edid_ctrl)
hdmi_edid_add_sink_video_format(edid_ctrl,
video_format);
if (video_format == HDMI_VFRMT_640x480p60_4_3)
has480p = true;
/* Make a note of the preferred video format */
if (i == 0)
sink_data->preferred_video_format =
@ -2091,7 +2082,7 @@ static void hdmi_edid_get_display_mode(struct hdmi_edid_ctrl *edid_ctrl)
desc_offset = edid_blk1[0x02];
if (desc_offset < (EDID_BLOCK_SIZE - EDID_DTD_LEN)) {
i = 0;
while (!edid_blk1[desc_offset]) {
while ((i < 4) && edid_blk1[desc_offset]) {
hdmi_edid_detail_desc(edid_ctrl,
edid_blk1+desc_offset,
&video_format);
@ -2103,8 +2094,6 @@ static void hdmi_edid_get_display_mode(struct hdmi_edid_ctrl *edid_ctrl)
hdmi_edid_add_sink_video_format(edid_ctrl,
video_format);
if (video_format == HDMI_VFRMT_640x480p60_4_3)
has480p = true;
/* Make a note of the preferred video format */
if (i == 0) {
@ -2192,15 +2181,6 @@ static void hdmi_edid_get_display_mode(struct hdmi_edid_ctrl *edid_ctrl)
if (!rc)
pr_debug("%s: 3D formats in VSD\n", __func__);
}
/*
* Need to add default 640 by 480 timings, in case not described
* in the EDID structure.
* All DTV sink devices should support this mode
*/
if (!has480p)
hdmi_edid_add_sink_video_format(edid_ctrl,
HDMI_VFRMT_640x480p60_4_3);
} /* hdmi_edid_get_display_mode */
u32 hdmi_edid_get_raw_data(void *input, u8 *buf, u32 size)
@ -2610,6 +2590,31 @@ void hdmi_edid_set_video_resolution(void *input, u32 resolution, bool reset)
}
} /* hdmi_edid_set_video_resolution */
void hdmi_edid_config_override(void *input, bool enable,
struct hdmi_edid_override_data *data)
{
struct hdmi_edid_ctrl *edid_ctrl = (struct hdmi_edid_ctrl *)input;
struct hdmi_edid_override_data *ov_data = &edid_ctrl->override_data;
if ((!edid_ctrl) || (enable && !data)) {
DEV_ERR("%s: invalid input\n", __func__);
return;
}
edid_ctrl->edid_override = enable;
pr_debug("EDID override %s\n", enable ? "enabled" : "disabled");
if (enable) {
ov_data->scramble = data->scramble;
ov_data->sink_mode = data->sink_mode;
ov_data->format = data->format;
ov_data->vic = data->vic;
pr_debug("%s: Override data: scramble=%d sink_mode=%d format=%d vic=%d\n",
__func__, ov_data->scramble, ov_data->sink_mode,
ov_data->format, ov_data->vic);
}
}
void hdmi_edid_deinit(void *input)
{
struct hdmi_edid_ctrl *edid_ctrl = (struct hdmi_edid_ctrl *)input;

View file

@ -1,4 +1,4 @@
/* Copyright (c) 2010-2016, The Linux Foundation. All rights reserved.
/* Copyright (c) 2010-2017, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@ -44,6 +44,20 @@ struct hdmi_edid_hdr_data {
u32 min_luminance;
};
/*
* struct hdmi_override_data - Resolution Override Data
* @scramble - scrambler enable
* @sink_mode - 0 for DVI and 1 for HDMI
* @format - pixel format (refer to msm_hdmi_modes.h)
* @vic - resolution code
*/
struct hdmi_edid_override_data {
int scramble;
int sink_mode;
int format;
int vic;
};
int hdmi_edid_parser(void *edid_ctrl);
u32 hdmi_edid_get_raw_data(void *edid_ctrl, u8 *buf, u32 size);
u8 hdmi_edid_get_sink_scaninfo(void *edid_ctrl, u32 resolution);
@ -63,5 +77,7 @@ u8 hdmi_edid_get_deep_color(void *edid_ctrl);
u32 hdmi_edid_get_max_pclk(void *edid_ctrl);
void hdmi_edid_get_hdr_data(void *edid_ctrl,
struct hdmi_edid_hdr_data **hdr_data);
void hdmi_edid_config_override(void *input, bool enable,
struct hdmi_edid_override_data *data);
#endif /* __HDMI_EDID_H__ */

View file

@ -1,4 +1,4 @@
/* Copyright (c) 2010-2016, The Linux Foundation. All rights reserved.
/* Copyright (c) 2010-2017, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@ -421,8 +421,10 @@ static inline void hdmi_tx_send_cable_notification(
if (hdmi_ctrl && hdmi_ctrl->ext_audio_data.intf_ops.hpd) {
u32 flags = 0;
if (hdmi_tx_is_dvi_mode(hdmi_ctrl))
flags |= MSM_EXT_DISP_HPD_NO_AUDIO;
flags |= MSM_EXT_DISP_HPD_VIDEO;
if (!hdmi_tx_is_dvi_mode(hdmi_ctrl))
flags |= MSM_EXT_DISP_HPD_AUDIO;
hdmi_ctrl->ext_audio_data.intf_ops.hpd(hdmi_ctrl->ext_pdev,
hdmi_ctrl->ext_audio_data.type, val, flags);

View file

@ -1,4 +1,4 @@
/* Copyright (c) 2010-2016, The Linux Foundation. All rights reserved.
/* Copyright (c) 2010-2017, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@ -555,6 +555,9 @@ int msm_hdmi_get_timing_info(
case HDMI_VFRMT_3840x2160p60_64_27:
MSM_HDMI_MODES_GET_DETAILS(mode, HDMI_VFRMT_3840x2160p60_64_27);
break;
case HDMI_VFRMT_640x480p59_4_3:
MSM_HDMI_MODES_GET_DETAILS(mode, HDMI_VFRMT_640x480p59_4_3);
break;
default:
ret = hdmi_get_resv_timing_info(mode, id);
}

View file

@ -1,4 +1,4 @@
/* Copyright (c) 2008-2016, The Linux Foundation. All rights reserved.
/* Copyright (c) 2008-2017, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@ -372,9 +372,11 @@ struct lcd_panel_info {
u32 h_back_porch;
u32 h_front_porch;
u32 h_pulse_width;
u32 h_active_low;
u32 v_back_porch;
u32 v_front_porch;
u32 v_pulse_width;
u32 v_active_low;
u32 border_clr;
u32 underflow_clr;
u32 hsync_skew;

View file

@ -1,4 +1,4 @@
/* Copyright (c) 2016, The Linux Foundation. All rights reserved.
/* Copyright (c) 2016-2017, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@ -42,6 +42,7 @@ struct msm_ext_disp {
struct list_head display_list;
struct mutex lock;
struct completion hpd_comp;
u32 flags;
};
static int msm_ext_disp_get_intf_data(struct msm_ext_disp *ext_disp,
@ -365,7 +366,7 @@ static int msm_ext_disp_process_display(struct msm_ext_disp *ext_disp,
{
int ret = 0;
if (flags & MSM_EXT_DISP_HPD_NO_VIDEO) {
if (!(flags & MSM_EXT_DISP_HPD_VIDEO)) {
pr_debug("skipping video setup for display (%s)\n",
msm_ext_disp_name(type));
goto end;
@ -398,7 +399,7 @@ static int msm_ext_disp_process_audio(struct msm_ext_disp *ext_disp,
{
int ret = 0;
if (flags & MSM_EXT_DISP_HPD_NO_AUDIO) {
if (!(flags & MSM_EXT_DISP_HPD_AUDIO)) {
pr_debug("skipping audio setup for display (%s)\n",
msm_ext_disp_name(type));
goto end;
@ -425,6 +426,47 @@ end:
return ret;
}
static bool msm_ext_disp_validate_connect(struct msm_ext_disp *ext_disp,
enum msm_ext_disp_type type, u32 flags)
{
/* allow new connections */
if (ext_disp->current_disp == EXT_DISPLAY_TYPE_MAX)
goto end;
/* if already connected, block a new connection */
if (ext_disp->current_disp != type)
return false;
/* if same display connected, block same connection type */
if (ext_disp->flags & flags)
return false;
end:
ext_disp->flags |= flags;
ext_disp->current_disp = type;
return true;
}
static bool msm_ext_disp_validate_disconnect(struct msm_ext_disp *ext_disp,
enum msm_ext_disp_type type, u32 flags)
{
/* check if nothing connected */
if (ext_disp->current_disp == EXT_DISPLAY_TYPE_MAX)
return false;
/* check if a different display's request */
if (ext_disp->current_disp != type)
return false;
/* allow only an already connected type */
if (ext_disp->flags & flags) {
ext_disp->flags &= ~flags;
return true;
}
return false;
}
static int msm_ext_disp_hpd(struct platform_device *pdev,
enum msm_ext_disp_type type,
enum msm_ext_disp_cable_state state,
@ -446,8 +488,8 @@ static int msm_ext_disp_hpd(struct platform_device *pdev,
mutex_lock(&ext_disp->lock);
pr_debug("HPD for display (%s), NEW STATE = %d\n",
msm_ext_disp_name(type), state);
pr_debug("HPD for display (%s), NEW STATE = %d, flags = %d\n",
msm_ext_disp_name(type), state, flags);
if (state < EXT_DISPLAY_CABLE_DISCONNECT ||
state >= EXT_DISPLAY_CABLE_STATE_MAX) {
@ -456,24 +498,13 @@ static int msm_ext_disp_hpd(struct platform_device *pdev,
goto end;
}
if ((state == EXT_DISPLAY_CABLE_CONNECT) &&
(ext_disp->current_disp != EXT_DISPLAY_TYPE_MAX)) {
pr_err("Display interface (%s) already connected\n",
msm_ext_disp_name(ext_disp->current_disp));
ret = -EINVAL;
goto end;
}
if ((state == EXT_DISPLAY_CABLE_DISCONNECT) &&
(ext_disp->current_disp != type)) {
pr_err("Display interface (%s) is not connected\n",
msm_ext_disp_name(type));
ret = -EINVAL;
goto end;
}
if (state == EXT_DISPLAY_CABLE_CONNECT) {
ext_disp->current_disp = type;
if (!msm_ext_disp_validate_connect(ext_disp, type, flags)) {
pr_err("Display interface (%s) already connected\n",
msm_ext_disp_name(ext_disp->current_disp));
ret = -EINVAL;
goto end;
}
ret = msm_ext_disp_process_display(ext_disp, type, state,
flags);
@ -490,11 +521,19 @@ static int msm_ext_disp_hpd(struct platform_device *pdev,
if (ret)
goto end;
} else {
if (!msm_ext_disp_validate_disconnect(ext_disp, type, flags)) {
pr_err("Display interface (%s) not connected\n",
msm_ext_disp_name(type));
ret = -EINVAL;
goto end;
}
msm_ext_disp_process_audio(ext_disp, type, state, flags);
msm_ext_disp_update_audio_ops(ext_disp, type, state, flags);
msm_ext_disp_process_display(ext_disp, type, state, flags);
ext_disp->current_disp = EXT_DISPLAY_TYPE_MAX;
if (!ext_disp->flags)
ext_disp->current_disp = EXT_DISPLAY_TYPE_MAX;
}
pr_debug("Hpd (%d) for display (%s)\n", state,
@ -653,7 +692,7 @@ static int msm_ext_disp_update_audio_ops(struct msm_ext_disp *ext_disp,
int ret = 0;
struct msm_ext_disp_audio_codec_ops *ops = ext_disp->ops;
if (flags & MSM_EXT_DISP_HPD_NO_AUDIO) {
if (!(flags & MSM_EXT_DISP_HPD_AUDIO)) {
pr_debug("skipping audio ops setup for display (%s)\n",
msm_ext_disp_name(type));
goto end;

View file

@ -1,6 +1,6 @@
/* include/linux/msm_ext_display.h
*
* Copyright (c) 2014-2016 The Linux Foundation. All rights reserved.
* Copyright (c) 2014-2017, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@ -24,11 +24,11 @@
/**
* Flags to be used with the HPD operation of the external display
* interface:
* MSM_EXT_DISP_HPD_NO_AUDIO: audio will not be routed to external display
* MSM_EXT_DISP_HPD_NO_VIDEO: video will not be routed to external display
* MSM_EXT_DISP_HPD_AUDIO: audio will be routed to external display
* MSM_EXT_DISP_HPD_VIDEO: video will be routed to external display
*/
#define MSM_EXT_DISP_HPD_NO_AUDIO BIT(0)
#define MSM_EXT_DISP_HPD_NO_VIDEO BIT(1)
#define MSM_EXT_DISP_HPD_AUDIO BIT(0)
#define MSM_EXT_DISP_HPD_VIDEO BIT(1)
/**
* struct ext_disp_cable_notify - cable notify handler structure

View file

@ -234,7 +234,11 @@ struct msm_hdmi_mode_timing_info {
#define HDMI_VFRMT_1920x1200p60_16_10 ETIII_OFF(8)
#define ETIII_VFRMT_END HDMI_VFRMT_1920x1200p60_16_10
#define RESERVE_OFF(x) (ETIII_VFRMT_END + x)
#define MISC_VFRMT_OFF(x) (ETIII_VFRMT_END + x)
#define HDMI_VFRMT_640x480p59_4_3 MISC_VFRMT_OFF(1)
#define MISC_VFRMT_END HDMI_VFRMT_640x480p59_4_3
#define RESERVE_OFF(x) (MISC_VFRMT_END + x)
#define HDMI_VFRMT_RESERVE1 RESERVE_OFF(1)
#define HDMI_VFRMT_RESERVE2 RESERVE_OFF(2)
@ -425,6 +429,11 @@ struct msm_hdmi_mode_timing_info {
{HDMI_VFRMT_3840x2160p60_64_27, 3840, 176, 88, 296, false, \
2160, 8, 10, 72, false, 594000, 60000, false, true, \
HDMI_RES_AR_64_27, 0}
#define HDMI_VFRMT_640x480p59_4_3_TIMING \
{HDMI_VFRMT_640x480p59_4_3, 640, 16, 96, 48, true, \
480, 10, 2, 33, true, 25170, 59928, false, true, \
HDMI_RES_AR_4_3, 1}
#define MSM_HDMI_MODES_SET_TIMING(LUT, MODE) do { \
struct msm_hdmi_mode_timing_info mode = MODE##_TIMING; \
@ -508,6 +517,8 @@ do { \
HDMI_VFRMT_3840x2160p50_64_27); \
MSM_HDMI_MODES_SET_TIMING(__lut, \
HDMI_VFRMT_3840x2160p60_64_27); \
MSM_HDMI_MODES_SET_TIMING(__lut, \
HDMI_VFRMT_640x480p59_4_3); \
} \
if (__type & MSM_HDMI_MODES_XTND) { \
MSM_HDMI_MODES_SET_TIMING(__lut, \