Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 21d19f62 authored by Linux Build Service Account's avatar Linux Build Service Account
Browse files

Promotion of kernel.lnx.4.4-161012.

CRs      Change ID                                   Subject
--------------------------------------------------------------------------------------------------------------
1070113   Ia9f26e8cf9a86c34d7fee3afee599d9924dd9835   msm: mdss: displayport: replace delayed work with work
1070113   I113988eb21f82eef022723c421b1c1c9d4dead9f   msm: mdss: edid: parse dtd and proper fps and pclk check
1068178   I703dc38bf7961291d40044f6517cdfa7cc69d85a   msm: mdss: displayport: fix edid read
1070113   I71139c504d9031839ff3c14cdd8cd6fdd885719d   msm: mdss: displayport: fix link training 2 for dp dongl
1070113   I6c6f9e0c9738af4766a7ff8acb3c932be55935de   msm: mdss: displayport: fix alt mode pin configurations

Change-Id: Ibef8b6f521cb23e4b37c57e8b027286fc023a7d2
CRs-Fixed: 1070113, 1068178
parents d4678902 c30ea8b0
Loading
Loading
Loading
Loading
+10 −12
Original line number Diff line number Diff line
@@ -1022,6 +1022,8 @@ static int dp_init_panel_info(struct mdss_dp_drv_pdata *dp_drv, u32 vic)
	pinfo->lcdc.hsync_skew = 0;
	pinfo->is_pluggable = true;

	dp_drv->bpp = pinfo->bpp;

	pr_debug("update res. vic= %d, pclk_rate = %llu\n",
				dp_drv->vic, pinfo->clk_rate);

@@ -1786,16 +1788,15 @@ static void mdss_dp_do_link_train(struct mdss_dp_drv_pdata *dp)
static void mdss_dp_event_work(struct work_struct *work)
{
	struct mdss_dp_drv_pdata *dp = NULL;
	struct delayed_work *dw = to_delayed_work(work);
	unsigned long flag;
	u32 todo = 0, dp_config_pkt[2];
	u32 todo = 0, config;

	if (!dw) {
	if (!work) {
		pr_err("invalid work structure\n");
		return;
	}

	dp = container_of(dw, struct mdss_dp_drv_pdata, dwork);
	dp = container_of(work, struct mdss_dp_drv_pdata, work);

	spin_lock_irqsave(&dp->event_lock, flag);
	todo = dp->current_event;
@@ -1840,11 +1841,9 @@ static void mdss_dp_event_work(struct work_struct *work)
			SVDM_CMD_TYPE_INITIATOR, 0x1, 0x0, 0x0);
		break;
	case EV_USBPD_DP_CONFIGURE:
		dp_config_pkt[0] = SVDM_HDR(USB_C_DP_SID, VDM_VERSION, 0x1,
			SVDM_CMD_TYPE_INITIATOR, DP_VDM_CONFIGURE);
		dp_config_pkt[1] = mdss_dp_usbpd_gen_config_pkt(dp);
		config = mdss_dp_usbpd_gen_config_pkt(dp);
		usbpd_send_svdm(dp->pd, USB_C_DP_SID, DP_VDM_CONFIGURE,
			SVDM_CMD_TYPE_INITIATOR, 0x1, dp_config_pkt, 0x2);
			SVDM_CMD_TYPE_INITIATOR, 0x1, &config, 0x1);
		break;
	default:
		pr_err("Unknown event:%d\n", todo);
@@ -1855,7 +1854,7 @@ static void dp_send_events(struct mdss_dp_drv_pdata *dp, u32 events)
{
	spin_lock(&dp->event_lock);
	dp->current_event = events;
	queue_delayed_work(dp->workq, &dp->dwork, HZ / 100);
	queue_work(dp->workq, &dp->work);
	spin_unlock(&dp->event_lock);
}

@@ -1931,7 +1930,7 @@ static int mdss_dp_event_setup(struct mdss_dp_drv_pdata *dp)
		return -EPERM;
	}

	INIT_DELAYED_WORK(&dp->dwork, mdss_dp_event_work);
	INIT_WORK(&dp->work, mdss_dp_event_work);
	return 0;
}

@@ -2050,8 +2049,7 @@ static void usbpd_response_callback(struct usbpd_svid_handler *hdlr, u8 cmd,
		}
		break;
	case DP_VDM_CONFIGURE:
		if ((dp_drv->cable_connected == true)
				|| (cmd_type == SVDM_CMD_TYPE_RESP_ACK)) {
		if (cmd_type == SVDM_CMD_TYPE_RESP_ACK) {
			dp_drv->alt_mode.current_state = DP_CONFIGURE_DONE;
			pr_debug("config USBPD to DP done\n");
			mdss_dp_host_init(&dp_drv->panel_data);
+1 −1
Original line number Diff line number Diff line
@@ -428,7 +428,7 @@ struct mdss_dp_drv_pdata {

	/* event */
	struct workqueue_struct *workq;
	struct delayed_work dwork;
	struct work_struct work;
	u32 current_event;
	spinlock_t event_lock;
	spinlock_t lock;
+63 −75
Original line number Diff line number Diff line
@@ -374,7 +374,19 @@ static int dp_aux_read_buf(struct mdss_dp_drv_pdata *ep, u32 addr,
/*
 * edid standard header bytes
 */
static char edid_hdr[8] = {0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00};
static u8 edid_hdr[8] = {0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00};

static bool dp_edid_is_valid_header(u8 *buf)
{
	int i;

	for (i = 0; i < ARRAY_SIZE(edid_hdr); i++) {
		if (buf[i] != edid_hdr[i])
			return false;
	}

	return true;
}

int dp_edid_buf_error(char *buf, int len)
{
@@ -396,11 +408,6 @@ int dp_edid_buf_error(char *buf, int len)
		return -EINVAL;
	}

	if (strncmp(buf, edid_hdr, strlen(edid_hdr))) {
		pr_err("Error: header\n");
		return -EINVAL;
	}

	return 0;
}

@@ -708,10 +715,11 @@ static int dp_aux_chan_ready(struct mdss_dp_drv_pdata *ep)

int mdss_dp_edid_read(struct mdss_dp_drv_pdata *dp)
{
	struct edp_buf *rp;
	int cnt, rlen;
	int ret = 0;
	int blk_num = 0;
	struct edp_buf *rp = &dp->rxp;
	int rlen, ret = 0;
	int edid_blk = 0, blk_num = 0, retries = 10;
	bool edid_parsing_done = false;
	const u8 cea_tag = 0x02;

	ret = dp_aux_chan_ready(dp);
	if (ret) {
@@ -719,25 +727,25 @@ int mdss_dp_edid_read(struct mdss_dp_drv_pdata *dp)
		return ret;
	}

	for (cnt = 5; cnt; cnt--) {
		rlen = dp_aux_read_buf
			(dp, EDID_START_ADDRESS, EDID_BLOCK_SIZE, 1);
		if (rlen > 0) {
			pr_debug("cnt=%d, block=%d, rlen=%d\n",
					cnt, blk_num, rlen);

			rp = &dp->rxp;
			if (!dp_edid_buf_error(rp->data, rp->len))
				break;
		}
	}

	if ((cnt <= 0) && (rlen != EDID_BLOCK_SIZE)) {
	do {
		rlen = dp_aux_read_buf(dp, EDID_START_ADDRESS +
				(blk_num * EDID_BLOCK_SIZE),
				EDID_BLOCK_SIZE, 1);
		if (rlen != EDID_BLOCK_SIZE) {
			pr_err("Read failed. rlen=%d\n", rlen);
		return -EINVAL;
			continue;
		}

	rp = &dp->rxp;
		pr_debug("blk_num=%d, rlen=%d\n", blk_num, rlen);

		if (dp_edid_is_valid_header(rp->data)) {
			if (dp_edid_buf_error(rp->data, rp->len))
				continue;

			if (edid_parsing_done) {
				blk_num++;
				continue;
			}

			dp_extract_edid_manufacturer(&dp->edid, rp->data);
			dp_extract_edid_product(&dp->edid, rp->data);
@@ -745,44 +753,30 @@ int mdss_dp_edid_read(struct mdss_dp_drv_pdata *dp)
			dp_extract_edid_ext_block_cnt(&dp->edid, rp->data);
			dp_extract_edid_video_support(&dp->edid, rp->data);
			dp_extract_edid_feature(&dp->edid, rp->data);
	dp_extract_edid_detailed_timing_description(&dp->edid, rp->data);
	/* for the first block initialize the edid buffer size */
	dp->edid_buf_size = 0;

	pr_debug("edid extension = %d\n",
			dp->edid.ext_block_cnt);
			dp_extract_edid_detailed_timing_description(&dp->edid,
				rp->data);

	memcpy(dp->edid_buf, rp->data, EDID_BLOCK_SIZE);
	dp->edid_buf_size += EDID_BLOCK_SIZE;
			edid_parsing_done = true;
		} else {
			edid_blk++;
			blk_num++;

	if (!dp->edid.ext_block_cnt)
		return 0;
			/* fix dongle byte shift issue */
			if (edid_blk == 1 && rp->data[0] != cea_tag) {
				u8 tmp[EDID_BLOCK_SIZE - 1];

	for (blk_num = 1; blk_num <= dp->edid.ext_block_cnt;
			blk_num++) {
		for (cnt = 5; cnt; cnt--) {
			rlen = dp_aux_read_buf
				(dp, EDID_START_ADDRESS +
				 (blk_num * EDID_BLOCK_SIZE),
				 EDID_BLOCK_SIZE, 1);
			if (rlen > 0) {
				pr_debug("cnt=%d, blk_num=%d, rlen=%d\n",
						cnt, blk_num, rlen);
				rp = &dp->rxp;
				if (!dp_edid_buf_error(rp->data, rp->len))
					break;
				memcpy(tmp, rp->data, EDID_BLOCK_SIZE - 1);
				rp->data[0] = cea_tag;
				memcpy(rp->data + 1, tmp, EDID_BLOCK_SIZE - 1);
			}
		}

		if ((cnt <= 0) && (rlen != EDID_BLOCK_SIZE)) {
			pr_err("Read failed. rlen=%d\n", rlen);
			return -EINVAL;
		}

		memcpy(dp->edid_buf + (blk_num * EDID_BLOCK_SIZE),
		memcpy(dp->edid_buf + (edid_blk * EDID_BLOCK_SIZE),
			rp->data, EDID_BLOCK_SIZE);
		dp->edid_buf_size += EDID_BLOCK_SIZE;
	}

		if (edid_blk == dp->edid.ext_block_cnt)
			return 0;
	} while (retries--);

	return 0;
}
@@ -1220,7 +1214,7 @@ static int dp_start_link_train_1(struct mdss_dp_drv_pdata *ep)

static int dp_start_link_train_2(struct mdss_dp_drv_pdata *ep)
{
	int tries;
	int tries = 0;
	int ret = 0;
	int usleep_time;
	char pattern;
@@ -1232,12 +1226,12 @@ static int dp_start_link_train_2(struct mdss_dp_drv_pdata *ep)
	else
		pattern = 0x02;

	dp_host_train_set(ep, pattern); /* train_2 */
	dp_voltage_pre_emphasise_set(ep);
	dp_train_pattern_set_write(ep, pattern | 0x20);/* train_2 */

	tries = 0;
	while (1) {
	do  {
		dp_voltage_pre_emphasise_set(ep);
		dp_host_train_set(ep, pattern);

		usleep_time = ep->dpcd.training_read_interval;
		usleep_range(usleep_time, usleep_time);

@@ -1249,14 +1243,13 @@ static int dp_start_link_train_2(struct mdss_dp_drv_pdata *ep)
		}

		tries++;
		if (tries > 5) {
		if (tries > 4) {
			ret = -1;
			break;
		}

		dp_sink_train_set_adjust(ep);
		dp_voltage_pre_emphasise_set(ep);
	}
	} while (1);

	return ret;
}
@@ -1328,7 +1321,6 @@ static void dp_clear_training_pattern(struct mdss_dp_drv_pdata *ep)
int mdss_dp_link_train(struct mdss_dp_drv_pdata *dp)
{
	int ret = 0;
	int usleep_time;

	ret = dp_aux_chan_ready(dp);
	if (ret) {
@@ -1349,8 +1341,6 @@ train_start:

	mdss_dp_state_ctrl(&dp->ctrl_io, 0);
	dp_clear_training_pattern(dp);
	usleep_time = dp->dpcd.training_read_interval;
	usleep_range(usleep_time, usleep_time);

	ret = dp_start_link_train_1(dp);
	if (ret < 0) {
@@ -1365,8 +1355,6 @@ train_start:

	pr_debug("Training 1 completed successfully\n");

	mdss_dp_state_ctrl(&dp->ctrl_io, 0);
	dp_clear_training_pattern(dp);
	ret = dp_start_link_train_2(dp);
	if (ret < 0) {
		if (dp_link_rate_down_shift(dp) == 0) {
+38 −1
Original line number Diff line number Diff line
@@ -32,6 +32,29 @@
#define AUDIO_FREQ_48		48000
#define DP_AUDIO_FREQ_COUNT	3

enum mdss_dp_pin_assignment {
	PIN_ASSIGNMENT_A,
	PIN_ASSIGNMENT_B,
	PIN_ASSIGNMENT_C,
	PIN_ASSIGNMENT_D,
	PIN_ASSIGNMENT_E,
	PIN_ASSIGNMENT_F,
	PIN_ASSIGNMENT_MAX,
};

static const char *mdss_dp_pin_name(u8 pin)
{
	switch (pin) {
	case PIN_ASSIGNMENT_A: return "PIN_ASSIGNMENT_A";
	case PIN_ASSIGNMENT_B: return "PIN_ASSIGNMENT_B";
	case PIN_ASSIGNMENT_C: return "PIN_ASSIGNMENT_C";
	case PIN_ASSIGNMENT_D: return "PIN_ASSIGNMENT_D";
	case PIN_ASSIGNMENT_E: return "PIN_ASSIGNMENT_E";
	case PIN_ASSIGNMENT_F: return "PIN_ASSIGNMENT_F";
	default: return "UNKNOWN";
	}
}

static const uint32_t naud_value[DP_AUDIO_FREQ_COUNT][DP_AUDIO_FREQ_COUNT] = {
	{ 10125, 16875, 33750 },
	{ 5625, 9375, 18750 },
@@ -477,9 +500,23 @@ void mdss_dp_usbpd_ext_dp_status(struct usbpd_dp_status *dp_status)

u32 mdss_dp_usbpd_gen_config_pkt(struct mdss_dp_drv_pdata *dp)
{
	u8 pin_cfg, pin;
	u32 config = 0;

	config |= (dp->alt_mode.dp_cap.dlink_pin_config << 8);
	pin_cfg = dp->alt_mode.dp_cap.dlink_pin_config;

	for (pin = PIN_ASSIGNMENT_A; pin < PIN_ASSIGNMENT_MAX; pin++) {
		if (pin_cfg & BIT(pin))
			break;
	}

	if (pin == PIN_ASSIGNMENT_MAX)
		pin = PIN_ASSIGNMENT_C;

	pr_debug("pin assignment: %s\n", mdss_dp_pin_name(pin));

	config |= BIT(pin) << 8;

	config |= (0x1 << 2); /* configure for DPv1.3 */
	config |= 0x2; /* Configuring for UFP_D */

+75 −95
Original line number Diff line number Diff line
@@ -698,7 +698,6 @@ static ssize_t hdmi_edid_sysfs_rda_3d_modes(struct device *dev,
		}
	}

	DEV_DBG("%s: '%s'\n", __func__, buf);
	ret += scnprintf(buf + ret, PAGE_SIZE - ret, "\n");

	return ret;
@@ -1567,7 +1566,9 @@ static void hdmi_edid_detail_desc(struct hdmi_edid_ctrl *edid_ctrl,
	frame_data = (active_h + blank_h) * (active_v + blank_v);

	if (frame_data) {
		int refresh_rate_khz = (pixel_clk * khz_to_hz) / frame_data;
		u64 refresh_rate = (u64)pixel_clk * khz_to_hz * khz_to_hz;

		do_div(refresh_rate, frame_data);

		timing.active_h      = active_h;
		timing.front_porch_h = front_porch_h;
@@ -1582,18 +1583,23 @@ static void hdmi_edid_detail_desc(struct hdmi_edid_ctrl *edid_ctrl,
					(front_porch_v + pulse_width_v);
		timing.active_low_v  = active_low_v;
		timing.pixel_freq    = pixel_clk;
		timing.refresh_rate  = refresh_rate_khz * khz_to_hz;
		timing.refresh_rate  = refresh_rate;
		timing.interlaced    = interlaced;
		timing.supported     = true;
		timing.ar            = aspect_ratio_4_3 ? HDMI_RES_AR_4_3 :
					(aspect_ratio_5_4 ? HDMI_RES_AR_5_4 :
					HDMI_RES_AR_16_9);

		DEV_DBG("%s: new res: %dx%d%s@%dHz\n", __func__,
		DEV_DBG("%s: new res: %dx%d%s@%d.%d%d%dHz\n", __func__,
			timing.active_h, timing.active_v,
			interlaced ? "i" : "p",
			timing.refresh_rate / khz_to_hz);
			timing.refresh_rate / khz_to_hz,
			(timing.refresh_rate % khz_to_hz) / 100,
			(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);
	} else {
		DEV_ERR("%s: Invalid frame data\n", __func__);
@@ -1642,6 +1648,7 @@ static void hdmi_edid_add_sink_video_format(struct hdmi_edid_ctrl *edid_ctrl,
	u32 supported = hdmi_edid_is_mode_supported(edid_ctrl, &timing);
	struct hdmi_edid_sink_data *sink_data = &edid_ctrl->sink_data;
	struct disp_mode_info *disp_mode_list = sink_data->disp_mode_list;
	u32 i = 0;

	if (video_format >= HDMI_VFRMT_MAX) {
		DEV_ERR("%s: video format: %s is not supported\n", __func__,
@@ -1653,6 +1660,15 @@ static void hdmi_edid_add_sink_video_format(struct hdmi_edid_ctrl *edid_ctrl,
		video_format, msm_hdmi_mode_2string(video_format),
		supported ? "Supported" : "Not-Supported");

	for (i = 0; i < sink_data->num_of_elements; i++) {
		u32 vic = disp_mode_list[i].video_format;

		if (vic == video_format) {
			DEV_DBG("%s: vic %d already added\n", __func__, vic);
			return;
		}
	}

	if (!ret && supported) {
		/* todo: MHL */
		disp_mode_list[sink_data->num_of_elements].video_format =
@@ -1970,6 +1986,7 @@ static void hdmi_edid_get_display_mode(struct hdmi_edid_ctrl *edid_ctrl)
	const u8 *svd = NULL;
	u32 has60hz_mode = false;
	u32 has50hz_mode = false;
	u32 desc_offset = 0;
	bool read_block0_res = false;
	struct hdmi_edid_sink_data *sink_data = NULL;

@@ -2033,47 +2050,10 @@ static void hdmi_edid_get_display_mode(struct hdmi_edid_ctrl *edid_ctrl)
			if (video_format == HDMI_VFRMT_640x480p60_4_3)
				has480p = true;
		}
	} else if (!num_of_cea_blocks || read_block0_res) {
		/* Detailed timing descriptors */
		u32 desc_offset = 0;
		/*
		 * * Maximum 4 timing descriptor in block 0 - No CEA
		 *   extension in this case
		 * * EDID_FIRST_TIMING_DESC[0x36] - 1st detailed timing
		 *   descriptor
		 * * EDID_DETAIL_TIMING_DESC_BLCK_SZ[0x12] - Each detailed
		 *   timing descriptor has block size of 18
		 */
		while (4 > i && 0 != edid_blk0[0x36+desc_offset]) {
			hdmi_edid_detail_desc(edid_ctrl,
				edid_blk0+0x36+desc_offset,
				&video_format);

			DEV_DBG("[%s:%d] Block-0 Adding vid fmt = [%s]\n",
				__func__, __LINE__,
				msm_hdmi_mode_2string(video_format));

			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 =
					video_format;
			}
			desc_offset += 0x12;
			++i;
	}
	} else if (1 == num_of_cea_blocks) {
		u32 desc_offset = 0;

		/*
		 * Read from both block 0 and block 1
		 * Read EDID block[0] as above
		 */
	i = 0;
	/* Read DTD resolutions from block0 */
	while (4 > i && 0 != edid_blk0[0x36+desc_offset]) {
		hdmi_edid_detail_desc(edid_ctrl,
			edid_blk0+0x36+desc_offset,
@@ -2108,7 +2088,8 @@ static void hdmi_edid_get_display_mode(struct hdmi_edid_ctrl *edid_ctrl)
	 * * EDID_BLOCK_SIZE = 0x80  Each page size in the EDID ROM
	 */
	desc_offset = edid_blk1[0x02];
		while (0 != edid_blk1[desc_offset]) {
	i = 0;
	while (!edid_blk1[desc_offset]) {
		hdmi_edid_detail_desc(edid_ctrl,
			edid_blk1+desc_offset,
			&video_format);
@@ -2130,7 +2111,6 @@ static void hdmi_edid_get_display_mode(struct hdmi_edid_ctrl *edid_ctrl)
		desc_offset += 0x12;
		++i;
	}
	}

	std_blk = 0;
	offset  = 0;
Loading