xref: /dflybsd-src/sys/dev/drm/i915/intel_dp.c (revision 3f2dd94a569761201b5b0a18b2f697f97fe1b9dc)
1e3adcf8fSFrançois Tigeot /*
2e3adcf8fSFrançois Tigeot  * Copyright © 2008 Intel Corporation
3e3adcf8fSFrançois Tigeot  *
4e3adcf8fSFrançois Tigeot  * Permission is hereby granted, free of charge, to any person obtaining a
5e3adcf8fSFrançois Tigeot  * copy of this software and associated documentation files (the "Software"),
6e3adcf8fSFrançois Tigeot  * to deal in the Software without restriction, including without limitation
7e3adcf8fSFrançois Tigeot  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8e3adcf8fSFrançois Tigeot  * and/or sell copies of the Software, and to permit persons to whom the
9e3adcf8fSFrançois Tigeot  * Software is furnished to do so, subject to the following conditions:
10e3adcf8fSFrançois Tigeot  *
11e3adcf8fSFrançois Tigeot  * The above copyright notice and this permission notice (including the next
12e3adcf8fSFrançois Tigeot  * paragraph) shall be included in all copies or substantial portions of the
13e3adcf8fSFrançois Tigeot  * Software.
14e3adcf8fSFrançois Tigeot  *
15e3adcf8fSFrançois Tigeot  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16e3adcf8fSFrançois Tigeot  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17e3adcf8fSFrançois Tigeot  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
18e3adcf8fSFrançois Tigeot  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19e3adcf8fSFrançois Tigeot  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20e3adcf8fSFrançois Tigeot  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
21e3adcf8fSFrançois Tigeot  * IN THE SOFTWARE.
22e3adcf8fSFrançois Tigeot  *
23e3adcf8fSFrançois Tigeot  * Authors:
24e3adcf8fSFrançois Tigeot  *    Keith Packard <keithp@keithp.com>
25e3adcf8fSFrançois Tigeot  *
26e3adcf8fSFrançois Tigeot  */
27e3adcf8fSFrançois Tigeot 
28e3440f96SFrançois Tigeot #include <linux/i2c.h>
291487f786SFrançois Tigeot #include <linux/slab.h>
30e3440f96SFrançois Tigeot #include <linux/export.h>
31a85cb24fSFrançois Tigeot #include <linux/types.h>
32352ff8bdSFrançois Tigeot #include <linux/notifier.h>
3339cfddd2SFrançois Tigeot #include <linux/reboot.h>
34a85cb24fSFrançois Tigeot #include <asm/byteorder.h>
3518e26a6dSFrançois Tigeot #include <drm/drmP.h>
362c9916cdSFrançois Tigeot #include <drm/drm_atomic_helper.h>
3718e26a6dSFrançois Tigeot #include <drm/drm_crtc.h>
3818e26a6dSFrançois Tigeot #include <drm/drm_crtc_helper.h>
3918e26a6dSFrançois Tigeot #include <drm/drm_edid.h>
4018e26a6dSFrançois Tigeot #include "intel_drv.h"
415c6c6f23SFrançois Tigeot #include <drm/i915_drm.h>
42e3adcf8fSFrançois Tigeot #include "i915_drv.h"
43e3adcf8fSFrançois Tigeot 
44e3adcf8fSFrançois Tigeot #define DP_LINK_CHECK_TIMEOUT	(10 * 1000)
45*3f2dd94aSFrançois Tigeot #define DP_DPRX_ESI_LEN 14
46e3adcf8fSFrançois Tigeot 
4719c468b4SFrançois Tigeot /* Compliance test status bits  */
4819c468b4SFrançois Tigeot #define INTEL_DP_RESOLUTION_SHIFT_MASK	0
4919c468b4SFrançois Tigeot #define INTEL_DP_RESOLUTION_PREFERRED	(1 << INTEL_DP_RESOLUTION_SHIFT_MASK)
5019c468b4SFrançois Tigeot #define INTEL_DP_RESOLUTION_STANDARD	(2 << INTEL_DP_RESOLUTION_SHIFT_MASK)
5119c468b4SFrançois Tigeot #define INTEL_DP_RESOLUTION_FAILSAFE	(3 << INTEL_DP_RESOLUTION_SHIFT_MASK)
5219c468b4SFrançois Tigeot 
539edbd4a0SFrançois Tigeot struct dp_link_dpll {
54a05eeebfSFrançois Tigeot 	int clock;
559edbd4a0SFrançois Tigeot 	struct dpll dpll;
569edbd4a0SFrançois Tigeot };
579edbd4a0SFrançois Tigeot 
589edbd4a0SFrançois Tigeot static const struct dp_link_dpll gen4_dpll[] = {
59a05eeebfSFrançois Tigeot 	{ 162000,
609edbd4a0SFrançois Tigeot 		{ .p1 = 2, .p2 = 10, .n = 2, .m1 = 23, .m2 = 8 } },
61a05eeebfSFrançois Tigeot 	{ 270000,
629edbd4a0SFrançois Tigeot 		{ .p1 = 1, .p2 = 10, .n = 1, .m1 = 14, .m2 = 2 } }
639edbd4a0SFrançois Tigeot };
649edbd4a0SFrançois Tigeot 
659edbd4a0SFrançois Tigeot static const struct dp_link_dpll pch_dpll[] = {
66a05eeebfSFrançois Tigeot 	{ 162000,
679edbd4a0SFrançois Tigeot 		{ .p1 = 2, .p2 = 10, .n = 1, .m1 = 12, .m2 = 9 } },
68a05eeebfSFrançois Tigeot 	{ 270000,
699edbd4a0SFrançois Tigeot 		{ .p1 = 1, .p2 = 10, .n = 2, .m1 = 14, .m2 = 8 } }
709edbd4a0SFrançois Tigeot };
719edbd4a0SFrançois Tigeot 
729edbd4a0SFrançois Tigeot static const struct dp_link_dpll vlv_dpll[] = {
73a05eeebfSFrançois Tigeot 	{ 162000,
749edbd4a0SFrançois Tigeot 		{ .p1 = 3, .p2 = 2, .n = 5, .m1 = 3, .m2 = 81 } },
75a05eeebfSFrançois Tigeot 	{ 270000,
769edbd4a0SFrançois Tigeot 		{ .p1 = 2, .p2 = 2, .n = 1, .m1 = 2, .m2 = 27 } }
779edbd4a0SFrançois Tigeot };
789edbd4a0SFrançois Tigeot 
79ba55f2f5SFrançois Tigeot /*
80ba55f2f5SFrançois Tigeot  * CHV supports eDP 1.4 that have  more link rates.
81ba55f2f5SFrançois Tigeot  * Below only provides the fixed rate but exclude variable rate.
82ba55f2f5SFrançois Tigeot  */
83ba55f2f5SFrançois Tigeot static const struct dp_link_dpll chv_dpll[] = {
84ba55f2f5SFrançois Tigeot 	/*
85ba55f2f5SFrançois Tigeot 	 * CHV requires to program fractional division for m2.
86ba55f2f5SFrançois Tigeot 	 * m2 is stored in fixed point format using formula below
87ba55f2f5SFrançois Tigeot 	 * (m2_int << 22) | m2_fraction
88ba55f2f5SFrançois Tigeot 	 */
89a05eeebfSFrançois Tigeot 	{ 162000,	/* m2_int = 32, m2_fraction = 1677722 */
90ba55f2f5SFrançois Tigeot 		{ .p1 = 4, .p2 = 2, .n = 1, .m1 = 2, .m2 = 0x819999a } },
91a05eeebfSFrançois Tigeot 	{ 270000,	/* m2_int = 27, m2_fraction = 0 */
92ba55f2f5SFrançois Tigeot 		{ .p1 = 4, .p2 = 1, .n = 1, .m1 = 2, .m2 = 0x6c00000 } },
93a05eeebfSFrançois Tigeot 	{ 540000,	/* m2_int = 27, m2_fraction = 0 */
94ba55f2f5SFrançois Tigeot 		{ .p1 = 2, .p2 = 1, .n = 1, .m1 = 2, .m2 = 0x6c00000 } }
95ba55f2f5SFrançois Tigeot };
9619c468b4SFrançois Tigeot 
97a05eeebfSFrançois Tigeot static const int bxt_rates[] = { 162000, 216000, 243000, 270000,
98a05eeebfSFrançois Tigeot 				  324000, 432000, 540000 };
9919c468b4SFrançois Tigeot static const int skl_rates[] = { 162000, 216000, 270000,
100477eb7f9SFrançois Tigeot 				  324000, 432000, 540000 };
101*3f2dd94aSFrançois Tigeot static const int cnl_rates[] = { 162000, 216000, 270000,
102*3f2dd94aSFrançois Tigeot 				 324000, 432000, 540000,
103*3f2dd94aSFrançois Tigeot 				 648000, 810000 };
104477eb7f9SFrançois Tigeot static const int default_rates[] = { 162000, 270000, 540000 };
105ba55f2f5SFrançois Tigeot 
106e3adcf8fSFrançois Tigeot /**
107*3f2dd94aSFrançois Tigeot  * intel_dp_is_edp - is the given port attached to an eDP panel (either CPU or PCH)
108e3adcf8fSFrançois Tigeot  * @intel_dp: DP struct
109e3adcf8fSFrançois Tigeot  *
110e3adcf8fSFrançois Tigeot  * If a CPU or PCH DP output is attached to an eDP panel, this function
111e3adcf8fSFrançois Tigeot  * will return true, and false otherwise.
112e3adcf8fSFrançois Tigeot  */
intel_dp_is_edp(struct intel_dp * intel_dp)113*3f2dd94aSFrançois Tigeot bool intel_dp_is_edp(struct intel_dp *intel_dp)
114e3adcf8fSFrançois Tigeot {
11519df918dSFrançois Tigeot 	struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp);
11619df918dSFrançois Tigeot 
11719df918dSFrançois Tigeot 	return intel_dig_port->base.type == INTEL_OUTPUT_EDP;
118e3adcf8fSFrançois Tigeot }
119e3adcf8fSFrançois Tigeot 
intel_dp_to_dev(struct intel_dp * intel_dp)12019df918dSFrançois Tigeot static struct drm_device *intel_dp_to_dev(struct intel_dp *intel_dp)
121e3adcf8fSFrançois Tigeot {
12219df918dSFrançois Tigeot 	struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp);
12319df918dSFrançois Tigeot 
12419df918dSFrançois Tigeot 	return intel_dig_port->base.base.dev;
125e3adcf8fSFrançois Tigeot }
126e3adcf8fSFrançois Tigeot 
intel_attached_dp(struct drm_connector * connector)127e3adcf8fSFrançois Tigeot static struct intel_dp *intel_attached_dp(struct drm_connector *connector)
128e3adcf8fSFrançois Tigeot {
12919df918dSFrançois Tigeot 	return enc_to_intel_dp(&intel_attached_encoder(connector)->base);
130e3adcf8fSFrançois Tigeot }
131e3adcf8fSFrançois Tigeot 
132e3adcf8fSFrançois Tigeot static void intel_dp_link_down(struct intel_dp *intel_dp);
1331b13d190SFrançois Tigeot static bool edp_panel_vdd_on(struct intel_dp *intel_dp);
134ba55f2f5SFrançois Tigeot static void edp_panel_vdd_off(struct intel_dp *intel_dp, bool sync);
1352c9916cdSFrançois Tigeot static void vlv_init_panel_power_sequencer(struct intel_dp *intel_dp);
1362c9916cdSFrançois Tigeot static void vlv_steal_power_sequencer(struct drm_device *dev,
1372c9916cdSFrançois Tigeot 				      enum i915_pipe pipe);
1388621f407SFrançois Tigeot static void intel_dp_unset_edid(struct intel_dp *intel_dp);
139e3adcf8fSFrançois Tigeot 
140*3f2dd94aSFrançois Tigeot /* update sink rates from dpcd */
intel_dp_set_sink_rates(struct intel_dp * intel_dp)141*3f2dd94aSFrançois Tigeot static void intel_dp_set_sink_rates(struct intel_dp *intel_dp)
142e3adcf8fSFrançois Tigeot {
143*3f2dd94aSFrançois Tigeot 	int i, max_rate;
144e3adcf8fSFrançois Tigeot 
145*3f2dd94aSFrançois Tigeot 	max_rate = drm_dp_bw_code_to_link_rate(intel_dp->dpcd[DP_MAX_LINK_RATE]);
146*3f2dd94aSFrançois Tigeot 
147*3f2dd94aSFrançois Tigeot 	for (i = 0; i < ARRAY_SIZE(default_rates); i++) {
148*3f2dd94aSFrançois Tigeot 		if (default_rates[i] > max_rate)
1495d0b1887SFrançois Tigeot 			break;
150*3f2dd94aSFrançois Tigeot 		intel_dp->sink_rates[i] = default_rates[i];
151e3adcf8fSFrançois Tigeot 	}
152e3adcf8fSFrançois Tigeot 
153*3f2dd94aSFrançois Tigeot 	intel_dp->num_sink_rates = i;
154*3f2dd94aSFrançois Tigeot }
155*3f2dd94aSFrançois Tigeot 
156*3f2dd94aSFrançois Tigeot /* Theoretical max between source and sink */
intel_dp_max_common_rate(struct intel_dp * intel_dp)157*3f2dd94aSFrançois Tigeot static int intel_dp_max_common_rate(struct intel_dp *intel_dp)
158*3f2dd94aSFrançois Tigeot {
159*3f2dd94aSFrançois Tigeot 	return intel_dp->common_rates[intel_dp->num_common_rates - 1];
160*3f2dd94aSFrançois Tigeot }
161*3f2dd94aSFrançois Tigeot 
162*3f2dd94aSFrançois Tigeot /* Theoretical max between source and sink */
intel_dp_max_common_lane_count(struct intel_dp * intel_dp)163*3f2dd94aSFrançois Tigeot static int intel_dp_max_common_lane_count(struct intel_dp *intel_dp)
164ba55f2f5SFrançois Tigeot {
165ba55f2f5SFrançois Tigeot 	struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp);
166*3f2dd94aSFrançois Tigeot 	int source_max = intel_dig_port->max_lanes;
167*3f2dd94aSFrançois Tigeot 	int sink_max = drm_dp_max_lane_count(intel_dp->dpcd);
168ba55f2f5SFrançois Tigeot 
169ba55f2f5SFrançois Tigeot 	return min(source_max, sink_max);
170ba55f2f5SFrançois Tigeot }
171ba55f2f5SFrançois Tigeot 
intel_dp_max_lane_count(struct intel_dp * intel_dp)172*3f2dd94aSFrançois Tigeot int intel_dp_max_lane_count(struct intel_dp *intel_dp)
173*3f2dd94aSFrançois Tigeot {
174*3f2dd94aSFrançois Tigeot 	return intel_dp->max_link_lane_count;
175*3f2dd94aSFrançois Tigeot }
176*3f2dd94aSFrançois Tigeot 
177a85cb24fSFrançois Tigeot int
intel_dp_link_required(int pixel_clock,int bpp)178e3adcf8fSFrançois Tigeot intel_dp_link_required(int pixel_clock, int bpp)
179e3adcf8fSFrançois Tigeot {
180a85cb24fSFrançois Tigeot 	/* pixel_clock is in kHz, divide bpp by 8 for bit to Byte conversion */
181a85cb24fSFrançois Tigeot 	return DIV_ROUND_UP(pixel_clock * bpp, 8);
182e3adcf8fSFrançois Tigeot }
183e3adcf8fSFrançois Tigeot 
184a85cb24fSFrançois Tigeot int
intel_dp_max_data_rate(int max_link_clock,int max_lanes)185e3adcf8fSFrançois Tigeot intel_dp_max_data_rate(int max_link_clock, int max_lanes)
186e3adcf8fSFrançois Tigeot {
187a85cb24fSFrançois Tigeot 	/* max_link_clock is the link symbol clock (LS_Clk) in kHz and not the
188a85cb24fSFrançois Tigeot 	 * link rate that is generally expressed in Gbps. Since, 8 bits of data
189a85cb24fSFrançois Tigeot 	 * is transmitted every LS_Clk per lane, there is no need to account for
190a85cb24fSFrançois Tigeot 	 * the channel encoding that is done in the PHY layer here.
191a85cb24fSFrançois Tigeot 	 */
192a85cb24fSFrançois Tigeot 
193a85cb24fSFrançois Tigeot 	return max_link_clock * max_lanes;
194e3adcf8fSFrançois Tigeot }
195e3adcf8fSFrançois Tigeot 
1961e12ee3bSFrançois Tigeot static int
intel_dp_downstream_max_dotclock(struct intel_dp * intel_dp)1971e12ee3bSFrançois Tigeot intel_dp_downstream_max_dotclock(struct intel_dp *intel_dp)
1981e12ee3bSFrançois Tigeot {
1991e12ee3bSFrançois Tigeot 	struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp);
2001e12ee3bSFrançois Tigeot 	struct intel_encoder *encoder = &intel_dig_port->base;
2011e12ee3bSFrançois Tigeot 	struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
2021e12ee3bSFrançois Tigeot 	int max_dotclk = dev_priv->max_dotclk_freq;
2031e12ee3bSFrançois Tigeot 	int ds_max_dotclk;
2041e12ee3bSFrançois Tigeot 
2051e12ee3bSFrançois Tigeot 	int type = intel_dp->downstream_ports[0] & DP_DS_PORT_TYPE_MASK;
2061e12ee3bSFrançois Tigeot 
2071e12ee3bSFrançois Tigeot 	if (type != DP_DS_PORT_TYPE_VGA)
2081e12ee3bSFrançois Tigeot 		return max_dotclk;
2091e12ee3bSFrançois Tigeot 
2101e12ee3bSFrançois Tigeot 	ds_max_dotclk = drm_dp_downstream_max_clock(intel_dp->dpcd,
2111e12ee3bSFrançois Tigeot 						    intel_dp->downstream_ports);
2121e12ee3bSFrançois Tigeot 
2131e12ee3bSFrançois Tigeot 	if (ds_max_dotclk != 0)
2141e12ee3bSFrançois Tigeot 		max_dotclk = min(max_dotclk, ds_max_dotclk);
2151e12ee3bSFrançois Tigeot 
2161e12ee3bSFrançois Tigeot 	return max_dotclk;
2171e12ee3bSFrançois Tigeot }
2181e12ee3bSFrançois Tigeot 
219*3f2dd94aSFrançois Tigeot static void
intel_dp_set_source_rates(struct intel_dp * intel_dp)220*3f2dd94aSFrançois Tigeot intel_dp_set_source_rates(struct intel_dp *intel_dp)
2214be47400SFrançois Tigeot {
2224be47400SFrançois Tigeot 	struct intel_digital_port *dig_port = dp_to_dig_port(intel_dp);
2234be47400SFrançois Tigeot 	struct drm_i915_private *dev_priv = to_i915(dig_port->base.base.dev);
224*3f2dd94aSFrançois Tigeot 	enum port port = dig_port->port;
225*3f2dd94aSFrançois Tigeot 	const int *source_rates;
2264be47400SFrançois Tigeot 	int size;
227*3f2dd94aSFrançois Tigeot 	u32 voltage;
228*3f2dd94aSFrançois Tigeot 
229*3f2dd94aSFrançois Tigeot 	/* This should only be done once */
230*3f2dd94aSFrançois Tigeot 	WARN_ON(intel_dp->source_rates || intel_dp->num_source_rates);
2314be47400SFrançois Tigeot 
232a85cb24fSFrançois Tigeot 	if (IS_GEN9_LP(dev_priv)) {
233*3f2dd94aSFrançois Tigeot 		source_rates = bxt_rates;
2344be47400SFrançois Tigeot 		size = ARRAY_SIZE(bxt_rates);
235*3f2dd94aSFrançois Tigeot 	} else if (IS_CANNONLAKE(dev_priv)) {
236*3f2dd94aSFrançois Tigeot 		source_rates = cnl_rates;
237*3f2dd94aSFrançois Tigeot 		size = ARRAY_SIZE(cnl_rates);
238*3f2dd94aSFrançois Tigeot 		voltage = I915_READ(CNL_PORT_COMP_DW3) & VOLTAGE_INFO_MASK;
239*3f2dd94aSFrançois Tigeot 		if (port == PORT_A || port == PORT_D ||
240*3f2dd94aSFrançois Tigeot 		    voltage == VOLTAGE_INFO_0_85V)
241*3f2dd94aSFrançois Tigeot 			size -= 2;
242a85cb24fSFrançois Tigeot 	} else if (IS_GEN9_BC(dev_priv)) {
243*3f2dd94aSFrançois Tigeot 		source_rates = skl_rates;
2444be47400SFrançois Tigeot 		size = ARRAY_SIZE(skl_rates);
245*3f2dd94aSFrançois Tigeot 	} else if ((IS_HASWELL(dev_priv) && !IS_HSW_ULX(dev_priv)) ||
246*3f2dd94aSFrançois Tigeot 		   IS_BROADWELL(dev_priv)) {
247*3f2dd94aSFrançois Tigeot 		source_rates = default_rates;
2484be47400SFrançois Tigeot 		size = ARRAY_SIZE(default_rates);
249*3f2dd94aSFrançois Tigeot 	} else {
250*3f2dd94aSFrançois Tigeot 		source_rates = default_rates;
251*3f2dd94aSFrançois Tigeot 		size = ARRAY_SIZE(default_rates) - 1;
2524be47400SFrançois Tigeot 	}
2534be47400SFrançois Tigeot 
254*3f2dd94aSFrançois Tigeot 	intel_dp->source_rates = source_rates;
255*3f2dd94aSFrançois Tigeot 	intel_dp->num_source_rates = size;
2564be47400SFrançois Tigeot }
2574be47400SFrançois Tigeot 
intersect_rates(const int * source_rates,int source_len,const int * sink_rates,int sink_len,int * common_rates)2584be47400SFrançois Tigeot static int intersect_rates(const int *source_rates, int source_len,
2594be47400SFrançois Tigeot 			   const int *sink_rates, int sink_len,
2604be47400SFrançois Tigeot 			   int *common_rates)
2614be47400SFrançois Tigeot {
2624be47400SFrançois Tigeot 	int i = 0, j = 0, k = 0;
2634be47400SFrançois Tigeot 
2644be47400SFrançois Tigeot 	while (i < source_len && j < sink_len) {
2654be47400SFrançois Tigeot 		if (source_rates[i] == sink_rates[j]) {
2664be47400SFrançois Tigeot 			if (WARN_ON(k >= DP_MAX_SUPPORTED_RATES))
2674be47400SFrançois Tigeot 				return k;
2684be47400SFrançois Tigeot 			common_rates[k] = source_rates[i];
2694be47400SFrançois Tigeot 			++k;
2704be47400SFrançois Tigeot 			++i;
2714be47400SFrançois Tigeot 			++j;
2724be47400SFrançois Tigeot 		} else if (source_rates[i] < sink_rates[j]) {
2734be47400SFrançois Tigeot 			++i;
2744be47400SFrançois Tigeot 		} else {
2754be47400SFrançois Tigeot 			++j;
2764be47400SFrançois Tigeot 		}
2774be47400SFrançois Tigeot 	}
2784be47400SFrançois Tigeot 	return k;
2794be47400SFrançois Tigeot }
2804be47400SFrançois Tigeot 
281*3f2dd94aSFrançois Tigeot /* return index of rate in rates array, or -1 if not found */
intel_dp_rate_index(const int * rates,int len,int rate)282*3f2dd94aSFrançois Tigeot static int intel_dp_rate_index(const int *rates, int len, int rate)
2834be47400SFrançois Tigeot {
284*3f2dd94aSFrançois Tigeot 	int i;
2854be47400SFrançois Tigeot 
286*3f2dd94aSFrançois Tigeot 	for (i = 0; i < len; i++)
287*3f2dd94aSFrançois Tigeot 		if (rate == rates[i])
288*3f2dd94aSFrançois Tigeot 			return i;
289a85cb24fSFrançois Tigeot 
290a85cb24fSFrançois Tigeot 	return -1;
291a85cb24fSFrançois Tigeot }
292a85cb24fSFrançois Tigeot 
intel_dp_set_common_rates(struct intel_dp * intel_dp)293*3f2dd94aSFrançois Tigeot static void intel_dp_set_common_rates(struct intel_dp *intel_dp)
294*3f2dd94aSFrançois Tigeot {
295*3f2dd94aSFrançois Tigeot 	WARN_ON(!intel_dp->num_source_rates || !intel_dp->num_sink_rates);
296*3f2dd94aSFrançois Tigeot 
297*3f2dd94aSFrançois Tigeot 	intel_dp->num_common_rates = intersect_rates(intel_dp->source_rates,
298*3f2dd94aSFrançois Tigeot 						     intel_dp->num_source_rates,
299*3f2dd94aSFrançois Tigeot 						     intel_dp->sink_rates,
300*3f2dd94aSFrançois Tigeot 						     intel_dp->num_sink_rates,
301*3f2dd94aSFrançois Tigeot 						     intel_dp->common_rates);
302*3f2dd94aSFrançois Tigeot 
303*3f2dd94aSFrançois Tigeot 	/* Paranoia, there should always be something in common. */
304*3f2dd94aSFrançois Tigeot 	if (WARN_ON(intel_dp->num_common_rates == 0)) {
305*3f2dd94aSFrançois Tigeot 		intel_dp->common_rates[0] = default_rates[0];
306*3f2dd94aSFrançois Tigeot 		intel_dp->num_common_rates = 1;
307*3f2dd94aSFrançois Tigeot 	}
308*3f2dd94aSFrançois Tigeot }
309*3f2dd94aSFrançois Tigeot 
310*3f2dd94aSFrançois Tigeot /* get length of common rates potentially limited by max_rate */
intel_dp_common_len_rate_limit(struct intel_dp * intel_dp,int max_rate)311*3f2dd94aSFrançois Tigeot static int intel_dp_common_len_rate_limit(struct intel_dp *intel_dp,
312*3f2dd94aSFrançois Tigeot 					  int max_rate)
313*3f2dd94aSFrançois Tigeot {
314*3f2dd94aSFrançois Tigeot 	const int *common_rates = intel_dp->common_rates;
315*3f2dd94aSFrançois Tigeot 	int i, common_len = intel_dp->num_common_rates;
316*3f2dd94aSFrançois Tigeot 
317*3f2dd94aSFrançois Tigeot 	/* Limit results by potentially reduced max rate */
318*3f2dd94aSFrançois Tigeot 	for (i = 0; i < common_len; i++) {
319*3f2dd94aSFrançois Tigeot 		if (common_rates[common_len - i - 1] <= max_rate)
320*3f2dd94aSFrançois Tigeot 			return common_len - i;
321*3f2dd94aSFrançois Tigeot 	}
322*3f2dd94aSFrançois Tigeot 
323*3f2dd94aSFrançois Tigeot 	return 0;
324*3f2dd94aSFrançois Tigeot }
325*3f2dd94aSFrançois Tigeot 
intel_dp_link_params_valid(struct intel_dp * intel_dp,int link_rate,uint8_t lane_count)326*3f2dd94aSFrançois Tigeot static bool intel_dp_link_params_valid(struct intel_dp *intel_dp, int link_rate,
327*3f2dd94aSFrançois Tigeot 				       uint8_t lane_count)
328*3f2dd94aSFrançois Tigeot {
329*3f2dd94aSFrançois Tigeot 	/*
330*3f2dd94aSFrançois Tigeot 	 * FIXME: we need to synchronize the current link parameters with
331*3f2dd94aSFrançois Tigeot 	 * hardware readout. Currently fast link training doesn't work on
332*3f2dd94aSFrançois Tigeot 	 * boot-up.
333*3f2dd94aSFrançois Tigeot 	 */
334*3f2dd94aSFrançois Tigeot 	if (link_rate == 0 ||
335*3f2dd94aSFrançois Tigeot 	    link_rate > intel_dp->max_link_rate)
336*3f2dd94aSFrançois Tigeot 		return false;
337*3f2dd94aSFrançois Tigeot 
338*3f2dd94aSFrançois Tigeot 	if (lane_count == 0 ||
339*3f2dd94aSFrançois Tigeot 	    lane_count > intel_dp_max_lane_count(intel_dp))
340*3f2dd94aSFrançois Tigeot 		return false;
341*3f2dd94aSFrançois Tigeot 
342*3f2dd94aSFrançois Tigeot 	return true;
343*3f2dd94aSFrançois Tigeot }
344*3f2dd94aSFrançois Tigeot 
intel_dp_get_link_train_fallback_values(struct intel_dp * intel_dp,int link_rate,uint8_t lane_count)345a85cb24fSFrançois Tigeot int intel_dp_get_link_train_fallback_values(struct intel_dp *intel_dp,
346a85cb24fSFrançois Tigeot 					    int link_rate, uint8_t lane_count)
347a85cb24fSFrançois Tigeot {
348*3f2dd94aSFrançois Tigeot 	int index;
349a85cb24fSFrançois Tigeot 
350*3f2dd94aSFrançois Tigeot 	index = intel_dp_rate_index(intel_dp->common_rates,
351*3f2dd94aSFrançois Tigeot 				    intel_dp->num_common_rates,
352a85cb24fSFrançois Tigeot 				    link_rate);
353*3f2dd94aSFrançois Tigeot 	if (index > 0) {
354*3f2dd94aSFrançois Tigeot 		intel_dp->max_link_rate = intel_dp->common_rates[index - 1];
355*3f2dd94aSFrançois Tigeot 		intel_dp->max_link_lane_count = lane_count;
356a85cb24fSFrançois Tigeot 	} else if (lane_count > 1) {
357*3f2dd94aSFrançois Tigeot 		intel_dp->max_link_rate = intel_dp_max_common_rate(intel_dp);
358*3f2dd94aSFrançois Tigeot 		intel_dp->max_link_lane_count = lane_count >> 1;
359a85cb24fSFrançois Tigeot 	} else {
360a85cb24fSFrançois Tigeot 		DRM_ERROR("Link Training Unsuccessful\n");
361a85cb24fSFrançois Tigeot 		return -1;
362a85cb24fSFrançois Tigeot 	}
363a85cb24fSFrançois Tigeot 
364a85cb24fSFrançois Tigeot 	return 0;
365a85cb24fSFrançois Tigeot }
366a85cb24fSFrançois Tigeot 
3679edbd4a0SFrançois Tigeot static enum drm_mode_status
intel_dp_mode_valid(struct drm_connector * connector,struct drm_display_mode * mode)368e3adcf8fSFrançois Tigeot intel_dp_mode_valid(struct drm_connector *connector,
369e3adcf8fSFrançois Tigeot 		    struct drm_display_mode *mode)
370e3adcf8fSFrançois Tigeot {
371e3adcf8fSFrançois Tigeot 	struct intel_dp *intel_dp = intel_attached_dp(connector);
37219df918dSFrançois Tigeot 	struct intel_connector *intel_connector = to_intel_connector(connector);
37319df918dSFrançois Tigeot 	struct drm_display_mode *fixed_mode = intel_connector->panel.fixed_mode;
3748e26cdf6SFrançois Tigeot 	int target_clock = mode->clock;
3758e26cdf6SFrançois Tigeot 	int max_rate, mode_rate, max_lanes, max_link_clock;
3761e12ee3bSFrançois Tigeot 	int max_dotclk;
3771e12ee3bSFrançois Tigeot 
3781e12ee3bSFrançois Tigeot 	max_dotclk = intel_dp_downstream_max_dotclock(intel_dp);
379e3adcf8fSFrançois Tigeot 
380*3f2dd94aSFrançois Tigeot 	if (intel_dp_is_edp(intel_dp) && fixed_mode) {
38119df918dSFrançois Tigeot 		if (mode->hdisplay > fixed_mode->hdisplay)
382e3adcf8fSFrançois Tigeot 			return MODE_PANEL;
383e3adcf8fSFrançois Tigeot 
38419df918dSFrançois Tigeot 		if (mode->vdisplay > fixed_mode->vdisplay)
385e3adcf8fSFrançois Tigeot 			return MODE_PANEL;
3868e26cdf6SFrançois Tigeot 
3878e26cdf6SFrançois Tigeot 		target_clock = fixed_mode->clock;
388e3adcf8fSFrançois Tigeot 	}
389e3adcf8fSFrançois Tigeot 
390477eb7f9SFrançois Tigeot 	max_link_clock = intel_dp_max_link_rate(intel_dp);
391ba55f2f5SFrançois Tigeot 	max_lanes = intel_dp_max_lane_count(intel_dp);
3928e26cdf6SFrançois Tigeot 
3938e26cdf6SFrançois Tigeot 	max_rate = intel_dp_max_data_rate(max_link_clock, max_lanes);
3948e26cdf6SFrançois Tigeot 	mode_rate = intel_dp_link_required(target_clock, 18);
3958e26cdf6SFrançois Tigeot 
396c0e85e96SFrançois Tigeot 	if (mode_rate > max_rate || target_clock > max_dotclk)
397e3adcf8fSFrançois Tigeot 		return MODE_CLOCK_HIGH;
398e3adcf8fSFrançois Tigeot 
399e3adcf8fSFrançois Tigeot 	if (mode->clock < 10000)
400e3adcf8fSFrançois Tigeot 		return MODE_CLOCK_LOW;
401e3adcf8fSFrançois Tigeot 
40219df918dSFrançois Tigeot 	if (mode->flags & DRM_MODE_FLAG_DBLCLK)
40319df918dSFrançois Tigeot 		return MODE_H_ILLEGAL;
40419df918dSFrançois Tigeot 
405e3adcf8fSFrançois Tigeot 	return MODE_OK;
406e3adcf8fSFrançois Tigeot }
407e3adcf8fSFrançois Tigeot 
intel_dp_pack_aux(const uint8_t * src,int src_bytes)4082c9916cdSFrançois Tigeot uint32_t intel_dp_pack_aux(const uint8_t *src, int src_bytes)
409e3adcf8fSFrançois Tigeot {
410e3adcf8fSFrançois Tigeot 	int	i;
411e3adcf8fSFrançois Tigeot 	uint32_t v = 0;
412e3adcf8fSFrançois Tigeot 
413e3adcf8fSFrançois Tigeot 	if (src_bytes > 4)
414e3adcf8fSFrançois Tigeot 		src_bytes = 4;
415e3adcf8fSFrançois Tigeot 	for (i = 0; i < src_bytes; i++)
416e3adcf8fSFrançois Tigeot 		v |= ((uint32_t) src[i]) << ((3-i) * 8);
417e3adcf8fSFrançois Tigeot 	return v;
418e3adcf8fSFrançois Tigeot }
419e3adcf8fSFrançois Tigeot 
intel_dp_unpack_aux(uint32_t src,uint8_t * dst,int dst_bytes)420477eb7f9SFrançois Tigeot static void intel_dp_unpack_aux(uint32_t src, uint8_t *dst, int dst_bytes)
421e3adcf8fSFrançois Tigeot {
422e3adcf8fSFrançois Tigeot 	int i;
423e3adcf8fSFrançois Tigeot 	if (dst_bytes > 4)
424e3adcf8fSFrançois Tigeot 		dst_bytes = 4;
425e3adcf8fSFrançois Tigeot 	for (i = 0; i < dst_bytes; i++)
426e3adcf8fSFrançois Tigeot 		dst[i] = src >> ((3-i) * 8);
427e3adcf8fSFrançois Tigeot }
428e3adcf8fSFrançois Tigeot 
4299edbd4a0SFrançois Tigeot static void
4309edbd4a0SFrançois Tigeot intel_dp_init_panel_power_sequencer(struct drm_device *dev,
4312c9916cdSFrançois Tigeot 				    struct intel_dp *intel_dp);
4329edbd4a0SFrançois Tigeot static void
4339edbd4a0SFrançois Tigeot intel_dp_init_panel_power_sequencer_registers(struct drm_device *dev,
4344be47400SFrançois Tigeot 					      struct intel_dp *intel_dp,
4354be47400SFrançois Tigeot 					      bool force_disable_vdd);
4361e12ee3bSFrançois Tigeot static void
4371e12ee3bSFrançois Tigeot intel_dp_pps_init(struct drm_device *dev, struct intel_dp *intel_dp);
4389edbd4a0SFrançois Tigeot 
pps_lock(struct intel_dp * intel_dp)4391b13d190SFrançois Tigeot static void pps_lock(struct intel_dp *intel_dp)
4401b13d190SFrançois Tigeot {
4411b13d190SFrançois Tigeot 	struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp);
4421b13d190SFrançois Tigeot 	struct intel_encoder *encoder = &intel_dig_port->base;
4431b13d190SFrançois Tigeot 	struct drm_device *dev = encoder->base.dev;
444303bf270SFrançois Tigeot 	struct drm_i915_private *dev_priv = to_i915(dev);
4451b13d190SFrançois Tigeot 
4461b13d190SFrançois Tigeot 	/*
4471b13d190SFrançois Tigeot 	 * See vlv_power_sequencer_reset() why we need
4481b13d190SFrançois Tigeot 	 * a power domain reference here.
4491b13d190SFrançois Tigeot 	 */
450a85cb24fSFrançois Tigeot 	intel_display_power_get(dev_priv, intel_dp->aux_power_domain);
4511b13d190SFrançois Tigeot 
4521b13d190SFrançois Tigeot 	mutex_lock(&dev_priv->pps_mutex);
4531b13d190SFrançois Tigeot }
4541b13d190SFrançois Tigeot 
pps_unlock(struct intel_dp * intel_dp)4551b13d190SFrançois Tigeot static void pps_unlock(struct intel_dp *intel_dp)
4561b13d190SFrançois Tigeot {
4571b13d190SFrançois Tigeot 	struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp);
4581b13d190SFrançois Tigeot 	struct intel_encoder *encoder = &intel_dig_port->base;
4591b13d190SFrançois Tigeot 	struct drm_device *dev = encoder->base.dev;
460303bf270SFrançois Tigeot 	struct drm_i915_private *dev_priv = to_i915(dev);
4611b13d190SFrançois Tigeot 
4621b13d190SFrançois Tigeot 	mutex_unlock(&dev_priv->pps_mutex);
4631b13d190SFrançois Tigeot 
464a85cb24fSFrançois Tigeot 	intel_display_power_put(dev_priv, intel_dp->aux_power_domain);
4651b13d190SFrançois Tigeot }
4661b13d190SFrançois Tigeot 
4672c9916cdSFrançois Tigeot static void
vlv_power_sequencer_kick(struct intel_dp * intel_dp)4682c9916cdSFrançois Tigeot vlv_power_sequencer_kick(struct intel_dp *intel_dp)
4692c9916cdSFrançois Tigeot {
4702c9916cdSFrançois Tigeot 	struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp);
4714be47400SFrançois Tigeot 	struct drm_i915_private *dev_priv = to_i915(intel_dig_port->base.base.dev);
4722c9916cdSFrançois Tigeot 	enum i915_pipe pipe = intel_dp->pps_pipe;
473352ff8bdSFrançois Tigeot 	bool pll_enabled, release_cl_override = false;
474352ff8bdSFrançois Tigeot 	enum dpio_phy phy = DPIO_PHY(pipe);
475352ff8bdSFrançois Tigeot 	enum dpio_channel ch = vlv_pipe_to_channel(pipe);
4762c9916cdSFrançois Tigeot 	uint32_t DP;
4772c9916cdSFrançois Tigeot 
4782c9916cdSFrançois Tigeot 	if (WARN(I915_READ(intel_dp->output_reg) & DP_PORT_EN,
4792c9916cdSFrançois Tigeot 		 "skipping pipe %c power seqeuncer kick due to port %c being active\n",
4802c9916cdSFrançois Tigeot 		 pipe_name(pipe), port_name(intel_dig_port->port)))
4812c9916cdSFrançois Tigeot 		return;
4822c9916cdSFrançois Tigeot 
4832c9916cdSFrançois Tigeot 	DRM_DEBUG_KMS("kicking pipe %c power sequencer for port %c\n",
4842c9916cdSFrançois Tigeot 		      pipe_name(pipe), port_name(intel_dig_port->port));
4852c9916cdSFrançois Tigeot 
4862c9916cdSFrançois Tigeot 	/* Preserve the BIOS-computed detected bit. This is
4872c9916cdSFrançois Tigeot 	 * supposed to be read-only.
4882c9916cdSFrançois Tigeot 	 */
4892c9916cdSFrançois Tigeot 	DP = I915_READ(intel_dp->output_reg) & DP_DETECTED;
4902c9916cdSFrançois Tigeot 	DP |= DP_VOLTAGE_0_4 | DP_PRE_EMPHASIS_0;
4912c9916cdSFrançois Tigeot 	DP |= DP_PORT_WIDTH(1);
4922c9916cdSFrançois Tigeot 	DP |= DP_LINK_TRAIN_PAT_1;
4932c9916cdSFrançois Tigeot 
4941e12ee3bSFrançois Tigeot 	if (IS_CHERRYVIEW(dev_priv))
4952c9916cdSFrançois Tigeot 		DP |= DP_PIPE_SELECT_CHV(pipe);
4962c9916cdSFrançois Tigeot 	else if (pipe == PIPE_B)
4972c9916cdSFrançois Tigeot 		DP |= DP_PIPEB_SELECT;
4982c9916cdSFrançois Tigeot 
4992c9916cdSFrançois Tigeot 	pll_enabled = I915_READ(DPLL(pipe)) & DPLL_VCO_ENABLE;
5002c9916cdSFrançois Tigeot 
5012c9916cdSFrançois Tigeot 	/*
5022c9916cdSFrançois Tigeot 	 * The DPLL for the pipe must be enabled for this to work.
5032c9916cdSFrançois Tigeot 	 * So enable temporarily it if it's not already enabled.
5042c9916cdSFrançois Tigeot 	 */
505352ff8bdSFrançois Tigeot 	if (!pll_enabled) {
5061e12ee3bSFrançois Tigeot 		release_cl_override = IS_CHERRYVIEW(dev_priv) &&
507352ff8bdSFrançois Tigeot 			!chv_phy_powergate_ch(dev_priv, phy, ch, true);
508352ff8bdSFrançois Tigeot 
5094be47400SFrançois Tigeot 		if (vlv_force_pll_on(dev_priv, pipe, IS_CHERRYVIEW(dev_priv) ?
510c0e85e96SFrançois Tigeot 				     &chv_dpll[0].dpll : &vlv_dpll[0].dpll)) {
511c0e85e96SFrançois Tigeot 			DRM_ERROR("Failed to force on pll for pipe %c!\n",
512c0e85e96SFrançois Tigeot 				  pipe_name(pipe));
513c0e85e96SFrançois Tigeot 			return;
514c0e85e96SFrançois Tigeot 		}
515352ff8bdSFrançois Tigeot 	}
5162c9916cdSFrançois Tigeot 
5172c9916cdSFrançois Tigeot 	/*
5182c9916cdSFrançois Tigeot 	 * Similar magic as in intel_dp_enable_port().
5192c9916cdSFrançois Tigeot 	 * We _must_ do this port enable + disable trick
5202c9916cdSFrançois Tigeot 	 * to make this power seqeuencer lock onto the port.
5212c9916cdSFrançois Tigeot 	 * Otherwise even VDD force bit won't work.
5222c9916cdSFrançois Tigeot 	 */
5232c9916cdSFrançois Tigeot 	I915_WRITE(intel_dp->output_reg, DP);
5242c9916cdSFrançois Tigeot 	POSTING_READ(intel_dp->output_reg);
5252c9916cdSFrançois Tigeot 
5262c9916cdSFrançois Tigeot 	I915_WRITE(intel_dp->output_reg, DP | DP_PORT_EN);
5272c9916cdSFrançois Tigeot 	POSTING_READ(intel_dp->output_reg);
5282c9916cdSFrançois Tigeot 
5292c9916cdSFrançois Tigeot 	I915_WRITE(intel_dp->output_reg, DP & ~DP_PORT_EN);
5302c9916cdSFrançois Tigeot 	POSTING_READ(intel_dp->output_reg);
5312c9916cdSFrançois Tigeot 
532352ff8bdSFrançois Tigeot 	if (!pll_enabled) {
5334be47400SFrançois Tigeot 		vlv_force_pll_off(dev_priv, pipe);
534352ff8bdSFrançois Tigeot 
535352ff8bdSFrançois Tigeot 		if (release_cl_override)
536352ff8bdSFrançois Tigeot 			chv_phy_powergate_ch(dev_priv, phy, ch, false);
537352ff8bdSFrançois Tigeot 	}
5382c9916cdSFrançois Tigeot }
5392c9916cdSFrançois Tigeot 
vlv_find_free_pps(struct drm_i915_private * dev_priv)540a85cb24fSFrançois Tigeot static enum i915_pipe vlv_find_free_pps(struct drm_i915_private *dev_priv)
541a85cb24fSFrançois Tigeot {
542a85cb24fSFrançois Tigeot 	struct intel_encoder *encoder;
543a85cb24fSFrançois Tigeot 	unsigned int pipes = (1 << PIPE_A) | (1 << PIPE_B);
544a85cb24fSFrançois Tigeot 
545a85cb24fSFrançois Tigeot 	/*
546a85cb24fSFrançois Tigeot 	 * We don't have power sequencer currently.
547a85cb24fSFrançois Tigeot 	 * Pick one that's not used by other ports.
548a85cb24fSFrançois Tigeot 	 */
549a85cb24fSFrançois Tigeot 	for_each_intel_encoder(&dev_priv->drm, encoder) {
550a85cb24fSFrançois Tigeot 		struct intel_dp *intel_dp;
551a85cb24fSFrançois Tigeot 
552a85cb24fSFrançois Tigeot 		if (encoder->type != INTEL_OUTPUT_DP &&
553a85cb24fSFrançois Tigeot 		    encoder->type != INTEL_OUTPUT_EDP)
554a85cb24fSFrançois Tigeot 			continue;
555a85cb24fSFrançois Tigeot 
556a85cb24fSFrançois Tigeot 		intel_dp = enc_to_intel_dp(&encoder->base);
557a85cb24fSFrançois Tigeot 
558a85cb24fSFrançois Tigeot 		if (encoder->type == INTEL_OUTPUT_EDP) {
559a85cb24fSFrançois Tigeot 			WARN_ON(intel_dp->active_pipe != INVALID_PIPE &&
560a85cb24fSFrançois Tigeot 				intel_dp->active_pipe != intel_dp->pps_pipe);
561a85cb24fSFrançois Tigeot 
562a85cb24fSFrançois Tigeot 			if (intel_dp->pps_pipe != INVALID_PIPE)
563a85cb24fSFrançois Tigeot 				pipes &= ~(1 << intel_dp->pps_pipe);
564a85cb24fSFrançois Tigeot 		} else {
565a85cb24fSFrançois Tigeot 			WARN_ON(intel_dp->pps_pipe != INVALID_PIPE);
566a85cb24fSFrançois Tigeot 
567a85cb24fSFrançois Tigeot 			if (intel_dp->active_pipe != INVALID_PIPE)
568a85cb24fSFrançois Tigeot 				pipes &= ~(1 << intel_dp->active_pipe);
569a85cb24fSFrançois Tigeot 		}
570a85cb24fSFrançois Tigeot 	}
571a85cb24fSFrançois Tigeot 
572a85cb24fSFrançois Tigeot 	if (pipes == 0)
573a85cb24fSFrançois Tigeot 		return INVALID_PIPE;
574a85cb24fSFrançois Tigeot 
575a85cb24fSFrançois Tigeot 	return ffs(pipes) - 1;
576a85cb24fSFrançois Tigeot }
577a85cb24fSFrançois Tigeot 
5789edbd4a0SFrançois Tigeot static enum i915_pipe
vlv_power_sequencer_pipe(struct intel_dp * intel_dp)5799edbd4a0SFrançois Tigeot vlv_power_sequencer_pipe(struct intel_dp *intel_dp)
5809edbd4a0SFrançois Tigeot {
5819edbd4a0SFrançois Tigeot 	struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp);
5829edbd4a0SFrançois Tigeot 	struct drm_device *dev = intel_dig_port->base.base.dev;
583303bf270SFrançois Tigeot 	struct drm_i915_private *dev_priv = to_i915(dev);
5842c9916cdSFrançois Tigeot 	enum i915_pipe pipe;
5851b13d190SFrançois Tigeot 
5861b13d190SFrançois Tigeot 	lockdep_assert_held(&dev_priv->pps_mutex);
5871b13d190SFrançois Tigeot 
5882c9916cdSFrançois Tigeot 	/* We should never land here with regular DP ports */
589*3f2dd94aSFrançois Tigeot 	WARN_ON(!intel_dp_is_edp(intel_dp));
5902c9916cdSFrançois Tigeot 
591a85cb24fSFrançois Tigeot 	WARN_ON(intel_dp->active_pipe != INVALID_PIPE &&
592a85cb24fSFrançois Tigeot 		intel_dp->active_pipe != intel_dp->pps_pipe);
593a85cb24fSFrançois Tigeot 
5941b13d190SFrançois Tigeot 	if (intel_dp->pps_pipe != INVALID_PIPE)
5951b13d190SFrançois Tigeot 		return intel_dp->pps_pipe;
5961b13d190SFrançois Tigeot 
597a85cb24fSFrançois Tigeot 	pipe = vlv_find_free_pps(dev_priv);
5981b13d190SFrançois Tigeot 
5991b13d190SFrançois Tigeot 	/*
6001b13d190SFrançois Tigeot 	 * Didn't find one. This should not happen since there
6011b13d190SFrançois Tigeot 	 * are two power sequencers and up to two eDP ports.
6021b13d190SFrançois Tigeot 	 */
603a85cb24fSFrançois Tigeot 	if (WARN_ON(pipe == INVALID_PIPE))
6042c9916cdSFrançois Tigeot 		pipe = PIPE_A;
6051b13d190SFrançois Tigeot 
6062c9916cdSFrançois Tigeot 	vlv_steal_power_sequencer(dev, pipe);
6072c9916cdSFrançois Tigeot 	intel_dp->pps_pipe = pipe;
6081b13d190SFrançois Tigeot 
6091b13d190SFrançois Tigeot 	DRM_DEBUG_KMS("picked pipe %c power sequencer for port %c\n",
6101b13d190SFrançois Tigeot 		      pipe_name(intel_dp->pps_pipe),
6111b13d190SFrançois Tigeot 		      port_name(intel_dig_port->port));
6121b13d190SFrançois Tigeot 
6131b13d190SFrançois Tigeot 	/* init power sequencer on this pipe and port */
6142c9916cdSFrançois Tigeot 	intel_dp_init_panel_power_sequencer(dev, intel_dp);
6154be47400SFrançois Tigeot 	intel_dp_init_panel_power_sequencer_registers(dev, intel_dp, true);
6162c9916cdSFrançois Tigeot 
6172c9916cdSFrançois Tigeot 	/*
6182c9916cdSFrançois Tigeot 	 * Even vdd force doesn't work until we've made
6192c9916cdSFrançois Tigeot 	 * the power sequencer lock in on the port.
6202c9916cdSFrançois Tigeot 	 */
6212c9916cdSFrançois Tigeot 	vlv_power_sequencer_kick(intel_dp);
6221b13d190SFrançois Tigeot 
6231b13d190SFrançois Tigeot 	return intel_dp->pps_pipe;
6241b13d190SFrançois Tigeot }
6251b13d190SFrançois Tigeot 
6261487f786SFrançois Tigeot static int
bxt_power_sequencer_idx(struct intel_dp * intel_dp)6271487f786SFrançois Tigeot bxt_power_sequencer_idx(struct intel_dp *intel_dp)
6281487f786SFrançois Tigeot {
6291487f786SFrançois Tigeot 	struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp);
6301487f786SFrançois Tigeot 	struct drm_device *dev = intel_dig_port->base.base.dev;
631303bf270SFrançois Tigeot 	struct drm_i915_private *dev_priv = to_i915(dev);
6321487f786SFrançois Tigeot 
6331487f786SFrançois Tigeot 	lockdep_assert_held(&dev_priv->pps_mutex);
6341487f786SFrançois Tigeot 
6351487f786SFrançois Tigeot 	/* We should never land here with regular DP ports */
636*3f2dd94aSFrançois Tigeot 	WARN_ON(!intel_dp_is_edp(intel_dp));
6371487f786SFrançois Tigeot 
6381487f786SFrançois Tigeot 	/*
6391487f786SFrançois Tigeot 	 * TODO: BXT has 2 PPS instances. The correct port->PPS instance
6401487f786SFrançois Tigeot 	 * mapping needs to be retrieved from VBT, for now just hard-code to
6411487f786SFrançois Tigeot 	 * use instance #0 always.
6421487f786SFrançois Tigeot 	 */
6431487f786SFrançois Tigeot 	if (!intel_dp->pps_reset)
6441487f786SFrançois Tigeot 		return 0;
6451487f786SFrançois Tigeot 
6461487f786SFrançois Tigeot 	intel_dp->pps_reset = false;
6471487f786SFrançois Tigeot 
6481487f786SFrançois Tigeot 	/*
6491487f786SFrançois Tigeot 	 * Only the HW needs to be reprogrammed, the SW state is fixed and
6501487f786SFrançois Tigeot 	 * has been setup during connector init.
6511487f786SFrançois Tigeot 	 */
6524be47400SFrançois Tigeot 	intel_dp_init_panel_power_sequencer_registers(dev, intel_dp, false);
6531487f786SFrançois Tigeot 
6541487f786SFrançois Tigeot 	return 0;
6551487f786SFrançois Tigeot }
6561487f786SFrançois Tigeot 
6571b13d190SFrançois Tigeot typedef bool (*vlv_pipe_check)(struct drm_i915_private *dev_priv,
6581b13d190SFrançois Tigeot 			       enum i915_pipe pipe);
6591b13d190SFrançois Tigeot 
vlv_pipe_has_pp_on(struct drm_i915_private * dev_priv,enum i915_pipe pipe)6601b13d190SFrançois Tigeot static bool vlv_pipe_has_pp_on(struct drm_i915_private *dev_priv,
6611b13d190SFrançois Tigeot 			       enum i915_pipe pipe)
6621b13d190SFrançois Tigeot {
6631e12ee3bSFrançois Tigeot 	return I915_READ(PP_STATUS(pipe)) & PP_ON;
6641b13d190SFrançois Tigeot }
6651b13d190SFrançois Tigeot 
vlv_pipe_has_vdd_on(struct drm_i915_private * dev_priv,enum i915_pipe pipe)6661b13d190SFrançois Tigeot static bool vlv_pipe_has_vdd_on(struct drm_i915_private *dev_priv,
6671b13d190SFrançois Tigeot 				enum i915_pipe pipe)
6681b13d190SFrançois Tigeot {
6691e12ee3bSFrançois Tigeot 	return I915_READ(PP_CONTROL(pipe)) & EDP_FORCE_VDD;
6701b13d190SFrançois Tigeot }
6711b13d190SFrançois Tigeot 
vlv_pipe_any(struct drm_i915_private * dev_priv,enum i915_pipe pipe)6721b13d190SFrançois Tigeot static bool vlv_pipe_any(struct drm_i915_private *dev_priv,
6731b13d190SFrançois Tigeot 			 enum i915_pipe pipe)
6741b13d190SFrançois Tigeot {
6751b13d190SFrançois Tigeot 	return true;
6761b13d190SFrançois Tigeot }
6771b13d190SFrançois Tigeot 
6781b13d190SFrançois Tigeot static enum i915_pipe
vlv_initial_pps_pipe(struct drm_i915_private * dev_priv,enum port port,vlv_pipe_check pipe_check)6791b13d190SFrançois Tigeot vlv_initial_pps_pipe(struct drm_i915_private *dev_priv,
6801b13d190SFrançois Tigeot 		     enum port port,
6811b13d190SFrançois Tigeot 		     vlv_pipe_check pipe_check)
6821b13d190SFrançois Tigeot {
6839edbd4a0SFrançois Tigeot 	enum i915_pipe pipe;
6849edbd4a0SFrançois Tigeot 
6859edbd4a0SFrançois Tigeot 	for (pipe = PIPE_A; pipe <= PIPE_B; pipe++) {
6861e12ee3bSFrançois Tigeot 		u32 port_sel = I915_READ(PP_ON_DELAYS(pipe)) &
6879edbd4a0SFrançois Tigeot 			PANEL_PORT_SELECT_MASK;
6881b13d190SFrançois Tigeot 
6891b13d190SFrançois Tigeot 		if (port_sel != PANEL_PORT_SELECT_VLV(port))
6901b13d190SFrançois Tigeot 			continue;
6911b13d190SFrançois Tigeot 
6921b13d190SFrançois Tigeot 		if (!pipe_check(dev_priv, pipe))
6931b13d190SFrançois Tigeot 			continue;
6941b13d190SFrançois Tigeot 
6959edbd4a0SFrançois Tigeot 		return pipe;
6969edbd4a0SFrançois Tigeot 	}
6979edbd4a0SFrançois Tigeot 
6981b13d190SFrançois Tigeot 	return INVALID_PIPE;
6991b13d190SFrançois Tigeot }
7001b13d190SFrançois Tigeot 
7011b13d190SFrançois Tigeot static void
vlv_initial_power_sequencer_setup(struct intel_dp * intel_dp)7021b13d190SFrançois Tigeot vlv_initial_power_sequencer_setup(struct intel_dp *intel_dp)
7031b13d190SFrançois Tigeot {
7041b13d190SFrançois Tigeot 	struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp);
7051b13d190SFrançois Tigeot 	struct drm_device *dev = intel_dig_port->base.base.dev;
706303bf270SFrançois Tigeot 	struct drm_i915_private *dev_priv = to_i915(dev);
7071b13d190SFrançois Tigeot 	enum port port = intel_dig_port->port;
7081b13d190SFrançois Tigeot 
7091b13d190SFrançois Tigeot 	lockdep_assert_held(&dev_priv->pps_mutex);
7101b13d190SFrançois Tigeot 
7111b13d190SFrançois Tigeot 	/* try to find a pipe with this port selected */
7121b13d190SFrançois Tigeot 	/* first pick one where the panel is on */
7131b13d190SFrançois Tigeot 	intel_dp->pps_pipe = vlv_initial_pps_pipe(dev_priv, port,
7141b13d190SFrançois Tigeot 						  vlv_pipe_has_pp_on);
7151b13d190SFrançois Tigeot 	/* didn't find one? pick one where vdd is on */
7161b13d190SFrançois Tigeot 	if (intel_dp->pps_pipe == INVALID_PIPE)
7171b13d190SFrançois Tigeot 		intel_dp->pps_pipe = vlv_initial_pps_pipe(dev_priv, port,
7181b13d190SFrançois Tigeot 							  vlv_pipe_has_vdd_on);
7191b13d190SFrançois Tigeot 	/* didn't find one? pick one with just the correct port */
7201b13d190SFrançois Tigeot 	if (intel_dp->pps_pipe == INVALID_PIPE)
7211b13d190SFrançois Tigeot 		intel_dp->pps_pipe = vlv_initial_pps_pipe(dev_priv, port,
7221b13d190SFrançois Tigeot 							  vlv_pipe_any);
7231b13d190SFrançois Tigeot 
7241b13d190SFrançois Tigeot 	/* didn't find one? just let vlv_power_sequencer_pipe() pick one when needed */
7251b13d190SFrançois Tigeot 	if (intel_dp->pps_pipe == INVALID_PIPE) {
7261b13d190SFrançois Tigeot 		DRM_DEBUG_KMS("no initial power sequencer for port %c\n",
7271b13d190SFrançois Tigeot 			      port_name(port));
7281b13d190SFrançois Tigeot 		return;
7291b13d190SFrançois Tigeot 	}
7301b13d190SFrançois Tigeot 
7311b13d190SFrançois Tigeot 	DRM_DEBUG_KMS("initial power sequencer for port %c: pipe %c\n",
7321b13d190SFrançois Tigeot 		      port_name(port), pipe_name(intel_dp->pps_pipe));
7331b13d190SFrançois Tigeot 
7342c9916cdSFrançois Tigeot 	intel_dp_init_panel_power_sequencer(dev, intel_dp);
7354be47400SFrançois Tigeot 	intel_dp_init_panel_power_sequencer_registers(dev, intel_dp, false);
7361b13d190SFrançois Tigeot }
7371b13d190SFrançois Tigeot 
intel_power_sequencer_reset(struct drm_i915_private * dev_priv)7381487f786SFrançois Tigeot void intel_power_sequencer_reset(struct drm_i915_private *dev_priv)
7391b13d190SFrançois Tigeot {
740303bf270SFrançois Tigeot 	struct drm_device *dev = &dev_priv->drm;
7411b13d190SFrançois Tigeot 	struct intel_encoder *encoder;
7421b13d190SFrançois Tigeot 
7431e12ee3bSFrançois Tigeot 	if (WARN_ON(!IS_VALLEYVIEW(dev_priv) && !IS_CHERRYVIEW(dev_priv) &&
744a85cb24fSFrançois Tigeot 		    !IS_GEN9_LP(dev_priv)))
7451b13d190SFrançois Tigeot 		return;
7461b13d190SFrançois Tigeot 
7471b13d190SFrançois Tigeot 	/*
7481b13d190SFrançois Tigeot 	 * We can't grab pps_mutex here due to deadlock with power_domain
7491b13d190SFrançois Tigeot 	 * mutex when power_domain functions are called while holding pps_mutex.
7501b13d190SFrançois Tigeot 	 * That also means that in order to use pps_pipe the code needs to
7511b13d190SFrançois Tigeot 	 * hold both a power domain reference and pps_mutex, and the power domain
7521b13d190SFrançois Tigeot 	 * reference get/put must be done while _not_ holding pps_mutex.
7531b13d190SFrançois Tigeot 	 * pps_{lock,unlock}() do these steps in the correct order, so one
7541b13d190SFrançois Tigeot 	 * should use them always.
7551b13d190SFrançois Tigeot 	 */
7561b13d190SFrançois Tigeot 
757aee94f86SFrançois Tigeot 	for_each_intel_encoder(dev, encoder) {
7581b13d190SFrançois Tigeot 		struct intel_dp *intel_dp;
7591b13d190SFrançois Tigeot 
760a85cb24fSFrançois Tigeot 		if (encoder->type != INTEL_OUTPUT_DP &&
761a85cb24fSFrançois Tigeot 		    encoder->type != INTEL_OUTPUT_EDP)
7621b13d190SFrançois Tigeot 			continue;
7631b13d190SFrançois Tigeot 
7641b13d190SFrançois Tigeot 		intel_dp = enc_to_intel_dp(&encoder->base);
765a85cb24fSFrançois Tigeot 
766a85cb24fSFrançois Tigeot 		WARN_ON(intel_dp->active_pipe != INVALID_PIPE);
767a85cb24fSFrançois Tigeot 
768a85cb24fSFrançois Tigeot 		if (encoder->type != INTEL_OUTPUT_EDP)
769a85cb24fSFrançois Tigeot 			continue;
770a85cb24fSFrançois Tigeot 
771a85cb24fSFrançois Tigeot 		if (IS_GEN9_LP(dev_priv))
7721487f786SFrançois Tigeot 			intel_dp->pps_reset = true;
7731487f786SFrançois Tigeot 		else
7741b13d190SFrançois Tigeot 			intel_dp->pps_pipe = INVALID_PIPE;
7751b13d190SFrançois Tigeot 	}
7769edbd4a0SFrançois Tigeot }
7779edbd4a0SFrançois Tigeot 
7781487f786SFrançois Tigeot struct pps_registers {
7791487f786SFrançois Tigeot 	i915_reg_t pp_ctrl;
7801487f786SFrançois Tigeot 	i915_reg_t pp_stat;
7811487f786SFrançois Tigeot 	i915_reg_t pp_on;
7821487f786SFrançois Tigeot 	i915_reg_t pp_off;
7831487f786SFrançois Tigeot 	i915_reg_t pp_div;
7841487f786SFrançois Tigeot };
7851487f786SFrançois Tigeot 
intel_pps_get_registers(struct drm_i915_private * dev_priv,struct intel_dp * intel_dp,struct pps_registers * regs)7861487f786SFrançois Tigeot static void intel_pps_get_registers(struct drm_i915_private *dev_priv,
7871487f786SFrançois Tigeot 				    struct intel_dp *intel_dp,
7881487f786SFrançois Tigeot 				    struct pps_registers *regs)
7891487f786SFrançois Tigeot {
7901e12ee3bSFrançois Tigeot 	int pps_idx = 0;
7911e12ee3bSFrançois Tigeot 
7921487f786SFrançois Tigeot 	memset(regs, 0, sizeof(*regs));
7931487f786SFrançois Tigeot 
794a85cb24fSFrançois Tigeot 	if (IS_GEN9_LP(dev_priv))
7951e12ee3bSFrançois Tigeot 		pps_idx = bxt_power_sequencer_idx(intel_dp);
7961e12ee3bSFrançois Tigeot 	else if (IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv))
7971e12ee3bSFrançois Tigeot 		pps_idx = vlv_power_sequencer_pipe(intel_dp);
7981487f786SFrançois Tigeot 
7991e12ee3bSFrançois Tigeot 	regs->pp_ctrl = PP_CONTROL(pps_idx);
8001e12ee3bSFrançois Tigeot 	regs->pp_stat = PP_STATUS(pps_idx);
8011e12ee3bSFrançois Tigeot 	regs->pp_on = PP_ON_DELAYS(pps_idx);
8021e12ee3bSFrançois Tigeot 	regs->pp_off = PP_OFF_DELAYS(pps_idx);
803*3f2dd94aSFrançois Tigeot 	if (!IS_GEN9_LP(dev_priv) && !HAS_PCH_CNP(dev_priv))
8041e12ee3bSFrançois Tigeot 		regs->pp_div = PP_DIVISOR(pps_idx);
8051487f786SFrançois Tigeot }
8061487f786SFrançois Tigeot 
807aee94f86SFrançois Tigeot static i915_reg_t
_pp_ctrl_reg(struct intel_dp * intel_dp)808aee94f86SFrançois Tigeot _pp_ctrl_reg(struct intel_dp *intel_dp)
8099edbd4a0SFrançois Tigeot {
8101487f786SFrançois Tigeot 	struct pps_registers regs;
8119edbd4a0SFrançois Tigeot 
8121487f786SFrançois Tigeot 	intel_pps_get_registers(to_i915(intel_dp_to_dev(intel_dp)), intel_dp,
8131487f786SFrançois Tigeot 				&regs);
8141487f786SFrançois Tigeot 
8151487f786SFrançois Tigeot 	return regs.pp_ctrl;
8169edbd4a0SFrançois Tigeot }
8179edbd4a0SFrançois Tigeot 
818aee94f86SFrançois Tigeot static i915_reg_t
_pp_stat_reg(struct intel_dp * intel_dp)819aee94f86SFrançois Tigeot _pp_stat_reg(struct intel_dp *intel_dp)
8209edbd4a0SFrançois Tigeot {
8211487f786SFrançois Tigeot 	struct pps_registers regs;
8229edbd4a0SFrançois Tigeot 
8231487f786SFrançois Tigeot 	intel_pps_get_registers(to_i915(intel_dp_to_dev(intel_dp)), intel_dp,
8241487f786SFrançois Tigeot 				&regs);
8251487f786SFrançois Tigeot 
8261487f786SFrançois Tigeot 	return regs.pp_stat;
8279edbd4a0SFrançois Tigeot }
8289edbd4a0SFrançois Tigeot 
829ba55f2f5SFrançois Tigeot /* Reboot notifier handler to shutdown panel power to guarantee T12 timing
830ba55f2f5SFrançois Tigeot    This function only applicable when panel PM state is not to be tracked */
edp_notify_handler(struct notifier_block * this,unsigned long code,void * unused)831ba55f2f5SFrançois Tigeot static int edp_notify_handler(struct notifier_block *this, unsigned long code,
832ba55f2f5SFrançois Tigeot 			      void *unused)
833ba55f2f5SFrançois Tigeot {
834ba55f2f5SFrançois Tigeot 	struct intel_dp *intel_dp = container_of(this, typeof(* intel_dp),
835ba55f2f5SFrançois Tigeot 						 edp_notifier);
836ba55f2f5SFrançois Tigeot 	struct drm_device *dev = intel_dp_to_dev(intel_dp);
837303bf270SFrançois Tigeot 	struct drm_i915_private *dev_priv = to_i915(dev);
838ba55f2f5SFrançois Tigeot 
839aee94f86SFrançois Tigeot #if 0
840*3f2dd94aSFrançois Tigeot 	if (!intel_dp_is_edp(intel_dp) || code != SYS_RESTART)
841aee94f86SFrançois Tigeot #endif
842*3f2dd94aSFrançois Tigeot 	if (!intel_dp_is_edp(intel_dp))
8431487f786SFrançois Tigeot 		return 0;
844ba55f2f5SFrançois Tigeot 
8451b13d190SFrançois Tigeot 	pps_lock(intel_dp);
8461b13d190SFrançois Tigeot 
8471e12ee3bSFrançois Tigeot 	if (IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv)) {
848aee94f86SFrançois Tigeot 		enum i915_pipe pipe = vlv_power_sequencer_pipe(intel_dp);
849aee94f86SFrançois Tigeot 		i915_reg_t pp_ctrl_reg, pp_div_reg;
850352ff8bdSFrançois Tigeot 		u32 pp_div;
8511b13d190SFrançois Tigeot 
8521e12ee3bSFrançois Tigeot 		pp_ctrl_reg = PP_CONTROL(pipe);
8531e12ee3bSFrançois Tigeot 		pp_div_reg  = PP_DIVISOR(pipe);
854ba55f2f5SFrançois Tigeot 		pp_div = I915_READ(pp_div_reg);
855ba55f2f5SFrançois Tigeot 		pp_div &= PP_REFERENCE_DIVIDER_MASK;
856ba55f2f5SFrançois Tigeot 
857ba55f2f5SFrançois Tigeot 		/* 0x1F write to PP_DIV_REG sets max cycle delay */
858ba55f2f5SFrançois Tigeot 		I915_WRITE(pp_div_reg, pp_div | 0x1F);
859ba55f2f5SFrançois Tigeot 		I915_WRITE(pp_ctrl_reg, PANEL_UNLOCK_REGS | PANEL_POWER_OFF);
860ba55f2f5SFrançois Tigeot 		msleep(intel_dp->panel_power_cycle_delay);
861ba55f2f5SFrançois Tigeot 	}
862ba55f2f5SFrançois Tigeot 
8631b13d190SFrançois Tigeot 	pps_unlock(intel_dp);
8641b13d190SFrançois Tigeot 
865ba55f2f5SFrançois Tigeot 	return 0;
866ba55f2f5SFrançois Tigeot }
867ba55f2f5SFrançois Tigeot 
edp_have_panel_power(struct intel_dp * intel_dp)868ba55f2f5SFrançois Tigeot static bool edp_have_panel_power(struct intel_dp *intel_dp)
869e3adcf8fSFrançois Tigeot {
87019df918dSFrançois Tigeot 	struct drm_device *dev = intel_dp_to_dev(intel_dp);
871303bf270SFrançois Tigeot 	struct drm_i915_private *dev_priv = to_i915(dev);
872e3adcf8fSFrançois Tigeot 
8731b13d190SFrançois Tigeot 	lockdep_assert_held(&dev_priv->pps_mutex);
8741b13d190SFrançois Tigeot 
8751e12ee3bSFrançois Tigeot 	if ((IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv)) &&
8762c9916cdSFrançois Tigeot 	    intel_dp->pps_pipe == INVALID_PIPE)
8772c9916cdSFrançois Tigeot 		return false;
8782c9916cdSFrançois Tigeot 
8799edbd4a0SFrançois Tigeot 	return (I915_READ(_pp_stat_reg(intel_dp)) & PP_ON) != 0;
880e3adcf8fSFrançois Tigeot }
881e3adcf8fSFrançois Tigeot 
edp_have_panel_vdd(struct intel_dp * intel_dp)882ba55f2f5SFrançois Tigeot static bool edp_have_panel_vdd(struct intel_dp *intel_dp)
883e3adcf8fSFrançois Tigeot {
88419df918dSFrançois Tigeot 	struct drm_device *dev = intel_dp_to_dev(intel_dp);
885303bf270SFrançois Tigeot 	struct drm_i915_private *dev_priv = to_i915(dev);
886e3adcf8fSFrançois Tigeot 
8871b13d190SFrançois Tigeot 	lockdep_assert_held(&dev_priv->pps_mutex);
8881b13d190SFrançois Tigeot 
8891e12ee3bSFrançois Tigeot 	if ((IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv)) &&
8902c9916cdSFrançois Tigeot 	    intel_dp->pps_pipe == INVALID_PIPE)
8912c9916cdSFrançois Tigeot 		return false;
8922c9916cdSFrançois Tigeot 
8931b13d190SFrançois Tigeot 	return I915_READ(_pp_ctrl_reg(intel_dp)) & EDP_FORCE_VDD;
894e3adcf8fSFrançois Tigeot }
895e3adcf8fSFrançois Tigeot 
896e3adcf8fSFrançois Tigeot static void
intel_dp_check_edp(struct intel_dp * intel_dp)897e3adcf8fSFrançois Tigeot intel_dp_check_edp(struct intel_dp *intel_dp)
898e3adcf8fSFrançois Tigeot {
89919df918dSFrançois Tigeot 	struct drm_device *dev = intel_dp_to_dev(intel_dp);
900303bf270SFrançois Tigeot 	struct drm_i915_private *dev_priv = to_i915(dev);
901e3adcf8fSFrançois Tigeot 
902*3f2dd94aSFrançois Tigeot 	if (!intel_dp_is_edp(intel_dp))
903e3adcf8fSFrançois Tigeot 		return;
9048e26cdf6SFrançois Tigeot 
905ba55f2f5SFrançois Tigeot 	if (!edp_have_panel_power(intel_dp) && !edp_have_panel_vdd(intel_dp)) {
90619df918dSFrançois Tigeot 		WARN(1, "eDP powered off while attempting aux channel communication.\n");
907e3adcf8fSFrançois Tigeot 		DRM_DEBUG_KMS("Status 0x%08x Control 0x%08x\n",
9089edbd4a0SFrançois Tigeot 			      I915_READ(_pp_stat_reg(intel_dp)),
9099edbd4a0SFrançois Tigeot 			      I915_READ(_pp_ctrl_reg(intel_dp)));
910e3adcf8fSFrançois Tigeot 	}
911e3adcf8fSFrançois Tigeot }
912e3adcf8fSFrançois Tigeot 
913a2fdbec6SFrançois Tigeot static uint32_t
intel_dp_aux_wait_done(struct intel_dp * intel_dp,bool has_aux_irq)914a2fdbec6SFrançois Tigeot intel_dp_aux_wait_done(struct intel_dp *intel_dp, bool has_aux_irq)
915a2fdbec6SFrançois Tigeot {
916a2fdbec6SFrançois Tigeot 	struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp);
917a2fdbec6SFrançois Tigeot 	struct drm_device *dev = intel_dig_port->base.base.dev;
918303bf270SFrançois Tigeot 	struct drm_i915_private *dev_priv = to_i915(dev);
919aee94f86SFrançois Tigeot 	i915_reg_t ch_ctl = intel_dp->aux_ch_ctl_reg;
920a2fdbec6SFrançois Tigeot 	uint32_t status;
921a2fdbec6SFrançois Tigeot 	bool done;
922a2fdbec6SFrançois Tigeot 
923a2fdbec6SFrançois Tigeot #define C (((status = I915_READ_NOTRACE(ch_ctl)) & DP_AUX_CH_CTL_SEND_BUSY) == 0)
924a2fdbec6SFrançois Tigeot 	if (has_aux_irq)
925a2fdbec6SFrançois Tigeot 		done = wait_event_timeout(dev_priv->gmbus_wait_queue, C,
9269edbd4a0SFrançois Tigeot 					  msecs_to_jiffies_timeout(10));
927a2fdbec6SFrançois Tigeot 	else
9288621f407SFrançois Tigeot 		done = wait_for(C, 10) == 0;
929a2fdbec6SFrançois Tigeot 	if (!done)
930a2fdbec6SFrançois Tigeot 		DRM_ERROR("dp aux hw did not signal timeout (has irq: %i)!\n",
931a2fdbec6SFrançois Tigeot 			  has_aux_irq);
932a2fdbec6SFrançois Tigeot #undef C
933a2fdbec6SFrançois Tigeot 
934a2fdbec6SFrançois Tigeot 	return status;
935a2fdbec6SFrançois Tigeot }
936a2fdbec6SFrançois Tigeot 
g4x_get_aux_clock_divider(struct intel_dp * intel_dp,int index)9378621f407SFrançois Tigeot static uint32_t g4x_get_aux_clock_divider(struct intel_dp *intel_dp, int index)
938ba55f2f5SFrançois Tigeot {
939ba55f2f5SFrançois Tigeot 	struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp);
9408621f407SFrançois Tigeot 	struct drm_i915_private *dev_priv = to_i915(intel_dig_port->base.base.dev);
9418621f407SFrançois Tigeot 
9428621f407SFrançois Tigeot 	if (index)
9438621f407SFrançois Tigeot 		return 0;
944ba55f2f5SFrançois Tigeot 
945ba55f2f5SFrançois Tigeot 	/*
946ba55f2f5SFrançois Tigeot 	 * The clock divider is based off the hrawclk, and would like to run at
9478621f407SFrançois Tigeot 	 * 2MHz.  So, take the hrawclk value and divide by 2000 and use that
948ba55f2f5SFrançois Tigeot 	 */
9498621f407SFrançois Tigeot 	return DIV_ROUND_CLOSEST(dev_priv->rawclk_freq, 2000);
950ba55f2f5SFrançois Tigeot }
951ba55f2f5SFrançois Tigeot 
ilk_get_aux_clock_divider(struct intel_dp * intel_dp,int index)952ba55f2f5SFrançois Tigeot static uint32_t ilk_get_aux_clock_divider(struct intel_dp *intel_dp, int index)
953ba55f2f5SFrançois Tigeot {
954ba55f2f5SFrançois Tigeot 	struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp);
9558621f407SFrançois Tigeot 	struct drm_i915_private *dev_priv = to_i915(intel_dig_port->base.base.dev);
956ba55f2f5SFrançois Tigeot 
957ba55f2f5SFrançois Tigeot 	if (index)
958ba55f2f5SFrançois Tigeot 		return 0;
959ba55f2f5SFrançois Tigeot 
9608621f407SFrançois Tigeot 	/*
9618621f407SFrançois Tigeot 	 * The clock divider is based off the cdclk or PCH rawclk, and would
9628621f407SFrançois Tigeot 	 * like to run at 2MHz.  So, take the cdclk or PCH rawclk value and
9638621f407SFrançois Tigeot 	 * divide by 2000 and use that
9648621f407SFrançois Tigeot 	 */
9658621f407SFrançois Tigeot 	if (intel_dig_port->port == PORT_A)
966a85cb24fSFrançois Tigeot 		return DIV_ROUND_CLOSEST(dev_priv->cdclk.hw.cdclk, 2000);
9678621f407SFrançois Tigeot 	else
9688621f407SFrançois Tigeot 		return DIV_ROUND_CLOSEST(dev_priv->rawclk_freq, 2000);
969ba55f2f5SFrançois Tigeot }
970ba55f2f5SFrançois Tigeot 
hsw_get_aux_clock_divider(struct intel_dp * intel_dp,int index)971ba55f2f5SFrançois Tigeot static uint32_t hsw_get_aux_clock_divider(struct intel_dp *intel_dp, int index)
9729edbd4a0SFrançois Tigeot {
9739edbd4a0SFrançois Tigeot 	struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp);
9748621f407SFrançois Tigeot 	struct drm_i915_private *dev_priv = to_i915(intel_dig_port->base.base.dev);
9759edbd4a0SFrançois Tigeot 
9768621f407SFrançois Tigeot 	if (intel_dig_port->port != PORT_A && HAS_PCH_LPT_H(dev_priv)) {
9779edbd4a0SFrançois Tigeot 		/* Workaround for non-ULT HSW */
9789edbd4a0SFrançois Tigeot 		switch (index) {
9799edbd4a0SFrançois Tigeot 		case 0: return 63;
9809edbd4a0SFrançois Tigeot 		case 1: return 72;
9819edbd4a0SFrançois Tigeot 		default: return 0;
9829edbd4a0SFrançois Tigeot 		}
9839edbd4a0SFrançois Tigeot 	}
9849edbd4a0SFrançois Tigeot 
9858621f407SFrançois Tigeot 	return ilk_get_aux_clock_divider(intel_dp, index);
986ba55f2f5SFrançois Tigeot }
987ba55f2f5SFrançois Tigeot 
skl_get_aux_clock_divider(struct intel_dp * intel_dp,int index)9882c9916cdSFrançois Tigeot static uint32_t skl_get_aux_clock_divider(struct intel_dp *intel_dp, int index)
9892c9916cdSFrançois Tigeot {
9902c9916cdSFrançois Tigeot 	/*
9912c9916cdSFrançois Tigeot 	 * SKL doesn't need us to program the AUX clock divider (Hardware will
9922c9916cdSFrançois Tigeot 	 * derive the clock from CDCLK automatically). We still implement the
9932c9916cdSFrançois Tigeot 	 * get_aux_clock_divider vfunc to plug-in into the existing code.
9942c9916cdSFrançois Tigeot 	 */
9952c9916cdSFrançois Tigeot 	return index ? 0 : 1;
9962c9916cdSFrançois Tigeot }
9972c9916cdSFrançois Tigeot 
g4x_get_aux_send_ctl(struct intel_dp * intel_dp,bool has_aux_irq,int send_bytes,uint32_t aux_clock_divider)9988621f407SFrançois Tigeot static uint32_t g4x_get_aux_send_ctl(struct intel_dp *intel_dp,
999ba55f2f5SFrançois Tigeot 				     bool has_aux_irq,
1000ba55f2f5SFrançois Tigeot 				     int send_bytes,
1001ba55f2f5SFrançois Tigeot 				     uint32_t aux_clock_divider)
1002ba55f2f5SFrançois Tigeot {
1003ba55f2f5SFrançois Tigeot 	struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp);
10041e12ee3bSFrançois Tigeot 	struct drm_i915_private *dev_priv =
10051e12ee3bSFrançois Tigeot 			to_i915(intel_dig_port->base.base.dev);
1006ba55f2f5SFrançois Tigeot 	uint32_t precharge, timeout;
1007ba55f2f5SFrançois Tigeot 
10081e12ee3bSFrançois Tigeot 	if (IS_GEN6(dev_priv))
1009ba55f2f5SFrançois Tigeot 		precharge = 3;
1010ba55f2f5SFrançois Tigeot 	else
1011ba55f2f5SFrançois Tigeot 		precharge = 5;
1012ba55f2f5SFrançois Tigeot 
1013*3f2dd94aSFrançois Tigeot 	if (IS_BROADWELL(dev_priv))
1014ba55f2f5SFrançois Tigeot 		timeout = DP_AUX_CH_CTL_TIME_OUT_600us;
1015ba55f2f5SFrançois Tigeot 	else
1016ba55f2f5SFrançois Tigeot 		timeout = DP_AUX_CH_CTL_TIME_OUT_400us;
1017ba55f2f5SFrançois Tigeot 
1018ba55f2f5SFrançois Tigeot 	return DP_AUX_CH_CTL_SEND_BUSY |
1019ba55f2f5SFrançois Tigeot 	       DP_AUX_CH_CTL_DONE |
1020ba55f2f5SFrançois Tigeot 	       (has_aux_irq ? DP_AUX_CH_CTL_INTERRUPT : 0) |
1021ba55f2f5SFrançois Tigeot 	       DP_AUX_CH_CTL_TIME_OUT_ERROR |
1022ba55f2f5SFrançois Tigeot 	       timeout |
1023ba55f2f5SFrançois Tigeot 	       DP_AUX_CH_CTL_RECEIVE_ERROR |
1024ba55f2f5SFrançois Tigeot 	       (send_bytes << DP_AUX_CH_CTL_MESSAGE_SIZE_SHIFT) |
1025ba55f2f5SFrançois Tigeot 	       (precharge << DP_AUX_CH_CTL_PRECHARGE_2US_SHIFT) |
1026ba55f2f5SFrançois Tigeot 	       (aux_clock_divider << DP_AUX_CH_CTL_BIT_CLOCK_2X_SHIFT);
1027ba55f2f5SFrançois Tigeot }
1028ba55f2f5SFrançois Tigeot 
skl_get_aux_send_ctl(struct intel_dp * intel_dp,bool has_aux_irq,int send_bytes,uint32_t unused)10292c9916cdSFrançois Tigeot static uint32_t skl_get_aux_send_ctl(struct intel_dp *intel_dp,
10302c9916cdSFrançois Tigeot 				      bool has_aux_irq,
10312c9916cdSFrançois Tigeot 				      int send_bytes,
10322c9916cdSFrançois Tigeot 				      uint32_t unused)
10332c9916cdSFrançois Tigeot {
10342c9916cdSFrançois Tigeot 	return DP_AUX_CH_CTL_SEND_BUSY |
10352c9916cdSFrançois Tigeot 	       DP_AUX_CH_CTL_DONE |
10362c9916cdSFrançois Tigeot 	       (has_aux_irq ? DP_AUX_CH_CTL_INTERRUPT : 0) |
10372c9916cdSFrançois Tigeot 	       DP_AUX_CH_CTL_TIME_OUT_ERROR |
1038*3f2dd94aSFrançois Tigeot 	       DP_AUX_CH_CTL_TIME_OUT_MAX |
10392c9916cdSFrançois Tigeot 	       DP_AUX_CH_CTL_RECEIVE_ERROR |
10402c9916cdSFrançois Tigeot 	       (send_bytes << DP_AUX_CH_CTL_MESSAGE_SIZE_SHIFT) |
10411487f786SFrançois Tigeot 	       DP_AUX_CH_CTL_FW_SYNC_PULSE_SKL(32) |
10422c9916cdSFrançois Tigeot 	       DP_AUX_CH_CTL_SYNC_PULSE_SKL(32);
10432c9916cdSFrançois Tigeot }
10442c9916cdSFrançois Tigeot 
1045e3adcf8fSFrançois Tigeot static int
intel_dp_aux_ch(struct intel_dp * intel_dp,const uint8_t * send,int send_bytes,uint8_t * recv,int recv_size)1046e3adcf8fSFrançois Tigeot intel_dp_aux_ch(struct intel_dp *intel_dp,
10472c9916cdSFrançois Tigeot 		const uint8_t *send, int send_bytes,
1048e3adcf8fSFrançois Tigeot 		uint8_t *recv, int recv_size)
1049e3adcf8fSFrançois Tigeot {
105019df918dSFrançois Tigeot 	struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp);
10514be47400SFrançois Tigeot 	struct drm_i915_private *dev_priv =
10524be47400SFrançois Tigeot 			to_i915(intel_dig_port->base.base.dev);
1053aee94f86SFrançois Tigeot 	i915_reg_t ch_ctl = intel_dp->aux_ch_ctl_reg;
10549edbd4a0SFrançois Tigeot 	uint32_t aux_clock_divider;
1055a2fdbec6SFrançois Tigeot 	int i, ret, recv_bytes;
1056e3adcf8fSFrançois Tigeot 	uint32_t status;
1057ba55f2f5SFrançois Tigeot 	int try, clock = 0;
10584be47400SFrançois Tigeot 	bool has_aux_irq = HAS_AUX_IRQ(dev_priv);
10591b13d190SFrançois Tigeot 	bool vdd;
10601b13d190SFrançois Tigeot 
10611b13d190SFrançois Tigeot 	pps_lock(intel_dp);
10621b13d190SFrançois Tigeot 
10631b13d190SFrançois Tigeot 	/*
10641b13d190SFrançois Tigeot 	 * We will be called with VDD already enabled for dpcd/edid/oui reads.
10651b13d190SFrançois Tigeot 	 * In such cases we want to leave VDD enabled and it's up to upper layers
10661b13d190SFrançois Tigeot 	 * to turn it off. But for eg. i2c-dev access we need to turn it on/off
10671b13d190SFrançois Tigeot 	 * ourselves.
10681b13d190SFrançois Tigeot 	 */
10691b13d190SFrançois Tigeot 	vdd = edp_panel_vdd_on(intel_dp);
1070a2fdbec6SFrançois Tigeot 
1071a2fdbec6SFrançois Tigeot 	/* dp aux is extremely sensitive to irq latency, hence request the
1072a2fdbec6SFrançois Tigeot 	 * lowest possible wakeup latency and so prevent the cpu from going into
1073a2fdbec6SFrançois Tigeot 	 * deep sleep states.
1074a2fdbec6SFrançois Tigeot 	 */
1075a2fdbec6SFrançois Tigeot 	pm_qos_update_request(&dev_priv->pm_qos, 0);
107619df918dSFrançois Tigeot 
1077e3adcf8fSFrançois Tigeot 	intel_dp_check_edp(intel_dp);
1078e3adcf8fSFrançois Tigeot 
1079e3adcf8fSFrançois Tigeot 	/* Try to wait for any previous AUX channel activity */
1080e3adcf8fSFrançois Tigeot 	for (try = 0; try < 3; try++) {
1081a2fdbec6SFrançois Tigeot 		status = I915_READ_NOTRACE(ch_ctl);
1082e3adcf8fSFrançois Tigeot 		if ((status & DP_AUX_CH_CTL_SEND_BUSY) == 0)
1083e3adcf8fSFrançois Tigeot 			break;
108419df918dSFrançois Tigeot 		msleep(1);
1085e3adcf8fSFrançois Tigeot 	}
1086e3adcf8fSFrançois Tigeot 
1087e3adcf8fSFrançois Tigeot 	if (try == 3) {
1088a05eeebfSFrançois Tigeot 		static u32 last_status = -1;
1089a05eeebfSFrançois Tigeot 		const u32 status = I915_READ(ch_ctl);
1090a05eeebfSFrançois Tigeot 
1091a05eeebfSFrançois Tigeot 		if (status != last_status) {
109219df918dSFrançois Tigeot 			WARN(1, "dp_aux_ch not started status 0x%08x\n",
1093a05eeebfSFrançois Tigeot 			     status);
1094a05eeebfSFrançois Tigeot 			last_status = status;
1095a05eeebfSFrançois Tigeot 		}
1096a05eeebfSFrançois Tigeot 
1097a2fdbec6SFrançois Tigeot 		ret = -EBUSY;
1098a2fdbec6SFrançois Tigeot 		goto out;
1099e3adcf8fSFrançois Tigeot 	}
1100e3adcf8fSFrançois Tigeot 
11019edbd4a0SFrançois Tigeot 	/* Only 5 data registers! */
11029edbd4a0SFrançois Tigeot 	if (WARN_ON(send_bytes > 20 || recv_size > 20)) {
11039edbd4a0SFrançois Tigeot 		ret = -E2BIG;
11049edbd4a0SFrançois Tigeot 		goto out;
11059edbd4a0SFrançois Tigeot 	}
11069edbd4a0SFrançois Tigeot 
1107ba55f2f5SFrançois Tigeot 	while ((aux_clock_divider = intel_dp->get_aux_clock_divider(intel_dp, clock++))) {
1108ba55f2f5SFrançois Tigeot 		u32 send_ctl = intel_dp->get_aux_send_ctl(intel_dp,
1109ba55f2f5SFrançois Tigeot 							  has_aux_irq,
1110ba55f2f5SFrançois Tigeot 							  send_bytes,
1111ba55f2f5SFrançois Tigeot 							  aux_clock_divider);
1112ba55f2f5SFrançois Tigeot 
1113e3adcf8fSFrançois Tigeot 		/* Must try at least 3 times according to DP spec */
1114e3adcf8fSFrançois Tigeot 		for (try = 0; try < 5; try++) {
1115e3adcf8fSFrançois Tigeot 			/* Load the send data into the aux channel data registers */
1116e3adcf8fSFrançois Tigeot 			for (i = 0; i < send_bytes; i += 4)
1117aee94f86SFrançois Tigeot 				I915_WRITE(intel_dp->aux_ch_data_reg[i >> 2],
11182c9916cdSFrançois Tigeot 					   intel_dp_pack_aux(send + i,
11192c9916cdSFrançois Tigeot 							     send_bytes - i));
1120e3adcf8fSFrançois Tigeot 
1121e3adcf8fSFrançois Tigeot 			/* Send the command and wait for it to complete */
1122ba55f2f5SFrançois Tigeot 			I915_WRITE(ch_ctl, send_ctl);
1123a2fdbec6SFrançois Tigeot 
1124a2fdbec6SFrançois Tigeot 			status = intel_dp_aux_wait_done(intel_dp, has_aux_irq);
1125e3adcf8fSFrançois Tigeot 
1126e3adcf8fSFrançois Tigeot 			/* Clear done status and any errors */
1127e3adcf8fSFrançois Tigeot 			I915_WRITE(ch_ctl,
1128e3adcf8fSFrançois Tigeot 				   status |
1129e3adcf8fSFrançois Tigeot 				   DP_AUX_CH_CTL_DONE |
1130e3adcf8fSFrançois Tigeot 				   DP_AUX_CH_CTL_TIME_OUT_ERROR |
1131e3adcf8fSFrançois Tigeot 				   DP_AUX_CH_CTL_RECEIVE_ERROR);
1132e3adcf8fSFrançois Tigeot 
113319c468b4SFrançois Tigeot 			if (status & DP_AUX_CH_CTL_TIME_OUT_ERROR)
1134e3adcf8fSFrançois Tigeot 				continue;
113519c468b4SFrançois Tigeot 
113619c468b4SFrançois Tigeot 			/* DP CTS 1.2 Core Rev 1.1, 4.2.1.1 & 4.2.1.2
113719c468b4SFrançois Tigeot 			 *   400us delay required for errors and timeouts
113819c468b4SFrançois Tigeot 			 *   Timeout errors from the HW already meet this
113919c468b4SFrançois Tigeot 			 *   requirement so skip to next iteration
114019c468b4SFrançois Tigeot 			 */
114119c468b4SFrançois Tigeot 			if (status & DP_AUX_CH_CTL_RECEIVE_ERROR) {
114219c468b4SFrançois Tigeot 				usleep_range(400, 500);
114319c468b4SFrançois Tigeot 				continue;
114419c468b4SFrançois Tigeot 			}
1145e3adcf8fSFrançois Tigeot 			if (status & DP_AUX_CH_CTL_DONE)
1146477eb7f9SFrançois Tigeot 				goto done;
1147e3adcf8fSFrançois Tigeot 		}
11489edbd4a0SFrançois Tigeot 	}
1149e3adcf8fSFrançois Tigeot 
1150e3adcf8fSFrançois Tigeot 	if ((status & DP_AUX_CH_CTL_DONE) == 0) {
1151e3adcf8fSFrançois Tigeot 		DRM_ERROR("dp_aux_ch not done status 0x%08x\n", status);
1152a2fdbec6SFrançois Tigeot 		ret = -EBUSY;
1153a2fdbec6SFrançois Tigeot 		goto out;
1154e3adcf8fSFrançois Tigeot 	}
1155e3adcf8fSFrançois Tigeot 
1156477eb7f9SFrançois Tigeot done:
1157e3adcf8fSFrançois Tigeot 	/* Check for timeout or receive error.
1158e3adcf8fSFrançois Tigeot 	 * Timeouts occur when the sink is not connected
1159e3adcf8fSFrançois Tigeot 	 */
1160e3adcf8fSFrançois Tigeot 	if (status & DP_AUX_CH_CTL_RECEIVE_ERROR) {
1161e3adcf8fSFrançois Tigeot 		DRM_ERROR("dp_aux_ch receive error status 0x%08x\n", status);
1162a2fdbec6SFrançois Tigeot 		ret = -EIO;
1163a2fdbec6SFrançois Tigeot 		goto out;
1164e3adcf8fSFrançois Tigeot 	}
1165e3adcf8fSFrançois Tigeot 
1166e3adcf8fSFrançois Tigeot 	/* Timeouts occur when the device isn't connected, so they're
1167e3adcf8fSFrançois Tigeot 	 * "normal" -- don't fill the kernel log with these */
1168e3adcf8fSFrançois Tigeot 	if (status & DP_AUX_CH_CTL_TIME_OUT_ERROR) {
1169e3adcf8fSFrançois Tigeot 		DRM_DEBUG_KMS("dp_aux_ch timeout status 0x%08x\n", status);
1170a2fdbec6SFrançois Tigeot 		ret = -ETIMEDOUT;
1171a2fdbec6SFrançois Tigeot 		goto out;
1172e3adcf8fSFrançois Tigeot 	}
1173e3adcf8fSFrançois Tigeot 
1174e3adcf8fSFrançois Tigeot 	/* Unload any bytes sent back from the other side */
1175e3adcf8fSFrançois Tigeot 	recv_bytes = ((status & DP_AUX_CH_CTL_MESSAGE_SIZE_MASK) >>
1176e3adcf8fSFrançois Tigeot 		      DP_AUX_CH_CTL_MESSAGE_SIZE_SHIFT);
1177aee94f86SFrançois Tigeot 
1178aee94f86SFrançois Tigeot 	/*
1179aee94f86SFrançois Tigeot 	 * By BSpec: "Message sizes of 0 or >20 are not allowed."
1180aee94f86SFrançois Tigeot 	 * We have no idea of what happened so we return -EBUSY so
1181aee94f86SFrançois Tigeot 	 * drm layer takes care for the necessary retries.
1182aee94f86SFrançois Tigeot 	 */
1183aee94f86SFrançois Tigeot 	if (recv_bytes == 0 || recv_bytes > 20) {
1184aee94f86SFrançois Tigeot 		DRM_DEBUG_KMS("Forbidden recv_bytes = %d on aux transaction\n",
1185aee94f86SFrançois Tigeot 			      recv_bytes);
1186aee94f86SFrançois Tigeot 		/*
1187aee94f86SFrançois Tigeot 		 * FIXME: This patch was created on top of a series that
1188aee94f86SFrançois Tigeot 		 * organize the retries at drm level. There EBUSY should
1189aee94f86SFrançois Tigeot 		 * also take care for 1ms wait before retrying.
1190aee94f86SFrançois Tigeot 		 * That aux retries re-org is still needed and after that is
1191aee94f86SFrançois Tigeot 		 * merged we remove this sleep from here.
1192aee94f86SFrançois Tigeot 		 */
1193aee94f86SFrançois Tigeot 		usleep_range(1000, 1500);
1194aee94f86SFrançois Tigeot 		ret = -EBUSY;
1195aee94f86SFrançois Tigeot 		goto out;
1196aee94f86SFrançois Tigeot 	}
1197aee94f86SFrançois Tigeot 
1198e3adcf8fSFrançois Tigeot 	if (recv_bytes > recv_size)
1199e3adcf8fSFrançois Tigeot 		recv_bytes = recv_size;
1200e3adcf8fSFrançois Tigeot 
1201e3adcf8fSFrançois Tigeot 	for (i = 0; i < recv_bytes; i += 4)
1202aee94f86SFrançois Tigeot 		intel_dp_unpack_aux(I915_READ(intel_dp->aux_ch_data_reg[i >> 2]),
1203e3adcf8fSFrançois Tigeot 				    recv + i, recv_bytes - i);
1204e3adcf8fSFrançois Tigeot 
1205a2fdbec6SFrançois Tigeot 	ret = recv_bytes;
1206a2fdbec6SFrançois Tigeot out:
1207a2fdbec6SFrançois Tigeot 	pm_qos_update_request(&dev_priv->pm_qos, PM_QOS_DEFAULT_VALUE);
1208a2fdbec6SFrançois Tigeot 
12091b13d190SFrançois Tigeot 	if (vdd)
12101b13d190SFrançois Tigeot 		edp_panel_vdd_off(intel_dp, false);
12111b13d190SFrançois Tigeot 
12121b13d190SFrançois Tigeot 	pps_unlock(intel_dp);
12131b13d190SFrançois Tigeot 
1214a2fdbec6SFrançois Tigeot 	return ret;
1215e3adcf8fSFrançois Tigeot }
1216e3adcf8fSFrançois Tigeot 
1217d13e957bSImre Vadász #define BARE_ADDRESS_SIZE	3
1218d13e957bSImre Vadász #define HEADER_SIZE		(BARE_ADDRESS_SIZE + 1)
1219d13e957bSImre Vadász static ssize_t
intel_dp_aux_transfer(struct drm_dp_aux * aux,struct drm_dp_aux_msg * msg)1220d13e957bSImre Vadász intel_dp_aux_transfer(struct drm_dp_aux *aux, struct drm_dp_aux_msg *msg)
1221d13e957bSImre Vadász {
1222d13e957bSImre Vadász 	struct intel_dp *intel_dp = container_of(aux, struct intel_dp, aux);
1223d13e957bSImre Vadász 	uint8_t txbuf[20], rxbuf[20];
1224d13e957bSImre Vadász 	size_t txsize, rxsize;
1225d13e957bSImre Vadász 	int ret;
1226d13e957bSImre Vadász 
1227477eb7f9SFrançois Tigeot 	txbuf[0] = (msg->request << 4) |
1228477eb7f9SFrançois Tigeot 		((msg->address >> 16) & 0xf);
1229477eb7f9SFrançois Tigeot 	txbuf[1] = (msg->address >> 8) & 0xff;
1230d13e957bSImre Vadász 	txbuf[2] = msg->address & 0xff;
1231d13e957bSImre Vadász 	txbuf[3] = msg->size - 1;
1232d13e957bSImre Vadász 
1233d13e957bSImre Vadász 	switch (msg->request & ~DP_AUX_I2C_MOT) {
1234d13e957bSImre Vadász 	case DP_AUX_NATIVE_WRITE:
1235d13e957bSImre Vadász 	case DP_AUX_I2C_WRITE:
1236352ff8bdSFrançois Tigeot 	case DP_AUX_I2C_WRITE_STATUS_UPDATE:
1237d13e957bSImre Vadász 		txsize = msg->size ? HEADER_SIZE + msg->size : BARE_ADDRESS_SIZE;
1238477eb7f9SFrançois Tigeot 		rxsize = 2; /* 0 or 1 data bytes */
1239d13e957bSImre Vadász 
1240d13e957bSImre Vadász 		if (WARN_ON(txsize > 20))
1241d13e957bSImre Vadász 			return -E2BIG;
1242d13e957bSImre Vadász 
124371f41f3eSFrançois Tigeot 		WARN_ON(!msg->buffer != !msg->size);
124471f41f3eSFrançois Tigeot 
1245c0e85e96SFrançois Tigeot 		if (msg->buffer)
1246d13e957bSImre Vadász 			memcpy(txbuf + HEADER_SIZE, msg->buffer, msg->size);
1247d13e957bSImre Vadász 
1248d13e957bSImre Vadász 		ret = intel_dp_aux_ch(intel_dp, txbuf, txsize, rxbuf, rxsize);
1249d13e957bSImre Vadász 		if (ret > 0) {
1250d13e957bSImre Vadász 			msg->reply = rxbuf[0] >> 4;
1251d13e957bSImre Vadász 
1252477eb7f9SFrançois Tigeot 			if (ret > 1) {
1253477eb7f9SFrançois Tigeot 				/* Number of bytes written in a short write. */
1254477eb7f9SFrançois Tigeot 				ret = clamp_t(int, rxbuf[1], 0, msg->size);
1255477eb7f9SFrançois Tigeot 			} else {
1256d13e957bSImre Vadász 				/* Return payload size. */
1257d13e957bSImre Vadász 				ret = msg->size;
1258d13e957bSImre Vadász 			}
1259477eb7f9SFrançois Tigeot 		}
1260d13e957bSImre Vadász 		break;
1261d13e957bSImre Vadász 
1262d13e957bSImre Vadász 	case DP_AUX_NATIVE_READ:
1263d13e957bSImre Vadász 	case DP_AUX_I2C_READ:
1264d13e957bSImre Vadász 		txsize = msg->size ? HEADER_SIZE : BARE_ADDRESS_SIZE;
1265d13e957bSImre Vadász 		rxsize = msg->size + 1;
1266d13e957bSImre Vadász 
1267d13e957bSImre Vadász 		if (WARN_ON(rxsize > 20))
1268d13e957bSImre Vadász 			return -E2BIG;
1269d13e957bSImre Vadász 
1270d13e957bSImre Vadász 		ret = intel_dp_aux_ch(intel_dp, txbuf, txsize, rxbuf, rxsize);
1271d13e957bSImre Vadász 		if (ret > 0) {
1272d13e957bSImre Vadász 			msg->reply = rxbuf[0] >> 4;
1273d13e957bSImre Vadász 			/*
1274d13e957bSImre Vadász 			 * Assume happy day, and copy the data. The caller is
1275d13e957bSImre Vadász 			 * expected to check msg->reply before touching it.
1276d13e957bSImre Vadász 			 *
1277d13e957bSImre Vadász 			 * Return payload size.
1278d13e957bSImre Vadász 			 */
1279d13e957bSImre Vadász 			ret--;
1280d13e957bSImre Vadász 			memcpy(msg->buffer, rxbuf + 1, ret);
1281d13e957bSImre Vadász 		}
1282d13e957bSImre Vadász 		break;
1283d13e957bSImre Vadász 
1284d13e957bSImre Vadász 	default:
1285d13e957bSImre Vadász 		ret = -EINVAL;
1286d13e957bSImre Vadász 		break;
1287d13e957bSImre Vadász 	}
1288d13e957bSImre Vadász 
1289d13e957bSImre Vadász 	return ret;
1290d13e957bSImre Vadász }
1291d13e957bSImre Vadász 
intel_aux_port(struct drm_i915_private * dev_priv,enum port port)1292bf017597SFrançois Tigeot static enum port intel_aux_port(struct drm_i915_private *dev_priv,
1293bf017597SFrançois Tigeot 				enum port port)
1294bf017597SFrançois Tigeot {
1295bf017597SFrançois Tigeot 	const struct ddi_vbt_port_info *info =
1296bf017597SFrançois Tigeot 		&dev_priv->vbt.ddi_port_info[port];
1297bf017597SFrançois Tigeot 	enum port aux_port;
1298bf017597SFrançois Tigeot 
1299bf017597SFrançois Tigeot 	if (!info->alternate_aux_channel) {
1300bf017597SFrançois Tigeot 		DRM_DEBUG_KMS("using AUX %c for port %c (platform default)\n",
1301bf017597SFrançois Tigeot 			      port_name(port), port_name(port));
1302bf017597SFrançois Tigeot 		return port;
1303bf017597SFrançois Tigeot 	}
1304bf017597SFrançois Tigeot 
1305bf017597SFrançois Tigeot 	switch (info->alternate_aux_channel) {
1306bf017597SFrançois Tigeot 	case DP_AUX_A:
1307bf017597SFrançois Tigeot 		aux_port = PORT_A;
1308bf017597SFrançois Tigeot 		break;
1309bf017597SFrançois Tigeot 	case DP_AUX_B:
1310bf017597SFrançois Tigeot 		aux_port = PORT_B;
1311bf017597SFrançois Tigeot 		break;
1312bf017597SFrançois Tigeot 	case DP_AUX_C:
1313bf017597SFrançois Tigeot 		aux_port = PORT_C;
1314bf017597SFrançois Tigeot 		break;
1315bf017597SFrançois Tigeot 	case DP_AUX_D:
1316bf017597SFrançois Tigeot 		aux_port = PORT_D;
1317bf017597SFrançois Tigeot 		break;
1318bf017597SFrançois Tigeot 	default:
1319bf017597SFrançois Tigeot 		MISSING_CASE(info->alternate_aux_channel);
1320bf017597SFrançois Tigeot 		aux_port = PORT_A;
1321bf017597SFrançois Tigeot 		break;
1322bf017597SFrançois Tigeot 	}
1323bf017597SFrançois Tigeot 
1324bf017597SFrançois Tigeot 	DRM_DEBUG_KMS("using AUX %c for port %c (VBT)\n",
1325bf017597SFrançois Tigeot 		      port_name(aux_port), port_name(port));
1326bf017597SFrançois Tigeot 
1327bf017597SFrançois Tigeot 	return aux_port;
1328bf017597SFrançois Tigeot }
1329bf017597SFrançois Tigeot 
g4x_aux_ctl_reg(struct drm_i915_private * dev_priv,enum port port)1330aee94f86SFrançois Tigeot static i915_reg_t g4x_aux_ctl_reg(struct drm_i915_private *dev_priv,
1331aee94f86SFrançois Tigeot 				  enum port port)
1332d13e957bSImre Vadász {
1333aee94f86SFrançois Tigeot 	switch (port) {
1334aee94f86SFrançois Tigeot 	case PORT_B:
1335aee94f86SFrançois Tigeot 	case PORT_C:
1336aee94f86SFrançois Tigeot 	case PORT_D:
1337aee94f86SFrançois Tigeot 		return DP_AUX_CH_CTL(port);
1338a05eeebfSFrançois Tigeot 	default:
1339aee94f86SFrançois Tigeot 		MISSING_CASE(port);
1340aee94f86SFrançois Tigeot 		return DP_AUX_CH_CTL(PORT_B);
1341a05eeebfSFrançois Tigeot 	}
1342a05eeebfSFrançois Tigeot }
1343a05eeebfSFrançois Tigeot 
g4x_aux_data_reg(struct drm_i915_private * dev_priv,enum port port,int index)1344aee94f86SFrançois Tigeot static i915_reg_t g4x_aux_data_reg(struct drm_i915_private *dev_priv,
1345aee94f86SFrançois Tigeot 				   enum port port, int index)
1346aee94f86SFrançois Tigeot {
1347aee94f86SFrançois Tigeot 	switch (port) {
1348aee94f86SFrançois Tigeot 	case PORT_B:
1349aee94f86SFrançois Tigeot 	case PORT_C:
1350aee94f86SFrançois Tigeot 	case PORT_D:
1351aee94f86SFrançois Tigeot 		return DP_AUX_CH_DATA(port, index);
1352aee94f86SFrançois Tigeot 	default:
1353aee94f86SFrançois Tigeot 		MISSING_CASE(port);
1354aee94f86SFrançois Tigeot 		return DP_AUX_CH_DATA(PORT_B, index);
1355aee94f86SFrançois Tigeot 	}
1356aee94f86SFrançois Tigeot }
1357aee94f86SFrançois Tigeot 
ilk_aux_ctl_reg(struct drm_i915_private * dev_priv,enum port port)1358aee94f86SFrançois Tigeot static i915_reg_t ilk_aux_ctl_reg(struct drm_i915_private *dev_priv,
1359aee94f86SFrançois Tigeot 				  enum port port)
1360aee94f86SFrançois Tigeot {
1361d13e957bSImre Vadász 	switch (port) {
1362d13e957bSImre Vadász 	case PORT_A:
1363aee94f86SFrançois Tigeot 		return DP_AUX_CH_CTL(port);
1364d13e957bSImre Vadász 	case PORT_B:
1365d13e957bSImre Vadász 	case PORT_C:
1366d13e957bSImre Vadász 	case PORT_D:
1367aee94f86SFrançois Tigeot 		return PCH_DP_AUX_CH_CTL(port);
1368d13e957bSImre Vadász 	default:
1369aee94f86SFrançois Tigeot 		MISSING_CASE(port);
1370aee94f86SFrançois Tigeot 		return DP_AUX_CH_CTL(PORT_A);
1371aee94f86SFrançois Tigeot 	}
1372aee94f86SFrançois Tigeot }
1373aee94f86SFrançois Tigeot 
ilk_aux_data_reg(struct drm_i915_private * dev_priv,enum port port,int index)1374aee94f86SFrançois Tigeot static i915_reg_t ilk_aux_data_reg(struct drm_i915_private *dev_priv,
1375aee94f86SFrançois Tigeot 				   enum port port, int index)
1376aee94f86SFrançois Tigeot {
1377aee94f86SFrançois Tigeot 	switch (port) {
1378aee94f86SFrançois Tigeot 	case PORT_A:
1379aee94f86SFrançois Tigeot 		return DP_AUX_CH_DATA(port, index);
1380aee94f86SFrançois Tigeot 	case PORT_B:
1381aee94f86SFrançois Tigeot 	case PORT_C:
1382aee94f86SFrançois Tigeot 	case PORT_D:
1383aee94f86SFrançois Tigeot 		return PCH_DP_AUX_CH_DATA(port, index);
1384aee94f86SFrançois Tigeot 	default:
1385aee94f86SFrançois Tigeot 		MISSING_CASE(port);
1386aee94f86SFrançois Tigeot 		return DP_AUX_CH_DATA(PORT_A, index);
1387aee94f86SFrançois Tigeot 	}
1388d13e957bSImre Vadász }
1389d13e957bSImre Vadász 
skl_aux_ctl_reg(struct drm_i915_private * dev_priv,enum port port)1390aee94f86SFrançois Tigeot static i915_reg_t skl_aux_ctl_reg(struct drm_i915_private *dev_priv,
1391aee94f86SFrançois Tigeot 				  enum port port)
1392aee94f86SFrançois Tigeot {
1393aee94f86SFrançois Tigeot 	switch (port) {
1394aee94f86SFrançois Tigeot 	case PORT_A:
1395aee94f86SFrançois Tigeot 	case PORT_B:
1396aee94f86SFrançois Tigeot 	case PORT_C:
1397aee94f86SFrançois Tigeot 	case PORT_D:
1398aee94f86SFrançois Tigeot 		return DP_AUX_CH_CTL(port);
1399aee94f86SFrançois Tigeot 	default:
1400aee94f86SFrançois Tigeot 		MISSING_CASE(port);
1401aee94f86SFrançois Tigeot 		return DP_AUX_CH_CTL(PORT_A);
1402aee94f86SFrançois Tigeot 	}
1403aee94f86SFrançois Tigeot }
1404aee94f86SFrançois Tigeot 
skl_aux_data_reg(struct drm_i915_private * dev_priv,enum port port,int index)1405aee94f86SFrançois Tigeot static i915_reg_t skl_aux_data_reg(struct drm_i915_private *dev_priv,
1406aee94f86SFrançois Tigeot 				   enum port port, int index)
1407aee94f86SFrançois Tigeot {
1408aee94f86SFrançois Tigeot 	switch (port) {
1409aee94f86SFrançois Tigeot 	case PORT_A:
1410aee94f86SFrançois Tigeot 	case PORT_B:
1411aee94f86SFrançois Tigeot 	case PORT_C:
1412aee94f86SFrançois Tigeot 	case PORT_D:
1413aee94f86SFrançois Tigeot 		return DP_AUX_CH_DATA(port, index);
1414aee94f86SFrançois Tigeot 	default:
1415aee94f86SFrançois Tigeot 		MISSING_CASE(port);
1416aee94f86SFrançois Tigeot 		return DP_AUX_CH_DATA(PORT_A, index);
1417aee94f86SFrançois Tigeot 	}
1418aee94f86SFrançois Tigeot }
1419aee94f86SFrançois Tigeot 
intel_aux_ctl_reg(struct drm_i915_private * dev_priv,enum port port)1420aee94f86SFrançois Tigeot static i915_reg_t intel_aux_ctl_reg(struct drm_i915_private *dev_priv,
1421aee94f86SFrançois Tigeot 				    enum port port)
1422aee94f86SFrançois Tigeot {
1423aee94f86SFrançois Tigeot 	if (INTEL_INFO(dev_priv)->gen >= 9)
1424aee94f86SFrançois Tigeot 		return skl_aux_ctl_reg(dev_priv, port);
1425aee94f86SFrançois Tigeot 	else if (HAS_PCH_SPLIT(dev_priv))
1426aee94f86SFrançois Tigeot 		return ilk_aux_ctl_reg(dev_priv, port);
1427aee94f86SFrançois Tigeot 	else
1428aee94f86SFrançois Tigeot 		return g4x_aux_ctl_reg(dev_priv, port);
1429aee94f86SFrançois Tigeot }
1430aee94f86SFrançois Tigeot 
intel_aux_data_reg(struct drm_i915_private * dev_priv,enum port port,int index)1431aee94f86SFrançois Tigeot static i915_reg_t intel_aux_data_reg(struct drm_i915_private *dev_priv,
1432aee94f86SFrançois Tigeot 				     enum port port, int index)
1433aee94f86SFrançois Tigeot {
1434aee94f86SFrançois Tigeot 	if (INTEL_INFO(dev_priv)->gen >= 9)
1435aee94f86SFrançois Tigeot 		return skl_aux_data_reg(dev_priv, port, index);
1436aee94f86SFrançois Tigeot 	else if (HAS_PCH_SPLIT(dev_priv))
1437aee94f86SFrançois Tigeot 		return ilk_aux_data_reg(dev_priv, port, index);
1438aee94f86SFrançois Tigeot 	else
1439aee94f86SFrançois Tigeot 		return g4x_aux_data_reg(dev_priv, port, index);
1440aee94f86SFrançois Tigeot }
1441aee94f86SFrançois Tigeot 
intel_aux_reg_init(struct intel_dp * intel_dp)1442aee94f86SFrançois Tigeot static void intel_aux_reg_init(struct intel_dp *intel_dp)
1443aee94f86SFrançois Tigeot {
1444aee94f86SFrançois Tigeot 	struct drm_i915_private *dev_priv = to_i915(intel_dp_to_dev(intel_dp));
1445bf017597SFrançois Tigeot 	enum port port = intel_aux_port(dev_priv,
1446bf017597SFrançois Tigeot 					dp_to_dig_port(intel_dp)->port);
1447aee94f86SFrançois Tigeot 	int i;
1448aee94f86SFrançois Tigeot 
1449aee94f86SFrançois Tigeot 	intel_dp->aux_ch_ctl_reg = intel_aux_ctl_reg(dev_priv, port);
1450aee94f86SFrançois Tigeot 	for (i = 0; i < ARRAY_SIZE(intel_dp->aux_ch_data_reg); i++)
1451aee94f86SFrançois Tigeot 		intel_dp->aux_ch_data_reg[i] = intel_aux_data_reg(dev_priv, port, i);
1452aee94f86SFrançois Tigeot }
1453aee94f86SFrançois Tigeot 
1454aee94f86SFrançois Tigeot static void
intel_dp_aux_fini(struct intel_dp * intel_dp)1455aee94f86SFrançois Tigeot intel_dp_aux_fini(struct intel_dp *intel_dp)
1456aee94f86SFrançois Tigeot {
1457aee94f86SFrançois Tigeot 	kfree(intel_dp->aux.name);
1458aee94f86SFrançois Tigeot }
1459aee94f86SFrançois Tigeot 
14601487f786SFrançois Tigeot static void
intel_dp_aux_init(struct intel_dp * intel_dp)14611e12ee3bSFrançois Tigeot intel_dp_aux_init(struct intel_dp *intel_dp)
1462aee94f86SFrançois Tigeot {
1463aee94f86SFrançois Tigeot 	struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp);
1464aee94f86SFrançois Tigeot 	enum port port = intel_dig_port->port;
1465aee94f86SFrançois Tigeot 
1466aee94f86SFrançois Tigeot 	intel_aux_reg_init(intel_dp);
14671487f786SFrançois Tigeot 	drm_dp_aux_init(&intel_dp->aux);
1468aee94f86SFrançois Tigeot 
14691487f786SFrançois Tigeot 	/* Failure to allocate our preferred name is not critical */
14708621f407SFrançois Tigeot 	intel_dp->aux.name = kasprintf(GFP_KERNEL, "DPDDC-%c", port_name(port));
1471d13e957bSImre Vadász 	intel_dp->aux.transfer = intel_dp_aux_transfer;
1472ba55f2f5SFrançois Tigeot }
1473ba55f2f5SFrançois Tigeot 
intel_dp_source_supports_hbr2(struct intel_dp * intel_dp)1474aee94f86SFrançois Tigeot bool intel_dp_source_supports_hbr2(struct intel_dp *intel_dp)
147519c468b4SFrançois Tigeot {
1476*3f2dd94aSFrançois Tigeot 	int max_rate = intel_dp->source_rates[intel_dp->num_source_rates - 1];
1477aee94f86SFrançois Tigeot 
1478*3f2dd94aSFrançois Tigeot 	return max_rate >= 540000;
147919c468b4SFrançois Tigeot }
148019c468b4SFrançois Tigeot 
148124edb884SFrançois Tigeot static void
intel_dp_set_clock(struct intel_encoder * encoder,struct intel_crtc_state * pipe_config)14825d0b1887SFrançois Tigeot intel_dp_set_clock(struct intel_encoder *encoder,
1483a05eeebfSFrançois Tigeot 		   struct intel_crtc_state *pipe_config)
14845d0b1887SFrançois Tigeot {
14855d0b1887SFrançois Tigeot 	struct drm_device *dev = encoder->base.dev;
14861e12ee3bSFrançois Tigeot 	struct drm_i915_private *dev_priv = to_i915(dev);
14879edbd4a0SFrançois Tigeot 	const struct dp_link_dpll *divisor = NULL;
14889edbd4a0SFrançois Tigeot 	int i, count = 0;
14895d0b1887SFrançois Tigeot 
14901e12ee3bSFrançois Tigeot 	if (IS_G4X(dev_priv)) {
14919edbd4a0SFrançois Tigeot 		divisor = gen4_dpll;
14929edbd4a0SFrançois Tigeot 		count = ARRAY_SIZE(gen4_dpll);
14931e12ee3bSFrançois Tigeot 	} else if (HAS_PCH_SPLIT(dev_priv)) {
14949edbd4a0SFrançois Tigeot 		divisor = pch_dpll;
14959edbd4a0SFrançois Tigeot 		count = ARRAY_SIZE(pch_dpll);
14961e12ee3bSFrançois Tigeot 	} else if (IS_CHERRYVIEW(dev_priv)) {
1497ba55f2f5SFrançois Tigeot 		divisor = chv_dpll;
1498ba55f2f5SFrançois Tigeot 		count = ARRAY_SIZE(chv_dpll);
14991e12ee3bSFrançois Tigeot 	} else if (IS_VALLEYVIEW(dev_priv)) {
15009edbd4a0SFrançois Tigeot 		divisor = vlv_dpll;
15019edbd4a0SFrançois Tigeot 		count = ARRAY_SIZE(vlv_dpll);
15029edbd4a0SFrançois Tigeot 	}
15039edbd4a0SFrançois Tigeot 
15049edbd4a0SFrançois Tigeot 	if (divisor && count) {
15059edbd4a0SFrançois Tigeot 		for (i = 0; i < count; i++) {
1506a05eeebfSFrançois Tigeot 			if (pipe_config->port_clock == divisor[i].clock) {
15079edbd4a0SFrançois Tigeot 				pipe_config->dpll = divisor[i].dpll;
15089edbd4a0SFrançois Tigeot 				pipe_config->clock_set = true;
15099edbd4a0SFrançois Tigeot 				break;
15109edbd4a0SFrançois Tigeot 			}
15119edbd4a0SFrançois Tigeot 		}
15125d0b1887SFrançois Tigeot 	}
15135d0b1887SFrançois Tigeot }
15145d0b1887SFrançois Tigeot 
snprintf_int_array(char * str,size_t len,const int * array,int nelem)1515477eb7f9SFrançois Tigeot static void snprintf_int_array(char *str, size_t len,
1516477eb7f9SFrançois Tigeot 			       const int *array, int nelem)
1517477eb7f9SFrançois Tigeot {
1518477eb7f9SFrançois Tigeot 	int i;
1519477eb7f9SFrançois Tigeot 
1520477eb7f9SFrançois Tigeot 	str[0] = '\0';
1521477eb7f9SFrançois Tigeot 
1522477eb7f9SFrançois Tigeot 	for (i = 0; i < nelem; i++) {
15231487f786SFrançois Tigeot 		int r = snprintf(str, len, "%s%d", i ? ", " : "", array[i]);
1524477eb7f9SFrançois Tigeot 		if (r >= len)
1525477eb7f9SFrançois Tigeot 			return;
1526477eb7f9SFrançois Tigeot 		str += r;
1527477eb7f9SFrançois Tigeot 		len -= r;
1528477eb7f9SFrançois Tigeot 	}
1529477eb7f9SFrançois Tigeot }
1530477eb7f9SFrançois Tigeot 
intel_dp_print_rates(struct intel_dp * intel_dp)1531477eb7f9SFrançois Tigeot static void intel_dp_print_rates(struct intel_dp *intel_dp)
1532477eb7f9SFrançois Tigeot {
1533477eb7f9SFrançois Tigeot 	char str[128]; /* FIXME: too big for stack? */
1534477eb7f9SFrançois Tigeot 
1535477eb7f9SFrançois Tigeot 	if ((drm_debug & DRM_UT_KMS) == 0)
1536477eb7f9SFrançois Tigeot 		return;
1537477eb7f9SFrançois Tigeot 
1538*3f2dd94aSFrançois Tigeot 	snprintf_int_array(str, sizeof(str),
1539*3f2dd94aSFrançois Tigeot 			   intel_dp->source_rates, intel_dp->num_source_rates);
1540477eb7f9SFrançois Tigeot 	DRM_DEBUG_KMS("source rates: %s\n", str);
1541477eb7f9SFrançois Tigeot 
1542*3f2dd94aSFrançois Tigeot 	snprintf_int_array(str, sizeof(str),
1543*3f2dd94aSFrançois Tigeot 			   intel_dp->sink_rates, intel_dp->num_sink_rates);
1544477eb7f9SFrançois Tigeot 	DRM_DEBUG_KMS("sink rates: %s\n", str);
1545477eb7f9SFrançois Tigeot 
1546*3f2dd94aSFrançois Tigeot 	snprintf_int_array(str, sizeof(str),
1547*3f2dd94aSFrançois Tigeot 			   intel_dp->common_rates, intel_dp->num_common_rates);
1548477eb7f9SFrançois Tigeot 	DRM_DEBUG_KMS("common rates: %s\n", str);
1549477eb7f9SFrançois Tigeot }
1550477eb7f9SFrançois Tigeot 
1551477eb7f9SFrançois Tigeot int
intel_dp_max_link_rate(struct intel_dp * intel_dp)1552477eb7f9SFrançois Tigeot intel_dp_max_link_rate(struct intel_dp *intel_dp)
1553477eb7f9SFrançois Tigeot {
1554477eb7f9SFrançois Tigeot 	int len;
1555477eb7f9SFrançois Tigeot 
1556*3f2dd94aSFrançois Tigeot 	len = intel_dp_common_len_rate_limit(intel_dp, intel_dp->max_link_rate);
1557477eb7f9SFrançois Tigeot 	if (WARN_ON(len <= 0))
1558477eb7f9SFrançois Tigeot 		return 162000;
1559477eb7f9SFrançois Tigeot 
1560*3f2dd94aSFrançois Tigeot 	return intel_dp->common_rates[len - 1];
1561477eb7f9SFrançois Tigeot }
1562477eb7f9SFrançois Tigeot 
intel_dp_rate_select(struct intel_dp * intel_dp,int rate)1563477eb7f9SFrançois Tigeot int intel_dp_rate_select(struct intel_dp *intel_dp, int rate)
1564477eb7f9SFrançois Tigeot {
1565*3f2dd94aSFrançois Tigeot 	int i = intel_dp_rate_index(intel_dp->sink_rates,
1566*3f2dd94aSFrançois Tigeot 				    intel_dp->num_sink_rates, rate);
1567*3f2dd94aSFrançois Tigeot 
1568*3f2dd94aSFrançois Tigeot 	if (WARN_ON(i < 0))
1569*3f2dd94aSFrançois Tigeot 		i = 0;
1570*3f2dd94aSFrançois Tigeot 
1571*3f2dd94aSFrançois Tigeot 	return i;
1572477eb7f9SFrançois Tigeot }
1573477eb7f9SFrançois Tigeot 
intel_dp_compute_rate(struct intel_dp * intel_dp,int port_clock,uint8_t * link_bw,uint8_t * rate_select)1574aee94f86SFrançois Tigeot void intel_dp_compute_rate(struct intel_dp *intel_dp, int port_clock,
1575352ff8bdSFrançois Tigeot 			   uint8_t *link_bw, uint8_t *rate_select)
1576352ff8bdSFrançois Tigeot {
1577*3f2dd94aSFrançois Tigeot 	/* eDP 1.4 rate select method. */
1578*3f2dd94aSFrançois Tigeot 	if (intel_dp->use_rate_select) {
1579352ff8bdSFrançois Tigeot 		*link_bw = 0;
1580352ff8bdSFrançois Tigeot 		*rate_select =
1581352ff8bdSFrançois Tigeot 			intel_dp_rate_select(intel_dp, port_clock);
1582352ff8bdSFrançois Tigeot 	} else {
1583352ff8bdSFrançois Tigeot 		*link_bw = drm_dp_link_rate_to_bw_code(port_clock);
1584352ff8bdSFrançois Tigeot 		*rate_select = 0;
1585352ff8bdSFrançois Tigeot 	}
1586352ff8bdSFrançois Tigeot }
1587352ff8bdSFrançois Tigeot 
intel_dp_compute_bpp(struct intel_dp * intel_dp,struct intel_crtc_state * pipe_config)15881e12ee3bSFrançois Tigeot static int intel_dp_compute_bpp(struct intel_dp *intel_dp,
15891e12ee3bSFrançois Tigeot 				struct intel_crtc_state *pipe_config)
15901e12ee3bSFrançois Tigeot {
15911e12ee3bSFrançois Tigeot 	int bpp, bpc;
15921e12ee3bSFrançois Tigeot 
15931e12ee3bSFrançois Tigeot 	bpp = pipe_config->pipe_bpp;
15941e12ee3bSFrançois Tigeot 	bpc = drm_dp_downstream_max_bpc(intel_dp->dpcd, intel_dp->downstream_ports);
15951e12ee3bSFrançois Tigeot 
15961e12ee3bSFrançois Tigeot 	if (bpc > 0)
15971e12ee3bSFrançois Tigeot 		bpp = min(bpp, 3*bpc);
15981e12ee3bSFrançois Tigeot 
1599a85cb24fSFrançois Tigeot 	/* For DP Compliance we override the computed bpp for the pipe */
1600a85cb24fSFrançois Tigeot 	if (intel_dp->compliance.test_data.bpc != 0) {
1601a85cb24fSFrançois Tigeot 		pipe_config->pipe_bpp =	3*intel_dp->compliance.test_data.bpc;
1602a85cb24fSFrançois Tigeot 		pipe_config->dither_force_disable = pipe_config->pipe_bpp == 6*3;
1603a85cb24fSFrançois Tigeot 		DRM_DEBUG_KMS("Setting pipe_bpp to %d\n",
1604a85cb24fSFrançois Tigeot 			      pipe_config->pipe_bpp);
1605a85cb24fSFrançois Tigeot 	}
16061e12ee3bSFrançois Tigeot 	return bpp;
16071e12ee3bSFrançois Tigeot }
16081e12ee3bSFrançois Tigeot 
intel_edp_compare_alt_mode(struct drm_display_mode * m1,struct drm_display_mode * m2)1609*3f2dd94aSFrançois Tigeot static bool intel_edp_compare_alt_mode(struct drm_display_mode *m1,
1610*3f2dd94aSFrançois Tigeot 				       struct drm_display_mode *m2)
1611*3f2dd94aSFrançois Tigeot {
1612*3f2dd94aSFrançois Tigeot 	bool bres = false;
1613*3f2dd94aSFrançois Tigeot 
1614*3f2dd94aSFrançois Tigeot 	if (m1 && m2)
1615*3f2dd94aSFrançois Tigeot 		bres = (m1->hdisplay == m2->hdisplay &&
1616*3f2dd94aSFrançois Tigeot 			m1->hsync_start == m2->hsync_start &&
1617*3f2dd94aSFrançois Tigeot 			m1->hsync_end == m2->hsync_end &&
1618*3f2dd94aSFrançois Tigeot 			m1->htotal == m2->htotal &&
1619*3f2dd94aSFrançois Tigeot 			m1->vdisplay == m2->vdisplay &&
1620*3f2dd94aSFrançois Tigeot 			m1->vsync_start == m2->vsync_start &&
1621*3f2dd94aSFrançois Tigeot 			m1->vsync_end == m2->vsync_end &&
1622*3f2dd94aSFrançois Tigeot 			m1->vtotal == m2->vtotal);
1623*3f2dd94aSFrançois Tigeot 	return bres;
1624*3f2dd94aSFrançois Tigeot }
1625*3f2dd94aSFrançois Tigeot 
162619df918dSFrançois Tigeot bool
intel_dp_compute_config(struct intel_encoder * encoder,struct intel_crtc_state * pipe_config,struct drm_connector_state * conn_state)16278e26cdf6SFrançois Tigeot intel_dp_compute_config(struct intel_encoder *encoder,
16281e12ee3bSFrançois Tigeot 			struct intel_crtc_state *pipe_config,
16291e12ee3bSFrançois Tigeot 			struct drm_connector_state *conn_state)
1630e3adcf8fSFrançois Tigeot {
16314be47400SFrançois Tigeot 	struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
16322c9916cdSFrançois Tigeot 	struct drm_display_mode *adjusted_mode = &pipe_config->base.adjusted_mode;
16338e26cdf6SFrançois Tigeot 	struct intel_dp *intel_dp = enc_to_intel_dp(&encoder->base);
16345d0b1887SFrançois Tigeot 	enum port port = dp_to_dig_port(intel_dp)->port;
1635477eb7f9SFrançois Tigeot 	struct intel_crtc *intel_crtc = to_intel_crtc(pipe_config->base.crtc);
163619df918dSFrançois Tigeot 	struct intel_connector *intel_connector = intel_dp->attached_connector;
1637*3f2dd94aSFrançois Tigeot 	struct intel_digital_connector_state *intel_conn_state =
1638*3f2dd94aSFrançois Tigeot 		to_intel_digital_connector_state(conn_state);
1639e3adcf8fSFrançois Tigeot 	int lane_count, clock;
1640ba55f2f5SFrançois Tigeot 	int min_lane_count = 1;
1641ba55f2f5SFrançois Tigeot 	int max_lane_count = intel_dp_max_lane_count(intel_dp);
1642ba55f2f5SFrançois Tigeot 	/* Conveniently, the link BW constants become indices with a shift...*/
1643ba55f2f5SFrançois Tigeot 	int min_clock = 0;
1644477eb7f9SFrançois Tigeot 	int max_clock;
164519df918dSFrançois Tigeot 	int bpp, mode_rate;
16465d0b1887SFrançois Tigeot 	int link_avail, link_clock;
1647477eb7f9SFrançois Tigeot 	int common_len;
1648352ff8bdSFrançois Tigeot 	uint8_t link_bw, rate_select;
1649a85cb24fSFrançois Tigeot 	bool reduce_m_n = drm_dp_has_quirk(&intel_dp->desc,
1650a85cb24fSFrançois Tigeot 					   DP_DPCD_QUIRK_LIMITED_M_N);
1651477eb7f9SFrançois Tigeot 
1652*3f2dd94aSFrançois Tigeot 	common_len = intel_dp_common_len_rate_limit(intel_dp,
1653*3f2dd94aSFrançois Tigeot 						    intel_dp->max_link_rate);
1654477eb7f9SFrançois Tigeot 
1655477eb7f9SFrançois Tigeot 	/* No common link rates between source and sink */
1656477eb7f9SFrançois Tigeot 	WARN_ON(common_len <= 0);
1657477eb7f9SFrançois Tigeot 
1658477eb7f9SFrançois Tigeot 	max_clock = common_len - 1;
16598e26cdf6SFrançois Tigeot 
16601e12ee3bSFrançois Tigeot 	if (HAS_PCH_SPLIT(dev_priv) && !HAS_DDI(dev_priv) && port != PORT_A)
16618e26cdf6SFrançois Tigeot 		pipe_config->has_pch_encoder = true;
16628e26cdf6SFrançois Tigeot 
16631b13d190SFrançois Tigeot 	pipe_config->has_drrs = false;
1664*3f2dd94aSFrançois Tigeot 	if (port == PORT_A)
1665*3f2dd94aSFrançois Tigeot 		pipe_config->has_audio = false;
1666*3f2dd94aSFrançois Tigeot 	else if (intel_conn_state->force_audio == HDMI_AUDIO_AUTO)
1667*3f2dd94aSFrançois Tigeot 		pipe_config->has_audio = intel_dp->has_audio;
1668*3f2dd94aSFrançois Tigeot 	else
1669*3f2dd94aSFrançois Tigeot 		pipe_config->has_audio = intel_conn_state->force_audio == HDMI_AUDIO_ON;
1670e3adcf8fSFrançois Tigeot 
1671*3f2dd94aSFrançois Tigeot 	if (intel_dp_is_edp(intel_dp) && intel_connector->panel.fixed_mode) {
1672*3f2dd94aSFrançois Tigeot 		struct drm_display_mode *panel_mode =
1673*3f2dd94aSFrançois Tigeot 			intel_connector->panel.alt_fixed_mode;
1674*3f2dd94aSFrançois Tigeot 		struct drm_display_mode *req_mode = &pipe_config->base.mode;
1675*3f2dd94aSFrançois Tigeot 
1676*3f2dd94aSFrançois Tigeot 		if (!intel_edp_compare_alt_mode(req_mode, panel_mode))
1677*3f2dd94aSFrançois Tigeot 			panel_mode = intel_connector->panel.fixed_mode;
1678*3f2dd94aSFrançois Tigeot 
1679*3f2dd94aSFrançois Tigeot 		drm_mode_debug_printmodeline(panel_mode);
1680*3f2dd94aSFrançois Tigeot 
1681*3f2dd94aSFrançois Tigeot 		intel_fixed_panel_mode(panel_mode, adjusted_mode);
168219c468b4SFrançois Tigeot 
16834be47400SFrançois Tigeot 		if (INTEL_GEN(dev_priv) >= 9) {
168419c468b4SFrançois Tigeot 			int ret;
1685a05eeebfSFrançois Tigeot 			ret = skl_update_scaler_crtc(pipe_config);
168619c468b4SFrançois Tigeot 			if (ret)
168719c468b4SFrançois Tigeot 				return ret;
168819c468b4SFrançois Tigeot 		}
168919c468b4SFrançois Tigeot 
16901e12ee3bSFrançois Tigeot 		if (HAS_GMCH_DISPLAY(dev_priv))
16915d0b1887SFrançois Tigeot 			intel_gmch_panel_fitting(intel_crtc, pipe_config,
1692*3f2dd94aSFrançois Tigeot 						 conn_state->scaling_mode);
16935d0b1887SFrançois Tigeot 		else
16945d0b1887SFrançois Tigeot 			intel_pch_panel_fitting(intel_crtc, pipe_config,
1695*3f2dd94aSFrançois Tigeot 						conn_state->scaling_mode);
1696e3adcf8fSFrançois Tigeot 	}
1697e3adcf8fSFrançois Tigeot 
169819df918dSFrançois Tigeot 	if (adjusted_mode->flags & DRM_MODE_FLAG_DBLCLK)
169919df918dSFrançois Tigeot 		return false;
170019df918dSFrançois Tigeot 
1701a85cb24fSFrançois Tigeot 	/* Use values requested by Compliance Test Request */
1702a85cb24fSFrançois Tigeot 	if (intel_dp->compliance.test_type == DP_TEST_LINK_TRAINING) {
1703*3f2dd94aSFrançois Tigeot 		int index;
1704*3f2dd94aSFrançois Tigeot 
1705*3f2dd94aSFrançois Tigeot 		/* Validate the compliance test data since max values
1706*3f2dd94aSFrançois Tigeot 		 * might have changed due to link train fallback.
1707*3f2dd94aSFrançois Tigeot 		 */
1708*3f2dd94aSFrançois Tigeot 		if (intel_dp_link_params_valid(intel_dp, intel_dp->compliance.test_link_rate,
1709*3f2dd94aSFrançois Tigeot 					       intel_dp->compliance.test_lane_count)) {
1710*3f2dd94aSFrançois Tigeot 			index = intel_dp_rate_index(intel_dp->common_rates,
1711*3f2dd94aSFrançois Tigeot 						    intel_dp->num_common_rates,
1712a85cb24fSFrançois Tigeot 						    intel_dp->compliance.test_link_rate);
1713*3f2dd94aSFrançois Tigeot 			if (index >= 0)
1714*3f2dd94aSFrançois Tigeot 				min_clock = max_clock = index;
1715a85cb24fSFrançois Tigeot 			min_lane_count = max_lane_count = intel_dp->compliance.test_lane_count;
1716a85cb24fSFrançois Tigeot 		}
1717*3f2dd94aSFrançois Tigeot 	}
171819df918dSFrançois Tigeot 	DRM_DEBUG_KMS("DP link computation with max lane count %i "
1719477eb7f9SFrançois Tigeot 		      "max bw %d pixel clock %iKHz\n",
1720*3f2dd94aSFrançois Tigeot 		      max_lane_count, intel_dp->common_rates[max_clock],
17219edbd4a0SFrançois Tigeot 		      adjusted_mode->crtc_clock);
172219df918dSFrançois Tigeot 
17238e26cdf6SFrançois Tigeot 	/* Walk through all bpp values. Luckily they're all nicely spaced with 2
17248e26cdf6SFrançois Tigeot 	 * bpc in between. */
17251e12ee3bSFrançois Tigeot 	bpp = intel_dp_compute_bpp(intel_dp, pipe_config);
1726*3f2dd94aSFrançois Tigeot 	if (intel_dp_is_edp(intel_dp)) {
1727a05eeebfSFrançois Tigeot 
1728a05eeebfSFrançois Tigeot 		/* Get bpp from vbt only for panels that dont have bpp in edid */
1729a05eeebfSFrançois Tigeot 		if (intel_connector->base.display_info.bpc == 0 &&
17308621f407SFrançois Tigeot 			(dev_priv->vbt.edp.bpp && dev_priv->vbt.edp.bpp < bpp)) {
17319edbd4a0SFrançois Tigeot 			DRM_DEBUG_KMS("clamping bpp for eDP panel to BIOS-provided %i\n",
17328621f407SFrançois Tigeot 				      dev_priv->vbt.edp.bpp);
17338621f407SFrançois Tigeot 			bpp = dev_priv->vbt.edp.bpp;
17349edbd4a0SFrançois Tigeot 		}
17358e26cdf6SFrançois Tigeot 
17361b13d190SFrançois Tigeot 		/*
17371b13d190SFrançois Tigeot 		 * Use the maximum clock and number of lanes the eDP panel
17381b13d190SFrançois Tigeot 		 * advertizes being capable of. The panels are generally
17391b13d190SFrançois Tigeot 		 * designed to support only a single clock and lane
17401b13d190SFrançois Tigeot 		 * configuration, and typically these values correspond to the
17411b13d190SFrançois Tigeot 		 * native resolution of the panel.
17421b13d190SFrançois Tigeot 		 */
1743ba55f2f5SFrançois Tigeot 		min_lane_count = max_lane_count;
17441b13d190SFrançois Tigeot 		min_clock = max_clock;
1745ba55f2f5SFrançois Tigeot 	}
1746ba55f2f5SFrançois Tigeot 
17478e26cdf6SFrançois Tigeot 	for (; bpp >= 6*3; bpp -= 2*3) {
17489edbd4a0SFrançois Tigeot 		mode_rate = intel_dp_link_required(adjusted_mode->crtc_clock,
17499edbd4a0SFrançois Tigeot 						   bpp);
17508e26cdf6SFrançois Tigeot 
1751ba55f2f5SFrançois Tigeot 		for (clock = min_clock; clock <= max_clock; clock++) {
1752477eb7f9SFrançois Tigeot 			for (lane_count = min_lane_count;
1753477eb7f9SFrançois Tigeot 				lane_count <= max_lane_count;
1754477eb7f9SFrançois Tigeot 				lane_count <<= 1) {
1755477eb7f9SFrançois Tigeot 
1756*3f2dd94aSFrançois Tigeot 				link_clock = intel_dp->common_rates[clock];
17578e26cdf6SFrançois Tigeot 				link_avail = intel_dp_max_data_rate(link_clock,
17588e26cdf6SFrançois Tigeot 								    lane_count);
17598e26cdf6SFrançois Tigeot 
17608e26cdf6SFrançois Tigeot 				if (mode_rate <= link_avail) {
17618e26cdf6SFrançois Tigeot 					goto found;
17628e26cdf6SFrançois Tigeot 				}
17638e26cdf6SFrançois Tigeot 			}
17648e26cdf6SFrançois Tigeot 		}
17658e26cdf6SFrançois Tigeot 	}
17668e26cdf6SFrançois Tigeot 
1767e3adcf8fSFrançois Tigeot 	return false;
1768e3adcf8fSFrançois Tigeot 
17698e26cdf6SFrançois Tigeot found:
1770*3f2dd94aSFrançois Tigeot 	if (intel_conn_state->broadcast_rgb == INTEL_BROADCAST_RGB_AUTO) {
1771a2fdbec6SFrançois Tigeot 		/*
1772a2fdbec6SFrançois Tigeot 		 * See:
1773a2fdbec6SFrançois Tigeot 		 * CEA-861-E - 5.1 Default Encoding Parameters
1774a2fdbec6SFrançois Tigeot 		 * VESA DisplayPort Ver.1.2a - 5.1.1.1 Video Colorimetry
1775a2fdbec6SFrançois Tigeot 		 */
1776352ff8bdSFrançois Tigeot 		pipe_config->limited_color_range =
1777a85cb24fSFrançois Tigeot 			bpp != 18 &&
1778a85cb24fSFrançois Tigeot 			drm_default_rgb_quant_range(adjusted_mode) ==
1779a85cb24fSFrançois Tigeot 			HDMI_QUANTIZATION_RANGE_LIMITED;
1780477eb7f9SFrançois Tigeot 	} else {
1781352ff8bdSFrançois Tigeot 		pipe_config->limited_color_range =
1782*3f2dd94aSFrançois Tigeot 			intel_conn_state->broadcast_rgb == INTEL_BROADCAST_RGB_LIMITED;
1783477eb7f9SFrançois Tigeot 	}
1784477eb7f9SFrançois Tigeot 
1785352ff8bdSFrançois Tigeot 	pipe_config->lane_count = lane_count;
1786352ff8bdSFrançois Tigeot 
17878e26cdf6SFrançois Tigeot 	pipe_config->pipe_bpp = bpp;
1788*3f2dd94aSFrançois Tigeot 	pipe_config->port_clock = intel_dp->common_rates[clock];
17898e26cdf6SFrançois Tigeot 
1790352ff8bdSFrançois Tigeot 	intel_dp_compute_rate(intel_dp, pipe_config->port_clock,
1791352ff8bdSFrançois Tigeot 			      &link_bw, &rate_select);
1792352ff8bdSFrançois Tigeot 
1793352ff8bdSFrançois Tigeot 	DRM_DEBUG_KMS("DP link bw %02x rate select %02x lane count %d clock %d bpp %d\n",
1794352ff8bdSFrançois Tigeot 		      link_bw, rate_select, pipe_config->lane_count,
17955d0b1887SFrançois Tigeot 		      pipe_config->port_clock, bpp);
179619df918dSFrançois Tigeot 	DRM_DEBUG_KMS("DP link bw required %i available %i\n",
179719df918dSFrançois Tigeot 		      mode_rate, link_avail);
17988e26cdf6SFrançois Tigeot 
17998e26cdf6SFrançois Tigeot 	intel_link_compute_m_n(bpp, lane_count,
18009edbd4a0SFrançois Tigeot 			       adjusted_mode->crtc_clock,
18019edbd4a0SFrançois Tigeot 			       pipe_config->port_clock,
1802a85cb24fSFrançois Tigeot 			       &pipe_config->dp_m_n,
1803a85cb24fSFrançois Tigeot 			       reduce_m_n);
18048e26cdf6SFrançois Tigeot 
1805ba55f2f5SFrançois Tigeot 	if (intel_connector->panel.downclock_mode != NULL &&
18062c9916cdSFrançois Tigeot 		dev_priv->drrs.type == SEAMLESS_DRRS_SUPPORT) {
18071b13d190SFrançois Tigeot 			pipe_config->has_drrs = true;
1808ba55f2f5SFrançois Tigeot 			intel_link_compute_m_n(bpp, lane_count,
1809ba55f2f5SFrançois Tigeot 				intel_connector->panel.downclock_mode->clock,
1810ba55f2f5SFrançois Tigeot 				pipe_config->port_clock,
1811a85cb24fSFrançois Tigeot 				&pipe_config->dp_m2_n2,
1812a85cb24fSFrançois Tigeot 				reduce_m_n);
1813ba55f2f5SFrançois Tigeot 	}
1814ba55f2f5SFrançois Tigeot 
18151487f786SFrançois Tigeot 	/*
18161487f786SFrançois Tigeot 	 * DPLL0 VCO may need to be adjusted to get the correct
18171487f786SFrançois Tigeot 	 * clock for eDP. This will affect cdclk as well.
18181487f786SFrançois Tigeot 	 */
1819*3f2dd94aSFrançois Tigeot 	if (intel_dp_is_edp(intel_dp) && IS_GEN9_BC(dev_priv)) {
18201487f786SFrançois Tigeot 		int vco;
18211487f786SFrançois Tigeot 
18221487f786SFrançois Tigeot 		switch (pipe_config->port_clock / 2) {
18231487f786SFrançois Tigeot 		case 108000:
18241487f786SFrançois Tigeot 		case 216000:
18251487f786SFrançois Tigeot 			vco = 8640000;
18261487f786SFrançois Tigeot 			break;
18271487f786SFrançois Tigeot 		default:
18281487f786SFrançois Tigeot 			vco = 8100000;
18291487f786SFrançois Tigeot 			break;
18301487f786SFrançois Tigeot 		}
18311487f786SFrançois Tigeot 
1832a85cb24fSFrançois Tigeot 		to_intel_atomic_state(pipe_config->base.state)->cdclk.logical.vco = vco;
18331487f786SFrançois Tigeot 	}
18341487f786SFrançois Tigeot 
18351e12ee3bSFrançois Tigeot 	if (!HAS_DDI(dev_priv))
1836a05eeebfSFrançois Tigeot 		intel_dp_set_clock(encoder, pipe_config);
18375d0b1887SFrançois Tigeot 
1838*3f2dd94aSFrançois Tigeot 	intel_psr_compute_config(intel_dp, pipe_config);
1839*3f2dd94aSFrançois Tigeot 
1840e3adcf8fSFrançois Tigeot 	return true;
1841e3adcf8fSFrançois Tigeot }
1842e3adcf8fSFrançois Tigeot 
intel_dp_set_link_params(struct intel_dp * intel_dp,int link_rate,uint8_t lane_count,bool link_mst)1843352ff8bdSFrançois Tigeot void intel_dp_set_link_params(struct intel_dp *intel_dp,
18441e12ee3bSFrançois Tigeot 			      int link_rate, uint8_t lane_count,
18451e12ee3bSFrançois Tigeot 			      bool link_mst)
1846352ff8bdSFrançois Tigeot {
18471e12ee3bSFrançois Tigeot 	intel_dp->link_rate = link_rate;
18481e12ee3bSFrançois Tigeot 	intel_dp->lane_count = lane_count;
18491e12ee3bSFrançois Tigeot 	intel_dp->link_mst = link_mst;
1850352ff8bdSFrançois Tigeot }
1851352ff8bdSFrançois Tigeot 
intel_dp_prepare(struct intel_encoder * encoder,const struct intel_crtc_state * pipe_config)18521e12ee3bSFrançois Tigeot static void intel_dp_prepare(struct intel_encoder *encoder,
1853*3f2dd94aSFrançois Tigeot 			     const struct intel_crtc_state *pipe_config)
1854e3adcf8fSFrançois Tigeot {
18559edbd4a0SFrançois Tigeot 	struct drm_device *dev = encoder->base.dev;
1856303bf270SFrançois Tigeot 	struct drm_i915_private *dev_priv = to_i915(dev);
18579edbd4a0SFrançois Tigeot 	struct intel_dp *intel_dp = enc_to_intel_dp(&encoder->base);
18585d0b1887SFrançois Tigeot 	enum port port = dp_to_dig_port(intel_dp)->port;
18599edbd4a0SFrançois Tigeot 	struct intel_crtc *crtc = to_intel_crtc(encoder->base.crtc);
18601e12ee3bSFrançois Tigeot 	const struct drm_display_mode *adjusted_mode = &pipe_config->base.adjusted_mode;
1861352ff8bdSFrançois Tigeot 
18621e12ee3bSFrançois Tigeot 	intel_dp_set_link_params(intel_dp, pipe_config->port_clock,
18631e12ee3bSFrançois Tigeot 				 pipe_config->lane_count,
18641e12ee3bSFrançois Tigeot 				 intel_crtc_has_type(pipe_config,
18651e12ee3bSFrançois Tigeot 						     INTEL_OUTPUT_DP_MST));
1866e3adcf8fSFrançois Tigeot 
1867e3adcf8fSFrançois Tigeot 	/*
1868e3adcf8fSFrançois Tigeot 	 * There are four kinds of DP registers:
1869e3adcf8fSFrançois Tigeot 	 *
1870e3adcf8fSFrançois Tigeot 	 * 	IBX PCH
1871e3adcf8fSFrançois Tigeot 	 * 	SNB CPU
1872e3adcf8fSFrançois Tigeot 	 *	IVB CPU
1873e3adcf8fSFrançois Tigeot 	 * 	CPT PCH
1874e3adcf8fSFrançois Tigeot 	 *
1875e3adcf8fSFrançois Tigeot 	 * IBX PCH and CPU are the same for almost everything,
1876e3adcf8fSFrançois Tigeot 	 * except that the CPU DP PLL is configured in this
1877e3adcf8fSFrançois Tigeot 	 * register
1878e3adcf8fSFrançois Tigeot 	 *
1879e3adcf8fSFrançois Tigeot 	 * CPT PCH is quite different, having many bits moved
1880e3adcf8fSFrançois Tigeot 	 * to the TRANS_DP_CTL register instead. That
1881e3adcf8fSFrançois Tigeot 	 * configuration happens (oddly) in ironlake_pch_enable
1882e3adcf8fSFrançois Tigeot 	 */
1883e3adcf8fSFrançois Tigeot 
1884e3adcf8fSFrançois Tigeot 	/* Preserve the BIOS-computed detected bit. This is
1885e3adcf8fSFrançois Tigeot 	 * supposed to be read-only.
1886e3adcf8fSFrançois Tigeot 	 */
1887e3adcf8fSFrançois Tigeot 	intel_dp->DP = I915_READ(intel_dp->output_reg) & DP_DETECTED;
1888e3adcf8fSFrançois Tigeot 
1889e3adcf8fSFrançois Tigeot 	/* Handle DP bits in common between all three register formats */
1890e3adcf8fSFrançois Tigeot 	intel_dp->DP |= DP_VOLTAGE_0_4 | DP_PRE_EMPHASIS_0;
18911e12ee3bSFrançois Tigeot 	intel_dp->DP |= DP_PORT_WIDTH(pipe_config->lane_count);
1892e3adcf8fSFrançois Tigeot 
1893e3adcf8fSFrançois Tigeot 	/* Split out the IBX/CPU vs CPT settings */
1894e3adcf8fSFrançois Tigeot 
18951e12ee3bSFrançois Tigeot 	if (IS_GEN7(dev_priv) && port == PORT_A) {
1896e3adcf8fSFrançois Tigeot 		if (adjusted_mode->flags & DRM_MODE_FLAG_PHSYNC)
1897e3adcf8fSFrançois Tigeot 			intel_dp->DP |= DP_SYNC_HS_HIGH;
1898e3adcf8fSFrançois Tigeot 		if (adjusted_mode->flags & DRM_MODE_FLAG_PVSYNC)
1899e3adcf8fSFrançois Tigeot 			intel_dp->DP |= DP_SYNC_VS_HIGH;
1900e3adcf8fSFrançois Tigeot 		intel_dp->DP |= DP_LINK_TRAIN_OFF_CPT;
1901e3adcf8fSFrançois Tigeot 
19029edbd4a0SFrançois Tigeot 		if (drm_dp_enhanced_frame_cap(intel_dp->dpcd))
1903e3adcf8fSFrançois Tigeot 			intel_dp->DP |= DP_ENHANCED_FRAMING;
1904e3adcf8fSFrançois Tigeot 
19055d0b1887SFrançois Tigeot 		intel_dp->DP |= crtc->pipe << 29;
19061e12ee3bSFrançois Tigeot 	} else if (HAS_PCH_CPT(dev_priv) && port != PORT_A) {
190719c468b4SFrançois Tigeot 		u32 trans_dp;
190819c468b4SFrançois Tigeot 
190919c468b4SFrançois Tigeot 		intel_dp->DP |= DP_LINK_TRAIN_OFF_CPT;
191019c468b4SFrançois Tigeot 
191119c468b4SFrançois Tigeot 		trans_dp = I915_READ(TRANS_DP_CTL(crtc->pipe));
191219c468b4SFrançois Tigeot 		if (drm_dp_enhanced_frame_cap(intel_dp->dpcd))
191319c468b4SFrançois Tigeot 			trans_dp |= TRANS_DP_ENH_FRAMING;
191419c468b4SFrançois Tigeot 		else
191519c468b4SFrançois Tigeot 			trans_dp &= ~TRANS_DP_ENH_FRAMING;
191619c468b4SFrançois Tigeot 		I915_WRITE(TRANS_DP_CTL(crtc->pipe), trans_dp);
191719c468b4SFrançois Tigeot 	} else {
19184be47400SFrançois Tigeot 		if (IS_G4X(dev_priv) && pipe_config->limited_color_range)
1919352ff8bdSFrançois Tigeot 			intel_dp->DP |= DP_COLOR_RANGE_16_235;
1920e3adcf8fSFrançois Tigeot 
1921e3adcf8fSFrançois Tigeot 		if (adjusted_mode->flags & DRM_MODE_FLAG_PHSYNC)
1922e3adcf8fSFrançois Tigeot 			intel_dp->DP |= DP_SYNC_HS_HIGH;
1923e3adcf8fSFrançois Tigeot 		if (adjusted_mode->flags & DRM_MODE_FLAG_PVSYNC)
1924e3adcf8fSFrançois Tigeot 			intel_dp->DP |= DP_SYNC_VS_HIGH;
1925e3adcf8fSFrançois Tigeot 		intel_dp->DP |= DP_LINK_TRAIN_OFF;
1926e3adcf8fSFrançois Tigeot 
19279edbd4a0SFrançois Tigeot 		if (drm_dp_enhanced_frame_cap(intel_dp->dpcd))
1928e3adcf8fSFrançois Tigeot 			intel_dp->DP |= DP_ENHANCED_FRAMING;
1929e3adcf8fSFrançois Tigeot 
19301e12ee3bSFrançois Tigeot 		if (IS_CHERRYVIEW(dev_priv))
1931ba55f2f5SFrançois Tigeot 			intel_dp->DP |= DP_PIPE_SELECT_CHV(crtc->pipe);
193219c468b4SFrançois Tigeot 		else if (crtc->pipe == PIPE_B)
193319c468b4SFrançois Tigeot 			intel_dp->DP |= DP_PIPEB_SELECT;
1934e3adcf8fSFrançois Tigeot 	}
1935e3adcf8fSFrançois Tigeot }
1936e3adcf8fSFrançois Tigeot 
1937ba55f2f5SFrançois Tigeot #define IDLE_ON_MASK		(PP_ON | PP_SEQUENCE_MASK | 0                     | PP_SEQUENCE_STATE_MASK)
1938ba55f2f5SFrançois Tigeot #define IDLE_ON_VALUE   	(PP_ON | PP_SEQUENCE_NONE | 0                     | PP_SEQUENCE_STATE_ON_IDLE)
1939e3adcf8fSFrançois Tigeot 
1940ba55f2f5SFrançois Tigeot #define IDLE_OFF_MASK		(PP_ON | PP_SEQUENCE_MASK | 0                     | 0)
1941ba55f2f5SFrançois Tigeot #define IDLE_OFF_VALUE		(0     | PP_SEQUENCE_NONE | 0                     | 0)
1942e3adcf8fSFrançois Tigeot 
1943ba55f2f5SFrançois Tigeot #define IDLE_CYCLE_MASK		(PP_ON | PP_SEQUENCE_MASK | PP_CYCLE_DELAY_ACTIVE | PP_SEQUENCE_STATE_MASK)
1944ba55f2f5SFrançois Tigeot #define IDLE_CYCLE_VALUE	(0     | PP_SEQUENCE_NONE | 0                     | PP_SEQUENCE_STATE_OFF_IDLE)
1945e3adcf8fSFrançois Tigeot 
19461487f786SFrançois Tigeot static void intel_pps_verify_state(struct drm_i915_private *dev_priv,
19471487f786SFrançois Tigeot 				   struct intel_dp *intel_dp);
19481487f786SFrançois Tigeot 
wait_panel_status(struct intel_dp * intel_dp,u32 mask,u32 value)1949ba55f2f5SFrançois Tigeot static void wait_panel_status(struct intel_dp *intel_dp,
1950e3adcf8fSFrançois Tigeot 				       u32 mask,
1951e3adcf8fSFrançois Tigeot 				       u32 value)
1952e3adcf8fSFrançois Tigeot {
195319df918dSFrançois Tigeot 	struct drm_device *dev = intel_dp_to_dev(intel_dp);
1954303bf270SFrançois Tigeot 	struct drm_i915_private *dev_priv = to_i915(dev);
1955aee94f86SFrançois Tigeot 	i915_reg_t pp_stat_reg, pp_ctrl_reg;
19568e26cdf6SFrançois Tigeot 
19571b13d190SFrançois Tigeot 	lockdep_assert_held(&dev_priv->pps_mutex);
19581b13d190SFrançois Tigeot 
19591487f786SFrançois Tigeot 	intel_pps_verify_state(dev_priv, intel_dp);
19601487f786SFrançois Tigeot 
19619edbd4a0SFrançois Tigeot 	pp_stat_reg = _pp_stat_reg(intel_dp);
19629edbd4a0SFrançois Tigeot 	pp_ctrl_reg = _pp_ctrl_reg(intel_dp);
1963e3adcf8fSFrançois Tigeot 
1964e3adcf8fSFrançois Tigeot 	DRM_DEBUG_KMS("mask %08x value %08x status %08x control %08x\n",
1965e3adcf8fSFrançois Tigeot 			mask, value,
19668e26cdf6SFrançois Tigeot 			I915_READ(pp_stat_reg),
19678e26cdf6SFrançois Tigeot 			I915_READ(pp_ctrl_reg));
1968e3adcf8fSFrançois Tigeot 
19691487f786SFrançois Tigeot 	if (intel_wait_for_register(dev_priv,
19701487f786SFrançois Tigeot 				    pp_stat_reg, mask, value,
19711487f786SFrançois Tigeot 				    5000))
1972e3adcf8fSFrançois Tigeot 		DRM_ERROR("Panel status timeout: status %08x control %08x\n",
19738e26cdf6SFrançois Tigeot 				I915_READ(pp_stat_reg),
19748e26cdf6SFrançois Tigeot 				I915_READ(pp_ctrl_reg));
19759edbd4a0SFrançois Tigeot 
19769edbd4a0SFrançois Tigeot 	DRM_DEBUG_KMS("Wait complete\n");
1977e3adcf8fSFrançois Tigeot }
1978e3adcf8fSFrançois Tigeot 
wait_panel_on(struct intel_dp * intel_dp)1979ba55f2f5SFrançois Tigeot static void wait_panel_on(struct intel_dp *intel_dp)
1980e3adcf8fSFrançois Tigeot {
1981e3adcf8fSFrançois Tigeot 	DRM_DEBUG_KMS("Wait for panel power on\n");
1982ba55f2f5SFrançois Tigeot 	wait_panel_status(intel_dp, IDLE_ON_MASK, IDLE_ON_VALUE);
1983e3adcf8fSFrançois Tigeot }
1984e3adcf8fSFrançois Tigeot 
wait_panel_off(struct intel_dp * intel_dp)1985ba55f2f5SFrançois Tigeot static void wait_panel_off(struct intel_dp *intel_dp)
1986e3adcf8fSFrançois Tigeot {
1987e3adcf8fSFrançois Tigeot 	DRM_DEBUG_KMS("Wait for panel power off time\n");
1988ba55f2f5SFrançois Tigeot 	wait_panel_status(intel_dp, IDLE_OFF_MASK, IDLE_OFF_VALUE);
1989e3adcf8fSFrançois Tigeot }
1990e3adcf8fSFrançois Tigeot 
wait_panel_power_cycle(struct intel_dp * intel_dp)1991ba55f2f5SFrançois Tigeot static void wait_panel_power_cycle(struct intel_dp *intel_dp)
1992e3adcf8fSFrançois Tigeot {
1993c0e85e96SFrançois Tigeot 	ktime_t panel_power_on_time;
1994c0e85e96SFrançois Tigeot 	s64 panel_power_off_duration;
1995c0e85e96SFrançois Tigeot 
1996e3adcf8fSFrançois Tigeot 	DRM_DEBUG_KMS("Wait for panel power cycle\n");
1997ba55f2f5SFrançois Tigeot 
1998c0e85e96SFrançois Tigeot 	/* take the difference of currrent time and panel power off time
1999c0e85e96SFrançois Tigeot 	 * and then make panel wait for t11_t12 if needed. */
2000c0e85e96SFrançois Tigeot 	panel_power_on_time = ktime_get_boottime();
2001c0e85e96SFrançois Tigeot 	panel_power_off_duration = ktime_ms_delta(panel_power_on_time, intel_dp->panel_power_off_time);
2002c0e85e96SFrançois Tigeot 
2003ba55f2f5SFrançois Tigeot 	/* When we disable the VDD override bit last we have to do the manual
2004ba55f2f5SFrançois Tigeot 	 * wait. */
2005c0e85e96SFrançois Tigeot 	if (panel_power_off_duration < (s64)intel_dp->panel_power_cycle_delay)
2006c0e85e96SFrançois Tigeot 		wait_remaining_ms_from_jiffies(jiffies,
2007c0e85e96SFrançois Tigeot 				       intel_dp->panel_power_cycle_delay - panel_power_off_duration);
2008ba55f2f5SFrançois Tigeot 
2009ba55f2f5SFrançois Tigeot 	wait_panel_status(intel_dp, IDLE_CYCLE_MASK, IDLE_CYCLE_VALUE);
2010e3adcf8fSFrançois Tigeot }
2011e3adcf8fSFrançois Tigeot 
wait_backlight_on(struct intel_dp * intel_dp)2012ba55f2f5SFrançois Tigeot static void wait_backlight_on(struct intel_dp *intel_dp)
2013ba55f2f5SFrançois Tigeot {
2014ba55f2f5SFrançois Tigeot 	wait_remaining_ms_from_jiffies(intel_dp->last_power_on,
2015ba55f2f5SFrançois Tigeot 				       intel_dp->backlight_on_delay);
2016ba55f2f5SFrançois Tigeot }
2017ba55f2f5SFrançois Tigeot 
edp_wait_backlight_off(struct intel_dp * intel_dp)2018ba55f2f5SFrançois Tigeot static void edp_wait_backlight_off(struct intel_dp *intel_dp)
2019ba55f2f5SFrançois Tigeot {
2020ba55f2f5SFrançois Tigeot 	wait_remaining_ms_from_jiffies(intel_dp->last_backlight_off,
2021ba55f2f5SFrançois Tigeot 				       intel_dp->backlight_off_delay);
2022ba55f2f5SFrançois Tigeot }
2023e3adcf8fSFrançois Tigeot 
2024e3adcf8fSFrançois Tigeot /* Read the current pp_control value, unlocking the register if it
2025e3adcf8fSFrançois Tigeot  * is locked
2026e3adcf8fSFrançois Tigeot  */
2027e3adcf8fSFrançois Tigeot 
ironlake_get_pp_control(struct intel_dp * intel_dp)20288e26cdf6SFrançois Tigeot static  u32 ironlake_get_pp_control(struct intel_dp *intel_dp)
2029e3adcf8fSFrançois Tigeot {
20308e26cdf6SFrançois Tigeot 	struct drm_device *dev = intel_dp_to_dev(intel_dp);
2031303bf270SFrançois Tigeot 	struct drm_i915_private *dev_priv = to_i915(dev);
20328e26cdf6SFrançois Tigeot 	u32 control;
20338e26cdf6SFrançois Tigeot 
20341b13d190SFrançois Tigeot 	lockdep_assert_held(&dev_priv->pps_mutex);
20351b13d190SFrançois Tigeot 
20369edbd4a0SFrançois Tigeot 	control = I915_READ(_pp_ctrl_reg(intel_dp));
20371e12ee3bSFrançois Tigeot 	if (WARN_ON(!HAS_DDI(dev_priv) &&
20381e12ee3bSFrançois Tigeot 		    (control & PANEL_UNLOCK_MASK) != PANEL_UNLOCK_REGS)) {
2039e3adcf8fSFrançois Tigeot 		control &= ~PANEL_UNLOCK_MASK;
2040e3adcf8fSFrançois Tigeot 		control |= PANEL_UNLOCK_REGS;
2041a05eeebfSFrançois Tigeot 	}
2042e3adcf8fSFrançois Tigeot 	return control;
2043e3adcf8fSFrançois Tigeot }
2044e3adcf8fSFrançois Tigeot 
20451b13d190SFrançois Tigeot /*
20461b13d190SFrançois Tigeot  * Must be paired with edp_panel_vdd_off().
20471b13d190SFrançois Tigeot  * Must hold pps_mutex around the whole on/off sequence.
20481b13d190SFrançois Tigeot  * Can be nested with intel_edp_panel_vdd_{on,off}() calls.
20491b13d190SFrançois Tigeot  */
edp_panel_vdd_on(struct intel_dp * intel_dp)20501b13d190SFrançois Tigeot static bool edp_panel_vdd_on(struct intel_dp *intel_dp)
2051e3adcf8fSFrançois Tigeot {
205219df918dSFrançois Tigeot 	struct drm_device *dev = intel_dp_to_dev(intel_dp);
2053ba55f2f5SFrançois Tigeot 	struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp);
2054303bf270SFrançois Tigeot 	struct drm_i915_private *dev_priv = to_i915(dev);
2055e3adcf8fSFrançois Tigeot 	u32 pp;
2056aee94f86SFrançois Tigeot 	i915_reg_t pp_stat_reg, pp_ctrl_reg;
20571b13d190SFrançois Tigeot 	bool need_to_disable = !intel_dp->want_panel_vdd;
20581b13d190SFrançois Tigeot 
20591b13d190SFrançois Tigeot 	lockdep_assert_held(&dev_priv->pps_mutex);
2060e3adcf8fSFrançois Tigeot 
2061*3f2dd94aSFrançois Tigeot 	if (!intel_dp_is_edp(intel_dp))
20621b13d190SFrançois Tigeot 		return false;
2063e3adcf8fSFrançois Tigeot 
20642c9916cdSFrançois Tigeot 	cancel_delayed_work(&intel_dp->panel_vdd_work);
2065e3adcf8fSFrançois Tigeot 	intel_dp->want_panel_vdd = true;
2066e3adcf8fSFrançois Tigeot 
2067ba55f2f5SFrançois Tigeot 	if (edp_have_panel_vdd(intel_dp))
20681b13d190SFrançois Tigeot 		return need_to_disable;
20699edbd4a0SFrançois Tigeot 
2070a85cb24fSFrançois Tigeot 	intel_display_power_get(dev_priv, intel_dp->aux_power_domain);
20719edbd4a0SFrançois Tigeot 
20722c9916cdSFrançois Tigeot 	DRM_DEBUG_KMS("Turning eDP port %c VDD on\n",
20732c9916cdSFrançois Tigeot 		      port_name(intel_dig_port->port));
2074e3adcf8fSFrançois Tigeot 
2075ba55f2f5SFrançois Tigeot 	if (!edp_have_panel_power(intel_dp))
2076ba55f2f5SFrançois Tigeot 		wait_panel_power_cycle(intel_dp);
2077e3adcf8fSFrançois Tigeot 
20788e26cdf6SFrançois Tigeot 	pp = ironlake_get_pp_control(intel_dp);
2079e3adcf8fSFrançois Tigeot 	pp |= EDP_FORCE_VDD;
2080e3adcf8fSFrançois Tigeot 
20819edbd4a0SFrançois Tigeot 	pp_stat_reg = _pp_stat_reg(intel_dp);
20829edbd4a0SFrançois Tigeot 	pp_ctrl_reg = _pp_ctrl_reg(intel_dp);
20838e26cdf6SFrançois Tigeot 
20848e26cdf6SFrançois Tigeot 	I915_WRITE(pp_ctrl_reg, pp);
20858e26cdf6SFrançois Tigeot 	POSTING_READ(pp_ctrl_reg);
20868e26cdf6SFrançois Tigeot 	DRM_DEBUG_KMS("PP_STATUS: 0x%08x PP_CONTROL: 0x%08x\n",
20878e26cdf6SFrançois Tigeot 			I915_READ(pp_stat_reg), I915_READ(pp_ctrl_reg));
2088e3adcf8fSFrançois Tigeot 	/*
2089e3adcf8fSFrançois Tigeot 	 * If the panel wasn't on, delay before accessing aux channel
2090e3adcf8fSFrançois Tigeot 	 */
2091ba55f2f5SFrançois Tigeot 	if (!edp_have_panel_power(intel_dp)) {
20922c9916cdSFrançois Tigeot 		DRM_DEBUG_KMS("eDP port %c panel power wasn't enabled\n",
20932c9916cdSFrançois Tigeot 			      port_name(intel_dig_port->port));
209419df918dSFrançois Tigeot 		msleep(intel_dp->panel_power_up_delay);
2095e3adcf8fSFrançois Tigeot 	}
20961b13d190SFrançois Tigeot 
20971b13d190SFrançois Tigeot 	return need_to_disable;
20981b13d190SFrançois Tigeot }
20991b13d190SFrançois Tigeot 
21001b13d190SFrançois Tigeot /*
21011b13d190SFrançois Tigeot  * Must be paired with intel_edp_panel_vdd_off() or
21021b13d190SFrançois Tigeot  * intel_edp_panel_off().
21031b13d190SFrançois Tigeot  * Nested calls to these functions are not allowed since
21041b13d190SFrançois Tigeot  * we drop the lock. Caller must use some higher level
21051b13d190SFrançois Tigeot  * locking to prevent nested calls from other threads.
21061b13d190SFrançois Tigeot  */
intel_edp_panel_vdd_on(struct intel_dp * intel_dp)21071b13d190SFrançois Tigeot void intel_edp_panel_vdd_on(struct intel_dp *intel_dp)
21081b13d190SFrançois Tigeot {
21091b13d190SFrançois Tigeot 	bool vdd;
21101b13d190SFrançois Tigeot 
2111*3f2dd94aSFrançois Tigeot 	if (!intel_dp_is_edp(intel_dp))
21121b13d190SFrançois Tigeot 		return;
21131b13d190SFrançois Tigeot 
21141b13d190SFrançois Tigeot 	pps_lock(intel_dp);
21151b13d190SFrançois Tigeot 	vdd = edp_panel_vdd_on(intel_dp);
21161b13d190SFrançois Tigeot 	pps_unlock(intel_dp);
21171b13d190SFrançois Tigeot 
21182c9916cdSFrançois Tigeot 	I915_STATE_WARN(!vdd, "eDP port %c VDD already requested on\n",
21192c9916cdSFrançois Tigeot 	     port_name(dp_to_dig_port(intel_dp)->port));
2120e3adcf8fSFrançois Tigeot }
2121e3adcf8fSFrançois Tigeot 
edp_panel_vdd_off_sync(struct intel_dp * intel_dp)2122ba55f2f5SFrançois Tigeot static void edp_panel_vdd_off_sync(struct intel_dp *intel_dp)
2123e3adcf8fSFrançois Tigeot {
212419df918dSFrançois Tigeot 	struct drm_device *dev = intel_dp_to_dev(intel_dp);
2125303bf270SFrançois Tigeot 	struct drm_i915_private *dev_priv = to_i915(dev);
2126ba55f2f5SFrançois Tigeot 	struct intel_digital_port *intel_dig_port =
2127ba55f2f5SFrançois Tigeot 		dp_to_dig_port(intel_dp);
21281b13d190SFrançois Tigeot 	u32 pp;
2129aee94f86SFrançois Tigeot 	i915_reg_t pp_stat_reg, pp_ctrl_reg;
21301b13d190SFrançois Tigeot 
21311b13d190SFrançois Tigeot 	lockdep_assert_held(&dev_priv->pps_mutex);
21321b13d190SFrançois Tigeot 
21331b13d190SFrançois Tigeot 	WARN_ON(intel_dp->want_panel_vdd);
21341b13d190SFrançois Tigeot 
21351b13d190SFrançois Tigeot 	if (!edp_have_panel_vdd(intel_dp))
21361b13d190SFrançois Tigeot 		return;
2137ba55f2f5SFrançois Tigeot 
21382c9916cdSFrançois Tigeot 	DRM_DEBUG_KMS("Turning eDP port %c VDD off\n",
21392c9916cdSFrançois Tigeot 		      port_name(intel_dig_port->port));
21409edbd4a0SFrançois Tigeot 
21418e26cdf6SFrançois Tigeot 	pp = ironlake_get_pp_control(intel_dp);
2142e3adcf8fSFrançois Tigeot 	pp &= ~EDP_FORCE_VDD;
21438e26cdf6SFrançois Tigeot 
21449edbd4a0SFrançois Tigeot 	pp_ctrl_reg = _pp_ctrl_reg(intel_dp);
21459edbd4a0SFrançois Tigeot 	pp_stat_reg = _pp_stat_reg(intel_dp);
21468e26cdf6SFrançois Tigeot 
21478e26cdf6SFrançois Tigeot 	I915_WRITE(pp_ctrl_reg, pp);
21488e26cdf6SFrançois Tigeot 	POSTING_READ(pp_ctrl_reg);
2149e3adcf8fSFrançois Tigeot 
2150e3adcf8fSFrançois Tigeot 	/* Make sure sequencer is idle before allowing subsequent activity */
21518e26cdf6SFrançois Tigeot 	DRM_DEBUG_KMS("PP_STATUS: 0x%08x PP_CONTROL: 0x%08x\n",
21528e26cdf6SFrançois Tigeot 	I915_READ(pp_stat_reg), I915_READ(pp_ctrl_reg));
21539edbd4a0SFrançois Tigeot 
21541e12ee3bSFrançois Tigeot 	if ((pp & PANEL_POWER_ON) == 0)
2155c0e85e96SFrançois Tigeot 		intel_dp->panel_power_off_time = ktime_get_boottime();
21569edbd4a0SFrançois Tigeot 
2157a85cb24fSFrançois Tigeot 	intel_display_power_put(dev_priv, intel_dp->aux_power_domain);
2158e3adcf8fSFrançois Tigeot }
2159e3adcf8fSFrançois Tigeot 
edp_panel_vdd_work(struct work_struct * __work)2160ba55f2f5SFrançois Tigeot static void edp_panel_vdd_work(struct work_struct *__work)
2161e3adcf8fSFrançois Tigeot {
2162abf1f4f4SFrançois Tigeot 	struct intel_dp *intel_dp = container_of(to_delayed_work(__work),
2163abf1f4f4SFrançois Tigeot 						 struct intel_dp, panel_vdd_work);
2164e3adcf8fSFrançois Tigeot 
21651b13d190SFrançois Tigeot 	pps_lock(intel_dp);
21661b13d190SFrançois Tigeot 	if (!intel_dp->want_panel_vdd)
2167ba55f2f5SFrançois Tigeot 		edp_panel_vdd_off_sync(intel_dp);
21681b13d190SFrançois Tigeot 	pps_unlock(intel_dp);
2169e3adcf8fSFrançois Tigeot }
2170e3adcf8fSFrançois Tigeot 
edp_panel_vdd_schedule_off(struct intel_dp * intel_dp)217124edb884SFrançois Tigeot static void edp_panel_vdd_schedule_off(struct intel_dp *intel_dp)
217224edb884SFrançois Tigeot {
217324edb884SFrançois Tigeot 	unsigned long delay;
217424edb884SFrançois Tigeot 
217524edb884SFrançois Tigeot 	/*
217624edb884SFrançois Tigeot 	 * Queue the timer to fire a long time from now (relative to the power
217724edb884SFrançois Tigeot 	 * down delay) to keep the panel power up across a sequence of
217824edb884SFrançois Tigeot 	 * operations.
217924edb884SFrançois Tigeot 	 */
218024edb884SFrançois Tigeot 	delay = msecs_to_jiffies(intel_dp->panel_power_cycle_delay * 5);
218124edb884SFrançois Tigeot 	schedule_delayed_work(&intel_dp->panel_vdd_work, delay);
218224edb884SFrançois Tigeot }
218324edb884SFrançois Tigeot 
21841b13d190SFrançois Tigeot /*
21851b13d190SFrançois Tigeot  * Must be paired with edp_panel_vdd_on().
21861b13d190SFrançois Tigeot  * Must hold pps_mutex around the whole on/off sequence.
21871b13d190SFrançois Tigeot  * Can be nested with intel_edp_panel_vdd_{on,off}() calls.
21881b13d190SFrançois Tigeot  */
edp_panel_vdd_off(struct intel_dp * intel_dp,bool sync)2189ba55f2f5SFrançois Tigeot static void edp_panel_vdd_off(struct intel_dp *intel_dp, bool sync)
2190e3adcf8fSFrançois Tigeot {
2191303bf270SFrançois Tigeot 	struct drm_i915_private *dev_priv = to_i915(intel_dp_to_dev(intel_dp));
21921b13d190SFrançois Tigeot 
21931b13d190SFrançois Tigeot 	lockdep_assert_held(&dev_priv->pps_mutex);
21941b13d190SFrançois Tigeot 
2195*3f2dd94aSFrançois Tigeot 	if (!intel_dp_is_edp(intel_dp))
2196e3adcf8fSFrançois Tigeot 		return;
2197e3adcf8fSFrançois Tigeot 
21982c9916cdSFrançois Tigeot 	I915_STATE_WARN(!intel_dp->want_panel_vdd, "eDP port %c VDD not forced on",
21992c9916cdSFrançois Tigeot 	     port_name(dp_to_dig_port(intel_dp)->port));
2200e3adcf8fSFrançois Tigeot 
2201e3adcf8fSFrançois Tigeot 	intel_dp->want_panel_vdd = false;
2202e3adcf8fSFrançois Tigeot 
220324edb884SFrançois Tigeot 	if (sync)
2204ba55f2f5SFrançois Tigeot 		edp_panel_vdd_off_sync(intel_dp);
220524edb884SFrançois Tigeot 	else
220624edb884SFrançois Tigeot 		edp_panel_vdd_schedule_off(intel_dp);
2207e3adcf8fSFrançois Tigeot }
2208e3adcf8fSFrançois Tigeot 
edp_panel_on(struct intel_dp * intel_dp)22092c9916cdSFrançois Tigeot static void edp_panel_on(struct intel_dp *intel_dp)
2210e3adcf8fSFrançois Tigeot {
221119df918dSFrançois Tigeot 	struct drm_device *dev = intel_dp_to_dev(intel_dp);
2212303bf270SFrançois Tigeot 	struct drm_i915_private *dev_priv = to_i915(dev);
2213e3adcf8fSFrançois Tigeot 	u32 pp;
2214aee94f86SFrançois Tigeot 	i915_reg_t pp_ctrl_reg;
2215e3adcf8fSFrançois Tigeot 
22162c9916cdSFrançois Tigeot 	lockdep_assert_held(&dev_priv->pps_mutex);
22172c9916cdSFrançois Tigeot 
2218*3f2dd94aSFrançois Tigeot 	if (!intel_dp_is_edp(intel_dp))
2219e3adcf8fSFrançois Tigeot 		return;
2220e3adcf8fSFrançois Tigeot 
22212c9916cdSFrançois Tigeot 	DRM_DEBUG_KMS("Turn eDP port %c panel power on\n",
22222c9916cdSFrançois Tigeot 		      port_name(dp_to_dig_port(intel_dp)->port));
2223e3adcf8fSFrançois Tigeot 
22242c9916cdSFrançois Tigeot 	if (WARN(edp_have_panel_power(intel_dp),
22252c9916cdSFrançois Tigeot 		 "eDP port %c panel power already on\n",
22262c9916cdSFrançois Tigeot 		 port_name(dp_to_dig_port(intel_dp)->port)))
22272c9916cdSFrançois Tigeot 		return;
2228e3adcf8fSFrançois Tigeot 
2229ba55f2f5SFrançois Tigeot 	wait_panel_power_cycle(intel_dp);
2230e3adcf8fSFrançois Tigeot 
22319edbd4a0SFrançois Tigeot 	pp_ctrl_reg = _pp_ctrl_reg(intel_dp);
22328e26cdf6SFrançois Tigeot 	pp = ironlake_get_pp_control(intel_dp);
22331e12ee3bSFrançois Tigeot 	if (IS_GEN5(dev_priv)) {
2234e3adcf8fSFrançois Tigeot 		/* ILK workaround: disable reset around power sequence */
2235e3adcf8fSFrançois Tigeot 		pp &= ~PANEL_POWER_RESET;
22369edbd4a0SFrançois Tigeot 		I915_WRITE(pp_ctrl_reg, pp);
22379edbd4a0SFrançois Tigeot 		POSTING_READ(pp_ctrl_reg);
2238e3adcf8fSFrançois Tigeot 	}
2239e3adcf8fSFrançois Tigeot 
22401e12ee3bSFrançois Tigeot 	pp |= PANEL_POWER_ON;
22411e12ee3bSFrançois Tigeot 	if (!IS_GEN5(dev_priv))
2242e3adcf8fSFrançois Tigeot 		pp |= PANEL_POWER_RESET;
2243e3adcf8fSFrançois Tigeot 
22448e26cdf6SFrançois Tigeot 	I915_WRITE(pp_ctrl_reg, pp);
22458e26cdf6SFrançois Tigeot 	POSTING_READ(pp_ctrl_reg);
2246e3adcf8fSFrançois Tigeot 
2247ba55f2f5SFrançois Tigeot 	wait_panel_on(intel_dp);
2248ba55f2f5SFrançois Tigeot 	intel_dp->last_power_on = jiffies;
2249e3adcf8fSFrançois Tigeot 
22501e12ee3bSFrançois Tigeot 	if (IS_GEN5(dev_priv)) {
2251e3adcf8fSFrançois Tigeot 		pp |= PANEL_POWER_RESET; /* restore panel reset bit */
22529edbd4a0SFrançois Tigeot 		I915_WRITE(pp_ctrl_reg, pp);
22539edbd4a0SFrançois Tigeot 		POSTING_READ(pp_ctrl_reg);
2254e3adcf8fSFrançois Tigeot 	}
22552c9916cdSFrançois Tigeot }
22561b13d190SFrançois Tigeot 
intel_edp_panel_on(struct intel_dp * intel_dp)22572c9916cdSFrançois Tigeot void intel_edp_panel_on(struct intel_dp *intel_dp)
22582c9916cdSFrançois Tigeot {
2259*3f2dd94aSFrançois Tigeot 	if (!intel_dp_is_edp(intel_dp))
22602c9916cdSFrançois Tigeot 		return;
22612c9916cdSFrançois Tigeot 
22622c9916cdSFrançois Tigeot 	pps_lock(intel_dp);
22632c9916cdSFrançois Tigeot 	edp_panel_on(intel_dp);
22641b13d190SFrançois Tigeot 	pps_unlock(intel_dp);
2265e3adcf8fSFrançois Tigeot }
2266e3adcf8fSFrançois Tigeot 
22672c9916cdSFrançois Tigeot 
edp_panel_off(struct intel_dp * intel_dp)22682c9916cdSFrançois Tigeot static void edp_panel_off(struct intel_dp *intel_dp)
2269e3adcf8fSFrançois Tigeot {
227019df918dSFrançois Tigeot 	struct drm_device *dev = intel_dp_to_dev(intel_dp);
2271303bf270SFrançois Tigeot 	struct drm_i915_private *dev_priv = to_i915(dev);
2272e3adcf8fSFrançois Tigeot 	u32 pp;
2273aee94f86SFrançois Tigeot 	i915_reg_t pp_ctrl_reg;
2274e3adcf8fSFrançois Tigeot 
22752c9916cdSFrançois Tigeot 	lockdep_assert_held(&dev_priv->pps_mutex);
22762c9916cdSFrançois Tigeot 
2277*3f2dd94aSFrançois Tigeot 	if (!intel_dp_is_edp(intel_dp))
2278e3adcf8fSFrançois Tigeot 		return;
2279e3adcf8fSFrançois Tigeot 
22802c9916cdSFrançois Tigeot 	DRM_DEBUG_KMS("Turn eDP port %c panel power off\n",
22812c9916cdSFrançois Tigeot 		      port_name(dp_to_dig_port(intel_dp)->port));
2282e3adcf8fSFrançois Tigeot 
22832c9916cdSFrançois Tigeot 	WARN(!intel_dp->want_panel_vdd, "Need eDP port %c VDD to turn off panel\n",
22842c9916cdSFrançois Tigeot 	     port_name(dp_to_dig_port(intel_dp)->port));
2285e3adcf8fSFrançois Tigeot 
22868e26cdf6SFrançois Tigeot 	pp = ironlake_get_pp_control(intel_dp);
228719df918dSFrançois Tigeot 	/* We need to switch off panel power _and_ force vdd, for otherwise some
228819df918dSFrançois Tigeot 	 * panels get very unhappy and cease to work. */
22891e12ee3bSFrançois Tigeot 	pp &= ~(PANEL_POWER_ON | PANEL_POWER_RESET | EDP_FORCE_VDD |
2290ba55f2f5SFrançois Tigeot 		EDP_BLC_ENABLE);
22918e26cdf6SFrançois Tigeot 
22929edbd4a0SFrançois Tigeot 	pp_ctrl_reg = _pp_ctrl_reg(intel_dp);
22938e26cdf6SFrançois Tigeot 
2294ba55f2f5SFrançois Tigeot 	intel_dp->want_panel_vdd = false;
2295ba55f2f5SFrançois Tigeot 
22968e26cdf6SFrançois Tigeot 	I915_WRITE(pp_ctrl_reg, pp);
22978e26cdf6SFrançois Tigeot 	POSTING_READ(pp_ctrl_reg);
2298e3adcf8fSFrançois Tigeot 
2299ba55f2f5SFrançois Tigeot 	wait_panel_off(intel_dp);
2300*3f2dd94aSFrançois Tigeot 	intel_dp->panel_power_off_time = ktime_get_boottime();
23019edbd4a0SFrançois Tigeot 
23029edbd4a0SFrançois Tigeot 	/* We got a reference when we enabled the VDD. */
2303a85cb24fSFrançois Tigeot 	intel_display_power_put(dev_priv, intel_dp->aux_power_domain);
23042c9916cdSFrançois Tigeot }
23051b13d190SFrançois Tigeot 
intel_edp_panel_off(struct intel_dp * intel_dp)23062c9916cdSFrançois Tigeot void intel_edp_panel_off(struct intel_dp *intel_dp)
23072c9916cdSFrançois Tigeot {
2308*3f2dd94aSFrançois Tigeot 	if (!intel_dp_is_edp(intel_dp))
23092c9916cdSFrançois Tigeot 		return;
23102c9916cdSFrançois Tigeot 
23112c9916cdSFrançois Tigeot 	pps_lock(intel_dp);
23122c9916cdSFrançois Tigeot 	edp_panel_off(intel_dp);
23131b13d190SFrançois Tigeot 	pps_unlock(intel_dp);
2314e3adcf8fSFrançois Tigeot }
2315e3adcf8fSFrançois Tigeot 
23161b13d190SFrançois Tigeot /* Enable backlight in the panel power control. */
_intel_edp_backlight_on(struct intel_dp * intel_dp)23171b13d190SFrançois Tigeot static void _intel_edp_backlight_on(struct intel_dp *intel_dp)
2318e3adcf8fSFrançois Tigeot {
231919df918dSFrançois Tigeot 	struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp);
232019df918dSFrançois Tigeot 	struct drm_device *dev = intel_dig_port->base.base.dev;
2321303bf270SFrançois Tigeot 	struct drm_i915_private *dev_priv = to_i915(dev);
2322e3adcf8fSFrançois Tigeot 	u32 pp;
2323aee94f86SFrançois Tigeot 	i915_reg_t pp_ctrl_reg;
2324e3adcf8fSFrançois Tigeot 
2325e3adcf8fSFrançois Tigeot 	/*
2326e3adcf8fSFrançois Tigeot 	 * If we enable the backlight right away following a panel power
2327e3adcf8fSFrançois Tigeot 	 * on, we may see slight flicker as the panel syncs with the eDP
2328e3adcf8fSFrançois Tigeot 	 * link.  So delay a bit to make sure the image is solid before
2329e3adcf8fSFrançois Tigeot 	 * allowing it to appear.
2330e3adcf8fSFrançois Tigeot 	 */
2331ba55f2f5SFrançois Tigeot 	wait_backlight_on(intel_dp);
23321b13d190SFrançois Tigeot 
23331b13d190SFrançois Tigeot 	pps_lock(intel_dp);
23341b13d190SFrançois Tigeot 
23358e26cdf6SFrançois Tigeot 	pp = ironlake_get_pp_control(intel_dp);
2336e3adcf8fSFrançois Tigeot 	pp |= EDP_BLC_ENABLE;
23378e26cdf6SFrançois Tigeot 
23389edbd4a0SFrançois Tigeot 	pp_ctrl_reg = _pp_ctrl_reg(intel_dp);
23398e26cdf6SFrançois Tigeot 
23408e26cdf6SFrançois Tigeot 	I915_WRITE(pp_ctrl_reg, pp);
23418e26cdf6SFrançois Tigeot 	POSTING_READ(pp_ctrl_reg);
23421b13d190SFrançois Tigeot 
23431b13d190SFrançois Tigeot 	pps_unlock(intel_dp);
2344e3adcf8fSFrançois Tigeot }
2345e3adcf8fSFrançois Tigeot 
23461b13d190SFrançois Tigeot /* Enable backlight PWM and backlight PP control. */
intel_edp_backlight_on(const struct intel_crtc_state * crtc_state,const struct drm_connector_state * conn_state)2347*3f2dd94aSFrançois Tigeot void intel_edp_backlight_on(const struct intel_crtc_state *crtc_state,
2348*3f2dd94aSFrançois Tigeot 			    const struct drm_connector_state *conn_state)
23491b13d190SFrançois Tigeot {
2350*3f2dd94aSFrançois Tigeot 	struct intel_dp *intel_dp = enc_to_intel_dp(conn_state->best_encoder);
2351*3f2dd94aSFrançois Tigeot 
2352*3f2dd94aSFrançois Tigeot 	if (!intel_dp_is_edp(intel_dp))
23531b13d190SFrançois Tigeot 		return;
23541b13d190SFrançois Tigeot 
23551b13d190SFrançois Tigeot 	DRM_DEBUG_KMS("\n");
23561b13d190SFrançois Tigeot 
2357*3f2dd94aSFrançois Tigeot 	intel_panel_enable_backlight(crtc_state, conn_state);
23581b13d190SFrançois Tigeot 	_intel_edp_backlight_on(intel_dp);
23591b13d190SFrançois Tigeot }
23601b13d190SFrançois Tigeot 
23611b13d190SFrançois Tigeot /* Disable backlight in the panel power control. */
_intel_edp_backlight_off(struct intel_dp * intel_dp)23621b13d190SFrançois Tigeot static void _intel_edp_backlight_off(struct intel_dp *intel_dp)
2363e3adcf8fSFrançois Tigeot {
236419df918dSFrançois Tigeot 	struct drm_device *dev = intel_dp_to_dev(intel_dp);
2365303bf270SFrançois Tigeot 	struct drm_i915_private *dev_priv = to_i915(dev);
2366e3adcf8fSFrançois Tigeot 	u32 pp;
2367aee94f86SFrançois Tigeot 	i915_reg_t pp_ctrl_reg;
2368e3adcf8fSFrançois Tigeot 
2369*3f2dd94aSFrançois Tigeot 	if (!intel_dp_is_edp(intel_dp))
2370e3adcf8fSFrançois Tigeot 		return;
2371e3adcf8fSFrançois Tigeot 
23721b13d190SFrançois Tigeot 	pps_lock(intel_dp);
23731b13d190SFrançois Tigeot 
23748e26cdf6SFrançois Tigeot 	pp = ironlake_get_pp_control(intel_dp);
2375e3adcf8fSFrançois Tigeot 	pp &= ~EDP_BLC_ENABLE;
23768e26cdf6SFrançois Tigeot 
23779edbd4a0SFrançois Tigeot 	pp_ctrl_reg = _pp_ctrl_reg(intel_dp);
23788e26cdf6SFrançois Tigeot 
23798e26cdf6SFrançois Tigeot 	I915_WRITE(pp_ctrl_reg, pp);
23808e26cdf6SFrançois Tigeot 	POSTING_READ(pp_ctrl_reg);
23811b13d190SFrançois Tigeot 
23821b13d190SFrançois Tigeot 	pps_unlock(intel_dp);
23831b13d190SFrançois Tigeot 
2384ba55f2f5SFrançois Tigeot 	intel_dp->last_backlight_off = jiffies;
238524edb884SFrançois Tigeot 	edp_wait_backlight_off(intel_dp);
23861b13d190SFrançois Tigeot }
238724edb884SFrançois Tigeot 
23881b13d190SFrançois Tigeot /* Disable backlight PP control and backlight PWM. */
intel_edp_backlight_off(const struct drm_connector_state * old_conn_state)2389*3f2dd94aSFrançois Tigeot void intel_edp_backlight_off(const struct drm_connector_state *old_conn_state)
23901b13d190SFrançois Tigeot {
2391*3f2dd94aSFrançois Tigeot 	struct intel_dp *intel_dp = enc_to_intel_dp(old_conn_state->best_encoder);
2392*3f2dd94aSFrançois Tigeot 
2393*3f2dd94aSFrançois Tigeot 	if (!intel_dp_is_edp(intel_dp))
23941b13d190SFrançois Tigeot 		return;
23951b13d190SFrançois Tigeot 
23961b13d190SFrançois Tigeot 	DRM_DEBUG_KMS("\n");
23971b13d190SFrançois Tigeot 
23981b13d190SFrançois Tigeot 	_intel_edp_backlight_off(intel_dp);
2399*3f2dd94aSFrançois Tigeot 	intel_panel_disable_backlight(old_conn_state);
2400e3adcf8fSFrançois Tigeot }
2401e3adcf8fSFrançois Tigeot 
24021b13d190SFrançois Tigeot /*
24031b13d190SFrançois Tigeot  * Hook for controlling the panel power control backlight through the bl_power
24041b13d190SFrançois Tigeot  * sysfs attribute. Take care to handle multiple calls.
24051b13d190SFrançois Tigeot  */
intel_edp_backlight_power(struct intel_connector * connector,bool enable)24061b13d190SFrançois Tigeot static void intel_edp_backlight_power(struct intel_connector *connector,
24071b13d190SFrançois Tigeot 				      bool enable)
24081b13d190SFrançois Tigeot {
24091b13d190SFrançois Tigeot 	struct intel_dp *intel_dp = intel_attached_dp(&connector->base);
24101b13d190SFrançois Tigeot 	bool is_enabled;
24111b13d190SFrançois Tigeot 
24121b13d190SFrançois Tigeot 	pps_lock(intel_dp);
24131b13d190SFrançois Tigeot 	is_enabled = ironlake_get_pp_control(intel_dp) & EDP_BLC_ENABLE;
24141b13d190SFrançois Tigeot 	pps_unlock(intel_dp);
24151b13d190SFrançois Tigeot 
24161b13d190SFrançois Tigeot 	if (is_enabled == enable)
24171b13d190SFrançois Tigeot 		return;
24181b13d190SFrançois Tigeot 
24191b13d190SFrançois Tigeot 	DRM_DEBUG_KMS("panel power control backlight %s\n",
24201b13d190SFrançois Tigeot 		      enable ? "enable" : "disable");
24211b13d190SFrançois Tigeot 
24221b13d190SFrançois Tigeot 	if (enable)
24231b13d190SFrançois Tigeot 		_intel_edp_backlight_on(intel_dp);
24241b13d190SFrançois Tigeot 	else
24251b13d190SFrançois Tigeot 		_intel_edp_backlight_off(intel_dp);
24261b13d190SFrançois Tigeot }
24271b13d190SFrançois Tigeot 
assert_dp_port(struct intel_dp * intel_dp,bool state)2428aee94f86SFrançois Tigeot static void assert_dp_port(struct intel_dp *intel_dp, bool state)
2429aee94f86SFrançois Tigeot {
2430aee94f86SFrançois Tigeot 	struct intel_digital_port *dig_port = dp_to_dig_port(intel_dp);
2431aee94f86SFrançois Tigeot 	struct drm_i915_private *dev_priv = to_i915(dig_port->base.base.dev);
2432aee94f86SFrançois Tigeot 	bool cur_state = I915_READ(intel_dp->output_reg) & DP_PORT_EN;
2433aee94f86SFrançois Tigeot 
2434aee94f86SFrançois Tigeot 	I915_STATE_WARN(cur_state != state,
2435aee94f86SFrançois Tigeot 			"DP port %c state assertion failure (expected %s, current %s)\n",
2436aee94f86SFrançois Tigeot 			port_name(dig_port->port),
2437c0e85e96SFrançois Tigeot 			onoff(state), onoff(cur_state));
2438aee94f86SFrançois Tigeot }
2439aee94f86SFrançois Tigeot #define assert_dp_port_disabled(d) assert_dp_port((d), false)
2440aee94f86SFrançois Tigeot 
assert_edp_pll(struct drm_i915_private * dev_priv,bool state)2441aee94f86SFrançois Tigeot static void assert_edp_pll(struct drm_i915_private *dev_priv, bool state)
2442aee94f86SFrançois Tigeot {
2443aee94f86SFrançois Tigeot 	bool cur_state = I915_READ(DP_A) & DP_PLL_ENABLE;
2444aee94f86SFrançois Tigeot 
2445aee94f86SFrançois Tigeot 	I915_STATE_WARN(cur_state != state,
2446aee94f86SFrançois Tigeot 			"eDP PLL state assertion failure (expected %s, current %s)\n",
2447c0e85e96SFrançois Tigeot 			onoff(state), onoff(cur_state));
2448aee94f86SFrançois Tigeot }
2449aee94f86SFrançois Tigeot #define assert_edp_pll_enabled(d) assert_edp_pll((d), true)
2450aee94f86SFrançois Tigeot #define assert_edp_pll_disabled(d) assert_edp_pll((d), false)
2451aee94f86SFrançois Tigeot 
ironlake_edp_pll_on(struct intel_dp * intel_dp,const struct intel_crtc_state * pipe_config)24521e12ee3bSFrançois Tigeot static void ironlake_edp_pll_on(struct intel_dp *intel_dp,
2453*3f2dd94aSFrançois Tigeot 				const struct intel_crtc_state *pipe_config)
2454e3adcf8fSFrançois Tigeot {
24551e12ee3bSFrançois Tigeot 	struct intel_crtc *crtc = to_intel_crtc(pipe_config->base.crtc);
2456aee94f86SFrançois Tigeot 	struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
2457e3adcf8fSFrançois Tigeot 
2458aee94f86SFrançois Tigeot 	assert_pipe_disabled(dev_priv, crtc->pipe);
2459aee94f86SFrançois Tigeot 	assert_dp_port_disabled(intel_dp);
2460aee94f86SFrançois Tigeot 	assert_edp_pll_disabled(dev_priv);
246119df918dSFrançois Tigeot 
2462aee94f86SFrançois Tigeot 	DRM_DEBUG_KMS("enabling eDP PLL for clock %d\n",
24631e12ee3bSFrançois Tigeot 		      pipe_config->port_clock);
246419df918dSFrançois Tigeot 
2465aee94f86SFrançois Tigeot 	intel_dp->DP &= ~DP_PLL_FREQ_MASK;
2466aee94f86SFrançois Tigeot 
24671e12ee3bSFrançois Tigeot 	if (pipe_config->port_clock == 162000)
2468aee94f86SFrançois Tigeot 		intel_dp->DP |= DP_PLL_FREQ_162MHZ;
2469aee94f86SFrançois Tigeot 	else
2470aee94f86SFrançois Tigeot 		intel_dp->DP |= DP_PLL_FREQ_270MHZ;
2471aee94f86SFrançois Tigeot 
2472aee94f86SFrançois Tigeot 	I915_WRITE(DP_A, intel_dp->DP);
2473aee94f86SFrançois Tigeot 	POSTING_READ(DP_A);
2474aee94f86SFrançois Tigeot 	udelay(500);
2475aee94f86SFrançois Tigeot 
24768621f407SFrançois Tigeot 	/*
24778621f407SFrançois Tigeot 	 * [DevILK] Work around required when enabling DP PLL
24788621f407SFrançois Tigeot 	 * while a pipe is enabled going to FDI:
24798621f407SFrançois Tigeot 	 * 1. Wait for the start of vertical blank on the enabled pipe going to FDI
24808621f407SFrançois Tigeot 	 * 2. Program DP PLL enable
24818621f407SFrançois Tigeot 	 */
24828621f407SFrançois Tigeot 	if (IS_GEN5(dev_priv))
24834be47400SFrançois Tigeot 		intel_wait_for_vblank_if_active(dev_priv, !crtc->pipe);
24848621f407SFrançois Tigeot 
248519df918dSFrançois Tigeot 	intel_dp->DP |= DP_PLL_ENABLE;
2486aee94f86SFrançois Tigeot 
248719df918dSFrançois Tigeot 	I915_WRITE(DP_A, intel_dp->DP);
2488e3adcf8fSFrançois Tigeot 	POSTING_READ(DP_A);
248919df918dSFrançois Tigeot 	udelay(200);
2490e3adcf8fSFrançois Tigeot }
2491e3adcf8fSFrançois Tigeot 
ironlake_edp_pll_off(struct intel_dp * intel_dp)249219df918dSFrançois Tigeot static void ironlake_edp_pll_off(struct intel_dp *intel_dp)
2493e3adcf8fSFrançois Tigeot {
249419df918dSFrançois Tigeot 	struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp);
2495aee94f86SFrançois Tigeot 	struct intel_crtc *crtc = to_intel_crtc(intel_dig_port->base.base.crtc);
2496aee94f86SFrançois Tigeot 	struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
2497e3adcf8fSFrançois Tigeot 
2498aee94f86SFrançois Tigeot 	assert_pipe_disabled(dev_priv, crtc->pipe);
2499aee94f86SFrançois Tigeot 	assert_dp_port_disabled(intel_dp);
2500aee94f86SFrançois Tigeot 	assert_edp_pll_enabled(dev_priv);
250119df918dSFrançois Tigeot 
2502aee94f86SFrançois Tigeot 	DRM_DEBUG_KMS("disabling eDP PLL\n");
250319df918dSFrançois Tigeot 
2504aee94f86SFrançois Tigeot 	intel_dp->DP &= ~DP_PLL_ENABLE;
2505aee94f86SFrançois Tigeot 
2506aee94f86SFrançois Tigeot 	I915_WRITE(DP_A, intel_dp->DP);
2507e3adcf8fSFrançois Tigeot 	POSTING_READ(DP_A);
250819df918dSFrançois Tigeot 	udelay(200);
2509e3adcf8fSFrançois Tigeot }
2510e3adcf8fSFrançois Tigeot 
2511e3adcf8fSFrançois Tigeot /* If the sink supports it, try to set the power state appropriately */
intel_dp_sink_dpms(struct intel_dp * intel_dp,int mode)251219df918dSFrançois Tigeot void intel_dp_sink_dpms(struct intel_dp *intel_dp, int mode)
2513e3adcf8fSFrançois Tigeot {
2514e3adcf8fSFrançois Tigeot 	int ret, i;
2515e3adcf8fSFrançois Tigeot 
2516e3adcf8fSFrançois Tigeot 	/* Should have a valid DPCD by this point */
2517e3adcf8fSFrançois Tigeot 	if (intel_dp->dpcd[DP_DPCD_REV] < 0x11)
2518e3adcf8fSFrançois Tigeot 		return;
2519e3adcf8fSFrançois Tigeot 
2520e3adcf8fSFrançois Tigeot 	if (mode != DRM_MODE_DPMS_ON) {
25216b231eabSImre Vadász 		ret = drm_dp_dpcd_writeb(&intel_dp->aux, DP_SET_POWER,
2522e3adcf8fSFrançois Tigeot 					 DP_SET_POWER_D3);
2523e3adcf8fSFrançois Tigeot 	} else {
2524a85cb24fSFrançois Tigeot 		struct intel_lspcon *lspcon = dp_to_lspcon(intel_dp);
2525a85cb24fSFrançois Tigeot 
2526e3adcf8fSFrançois Tigeot 		/*
2527e3adcf8fSFrançois Tigeot 		 * When turning on, we need to retry for 1ms to give the sink
2528e3adcf8fSFrançois Tigeot 		 * time to wake up.
2529e3adcf8fSFrançois Tigeot 		 */
2530e3adcf8fSFrançois Tigeot 		for (i = 0; i < 3; i++) {
25316b231eabSImre Vadász 			ret = drm_dp_dpcd_writeb(&intel_dp->aux, DP_SET_POWER,
2532e3adcf8fSFrançois Tigeot 						 DP_SET_POWER_D0);
2533e3adcf8fSFrançois Tigeot 			if (ret == 1)
2534e3adcf8fSFrançois Tigeot 				break;
2535e3440f96SFrançois Tigeot 			msleep(1);
2536e3adcf8fSFrançois Tigeot 		}
2537a85cb24fSFrançois Tigeot 
2538a85cb24fSFrançois Tigeot 		if (ret == 1 && lspcon->active)
2539a85cb24fSFrançois Tigeot 			lspcon_wait_pcon_mode(lspcon);
2540e3adcf8fSFrançois Tigeot 	}
25411b13d190SFrançois Tigeot 
25421b13d190SFrançois Tigeot 	if (ret != 1)
25431b13d190SFrançois Tigeot 		DRM_DEBUG_KMS("failed to %s sink power state\n",
25441b13d190SFrançois Tigeot 			      mode == DRM_MODE_DPMS_ON ? "enable" : "disable");
2545e3adcf8fSFrançois Tigeot }
2546e3adcf8fSFrançois Tigeot 
intel_dp_get_hw_state(struct intel_encoder * encoder,enum i915_pipe * pipe)254719df918dSFrançois Tigeot static bool intel_dp_get_hw_state(struct intel_encoder *encoder,
254819df918dSFrançois Tigeot 				  enum i915_pipe *pipe)
2549e3adcf8fSFrançois Tigeot {
255019df918dSFrançois Tigeot 	struct intel_dp *intel_dp = enc_to_intel_dp(&encoder->base);
25515d0b1887SFrançois Tigeot 	enum port port = dp_to_dig_port(intel_dp)->port;
255219df918dSFrançois Tigeot 	struct drm_device *dev = encoder->base.dev;
2553303bf270SFrançois Tigeot 	struct drm_i915_private *dev_priv = to_i915(dev);
2554ba55f2f5SFrançois Tigeot 	u32 tmp;
2555aee94f86SFrançois Tigeot 	bool ret;
2556ba55f2f5SFrançois Tigeot 
2557a85cb24fSFrançois Tigeot 	if (!intel_display_power_get_if_enabled(dev_priv,
2558a85cb24fSFrançois Tigeot 						encoder->power_domain))
2559ba55f2f5SFrançois Tigeot 		return false;
2560ba55f2f5SFrançois Tigeot 
2561aee94f86SFrançois Tigeot 	ret = false;
2562aee94f86SFrançois Tigeot 
2563ba55f2f5SFrançois Tigeot 	tmp = I915_READ(intel_dp->output_reg);
2564e3adcf8fSFrançois Tigeot 
256519df918dSFrançois Tigeot 	if (!(tmp & DP_PORT_EN))
2566aee94f86SFrançois Tigeot 		goto out;
256719df918dSFrançois Tigeot 
25681e12ee3bSFrançois Tigeot 	if (IS_GEN7(dev_priv) && port == PORT_A) {
256919df918dSFrançois Tigeot 		*pipe = PORT_TO_PIPE_CPT(tmp);
25701e12ee3bSFrançois Tigeot 	} else if (HAS_PCH_CPT(dev_priv) && port != PORT_A) {
257119c468b4SFrançois Tigeot 		enum i915_pipe p;
257219df918dSFrançois Tigeot 
257319c468b4SFrançois Tigeot 		for_each_pipe(dev_priv, p) {
257419c468b4SFrançois Tigeot 			u32 trans_dp = I915_READ(TRANS_DP_CTL(p));
257519c468b4SFrançois Tigeot 			if (TRANS_DP_PIPE_TO_PORT(trans_dp) == port) {
257619c468b4SFrançois Tigeot 				*pipe = p;
2577aee94f86SFrançois Tigeot 				ret = true;
2578aee94f86SFrançois Tigeot 
2579aee94f86SFrançois Tigeot 				goto out;
258019df918dSFrançois Tigeot 			}
258119df918dSFrançois Tigeot 		}
258219df918dSFrançois Tigeot 
258319df918dSFrançois Tigeot 		DRM_DEBUG_KMS("No pipe for dp port 0x%x found\n",
2584aee94f86SFrançois Tigeot 			      i915_mmio_reg_offset(intel_dp->output_reg));
25851e12ee3bSFrançois Tigeot 	} else if (IS_CHERRYVIEW(dev_priv)) {
258619c468b4SFrançois Tigeot 		*pipe = DP_PORT_TO_PIPE_CHV(tmp);
258719c468b4SFrançois Tigeot 	} else {
258819c468b4SFrançois Tigeot 		*pipe = PORT_TO_PIPE(tmp);
258919df918dSFrançois Tigeot 	}
259019df918dSFrançois Tigeot 
2591aee94f86SFrançois Tigeot 	ret = true;
2592aee94f86SFrançois Tigeot 
2593aee94f86SFrançois Tigeot out:
2594a85cb24fSFrançois Tigeot 	intel_display_power_put(dev_priv, encoder->power_domain);
2595aee94f86SFrançois Tigeot 
2596aee94f86SFrançois Tigeot 	return ret;
259719df918dSFrançois Tigeot }
259819df918dSFrançois Tigeot 
intel_dp_get_config(struct intel_encoder * encoder,struct intel_crtc_state * pipe_config)25995d0b1887SFrançois Tigeot static void intel_dp_get_config(struct intel_encoder *encoder,
26002c9916cdSFrançois Tigeot 				struct intel_crtc_state *pipe_config)
26015d0b1887SFrançois Tigeot {
26025d0b1887SFrançois Tigeot 	struct intel_dp *intel_dp = enc_to_intel_dp(&encoder->base);
26035d0b1887SFrançois Tigeot 	u32 tmp, flags = 0;
26045d0b1887SFrançois Tigeot 	struct drm_device *dev = encoder->base.dev;
2605303bf270SFrançois Tigeot 	struct drm_i915_private *dev_priv = to_i915(dev);
26065d0b1887SFrançois Tigeot 	enum port port = dp_to_dig_port(intel_dp)->port;
26075d0b1887SFrançois Tigeot 	struct intel_crtc *crtc = to_intel_crtc(encoder->base.crtc);
26085d0b1887SFrançois Tigeot 
26095d0b1887SFrançois Tigeot 	tmp = I915_READ(intel_dp->output_reg);
2610477eb7f9SFrançois Tigeot 
2611477eb7f9SFrançois Tigeot 	pipe_config->has_audio = tmp & DP_AUDIO_OUTPUT_ENABLE && port != PORT_A;
2612ba55f2f5SFrançois Tigeot 
26131e12ee3bSFrançois Tigeot 	if (HAS_PCH_CPT(dev_priv) && port != PORT_A) {
2614352ff8bdSFrançois Tigeot 		u32 trans_dp = I915_READ(TRANS_DP_CTL(crtc->pipe));
2615352ff8bdSFrançois Tigeot 
2616352ff8bdSFrançois Tigeot 		if (trans_dp & TRANS_DP_HSYNC_ACTIVE_HIGH)
26175d0b1887SFrançois Tigeot 			flags |= DRM_MODE_FLAG_PHSYNC;
26185d0b1887SFrançois Tigeot 		else
26195d0b1887SFrançois Tigeot 			flags |= DRM_MODE_FLAG_NHSYNC;
26205d0b1887SFrançois Tigeot 
2621352ff8bdSFrançois Tigeot 		if (trans_dp & TRANS_DP_VSYNC_ACTIVE_HIGH)
26225d0b1887SFrançois Tigeot 			flags |= DRM_MODE_FLAG_PVSYNC;
26235d0b1887SFrançois Tigeot 		else
26245d0b1887SFrançois Tigeot 			flags |= DRM_MODE_FLAG_NVSYNC;
262519c468b4SFrançois Tigeot 	} else {
262619c468b4SFrançois Tigeot 		if (tmp & DP_SYNC_HS_HIGH)
262719c468b4SFrançois Tigeot 			flags |= DRM_MODE_FLAG_PHSYNC;
262819c468b4SFrançois Tigeot 		else
262919c468b4SFrançois Tigeot 			flags |= DRM_MODE_FLAG_NHSYNC;
263019c468b4SFrançois Tigeot 
263119c468b4SFrançois Tigeot 		if (tmp & DP_SYNC_VS_HIGH)
263219c468b4SFrançois Tigeot 			flags |= DRM_MODE_FLAG_PVSYNC;
263319c468b4SFrançois Tigeot 		else
263419c468b4SFrançois Tigeot 			flags |= DRM_MODE_FLAG_NVSYNC;
26355d0b1887SFrançois Tigeot 	}
26365d0b1887SFrançois Tigeot 
26372c9916cdSFrançois Tigeot 	pipe_config->base.adjusted_mode.flags |= flags;
26389edbd4a0SFrançois Tigeot 
26394be47400SFrançois Tigeot 	if (IS_G4X(dev_priv) && tmp & DP_COLOR_RANGE_16_235)
264024edb884SFrançois Tigeot 		pipe_config->limited_color_range = true;
264124edb884SFrançois Tigeot 
2642352ff8bdSFrançois Tigeot 	pipe_config->lane_count =
2643352ff8bdSFrançois Tigeot 		((tmp & DP_PORT_WIDTH_MASK) >> DP_PORT_WIDTH_SHIFT) + 1;
2644352ff8bdSFrançois Tigeot 
26459edbd4a0SFrançois Tigeot 	intel_dp_get_m_n(crtc, pipe_config);
26469edbd4a0SFrançois Tigeot 
26479edbd4a0SFrançois Tigeot 	if (port == PORT_A) {
2648aee94f86SFrançois Tigeot 		if ((I915_READ(DP_A) & DP_PLL_FREQ_MASK) == DP_PLL_FREQ_162MHZ)
26499edbd4a0SFrançois Tigeot 			pipe_config->port_clock = 162000;
26509edbd4a0SFrançois Tigeot 		else
26519edbd4a0SFrançois Tigeot 			pipe_config->port_clock = 270000;
26529edbd4a0SFrançois Tigeot 	}
26539edbd4a0SFrançois Tigeot 
26548621f407SFrançois Tigeot 	pipe_config->base.adjusted_mode.crtc_clock =
26558621f407SFrançois Tigeot 		intel_dotclock_calculate(pipe_config->port_clock,
26569edbd4a0SFrançois Tigeot 					 &pipe_config->dp_m_n);
26579edbd4a0SFrançois Tigeot 
2658*3f2dd94aSFrançois Tigeot 	if (intel_dp_is_edp(intel_dp) && dev_priv->vbt.edp.bpp &&
26598621f407SFrançois Tigeot 	    pipe_config->pipe_bpp > dev_priv->vbt.edp.bpp) {
26609edbd4a0SFrançois Tigeot 		/*
26619edbd4a0SFrançois Tigeot 		 * This is a big fat ugly hack.
26629edbd4a0SFrançois Tigeot 		 *
26639edbd4a0SFrançois Tigeot 		 * Some machines in UEFI boot mode provide us a VBT that has 18
26649edbd4a0SFrançois Tigeot 		 * bpp and 1.62 GHz link bandwidth for eDP, which for reasons
26659edbd4a0SFrançois Tigeot 		 * unknown we fail to light up. Yet the same BIOS boots up with
26669edbd4a0SFrançois Tigeot 		 * 24 bpp and 2.7 GHz link. Use the same bpp as the BIOS uses as
26679edbd4a0SFrançois Tigeot 		 * max, not what it tells us to use.
26689edbd4a0SFrançois Tigeot 		 *
26699edbd4a0SFrançois Tigeot 		 * Note: This will still be broken if the eDP panel is not lit
26709edbd4a0SFrançois Tigeot 		 * up by the BIOS, and thus we can't get the mode at module
26719edbd4a0SFrançois Tigeot 		 * load.
26729edbd4a0SFrançois Tigeot 		 */
26739edbd4a0SFrançois Tigeot 		DRM_DEBUG_KMS("pipe has %d bpp for eDP panel, overriding BIOS-provided max %d bpp\n",
26748621f407SFrançois Tigeot 			      pipe_config->pipe_bpp, dev_priv->vbt.edp.bpp);
26758621f407SFrançois Tigeot 		dev_priv->vbt.edp.bpp = pipe_config->pipe_bpp;
26769edbd4a0SFrançois Tigeot 	}
26779edbd4a0SFrançois Tigeot }
26789edbd4a0SFrançois Tigeot 
intel_disable_dp(struct intel_encoder * encoder,const struct intel_crtc_state * old_crtc_state,const struct drm_connector_state * old_conn_state)26791e12ee3bSFrançois Tigeot static void intel_disable_dp(struct intel_encoder *encoder,
2680*3f2dd94aSFrançois Tigeot 			     const struct intel_crtc_state *old_crtc_state,
2681*3f2dd94aSFrançois Tigeot 			     const struct drm_connector_state *old_conn_state)
268219df918dSFrançois Tigeot {
268319df918dSFrançois Tigeot 	struct intel_dp *intel_dp = enc_to_intel_dp(&encoder->base);
26842c9916cdSFrançois Tigeot 
26851e12ee3bSFrançois Tigeot 	if (old_crtc_state->has_audio)
26862c9916cdSFrançois Tigeot 		intel_audio_codec_disable(encoder);
26872c9916cdSFrançois Tigeot 
268819df918dSFrançois Tigeot 	/* Make sure the panel is off before trying to change the mode. But also
268919df918dSFrançois Tigeot 	 * ensure that we have vdd while we switch off the panel. */
2690ba55f2f5SFrançois Tigeot 	intel_edp_panel_vdd_on(intel_dp);
2691*3f2dd94aSFrançois Tigeot 	intel_edp_backlight_off(old_conn_state);
26929edbd4a0SFrançois Tigeot 	intel_dp_sink_dpms(intel_dp, DRM_MODE_DPMS_OFF);
2693ba55f2f5SFrançois Tigeot 	intel_edp_panel_off(intel_dp);
2694*3f2dd94aSFrançois Tigeot }
2695*3f2dd94aSFrançois Tigeot 
g4x_disable_dp(struct intel_encoder * encoder,const struct intel_crtc_state * old_crtc_state,const struct drm_connector_state * old_conn_state)2696*3f2dd94aSFrançois Tigeot static void g4x_disable_dp(struct intel_encoder *encoder,
2697*3f2dd94aSFrançois Tigeot 			   const struct intel_crtc_state *old_crtc_state,
2698*3f2dd94aSFrançois Tigeot 			   const struct drm_connector_state *old_conn_state)
2699*3f2dd94aSFrançois Tigeot {
2700*3f2dd94aSFrançois Tigeot 	struct intel_dp *intel_dp = enc_to_intel_dp(&encoder->base);
2701*3f2dd94aSFrançois Tigeot 
2702*3f2dd94aSFrançois Tigeot 	intel_disable_dp(encoder, old_crtc_state, old_conn_state);
2703e3adcf8fSFrançois Tigeot 
27041b13d190SFrançois Tigeot 	/* disable the port before the pipe on g4x */
2705e3adcf8fSFrançois Tigeot 	intel_dp_link_down(intel_dp);
2706e3adcf8fSFrançois Tigeot }
2707e3adcf8fSFrançois Tigeot 
ilk_disable_dp(struct intel_encoder * encoder,const struct intel_crtc_state * old_crtc_state,const struct drm_connector_state * old_conn_state)2708*3f2dd94aSFrançois Tigeot static void ilk_disable_dp(struct intel_encoder *encoder,
2709*3f2dd94aSFrançois Tigeot 			   const struct intel_crtc_state *old_crtc_state,
2710*3f2dd94aSFrançois Tigeot 			   const struct drm_connector_state *old_conn_state)
2711*3f2dd94aSFrançois Tigeot {
2712*3f2dd94aSFrançois Tigeot 	intel_disable_dp(encoder, old_crtc_state, old_conn_state);
2713*3f2dd94aSFrançois Tigeot }
2714*3f2dd94aSFrançois Tigeot 
vlv_disable_dp(struct intel_encoder * encoder,const struct intel_crtc_state * old_crtc_state,const struct drm_connector_state * old_conn_state)2715*3f2dd94aSFrançois Tigeot static void vlv_disable_dp(struct intel_encoder *encoder,
2716*3f2dd94aSFrançois Tigeot 			   const struct intel_crtc_state *old_crtc_state,
2717*3f2dd94aSFrançois Tigeot 			   const struct drm_connector_state *old_conn_state)
2718*3f2dd94aSFrançois Tigeot {
2719*3f2dd94aSFrançois Tigeot 	struct intel_dp *intel_dp = enc_to_intel_dp(&encoder->base);
2720*3f2dd94aSFrançois Tigeot 
2721*3f2dd94aSFrançois Tigeot 	intel_psr_disable(intel_dp, old_crtc_state);
2722*3f2dd94aSFrançois Tigeot 
2723*3f2dd94aSFrançois Tigeot 	intel_disable_dp(encoder, old_crtc_state, old_conn_state);
2724*3f2dd94aSFrançois Tigeot }
2725*3f2dd94aSFrançois Tigeot 
ilk_post_disable_dp(struct intel_encoder * encoder,const struct intel_crtc_state * old_crtc_state,const struct drm_connector_state * old_conn_state)27261e12ee3bSFrançois Tigeot static void ilk_post_disable_dp(struct intel_encoder *encoder,
2727*3f2dd94aSFrançois Tigeot 				const struct intel_crtc_state *old_crtc_state,
2728*3f2dd94aSFrançois Tigeot 				const struct drm_connector_state *old_conn_state)
2729e3adcf8fSFrançois Tigeot {
273019df918dSFrançois Tigeot 	struct intel_dp *intel_dp = enc_to_intel_dp(&encoder->base);
27315d0b1887SFrançois Tigeot 	enum port port = dp_to_dig_port(intel_dp)->port;
2732e3adcf8fSFrançois Tigeot 
273319df918dSFrançois Tigeot 	intel_dp_link_down(intel_dp);
2734aee94f86SFrançois Tigeot 
2735aee94f86SFrançois Tigeot 	/* Only ilk+ has port A */
27361b13d190SFrançois Tigeot 	if (port == PORT_A)
273719df918dSFrançois Tigeot 		ironlake_edp_pll_off(intel_dp);
273819df918dSFrançois Tigeot }
2739ba55f2f5SFrançois Tigeot 
vlv_post_disable_dp(struct intel_encoder * encoder,const struct intel_crtc_state * old_crtc_state,const struct drm_connector_state * old_conn_state)27401e12ee3bSFrançois Tigeot static void vlv_post_disable_dp(struct intel_encoder *encoder,
2741*3f2dd94aSFrançois Tigeot 				const struct intel_crtc_state *old_crtc_state,
2742*3f2dd94aSFrançois Tigeot 				const struct drm_connector_state *old_conn_state)
2743ba55f2f5SFrançois Tigeot {
2744ba55f2f5SFrançois Tigeot 	struct intel_dp *intel_dp = enc_to_intel_dp(&encoder->base);
2745ba55f2f5SFrançois Tigeot 
2746ba55f2f5SFrançois Tigeot 	intel_dp_link_down(intel_dp);
2747ba55f2f5SFrançois Tigeot }
2748ba55f2f5SFrançois Tigeot 
chv_post_disable_dp(struct intel_encoder * encoder,const struct intel_crtc_state * old_crtc_state,const struct drm_connector_state * old_conn_state)27491e12ee3bSFrançois Tigeot static void chv_post_disable_dp(struct intel_encoder *encoder,
2750*3f2dd94aSFrançois Tigeot 				const struct intel_crtc_state *old_crtc_state,
2751*3f2dd94aSFrançois Tigeot 				const struct drm_connector_state *old_conn_state)
2752ba55f2f5SFrançois Tigeot {
2753ba55f2f5SFrançois Tigeot 	struct intel_dp *intel_dp = enc_to_intel_dp(&encoder->base);
2754ba55f2f5SFrançois Tigeot 	struct drm_device *dev = encoder->base.dev;
2755303bf270SFrançois Tigeot 	struct drm_i915_private *dev_priv = to_i915(dev);
2756ba55f2f5SFrançois Tigeot 
2757ba55f2f5SFrançois Tigeot 	intel_dp_link_down(intel_dp);
2758ba55f2f5SFrançois Tigeot 
275919c468b4SFrançois Tigeot 	mutex_lock(&dev_priv->sb_lock);
2760ba55f2f5SFrançois Tigeot 
2761352ff8bdSFrançois Tigeot 	/* Assert data lane reset */
2762352ff8bdSFrançois Tigeot 	chv_data_lane_soft_reset(encoder, true);
2763ba55f2f5SFrançois Tigeot 
276419c468b4SFrançois Tigeot 	mutex_unlock(&dev_priv->sb_lock);
2765e3adcf8fSFrançois Tigeot }
2766e3adcf8fSFrançois Tigeot 
27671b13d190SFrançois Tigeot static void
_intel_dp_set_link_train(struct intel_dp * intel_dp,uint32_t * DP,uint8_t dp_train_pat)27681b13d190SFrançois Tigeot _intel_dp_set_link_train(struct intel_dp *intel_dp,
27691b13d190SFrançois Tigeot 			 uint32_t *DP,
27701b13d190SFrançois Tigeot 			 uint8_t dp_train_pat)
27711b13d190SFrançois Tigeot {
27721b13d190SFrançois Tigeot 	struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp);
27731b13d190SFrançois Tigeot 	struct drm_device *dev = intel_dig_port->base.base.dev;
2774303bf270SFrançois Tigeot 	struct drm_i915_private *dev_priv = to_i915(dev);
27751b13d190SFrançois Tigeot 	enum port port = intel_dig_port->port;
27761b13d190SFrançois Tigeot 
27771e12ee3bSFrançois Tigeot 	if (dp_train_pat & DP_TRAINING_PATTERN_MASK)
27781e12ee3bSFrançois Tigeot 		DRM_DEBUG_KMS("Using DP training pattern TPS%d\n",
27791e12ee3bSFrançois Tigeot 			      dp_train_pat & DP_TRAINING_PATTERN_MASK);
27801e12ee3bSFrançois Tigeot 
27811e12ee3bSFrançois Tigeot 	if (HAS_DDI(dev_priv)) {
27821b13d190SFrançois Tigeot 		uint32_t temp = I915_READ(DP_TP_CTL(port));
27831b13d190SFrançois Tigeot 
27841b13d190SFrançois Tigeot 		if (dp_train_pat & DP_LINK_SCRAMBLING_DISABLE)
27851b13d190SFrançois Tigeot 			temp |= DP_TP_CTL_SCRAMBLE_DISABLE;
27861b13d190SFrançois Tigeot 		else
27871b13d190SFrançois Tigeot 			temp &= ~DP_TP_CTL_SCRAMBLE_DISABLE;
27881b13d190SFrançois Tigeot 
27891b13d190SFrançois Tigeot 		temp &= ~DP_TP_CTL_LINK_TRAIN_MASK;
27901b13d190SFrançois Tigeot 		switch (dp_train_pat & DP_TRAINING_PATTERN_MASK) {
27911b13d190SFrançois Tigeot 		case DP_TRAINING_PATTERN_DISABLE:
27921b13d190SFrançois Tigeot 			temp |= DP_TP_CTL_LINK_TRAIN_NORMAL;
27931b13d190SFrançois Tigeot 
27941b13d190SFrançois Tigeot 			break;
27951b13d190SFrançois Tigeot 		case DP_TRAINING_PATTERN_1:
27961b13d190SFrançois Tigeot 			temp |= DP_TP_CTL_LINK_TRAIN_PAT1;
27971b13d190SFrançois Tigeot 			break;
27981b13d190SFrançois Tigeot 		case DP_TRAINING_PATTERN_2:
27991b13d190SFrançois Tigeot 			temp |= DP_TP_CTL_LINK_TRAIN_PAT2;
28001b13d190SFrançois Tigeot 			break;
28011b13d190SFrançois Tigeot 		case DP_TRAINING_PATTERN_3:
28021b13d190SFrançois Tigeot 			temp |= DP_TP_CTL_LINK_TRAIN_PAT3;
28031b13d190SFrançois Tigeot 			break;
28041b13d190SFrançois Tigeot 		}
28051b13d190SFrançois Tigeot 		I915_WRITE(DP_TP_CTL(port), temp);
28061b13d190SFrançois Tigeot 
28071e12ee3bSFrançois Tigeot 	} else if ((IS_GEN7(dev_priv) && port == PORT_A) ||
28081e12ee3bSFrançois Tigeot 		   (HAS_PCH_CPT(dev_priv) && port != PORT_A)) {
28091b13d190SFrançois Tigeot 		*DP &= ~DP_LINK_TRAIN_MASK_CPT;
28101b13d190SFrançois Tigeot 
28111b13d190SFrançois Tigeot 		switch (dp_train_pat & DP_TRAINING_PATTERN_MASK) {
28121b13d190SFrançois Tigeot 		case DP_TRAINING_PATTERN_DISABLE:
28131b13d190SFrançois Tigeot 			*DP |= DP_LINK_TRAIN_OFF_CPT;
28141b13d190SFrançois Tigeot 			break;
28151b13d190SFrançois Tigeot 		case DP_TRAINING_PATTERN_1:
28161b13d190SFrançois Tigeot 			*DP |= DP_LINK_TRAIN_PAT_1_CPT;
28171b13d190SFrançois Tigeot 			break;
28181b13d190SFrançois Tigeot 		case DP_TRAINING_PATTERN_2:
28191b13d190SFrançois Tigeot 			*DP |= DP_LINK_TRAIN_PAT_2_CPT;
28201b13d190SFrançois Tigeot 			break;
28211b13d190SFrançois Tigeot 		case DP_TRAINING_PATTERN_3:
28221e12ee3bSFrançois Tigeot 			DRM_DEBUG_KMS("TPS3 not supported, using TPS2 instead\n");
28231b13d190SFrançois Tigeot 			*DP |= DP_LINK_TRAIN_PAT_2_CPT;
28241b13d190SFrançois Tigeot 			break;
28251b13d190SFrançois Tigeot 		}
28261b13d190SFrançois Tigeot 
28271b13d190SFrançois Tigeot 	} else {
28281e12ee3bSFrançois Tigeot 		if (IS_CHERRYVIEW(dev_priv))
28291b13d190SFrançois Tigeot 			*DP &= ~DP_LINK_TRAIN_MASK_CHV;
28301b13d190SFrançois Tigeot 		else
28311b13d190SFrançois Tigeot 			*DP &= ~DP_LINK_TRAIN_MASK;
28321b13d190SFrançois Tigeot 
28331b13d190SFrançois Tigeot 		switch (dp_train_pat & DP_TRAINING_PATTERN_MASK) {
28341b13d190SFrançois Tigeot 		case DP_TRAINING_PATTERN_DISABLE:
28351b13d190SFrançois Tigeot 			*DP |= DP_LINK_TRAIN_OFF;
28361b13d190SFrançois Tigeot 			break;
28371b13d190SFrançois Tigeot 		case DP_TRAINING_PATTERN_1:
28381b13d190SFrançois Tigeot 			*DP |= DP_LINK_TRAIN_PAT_1;
28391b13d190SFrançois Tigeot 			break;
28401b13d190SFrançois Tigeot 		case DP_TRAINING_PATTERN_2:
28411b13d190SFrançois Tigeot 			*DP |= DP_LINK_TRAIN_PAT_2;
28421b13d190SFrançois Tigeot 			break;
28431b13d190SFrançois Tigeot 		case DP_TRAINING_PATTERN_3:
28441e12ee3bSFrançois Tigeot 			if (IS_CHERRYVIEW(dev_priv)) {
28451b13d190SFrançois Tigeot 				*DP |= DP_LINK_TRAIN_PAT_3_CHV;
28461b13d190SFrançois Tigeot 			} else {
28471e12ee3bSFrançois Tigeot 				DRM_DEBUG_KMS("TPS3 not supported, using TPS2 instead\n");
28481b13d190SFrançois Tigeot 				*DP |= DP_LINK_TRAIN_PAT_2;
28491b13d190SFrançois Tigeot 			}
28501b13d190SFrançois Tigeot 			break;
28511b13d190SFrançois Tigeot 		}
28521b13d190SFrançois Tigeot 	}
28531b13d190SFrançois Tigeot }
28541b13d190SFrançois Tigeot 
intel_dp_enable_port(struct intel_dp * intel_dp,const struct intel_crtc_state * old_crtc_state)28551e12ee3bSFrançois Tigeot static void intel_dp_enable_port(struct intel_dp *intel_dp,
2856*3f2dd94aSFrançois Tigeot 				 const struct intel_crtc_state *old_crtc_state)
28571b13d190SFrançois Tigeot {
28581b13d190SFrançois Tigeot 	struct drm_device *dev = intel_dp_to_dev(intel_dp);
2859303bf270SFrançois Tigeot 	struct drm_i915_private *dev_priv = to_i915(dev);
28601b13d190SFrançois Tigeot 
28611b13d190SFrançois Tigeot 	/* enable with pattern 1 (as per spec) */
28621b13d190SFrançois Tigeot 
28631e12ee3bSFrançois Tigeot 	intel_dp_program_link_training_pattern(intel_dp, DP_TRAINING_PATTERN_1);
28642c9916cdSFrançois Tigeot 
28652c9916cdSFrançois Tigeot 	/*
28662c9916cdSFrançois Tigeot 	 * Magic for VLV/CHV. We _must_ first set up the register
28672c9916cdSFrançois Tigeot 	 * without actually enabling the port, and then do another
28682c9916cdSFrançois Tigeot 	 * write to enable the port. Otherwise link training will
28692c9916cdSFrançois Tigeot 	 * fail when the power sequencer is freshly used for this port.
28702c9916cdSFrançois Tigeot 	 */
28712c9916cdSFrançois Tigeot 	intel_dp->DP |= DP_PORT_EN;
28721e12ee3bSFrançois Tigeot 	if (old_crtc_state->has_audio)
2873aee94f86SFrançois Tigeot 		intel_dp->DP |= DP_AUDIO_OUTPUT_ENABLE;
28742c9916cdSFrançois Tigeot 
28752c9916cdSFrançois Tigeot 	I915_WRITE(intel_dp->output_reg, intel_dp->DP);
28762c9916cdSFrançois Tigeot 	POSTING_READ(intel_dp->output_reg);
28771b13d190SFrançois Tigeot }
28781b13d190SFrançois Tigeot 
intel_enable_dp(struct intel_encoder * encoder,const struct intel_crtc_state * pipe_config,const struct drm_connector_state * conn_state)28791e12ee3bSFrançois Tigeot static void intel_enable_dp(struct intel_encoder *encoder,
2880*3f2dd94aSFrançois Tigeot 			    const struct intel_crtc_state *pipe_config,
2881*3f2dd94aSFrançois Tigeot 			    const struct drm_connector_state *conn_state)
2882e3adcf8fSFrançois Tigeot {
288319df918dSFrançois Tigeot 	struct intel_dp *intel_dp = enc_to_intel_dp(&encoder->base);
288419df918dSFrançois Tigeot 	struct drm_device *dev = encoder->base.dev;
2885303bf270SFrançois Tigeot 	struct drm_i915_private *dev_priv = to_i915(dev);
28862c9916cdSFrançois Tigeot 	struct intel_crtc *crtc = to_intel_crtc(encoder->base.crtc);
2887e3adcf8fSFrançois Tigeot 	uint32_t dp_reg = I915_READ(intel_dp->output_reg);
2888aee94f86SFrançois Tigeot 	enum i915_pipe pipe = crtc->pipe;
2889e3adcf8fSFrançois Tigeot 
289019df918dSFrançois Tigeot 	if (WARN_ON(dp_reg & DP_PORT_EN))
289119df918dSFrançois Tigeot 		return;
2892e3adcf8fSFrançois Tigeot 
28932c9916cdSFrançois Tigeot 	pps_lock(intel_dp);
28942c9916cdSFrançois Tigeot 
28951e12ee3bSFrançois Tigeot 	if (IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv))
28962c9916cdSFrançois Tigeot 		vlv_init_panel_power_sequencer(intel_dp);
28972c9916cdSFrançois Tigeot 
28981e12ee3bSFrançois Tigeot 	intel_dp_enable_port(intel_dp, pipe_config);
28992c9916cdSFrançois Tigeot 
29002c9916cdSFrançois Tigeot 	edp_panel_vdd_on(intel_dp);
29012c9916cdSFrançois Tigeot 	edp_panel_on(intel_dp);
29022c9916cdSFrançois Tigeot 	edp_panel_vdd_off(intel_dp, true);
29032c9916cdSFrançois Tigeot 
29042c9916cdSFrançois Tigeot 	pps_unlock(intel_dp);
29052c9916cdSFrançois Tigeot 
29061e12ee3bSFrançois Tigeot 	if (IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv)) {
2907352ff8bdSFrançois Tigeot 		unsigned int lane_mask = 0x0;
2908352ff8bdSFrançois Tigeot 
29091e12ee3bSFrançois Tigeot 		if (IS_CHERRYVIEW(dev_priv))
29101e12ee3bSFrançois Tigeot 			lane_mask = intel_dp_unused_lane_mask(pipe_config->lane_count);
2911352ff8bdSFrançois Tigeot 
291219c468b4SFrançois Tigeot 		vlv_wait_port_ready(dev_priv, dp_to_dig_port(intel_dp),
291319c468b4SFrançois Tigeot 				    lane_mask);
2914352ff8bdSFrançois Tigeot 	}
29152c9916cdSFrançois Tigeot 
291619df918dSFrançois Tigeot 	intel_dp_sink_dpms(intel_dp, DRM_MODE_DPMS_ON);
2917e3adcf8fSFrançois Tigeot 	intel_dp_start_link_train(intel_dp);
29188e26cdf6SFrançois Tigeot 	intel_dp_stop_link_train(intel_dp);
29192c9916cdSFrançois Tigeot 
29201e12ee3bSFrançois Tigeot 	if (pipe_config->has_audio) {
29212c9916cdSFrançois Tigeot 		DRM_DEBUG_DRIVER("Enabling DP audio on pipe %c\n",
2922aee94f86SFrançois Tigeot 				 pipe_name(pipe));
29234be47400SFrançois Tigeot 		intel_audio_codec_enable(encoder, pipe_config, conn_state);
29242c9916cdSFrançois Tigeot 	}
29259edbd4a0SFrançois Tigeot }
29269edbd4a0SFrançois Tigeot 
g4x_enable_dp(struct intel_encoder * encoder,const struct intel_crtc_state * pipe_config,const struct drm_connector_state * conn_state)29271e12ee3bSFrançois Tigeot static void g4x_enable_dp(struct intel_encoder *encoder,
2928*3f2dd94aSFrançois Tigeot 			  const struct intel_crtc_state *pipe_config,
2929*3f2dd94aSFrançois Tigeot 			  const struct drm_connector_state *conn_state)
29309edbd4a0SFrançois Tigeot {
29314be47400SFrançois Tigeot 	intel_enable_dp(encoder, pipe_config, conn_state);
2932*3f2dd94aSFrançois Tigeot 	intel_edp_backlight_on(pipe_config, conn_state);
2933e3adcf8fSFrançois Tigeot }
293419df918dSFrançois Tigeot 
vlv_enable_dp(struct intel_encoder * encoder,const struct intel_crtc_state * pipe_config,const struct drm_connector_state * conn_state)29351e12ee3bSFrançois Tigeot static void vlv_enable_dp(struct intel_encoder *encoder,
2936*3f2dd94aSFrançois Tigeot 			  const struct intel_crtc_state *pipe_config,
2937*3f2dd94aSFrançois Tigeot 			  const struct drm_connector_state *conn_state)
29389edbd4a0SFrançois Tigeot {
29399edbd4a0SFrançois Tigeot 	struct intel_dp *intel_dp = enc_to_intel_dp(&encoder->base);
29409edbd4a0SFrançois Tigeot 
2941*3f2dd94aSFrançois Tigeot 	intel_edp_backlight_on(pipe_config, conn_state);
2942*3f2dd94aSFrançois Tigeot 	intel_psr_enable(intel_dp, pipe_config);
29439edbd4a0SFrançois Tigeot }
29449edbd4a0SFrançois Tigeot 
g4x_pre_enable_dp(struct intel_encoder * encoder,const struct intel_crtc_state * pipe_config,const struct drm_connector_state * conn_state)29451e12ee3bSFrançois Tigeot static void g4x_pre_enable_dp(struct intel_encoder *encoder,
2946*3f2dd94aSFrançois Tigeot 			      const struct intel_crtc_state *pipe_config,
2947*3f2dd94aSFrançois Tigeot 			      const struct drm_connector_state *conn_state)
29489edbd4a0SFrançois Tigeot {
29499edbd4a0SFrançois Tigeot 	struct intel_dp *intel_dp = enc_to_intel_dp(&encoder->base);
2950aee94f86SFrançois Tigeot 	enum port port = dp_to_dig_port(intel_dp)->port;
29519edbd4a0SFrançois Tigeot 
29521e12ee3bSFrançois Tigeot 	intel_dp_prepare(encoder, pipe_config);
2953ba55f2f5SFrançois Tigeot 
2954aee94f86SFrançois Tigeot 	/* Only ilk+ has port A */
2955aee94f86SFrançois Tigeot 	if (port == PORT_A)
29561e12ee3bSFrançois Tigeot 		ironlake_edp_pll_on(intel_dp, pipe_config);
2957ba55f2f5SFrançois Tigeot }
29589edbd4a0SFrançois Tigeot 
vlv_detach_power_sequencer(struct intel_dp * intel_dp)29592c9916cdSFrançois Tigeot static void vlv_detach_power_sequencer(struct intel_dp *intel_dp)
29602c9916cdSFrançois Tigeot {
29612c9916cdSFrançois Tigeot 	struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp);
2962bf017597SFrançois Tigeot 	struct drm_i915_private *dev_priv = to_i915(intel_dig_port->base.base.dev);
29632c9916cdSFrançois Tigeot 	enum i915_pipe pipe = intel_dp->pps_pipe;
29641e12ee3bSFrançois Tigeot 	i915_reg_t pp_on_reg = PP_ON_DELAYS(pipe);
29652c9916cdSFrançois Tigeot 
2966a85cb24fSFrançois Tigeot 	WARN_ON(intel_dp->active_pipe != INVALID_PIPE);
2967a85cb24fSFrançois Tigeot 
29684be47400SFrançois Tigeot 	if (WARN_ON(pipe != PIPE_A && pipe != PIPE_B))
29694be47400SFrançois Tigeot 		return;
29704be47400SFrançois Tigeot 
29712c9916cdSFrançois Tigeot 	edp_panel_vdd_off_sync(intel_dp);
29722c9916cdSFrançois Tigeot 
29732c9916cdSFrançois Tigeot 	/*
29742c9916cdSFrançois Tigeot 	 * VLV seems to get confused when multiple power seqeuencers
29752c9916cdSFrançois Tigeot 	 * have the same port selected (even if only one has power/vdd
29762c9916cdSFrançois Tigeot 	 * enabled). The failure manifests as vlv_wait_port_ready() failing
29772c9916cdSFrançois Tigeot 	 * CHV on the other hand doesn't seem to mind having the same port
29782c9916cdSFrançois Tigeot 	 * selected in multiple power seqeuencers, but let's clear the
29792c9916cdSFrançois Tigeot 	 * port select always when logically disconnecting a power sequencer
29802c9916cdSFrançois Tigeot 	 * from a port.
29812c9916cdSFrançois Tigeot 	 */
29822c9916cdSFrançois Tigeot 	DRM_DEBUG_KMS("detaching pipe %c power sequencer from port %c\n",
29832c9916cdSFrançois Tigeot 		      pipe_name(pipe), port_name(intel_dig_port->port));
29842c9916cdSFrançois Tigeot 	I915_WRITE(pp_on_reg, 0);
29852c9916cdSFrançois Tigeot 	POSTING_READ(pp_on_reg);
29862c9916cdSFrançois Tigeot 
29872c9916cdSFrançois Tigeot 	intel_dp->pps_pipe = INVALID_PIPE;
29882c9916cdSFrançois Tigeot }
29892c9916cdSFrançois Tigeot 
vlv_steal_power_sequencer(struct drm_device * dev,enum i915_pipe pipe)29901b13d190SFrançois Tigeot static void vlv_steal_power_sequencer(struct drm_device *dev,
29911b13d190SFrançois Tigeot 				      enum i915_pipe pipe)
29921b13d190SFrançois Tigeot {
2993303bf270SFrançois Tigeot 	struct drm_i915_private *dev_priv = to_i915(dev);
29941b13d190SFrançois Tigeot 	struct intel_encoder *encoder;
29951b13d190SFrançois Tigeot 
29961b13d190SFrançois Tigeot 	lockdep_assert_held(&dev_priv->pps_mutex);
29971b13d190SFrançois Tigeot 
2998aee94f86SFrançois Tigeot 	for_each_intel_encoder(dev, encoder) {
29991b13d190SFrançois Tigeot 		struct intel_dp *intel_dp;
30001b13d190SFrançois Tigeot 		enum port port;
30011b13d190SFrançois Tigeot 
3002a85cb24fSFrançois Tigeot 		if (encoder->type != INTEL_OUTPUT_DP &&
3003a85cb24fSFrançois Tigeot 		    encoder->type != INTEL_OUTPUT_EDP)
30041b13d190SFrançois Tigeot 			continue;
30051b13d190SFrançois Tigeot 
30061b13d190SFrançois Tigeot 		intel_dp = enc_to_intel_dp(&encoder->base);
30071b13d190SFrançois Tigeot 		port = dp_to_dig_port(intel_dp)->port;
30081b13d190SFrançois Tigeot 
3009a85cb24fSFrançois Tigeot 		WARN(intel_dp->active_pipe == pipe,
3010a85cb24fSFrançois Tigeot 		     "stealing pipe %c power sequencer from active (e)DP port %c\n",
3011a85cb24fSFrançois Tigeot 		     pipe_name(pipe), port_name(port));
3012a85cb24fSFrançois Tigeot 
30131b13d190SFrançois Tigeot 		if (intel_dp->pps_pipe != pipe)
30141b13d190SFrançois Tigeot 			continue;
30151b13d190SFrançois Tigeot 
30161b13d190SFrançois Tigeot 		DRM_DEBUG_KMS("stealing pipe %c power sequencer from port %c\n",
30171b13d190SFrançois Tigeot 			      pipe_name(pipe), port_name(port));
30181b13d190SFrançois Tigeot 
30192c9916cdSFrançois Tigeot 		/* make sure vdd is off before we steal it */
30202c9916cdSFrançois Tigeot 		vlv_detach_power_sequencer(intel_dp);
30211b13d190SFrançois Tigeot 	}
30221b13d190SFrançois Tigeot }
30231b13d190SFrançois Tigeot 
vlv_init_panel_power_sequencer(struct intel_dp * intel_dp)30241b13d190SFrançois Tigeot static void vlv_init_panel_power_sequencer(struct intel_dp *intel_dp)
30251b13d190SFrançois Tigeot {
30261b13d190SFrançois Tigeot 	struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp);
30271b13d190SFrançois Tigeot 	struct intel_encoder *encoder = &intel_dig_port->base;
30281b13d190SFrançois Tigeot 	struct drm_device *dev = encoder->base.dev;
3029303bf270SFrançois Tigeot 	struct drm_i915_private *dev_priv = to_i915(dev);
30301b13d190SFrançois Tigeot 	struct intel_crtc *crtc = to_intel_crtc(encoder->base.crtc);
30311b13d190SFrançois Tigeot 
30321b13d190SFrançois Tigeot 	lockdep_assert_held(&dev_priv->pps_mutex);
30331b13d190SFrançois Tigeot 
3034a85cb24fSFrançois Tigeot 	WARN_ON(intel_dp->active_pipe != INVALID_PIPE);
30352c9916cdSFrançois Tigeot 
3036a85cb24fSFrançois Tigeot 	if (intel_dp->pps_pipe != INVALID_PIPE &&
3037a85cb24fSFrançois Tigeot 	    intel_dp->pps_pipe != crtc->pipe) {
30381b13d190SFrançois Tigeot 		/*
30391b13d190SFrançois Tigeot 		 * If another power sequencer was being used on this
30401b13d190SFrançois Tigeot 		 * port previously make sure to turn off vdd there while
30411b13d190SFrançois Tigeot 		 * we still have control of it.
30421b13d190SFrançois Tigeot 		 */
30432c9916cdSFrançois Tigeot 		vlv_detach_power_sequencer(intel_dp);
3044a85cb24fSFrançois Tigeot 	}
30451b13d190SFrançois Tigeot 
30461b13d190SFrançois Tigeot 	/*
30471b13d190SFrançois Tigeot 	 * We may be stealing the power
30481b13d190SFrançois Tigeot 	 * sequencer from another port.
30491b13d190SFrançois Tigeot 	 */
30501b13d190SFrançois Tigeot 	vlv_steal_power_sequencer(dev, crtc->pipe);
30511b13d190SFrançois Tigeot 
3052a85cb24fSFrançois Tigeot 	intel_dp->active_pipe = crtc->pipe;
3053a85cb24fSFrançois Tigeot 
3054*3f2dd94aSFrançois Tigeot 	if (!intel_dp_is_edp(intel_dp))
3055a85cb24fSFrançois Tigeot 		return;
3056a85cb24fSFrançois Tigeot 
30571b13d190SFrançois Tigeot 	/* now it's all ours */
30581b13d190SFrançois Tigeot 	intel_dp->pps_pipe = crtc->pipe;
30591b13d190SFrançois Tigeot 
30601b13d190SFrançois Tigeot 	DRM_DEBUG_KMS("initializing pipe %c power sequencer for port %c\n",
30611b13d190SFrançois Tigeot 		      pipe_name(intel_dp->pps_pipe), port_name(intel_dig_port->port));
30621b13d190SFrançois Tigeot 
30631b13d190SFrançois Tigeot 	/* init power sequencer on this pipe and port */
30642c9916cdSFrançois Tigeot 	intel_dp_init_panel_power_sequencer(dev, intel_dp);
30654be47400SFrançois Tigeot 	intel_dp_init_panel_power_sequencer_registers(dev, intel_dp, true);
30661b13d190SFrançois Tigeot }
30671b13d190SFrançois Tigeot 
vlv_pre_enable_dp(struct intel_encoder * encoder,const struct intel_crtc_state * pipe_config,const struct drm_connector_state * conn_state)30681e12ee3bSFrançois Tigeot static void vlv_pre_enable_dp(struct intel_encoder *encoder,
3069*3f2dd94aSFrançois Tigeot 			      const struct intel_crtc_state *pipe_config,
3070*3f2dd94aSFrançois Tigeot 			      const struct drm_connector_state *conn_state)
307119df918dSFrançois Tigeot {
30721487f786SFrançois Tigeot 	vlv_phy_pre_encoder_enable(encoder);
30739edbd4a0SFrançois Tigeot 
30744be47400SFrançois Tigeot 	intel_enable_dp(encoder, pipe_config, conn_state);
30759edbd4a0SFrançois Tigeot }
30769edbd4a0SFrançois Tigeot 
vlv_dp_pre_pll_enable(struct intel_encoder * encoder,const struct intel_crtc_state * pipe_config,const struct drm_connector_state * conn_state)30771e12ee3bSFrançois Tigeot static void vlv_dp_pre_pll_enable(struct intel_encoder *encoder,
3078*3f2dd94aSFrançois Tigeot 				  const struct intel_crtc_state *pipe_config,
3079*3f2dd94aSFrançois Tigeot 				  const struct drm_connector_state *conn_state)
30805d0b1887SFrançois Tigeot {
30811e12ee3bSFrançois Tigeot 	intel_dp_prepare(encoder, pipe_config);
3082ba55f2f5SFrançois Tigeot 
30831487f786SFrançois Tigeot 	vlv_phy_pre_pll_enable(encoder);
3084e3adcf8fSFrançois Tigeot }
308519df918dSFrançois Tigeot 
chv_pre_enable_dp(struct intel_encoder * encoder,const struct intel_crtc_state * pipe_config,const struct drm_connector_state * conn_state)30861e12ee3bSFrançois Tigeot static void chv_pre_enable_dp(struct intel_encoder *encoder,
3087*3f2dd94aSFrançois Tigeot 			      const struct intel_crtc_state *pipe_config,
3088*3f2dd94aSFrançois Tigeot 			      const struct drm_connector_state *conn_state)
3089ba55f2f5SFrançois Tigeot {
30901487f786SFrançois Tigeot 	chv_phy_pre_encoder_enable(encoder);
3091ba55f2f5SFrançois Tigeot 
30924be47400SFrançois Tigeot 	intel_enable_dp(encoder, pipe_config, conn_state);
3093352ff8bdSFrançois Tigeot 
3094352ff8bdSFrançois Tigeot 	/* Second common lane will stay alive on its own now */
30951487f786SFrançois Tigeot 	chv_phy_release_cl2_override(encoder);
3096ba55f2f5SFrançois Tigeot }
3097ba55f2f5SFrançois Tigeot 
chv_dp_pre_pll_enable(struct intel_encoder * encoder,const struct intel_crtc_state * pipe_config,const struct drm_connector_state * conn_state)30981e12ee3bSFrançois Tigeot static void chv_dp_pre_pll_enable(struct intel_encoder *encoder,
3099*3f2dd94aSFrançois Tigeot 				  const struct intel_crtc_state *pipe_config,
3100*3f2dd94aSFrançois Tigeot 				  const struct drm_connector_state *conn_state)
310124edb884SFrançois Tigeot {
31021e12ee3bSFrançois Tigeot 	intel_dp_prepare(encoder, pipe_config);
3103477eb7f9SFrançois Tigeot 
31041487f786SFrançois Tigeot 	chv_phy_pre_pll_enable(encoder);
310524edb884SFrançois Tigeot }
310624edb884SFrançois Tigeot 
chv_dp_post_pll_disable(struct intel_encoder * encoder,const struct intel_crtc_state * pipe_config,const struct drm_connector_state * conn_state)31071e12ee3bSFrançois Tigeot static void chv_dp_post_pll_disable(struct intel_encoder *encoder,
3108*3f2dd94aSFrançois Tigeot 				    const struct intel_crtc_state *pipe_config,
3109*3f2dd94aSFrançois Tigeot 				    const struct drm_connector_state *conn_state)
3110352ff8bdSFrançois Tigeot {
31111487f786SFrançois Tigeot 	chv_phy_post_pll_disable(encoder);
3112352ff8bdSFrançois Tigeot }
3113352ff8bdSFrançois Tigeot 
3114e3adcf8fSFrançois Tigeot /*
3115e3adcf8fSFrançois Tigeot  * Fetch AUX CH registers 0x202 - 0x207 which contain
3116e3adcf8fSFrançois Tigeot  * link status information
3117e3adcf8fSFrançois Tigeot  */
3118aee94f86SFrançois Tigeot bool
intel_dp_get_link_status(struct intel_dp * intel_dp,uint8_t link_status[DP_LINK_STATUS_SIZE])3119e3adcf8fSFrançois Tigeot intel_dp_get_link_status(struct intel_dp *intel_dp, uint8_t link_status[DP_LINK_STATUS_SIZE])
3120e3adcf8fSFrançois Tigeot {
31218621f407SFrançois Tigeot 	return drm_dp_dpcd_read(&intel_dp->aux, DP_LANE0_1_STATUS, link_status,
31226b231eabSImre Vadász 				DP_LINK_STATUS_SIZE) == DP_LINK_STATUS_SIZE;
3123e3adcf8fSFrançois Tigeot }
3124e3adcf8fSFrançois Tigeot 
intel_dp_get_y_cord_status(struct intel_dp * intel_dp)3125a85cb24fSFrançois Tigeot static bool intel_dp_get_y_cord_status(struct intel_dp *intel_dp)
3126a85cb24fSFrançois Tigeot {
3127a85cb24fSFrançois Tigeot 	uint8_t psr_caps = 0;
3128a85cb24fSFrançois Tigeot 
3129*3f2dd94aSFrançois Tigeot 	if (drm_dp_dpcd_readb(&intel_dp->aux, DP_PSR_CAPS, &psr_caps) != 1)
3130*3f2dd94aSFrançois Tigeot 		return false;
3131a85cb24fSFrançois Tigeot 	return psr_caps & DP_PSR2_SU_Y_COORDINATE_REQUIRED;
3132a85cb24fSFrançois Tigeot }
3133a85cb24fSFrançois Tigeot 
intel_dp_get_colorimetry_status(struct intel_dp * intel_dp)3134a85cb24fSFrançois Tigeot static bool intel_dp_get_colorimetry_status(struct intel_dp *intel_dp)
3135a85cb24fSFrançois Tigeot {
3136a85cb24fSFrançois Tigeot 	uint8_t dprx = 0;
3137a85cb24fSFrançois Tigeot 
3138*3f2dd94aSFrançois Tigeot 	if (drm_dp_dpcd_readb(&intel_dp->aux, DP_DPRX_FEATURE_ENUMERATION_LIST,
3139*3f2dd94aSFrançois Tigeot 			      &dprx) != 1)
3140*3f2dd94aSFrançois Tigeot 		return false;
3141a85cb24fSFrançois Tigeot 	return dprx & DP_VSC_SDP_EXT_FOR_COLORIMETRY_SUPPORTED;
3142a85cb24fSFrançois Tigeot }
3143a85cb24fSFrançois Tigeot 
intel_dp_get_alpm_status(struct intel_dp * intel_dp)3144a85cb24fSFrançois Tigeot static bool intel_dp_get_alpm_status(struct intel_dp *intel_dp)
3145a85cb24fSFrançois Tigeot {
3146a85cb24fSFrançois Tigeot 	uint8_t alpm_caps = 0;
3147a85cb24fSFrançois Tigeot 
3148*3f2dd94aSFrançois Tigeot 	if (drm_dp_dpcd_readb(&intel_dp->aux, DP_RECEIVER_ALPM_CAP,
3149*3f2dd94aSFrançois Tigeot 			      &alpm_caps) != 1)
3150*3f2dd94aSFrançois Tigeot 		return false;
3151a85cb24fSFrançois Tigeot 	return alpm_caps & DP_ALPM_CAP;
3152a85cb24fSFrançois Tigeot }
3153a85cb24fSFrançois Tigeot 
315424edb884SFrançois Tigeot /* These are source-specific values. */
3155aee94f86SFrançois Tigeot uint8_t
intel_dp_voltage_max(struct intel_dp * intel_dp)3156e3adcf8fSFrançois Tigeot intel_dp_voltage_max(struct intel_dp *intel_dp)
3157e3adcf8fSFrançois Tigeot {
31584be47400SFrançois Tigeot 	struct drm_i915_private *dev_priv = to_i915(intel_dp_to_dev(intel_dp));
31595d0b1887SFrançois Tigeot 	enum port port = dp_to_dig_port(intel_dp)->port;
3160e3adcf8fSFrançois Tigeot 
3161*3f2dd94aSFrançois Tigeot 	if (INTEL_GEN(dev_priv) >= 9) {
3162a85cb24fSFrançois Tigeot 		struct intel_encoder *encoder = &dp_to_dig_port(intel_dp)->base;
3163a85cb24fSFrançois Tigeot 		return intel_ddi_dp_voltage_max(encoder);
31641e12ee3bSFrançois Tigeot 	} else if (IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv))
31651b13d190SFrançois Tigeot 		return DP_TRAIN_VOLTAGE_SWING_LEVEL_3;
31661e12ee3bSFrançois Tigeot 	else if (IS_GEN7(dev_priv) && port == PORT_A)
31671b13d190SFrançois Tigeot 		return DP_TRAIN_VOLTAGE_SWING_LEVEL_2;
31681e12ee3bSFrançois Tigeot 	else if (HAS_PCH_CPT(dev_priv) && port != PORT_A)
31691b13d190SFrançois Tigeot 		return DP_TRAIN_VOLTAGE_SWING_LEVEL_3;
3170e3adcf8fSFrançois Tigeot 	else
31711b13d190SFrançois Tigeot 		return DP_TRAIN_VOLTAGE_SWING_LEVEL_2;
3172e3adcf8fSFrançois Tigeot }
3173e3adcf8fSFrançois Tigeot 
3174aee94f86SFrançois Tigeot uint8_t
intel_dp_pre_emphasis_max(struct intel_dp * intel_dp,uint8_t voltage_swing)3175e3adcf8fSFrançois Tigeot intel_dp_pre_emphasis_max(struct intel_dp *intel_dp, uint8_t voltage_swing)
3176e3adcf8fSFrançois Tigeot {
31771e12ee3bSFrançois Tigeot 	struct drm_i915_private *dev_priv = to_i915(intel_dp_to_dev(intel_dp));
31785d0b1887SFrançois Tigeot 	enum port port = dp_to_dig_port(intel_dp)->port;
3179e3adcf8fSFrançois Tigeot 
31801e12ee3bSFrançois Tigeot 	if (INTEL_GEN(dev_priv) >= 9) {
31812c9916cdSFrançois Tigeot 		switch (voltage_swing & DP_TRAIN_VOLTAGE_SWING_MASK) {
31822c9916cdSFrançois Tigeot 		case DP_TRAIN_VOLTAGE_SWING_LEVEL_0:
31832c9916cdSFrançois Tigeot 			return DP_TRAIN_PRE_EMPH_LEVEL_3;
31842c9916cdSFrançois Tigeot 		case DP_TRAIN_VOLTAGE_SWING_LEVEL_1:
31852c9916cdSFrançois Tigeot 			return DP_TRAIN_PRE_EMPH_LEVEL_2;
31862c9916cdSFrançois Tigeot 		case DP_TRAIN_VOLTAGE_SWING_LEVEL_2:
31872c9916cdSFrançois Tigeot 			return DP_TRAIN_PRE_EMPH_LEVEL_1;
3188477eb7f9SFrançois Tigeot 		case DP_TRAIN_VOLTAGE_SWING_LEVEL_3:
3189477eb7f9SFrançois Tigeot 			return DP_TRAIN_PRE_EMPH_LEVEL_0;
31902c9916cdSFrançois Tigeot 		default:
31912c9916cdSFrançois Tigeot 			return DP_TRAIN_PRE_EMPH_LEVEL_0;
31922c9916cdSFrançois Tigeot 		}
31931e12ee3bSFrançois Tigeot 	} else if (IS_HASWELL(dev_priv) || IS_BROADWELL(dev_priv)) {
319419df918dSFrançois Tigeot 		switch (voltage_swing & DP_TRAIN_VOLTAGE_SWING_MASK) {
31951b13d190SFrançois Tigeot 		case DP_TRAIN_VOLTAGE_SWING_LEVEL_0:
31961b13d190SFrançois Tigeot 			return DP_TRAIN_PRE_EMPH_LEVEL_3;
31971b13d190SFrançois Tigeot 		case DP_TRAIN_VOLTAGE_SWING_LEVEL_1:
31981b13d190SFrançois Tigeot 			return DP_TRAIN_PRE_EMPH_LEVEL_2;
31991b13d190SFrançois Tigeot 		case DP_TRAIN_VOLTAGE_SWING_LEVEL_2:
32001b13d190SFrançois Tigeot 			return DP_TRAIN_PRE_EMPH_LEVEL_1;
32011b13d190SFrançois Tigeot 		case DP_TRAIN_VOLTAGE_SWING_LEVEL_3:
320219df918dSFrançois Tigeot 		default:
32031b13d190SFrançois Tigeot 			return DP_TRAIN_PRE_EMPH_LEVEL_0;
320419df918dSFrançois Tigeot 		}
32051e12ee3bSFrançois Tigeot 	} else if (IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv)) {
32065d0b1887SFrançois Tigeot 		switch (voltage_swing & DP_TRAIN_VOLTAGE_SWING_MASK) {
32071b13d190SFrançois Tigeot 		case DP_TRAIN_VOLTAGE_SWING_LEVEL_0:
32081b13d190SFrançois Tigeot 			return DP_TRAIN_PRE_EMPH_LEVEL_3;
32091b13d190SFrançois Tigeot 		case DP_TRAIN_VOLTAGE_SWING_LEVEL_1:
32101b13d190SFrançois Tigeot 			return DP_TRAIN_PRE_EMPH_LEVEL_2;
32111b13d190SFrançois Tigeot 		case DP_TRAIN_VOLTAGE_SWING_LEVEL_2:
32121b13d190SFrançois Tigeot 			return DP_TRAIN_PRE_EMPH_LEVEL_1;
32131b13d190SFrançois Tigeot 		case DP_TRAIN_VOLTAGE_SWING_LEVEL_3:
32145d0b1887SFrançois Tigeot 		default:
32151b13d190SFrançois Tigeot 			return DP_TRAIN_PRE_EMPH_LEVEL_0;
32165d0b1887SFrançois Tigeot 		}
32171e12ee3bSFrançois Tigeot 	} else if (IS_GEN7(dev_priv) && port == PORT_A) {
3218e3adcf8fSFrançois Tigeot 		switch (voltage_swing & DP_TRAIN_VOLTAGE_SWING_MASK) {
32191b13d190SFrançois Tigeot 		case DP_TRAIN_VOLTAGE_SWING_LEVEL_0:
32201b13d190SFrançois Tigeot 			return DP_TRAIN_PRE_EMPH_LEVEL_2;
32211b13d190SFrançois Tigeot 		case DP_TRAIN_VOLTAGE_SWING_LEVEL_1:
32221b13d190SFrançois Tigeot 		case DP_TRAIN_VOLTAGE_SWING_LEVEL_2:
32231b13d190SFrançois Tigeot 			return DP_TRAIN_PRE_EMPH_LEVEL_1;
3224e3adcf8fSFrançois Tigeot 		default:
32251b13d190SFrançois Tigeot 			return DP_TRAIN_PRE_EMPH_LEVEL_0;
3226e3adcf8fSFrançois Tigeot 		}
3227e3adcf8fSFrançois Tigeot 	} else {
3228e3adcf8fSFrançois Tigeot 		switch (voltage_swing & DP_TRAIN_VOLTAGE_SWING_MASK) {
32291b13d190SFrançois Tigeot 		case DP_TRAIN_VOLTAGE_SWING_LEVEL_0:
32301b13d190SFrançois Tigeot 			return DP_TRAIN_PRE_EMPH_LEVEL_2;
32311b13d190SFrançois Tigeot 		case DP_TRAIN_VOLTAGE_SWING_LEVEL_1:
32321b13d190SFrançois Tigeot 			return DP_TRAIN_PRE_EMPH_LEVEL_2;
32331b13d190SFrançois Tigeot 		case DP_TRAIN_VOLTAGE_SWING_LEVEL_2:
32341b13d190SFrançois Tigeot 			return DP_TRAIN_PRE_EMPH_LEVEL_1;
32351b13d190SFrançois Tigeot 		case DP_TRAIN_VOLTAGE_SWING_LEVEL_3:
3236e3adcf8fSFrançois Tigeot 		default:
32371b13d190SFrançois Tigeot 			return DP_TRAIN_PRE_EMPH_LEVEL_0;
3238e3adcf8fSFrançois Tigeot 		}
3239e3adcf8fSFrançois Tigeot 	}
3240e3adcf8fSFrançois Tigeot }
3241e3adcf8fSFrançois Tigeot 
vlv_signal_levels(struct intel_dp * intel_dp)324219c468b4SFrançois Tigeot static uint32_t vlv_signal_levels(struct intel_dp *intel_dp)
32435d0b1887SFrançois Tigeot {
32441487f786SFrançois Tigeot 	struct intel_encoder *encoder = &dp_to_dig_port(intel_dp)->base;
32455d0b1887SFrançois Tigeot 	unsigned long demph_reg_value, preemph_reg_value,
32465d0b1887SFrançois Tigeot 		uniqtranscale_reg_value;
32475d0b1887SFrançois Tigeot 	uint8_t train_set = intel_dp->train_set[0];
32485d0b1887SFrançois Tigeot 
32495d0b1887SFrançois Tigeot 	switch (train_set & DP_TRAIN_PRE_EMPHASIS_MASK) {
32501b13d190SFrançois Tigeot 	case DP_TRAIN_PRE_EMPH_LEVEL_0:
32515d0b1887SFrançois Tigeot 		preemph_reg_value = 0x0004000;
32525d0b1887SFrançois Tigeot 		switch (train_set & DP_TRAIN_VOLTAGE_SWING_MASK) {
32531b13d190SFrançois Tigeot 		case DP_TRAIN_VOLTAGE_SWING_LEVEL_0:
32545d0b1887SFrançois Tigeot 			demph_reg_value = 0x2B405555;
32555d0b1887SFrançois Tigeot 			uniqtranscale_reg_value = 0x552AB83A;
32565d0b1887SFrançois Tigeot 			break;
32571b13d190SFrançois Tigeot 		case DP_TRAIN_VOLTAGE_SWING_LEVEL_1:
32585d0b1887SFrançois Tigeot 			demph_reg_value = 0x2B404040;
32595d0b1887SFrançois Tigeot 			uniqtranscale_reg_value = 0x5548B83A;
32605d0b1887SFrançois Tigeot 			break;
32611b13d190SFrançois Tigeot 		case DP_TRAIN_VOLTAGE_SWING_LEVEL_2:
32625d0b1887SFrançois Tigeot 			demph_reg_value = 0x2B245555;
32635d0b1887SFrançois Tigeot 			uniqtranscale_reg_value = 0x5560B83A;
32645d0b1887SFrançois Tigeot 			break;
32651b13d190SFrançois Tigeot 		case DP_TRAIN_VOLTAGE_SWING_LEVEL_3:
32665d0b1887SFrançois Tigeot 			demph_reg_value = 0x2B405555;
32675d0b1887SFrançois Tigeot 			uniqtranscale_reg_value = 0x5598DA3A;
32685d0b1887SFrançois Tigeot 			break;
32695d0b1887SFrançois Tigeot 		default:
32705d0b1887SFrançois Tigeot 			return 0;
32715d0b1887SFrançois Tigeot 		}
32725d0b1887SFrançois Tigeot 		break;
32731b13d190SFrançois Tigeot 	case DP_TRAIN_PRE_EMPH_LEVEL_1:
32745d0b1887SFrançois Tigeot 		preemph_reg_value = 0x0002000;
32755d0b1887SFrançois Tigeot 		switch (train_set & DP_TRAIN_VOLTAGE_SWING_MASK) {
32761b13d190SFrançois Tigeot 		case DP_TRAIN_VOLTAGE_SWING_LEVEL_0:
32775d0b1887SFrançois Tigeot 			demph_reg_value = 0x2B404040;
32785d0b1887SFrançois Tigeot 			uniqtranscale_reg_value = 0x5552B83A;
32795d0b1887SFrançois Tigeot 			break;
32801b13d190SFrançois Tigeot 		case DP_TRAIN_VOLTAGE_SWING_LEVEL_1:
32815d0b1887SFrançois Tigeot 			demph_reg_value = 0x2B404848;
32825d0b1887SFrançois Tigeot 			uniqtranscale_reg_value = 0x5580B83A;
32835d0b1887SFrançois Tigeot 			break;
32841b13d190SFrançois Tigeot 		case DP_TRAIN_VOLTAGE_SWING_LEVEL_2:
32855d0b1887SFrançois Tigeot 			demph_reg_value = 0x2B404040;
32865d0b1887SFrançois Tigeot 			uniqtranscale_reg_value = 0x55ADDA3A;
32875d0b1887SFrançois Tigeot 			break;
32885d0b1887SFrançois Tigeot 		default:
32895d0b1887SFrançois Tigeot 			return 0;
32905d0b1887SFrançois Tigeot 		}
32915d0b1887SFrançois Tigeot 		break;
32921b13d190SFrançois Tigeot 	case DP_TRAIN_PRE_EMPH_LEVEL_2:
32935d0b1887SFrançois Tigeot 		preemph_reg_value = 0x0000000;
32945d0b1887SFrançois Tigeot 		switch (train_set & DP_TRAIN_VOLTAGE_SWING_MASK) {
32951b13d190SFrançois Tigeot 		case DP_TRAIN_VOLTAGE_SWING_LEVEL_0:
32965d0b1887SFrançois Tigeot 			demph_reg_value = 0x2B305555;
32975d0b1887SFrançois Tigeot 			uniqtranscale_reg_value = 0x5570B83A;
32985d0b1887SFrançois Tigeot 			break;
32991b13d190SFrançois Tigeot 		case DP_TRAIN_VOLTAGE_SWING_LEVEL_1:
33005d0b1887SFrançois Tigeot 			demph_reg_value = 0x2B2B4040;
33015d0b1887SFrançois Tigeot 			uniqtranscale_reg_value = 0x55ADDA3A;
33025d0b1887SFrançois Tigeot 			break;
33035d0b1887SFrançois Tigeot 		default:
33045d0b1887SFrançois Tigeot 			return 0;
33055d0b1887SFrançois Tigeot 		}
33065d0b1887SFrançois Tigeot 		break;
33071b13d190SFrançois Tigeot 	case DP_TRAIN_PRE_EMPH_LEVEL_3:
33085d0b1887SFrançois Tigeot 		preemph_reg_value = 0x0006000;
33095d0b1887SFrançois Tigeot 		switch (train_set & DP_TRAIN_VOLTAGE_SWING_MASK) {
33101b13d190SFrançois Tigeot 		case DP_TRAIN_VOLTAGE_SWING_LEVEL_0:
33115d0b1887SFrançois Tigeot 			demph_reg_value = 0x1B405555;
33125d0b1887SFrançois Tigeot 			uniqtranscale_reg_value = 0x55ADDA3A;
33135d0b1887SFrançois Tigeot 			break;
33145d0b1887SFrançois Tigeot 		default:
33155d0b1887SFrançois Tigeot 			return 0;
33165d0b1887SFrançois Tigeot 		}
33175d0b1887SFrançois Tigeot 		break;
33185d0b1887SFrançois Tigeot 	default:
33195d0b1887SFrançois Tigeot 		return 0;
33205d0b1887SFrançois Tigeot 	}
33215d0b1887SFrançois Tigeot 
33221487f786SFrançois Tigeot 	vlv_set_phy_signal_level(encoder, demph_reg_value, preemph_reg_value,
33231487f786SFrançois Tigeot 				 uniqtranscale_reg_value, 0);
33245d0b1887SFrançois Tigeot 
33255d0b1887SFrançois Tigeot 	return 0;
33265d0b1887SFrançois Tigeot }
33275d0b1887SFrançois Tigeot 
chv_signal_levels(struct intel_dp * intel_dp)332819c468b4SFrançois Tigeot static uint32_t chv_signal_levels(struct intel_dp *intel_dp)
3329ba55f2f5SFrançois Tigeot {
33301487f786SFrançois Tigeot 	struct intel_encoder *encoder = &dp_to_dig_port(intel_dp)->base;
33311487f786SFrançois Tigeot 	u32 deemph_reg_value, margin_reg_value;
33321487f786SFrançois Tigeot 	bool uniq_trans_scale = false;
3333ba55f2f5SFrançois Tigeot 	uint8_t train_set = intel_dp->train_set[0];
3334ba55f2f5SFrançois Tigeot 
3335ba55f2f5SFrançois Tigeot 	switch (train_set & DP_TRAIN_PRE_EMPHASIS_MASK) {
33361b13d190SFrançois Tigeot 	case DP_TRAIN_PRE_EMPH_LEVEL_0:
3337ba55f2f5SFrançois Tigeot 		switch (train_set & DP_TRAIN_VOLTAGE_SWING_MASK) {
33381b13d190SFrançois Tigeot 		case DP_TRAIN_VOLTAGE_SWING_LEVEL_0:
3339ba55f2f5SFrançois Tigeot 			deemph_reg_value = 128;
3340ba55f2f5SFrançois Tigeot 			margin_reg_value = 52;
3341ba55f2f5SFrançois Tigeot 			break;
33421b13d190SFrançois Tigeot 		case DP_TRAIN_VOLTAGE_SWING_LEVEL_1:
3343ba55f2f5SFrançois Tigeot 			deemph_reg_value = 128;
3344ba55f2f5SFrançois Tigeot 			margin_reg_value = 77;
3345ba55f2f5SFrançois Tigeot 			break;
33461b13d190SFrançois Tigeot 		case DP_TRAIN_VOLTAGE_SWING_LEVEL_2:
3347ba55f2f5SFrançois Tigeot 			deemph_reg_value = 128;
3348ba55f2f5SFrançois Tigeot 			margin_reg_value = 102;
3349ba55f2f5SFrançois Tigeot 			break;
33501b13d190SFrançois Tigeot 		case DP_TRAIN_VOLTAGE_SWING_LEVEL_3:
3351ba55f2f5SFrançois Tigeot 			deemph_reg_value = 128;
3352ba55f2f5SFrançois Tigeot 			margin_reg_value = 154;
33531487f786SFrançois Tigeot 			uniq_trans_scale = true;
3354ba55f2f5SFrançois Tigeot 			break;
3355ba55f2f5SFrançois Tigeot 		default:
3356ba55f2f5SFrançois Tigeot 			return 0;
3357ba55f2f5SFrançois Tigeot 		}
3358ba55f2f5SFrançois Tigeot 		break;
33591b13d190SFrançois Tigeot 	case DP_TRAIN_PRE_EMPH_LEVEL_1:
3360ba55f2f5SFrançois Tigeot 		switch (train_set & DP_TRAIN_VOLTAGE_SWING_MASK) {
33611b13d190SFrançois Tigeot 		case DP_TRAIN_VOLTAGE_SWING_LEVEL_0:
3362ba55f2f5SFrançois Tigeot 			deemph_reg_value = 85;
3363ba55f2f5SFrançois Tigeot 			margin_reg_value = 78;
3364ba55f2f5SFrançois Tigeot 			break;
33651b13d190SFrançois Tigeot 		case DP_TRAIN_VOLTAGE_SWING_LEVEL_1:
3366ba55f2f5SFrançois Tigeot 			deemph_reg_value = 85;
3367ba55f2f5SFrançois Tigeot 			margin_reg_value = 116;
3368ba55f2f5SFrançois Tigeot 			break;
33691b13d190SFrançois Tigeot 		case DP_TRAIN_VOLTAGE_SWING_LEVEL_2:
3370ba55f2f5SFrançois Tigeot 			deemph_reg_value = 85;
3371ba55f2f5SFrançois Tigeot 			margin_reg_value = 154;
3372ba55f2f5SFrançois Tigeot 			break;
3373ba55f2f5SFrançois Tigeot 		default:
3374ba55f2f5SFrançois Tigeot 			return 0;
3375ba55f2f5SFrançois Tigeot 		}
3376ba55f2f5SFrançois Tigeot 		break;
33771b13d190SFrançois Tigeot 	case DP_TRAIN_PRE_EMPH_LEVEL_2:
3378ba55f2f5SFrançois Tigeot 		switch (train_set & DP_TRAIN_VOLTAGE_SWING_MASK) {
33791b13d190SFrançois Tigeot 		case DP_TRAIN_VOLTAGE_SWING_LEVEL_0:
3380ba55f2f5SFrançois Tigeot 			deemph_reg_value = 64;
3381ba55f2f5SFrançois Tigeot 			margin_reg_value = 104;
3382ba55f2f5SFrançois Tigeot 			break;
33831b13d190SFrançois Tigeot 		case DP_TRAIN_VOLTAGE_SWING_LEVEL_1:
3384ba55f2f5SFrançois Tigeot 			deemph_reg_value = 64;
3385ba55f2f5SFrançois Tigeot 			margin_reg_value = 154;
3386ba55f2f5SFrançois Tigeot 			break;
3387ba55f2f5SFrançois Tigeot 		default:
3388ba55f2f5SFrançois Tigeot 			return 0;
3389ba55f2f5SFrançois Tigeot 		}
3390ba55f2f5SFrançois Tigeot 		break;
33911b13d190SFrançois Tigeot 	case DP_TRAIN_PRE_EMPH_LEVEL_3:
3392ba55f2f5SFrançois Tigeot 		switch (train_set & DP_TRAIN_VOLTAGE_SWING_MASK) {
33931b13d190SFrançois Tigeot 		case DP_TRAIN_VOLTAGE_SWING_LEVEL_0:
3394ba55f2f5SFrançois Tigeot 			deemph_reg_value = 43;
3395ba55f2f5SFrançois Tigeot 			margin_reg_value = 154;
3396ba55f2f5SFrançois Tigeot 			break;
3397ba55f2f5SFrançois Tigeot 		default:
3398ba55f2f5SFrançois Tigeot 			return 0;
3399ba55f2f5SFrançois Tigeot 		}
3400ba55f2f5SFrançois Tigeot 		break;
3401ba55f2f5SFrançois Tigeot 	default:
3402ba55f2f5SFrançois Tigeot 		return 0;
3403ba55f2f5SFrançois Tigeot 	}
3404ba55f2f5SFrançois Tigeot 
34051487f786SFrançois Tigeot 	chv_set_phy_signal_level(encoder, deemph_reg_value,
34061487f786SFrançois Tigeot 				 margin_reg_value, uniq_trans_scale);
3407ba55f2f5SFrançois Tigeot 
3408ba55f2f5SFrançois Tigeot 	return 0;
3409ba55f2f5SFrançois Tigeot }
3410ba55f2f5SFrançois Tigeot 
3411e3adcf8fSFrançois Tigeot static uint32_t
gen4_signal_levels(uint8_t train_set)341219c468b4SFrançois Tigeot gen4_signal_levels(uint8_t train_set)
3413e3adcf8fSFrançois Tigeot {
3414e3adcf8fSFrançois Tigeot 	uint32_t	signal_levels = 0;
3415e3adcf8fSFrançois Tigeot 
3416e3adcf8fSFrançois Tigeot 	switch (train_set & DP_TRAIN_VOLTAGE_SWING_MASK) {
34171b13d190SFrançois Tigeot 	case DP_TRAIN_VOLTAGE_SWING_LEVEL_0:
3418e3adcf8fSFrançois Tigeot 	default:
3419e3adcf8fSFrançois Tigeot 		signal_levels |= DP_VOLTAGE_0_4;
3420e3adcf8fSFrançois Tigeot 		break;
34211b13d190SFrançois Tigeot 	case DP_TRAIN_VOLTAGE_SWING_LEVEL_1:
3422e3adcf8fSFrançois Tigeot 		signal_levels |= DP_VOLTAGE_0_6;
3423e3adcf8fSFrançois Tigeot 		break;
34241b13d190SFrançois Tigeot 	case DP_TRAIN_VOLTAGE_SWING_LEVEL_2:
3425e3adcf8fSFrançois Tigeot 		signal_levels |= DP_VOLTAGE_0_8;
3426e3adcf8fSFrançois Tigeot 		break;
34271b13d190SFrançois Tigeot 	case DP_TRAIN_VOLTAGE_SWING_LEVEL_3:
3428e3adcf8fSFrançois Tigeot 		signal_levels |= DP_VOLTAGE_1_2;
3429e3adcf8fSFrançois Tigeot 		break;
3430e3adcf8fSFrançois Tigeot 	}
3431e3adcf8fSFrançois Tigeot 	switch (train_set & DP_TRAIN_PRE_EMPHASIS_MASK) {
34321b13d190SFrançois Tigeot 	case DP_TRAIN_PRE_EMPH_LEVEL_0:
3433e3adcf8fSFrançois Tigeot 	default:
3434e3adcf8fSFrançois Tigeot 		signal_levels |= DP_PRE_EMPHASIS_0;
3435e3adcf8fSFrançois Tigeot 		break;
34361b13d190SFrançois Tigeot 	case DP_TRAIN_PRE_EMPH_LEVEL_1:
3437e3adcf8fSFrançois Tigeot 		signal_levels |= DP_PRE_EMPHASIS_3_5;
3438e3adcf8fSFrançois Tigeot 		break;
34391b13d190SFrançois Tigeot 	case DP_TRAIN_PRE_EMPH_LEVEL_2:
3440e3adcf8fSFrançois Tigeot 		signal_levels |= DP_PRE_EMPHASIS_6;
3441e3adcf8fSFrançois Tigeot 		break;
34421b13d190SFrançois Tigeot 	case DP_TRAIN_PRE_EMPH_LEVEL_3:
3443e3adcf8fSFrançois Tigeot 		signal_levels |= DP_PRE_EMPHASIS_9_5;
3444e3adcf8fSFrançois Tigeot 		break;
3445e3adcf8fSFrançois Tigeot 	}
3446e3adcf8fSFrançois Tigeot 	return signal_levels;
3447e3adcf8fSFrançois Tigeot }
3448e3adcf8fSFrançois Tigeot 
3449e3adcf8fSFrançois Tigeot /* Gen6's DP voltage swing and pre-emphasis control */
3450e3adcf8fSFrançois Tigeot static uint32_t
gen6_edp_signal_levels(uint8_t train_set)345119c468b4SFrançois Tigeot gen6_edp_signal_levels(uint8_t train_set)
3452e3adcf8fSFrançois Tigeot {
3453e3adcf8fSFrançois Tigeot 	int signal_levels = train_set & (DP_TRAIN_VOLTAGE_SWING_MASK |
3454e3adcf8fSFrançois Tigeot 					 DP_TRAIN_PRE_EMPHASIS_MASK);
3455e3adcf8fSFrançois Tigeot 	switch (signal_levels) {
34561b13d190SFrançois Tigeot 	case DP_TRAIN_VOLTAGE_SWING_LEVEL_0 | DP_TRAIN_PRE_EMPH_LEVEL_0:
34571b13d190SFrançois Tigeot 	case DP_TRAIN_VOLTAGE_SWING_LEVEL_1 | DP_TRAIN_PRE_EMPH_LEVEL_0:
3458e3adcf8fSFrançois Tigeot 		return EDP_LINK_TRAIN_400_600MV_0DB_SNB_B;
34591b13d190SFrançois Tigeot 	case DP_TRAIN_VOLTAGE_SWING_LEVEL_0 | DP_TRAIN_PRE_EMPH_LEVEL_1:
3460e3adcf8fSFrançois Tigeot 		return EDP_LINK_TRAIN_400MV_3_5DB_SNB_B;
34611b13d190SFrançois Tigeot 	case DP_TRAIN_VOLTAGE_SWING_LEVEL_0 | DP_TRAIN_PRE_EMPH_LEVEL_2:
34621b13d190SFrançois Tigeot 	case DP_TRAIN_VOLTAGE_SWING_LEVEL_1 | DP_TRAIN_PRE_EMPH_LEVEL_2:
3463e3adcf8fSFrançois Tigeot 		return EDP_LINK_TRAIN_400_600MV_6DB_SNB_B;
34641b13d190SFrançois Tigeot 	case DP_TRAIN_VOLTAGE_SWING_LEVEL_1 | DP_TRAIN_PRE_EMPH_LEVEL_1:
34651b13d190SFrançois Tigeot 	case DP_TRAIN_VOLTAGE_SWING_LEVEL_2 | DP_TRAIN_PRE_EMPH_LEVEL_1:
3466e3adcf8fSFrançois Tigeot 		return EDP_LINK_TRAIN_600_800MV_3_5DB_SNB_B;
34671b13d190SFrançois Tigeot 	case DP_TRAIN_VOLTAGE_SWING_LEVEL_2 | DP_TRAIN_PRE_EMPH_LEVEL_0:
34681b13d190SFrançois Tigeot 	case DP_TRAIN_VOLTAGE_SWING_LEVEL_3 | DP_TRAIN_PRE_EMPH_LEVEL_0:
3469e3adcf8fSFrançois Tigeot 		return EDP_LINK_TRAIN_800_1200MV_0DB_SNB_B;
3470e3adcf8fSFrançois Tigeot 	default:
3471e3adcf8fSFrançois Tigeot 		DRM_DEBUG_KMS("Unsupported voltage swing/pre-emphasis level:"
3472e3adcf8fSFrançois Tigeot 			      "0x%x\n", signal_levels);
3473e3adcf8fSFrançois Tigeot 		return EDP_LINK_TRAIN_400_600MV_0DB_SNB_B;
3474e3adcf8fSFrançois Tigeot 	}
3475e3adcf8fSFrançois Tigeot }
3476e3adcf8fSFrançois Tigeot 
3477e3adcf8fSFrançois Tigeot /* Gen7's DP voltage swing and pre-emphasis control */
3478e3adcf8fSFrançois Tigeot static uint32_t
gen7_edp_signal_levels(uint8_t train_set)347919c468b4SFrançois Tigeot gen7_edp_signal_levels(uint8_t train_set)
3480e3adcf8fSFrançois Tigeot {
3481e3adcf8fSFrançois Tigeot 	int signal_levels = train_set & (DP_TRAIN_VOLTAGE_SWING_MASK |
3482e3adcf8fSFrançois Tigeot 					 DP_TRAIN_PRE_EMPHASIS_MASK);
3483e3adcf8fSFrançois Tigeot 	switch (signal_levels) {
34841b13d190SFrançois Tigeot 	case DP_TRAIN_VOLTAGE_SWING_LEVEL_0 | DP_TRAIN_PRE_EMPH_LEVEL_0:
3485e3adcf8fSFrançois Tigeot 		return EDP_LINK_TRAIN_400MV_0DB_IVB;
34861b13d190SFrançois Tigeot 	case DP_TRAIN_VOLTAGE_SWING_LEVEL_0 | DP_TRAIN_PRE_EMPH_LEVEL_1:
3487e3adcf8fSFrançois Tigeot 		return EDP_LINK_TRAIN_400MV_3_5DB_IVB;
34881b13d190SFrançois Tigeot 	case DP_TRAIN_VOLTAGE_SWING_LEVEL_0 | DP_TRAIN_PRE_EMPH_LEVEL_2:
3489e3adcf8fSFrançois Tigeot 		return EDP_LINK_TRAIN_400MV_6DB_IVB;
3490e3adcf8fSFrançois Tigeot 
34911b13d190SFrançois Tigeot 	case DP_TRAIN_VOLTAGE_SWING_LEVEL_1 | DP_TRAIN_PRE_EMPH_LEVEL_0:
3492e3adcf8fSFrançois Tigeot 		return EDP_LINK_TRAIN_600MV_0DB_IVB;
34931b13d190SFrançois Tigeot 	case DP_TRAIN_VOLTAGE_SWING_LEVEL_1 | DP_TRAIN_PRE_EMPH_LEVEL_1:
3494e3adcf8fSFrançois Tigeot 		return EDP_LINK_TRAIN_600MV_3_5DB_IVB;
3495e3adcf8fSFrançois Tigeot 
34961b13d190SFrançois Tigeot 	case DP_TRAIN_VOLTAGE_SWING_LEVEL_2 | DP_TRAIN_PRE_EMPH_LEVEL_0:
3497e3adcf8fSFrançois Tigeot 		return EDP_LINK_TRAIN_800MV_0DB_IVB;
34981b13d190SFrançois Tigeot 	case DP_TRAIN_VOLTAGE_SWING_LEVEL_2 | DP_TRAIN_PRE_EMPH_LEVEL_1:
3499e3adcf8fSFrançois Tigeot 		return EDP_LINK_TRAIN_800MV_3_5DB_IVB;
3500e3adcf8fSFrançois Tigeot 
3501e3adcf8fSFrançois Tigeot 	default:
3502e3adcf8fSFrançois Tigeot 		DRM_DEBUG_KMS("Unsupported voltage swing/pre-emphasis level:"
3503e3adcf8fSFrançois Tigeot 			      "0x%x\n", signal_levels);
3504e3adcf8fSFrançois Tigeot 		return EDP_LINK_TRAIN_500MV_0DB_IVB;
3505e3adcf8fSFrançois Tigeot 	}
3506e3adcf8fSFrançois Tigeot }
3507e3adcf8fSFrançois Tigeot 
3508aee94f86SFrançois Tigeot void
intel_dp_set_signal_levels(struct intel_dp * intel_dp)3509aee94f86SFrançois Tigeot intel_dp_set_signal_levels(struct intel_dp *intel_dp)
3510a2fdbec6SFrançois Tigeot {
3511a2fdbec6SFrançois Tigeot 	struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp);
35125d0b1887SFrançois Tigeot 	enum port port = intel_dig_port->port;
3513a2fdbec6SFrançois Tigeot 	struct drm_device *dev = intel_dig_port->base.base.dev;
3514aee94f86SFrançois Tigeot 	struct drm_i915_private *dev_priv = to_i915(dev);
3515a05eeebfSFrançois Tigeot 	uint32_t signal_levels, mask = 0;
3516a2fdbec6SFrançois Tigeot 	uint8_t train_set = intel_dp->train_set[0];
3517a2fdbec6SFrançois Tigeot 
3518*3f2dd94aSFrançois Tigeot 	if (IS_GEN9_LP(dev_priv) || IS_CANNONLAKE(dev_priv)) {
3519*3f2dd94aSFrançois Tigeot 		signal_levels = bxt_signal_levels(intel_dp);
3520*3f2dd94aSFrançois Tigeot 	} else if (HAS_DDI(dev_priv)) {
3521a05eeebfSFrançois Tigeot 		signal_levels = ddi_signal_levels(intel_dp);
3522a2fdbec6SFrançois Tigeot 		mask = DDI_BUF_EMP_MASK;
35231e12ee3bSFrançois Tigeot 	} else if (IS_CHERRYVIEW(dev_priv)) {
352419c468b4SFrançois Tigeot 		signal_levels = chv_signal_levels(intel_dp);
35251e12ee3bSFrançois Tigeot 	} else if (IS_VALLEYVIEW(dev_priv)) {
352619c468b4SFrançois Tigeot 		signal_levels = vlv_signal_levels(intel_dp);
35271e12ee3bSFrançois Tigeot 	} else if (IS_GEN7(dev_priv) && port == PORT_A) {
352819c468b4SFrançois Tigeot 		signal_levels = gen7_edp_signal_levels(train_set);
3529a2fdbec6SFrançois Tigeot 		mask = EDP_LINK_TRAIN_VOL_EMP_MASK_IVB;
35301e12ee3bSFrançois Tigeot 	} else if (IS_GEN6(dev_priv) && port == PORT_A) {
353119c468b4SFrançois Tigeot 		signal_levels = gen6_edp_signal_levels(train_set);
3532a2fdbec6SFrançois Tigeot 		mask = EDP_LINK_TRAIN_VOL_EMP_MASK_SNB;
3533a2fdbec6SFrançois Tigeot 	} else {
353419c468b4SFrançois Tigeot 		signal_levels = gen4_signal_levels(train_set);
3535a2fdbec6SFrançois Tigeot 		mask = DP_VOLTAGE_MASK | DP_PRE_EMPHASIS_MASK;
3536a2fdbec6SFrançois Tigeot 	}
3537a2fdbec6SFrançois Tigeot 
353819c468b4SFrançois Tigeot 	if (mask)
3539a2fdbec6SFrançois Tigeot 		DRM_DEBUG_KMS("Using signal levels %08x\n", signal_levels);
3540a2fdbec6SFrançois Tigeot 
354119c468b4SFrançois Tigeot 	DRM_DEBUG_KMS("Using vswing level %d\n",
354219c468b4SFrançois Tigeot 		train_set & DP_TRAIN_VOLTAGE_SWING_MASK);
354319c468b4SFrançois Tigeot 	DRM_DEBUG_KMS("Using pre-emphasis level %d\n",
354419c468b4SFrançois Tigeot 		(train_set & DP_TRAIN_PRE_EMPHASIS_MASK) >>
354519c468b4SFrançois Tigeot 			DP_TRAIN_PRE_EMPHASIS_SHIFT);
354619c468b4SFrançois Tigeot 
3547aee94f86SFrançois Tigeot 	intel_dp->DP = (intel_dp->DP & ~mask) | signal_levels;
3548aee94f86SFrançois Tigeot 
3549aee94f86SFrançois Tigeot 	I915_WRITE(intel_dp->output_reg, intel_dp->DP);
3550aee94f86SFrançois Tigeot 	POSTING_READ(intel_dp->output_reg);
3551a2fdbec6SFrançois Tigeot }
3552a2fdbec6SFrançois Tigeot 
3553aee94f86SFrançois Tigeot void
intel_dp_program_link_training_pattern(struct intel_dp * intel_dp,uint8_t dp_train_pat)3554aee94f86SFrançois Tigeot intel_dp_program_link_training_pattern(struct intel_dp *intel_dp,
3555e3adcf8fSFrançois Tigeot 				       uint8_t dp_train_pat)
3556e3adcf8fSFrançois Tigeot {
355719df918dSFrançois Tigeot 	struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp);
3558352ff8bdSFrançois Tigeot 	struct drm_i915_private *dev_priv =
3559352ff8bdSFrançois Tigeot 		to_i915(intel_dig_port->base.base.dev);
356019df918dSFrançois Tigeot 
3561aee94f86SFrançois Tigeot 	_intel_dp_set_link_train(intel_dp, &intel_dp->DP, dp_train_pat);
3562e3adcf8fSFrançois Tigeot 
3563aee94f86SFrançois Tigeot 	I915_WRITE(intel_dp->output_reg, intel_dp->DP);
3564e3adcf8fSFrançois Tigeot 	POSTING_READ(intel_dp->output_reg);
356519df918dSFrançois Tigeot }
3566e3adcf8fSFrançois Tigeot 
intel_dp_set_idle_link_train(struct intel_dp * intel_dp)3567aee94f86SFrançois Tigeot void intel_dp_set_idle_link_train(struct intel_dp *intel_dp)
35688e26cdf6SFrançois Tigeot {
35698e26cdf6SFrançois Tigeot 	struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp);
35708e26cdf6SFrançois Tigeot 	struct drm_device *dev = intel_dig_port->base.base.dev;
3571303bf270SFrançois Tigeot 	struct drm_i915_private *dev_priv = to_i915(dev);
35728e26cdf6SFrançois Tigeot 	enum port port = intel_dig_port->port;
35738e26cdf6SFrançois Tigeot 	uint32_t val;
35748e26cdf6SFrançois Tigeot 
35751e12ee3bSFrançois Tigeot 	if (!HAS_DDI(dev_priv))
35768e26cdf6SFrançois Tigeot 		return;
35778e26cdf6SFrançois Tigeot 
35788e26cdf6SFrançois Tigeot 	val = I915_READ(DP_TP_CTL(port));
35798e26cdf6SFrançois Tigeot 	val &= ~DP_TP_CTL_LINK_TRAIN_MASK;
35808e26cdf6SFrançois Tigeot 	val |= DP_TP_CTL_LINK_TRAIN_IDLE;
35818e26cdf6SFrançois Tigeot 	I915_WRITE(DP_TP_CTL(port), val);
35828e26cdf6SFrançois Tigeot 
35838e26cdf6SFrançois Tigeot 	/*
35848e26cdf6SFrançois Tigeot 	 * On PORT_A we can have only eDP in SST mode. There the only reason
35858e26cdf6SFrançois Tigeot 	 * we need to set idle transmission mode is to work around a HW issue
35868e26cdf6SFrançois Tigeot 	 * where we enable the pipe while not in idle link-training mode.
35878e26cdf6SFrançois Tigeot 	 * In this case there is requirement to wait for a minimum number of
35888e26cdf6SFrançois Tigeot 	 * idle patterns to be sent.
35898e26cdf6SFrançois Tigeot 	 */
35908e26cdf6SFrançois Tigeot 	if (port == PORT_A)
35918e26cdf6SFrançois Tigeot 		return;
35928e26cdf6SFrançois Tigeot 
35931487f786SFrançois Tigeot 	if (intel_wait_for_register(dev_priv,DP_TP_STATUS(port),
35941487f786SFrançois Tigeot 				    DP_TP_STATUS_IDLE_DONE,
35951487f786SFrançois Tigeot 				    DP_TP_STATUS_IDLE_DONE,
35968e26cdf6SFrançois Tigeot 				    1))
35978e26cdf6SFrançois Tigeot 		DRM_ERROR("Timed out waiting for DP idle patterns\n");
35988e26cdf6SFrançois Tigeot }
35998e26cdf6SFrançois Tigeot 
3600e3adcf8fSFrançois Tigeot static void
intel_dp_link_down(struct intel_dp * intel_dp)3601e3adcf8fSFrançois Tigeot intel_dp_link_down(struct intel_dp *intel_dp)
3602e3adcf8fSFrançois Tigeot {
360319df918dSFrançois Tigeot 	struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp);
360419c468b4SFrançois Tigeot 	struct intel_crtc *crtc = to_intel_crtc(intel_dig_port->base.base.crtc);
36055d0b1887SFrançois Tigeot 	enum port port = intel_dig_port->port;
360619df918dSFrançois Tigeot 	struct drm_device *dev = intel_dig_port->base.base.dev;
3607303bf270SFrançois Tigeot 	struct drm_i915_private *dev_priv = to_i915(dev);
3608e3adcf8fSFrançois Tigeot 	uint32_t DP = intel_dp->DP;
3609e3adcf8fSFrançois Tigeot 
36101e12ee3bSFrançois Tigeot 	if (WARN_ON(HAS_DDI(dev_priv)))
361119df918dSFrançois Tigeot 		return;
361219df918dSFrançois Tigeot 
361319df918dSFrançois Tigeot 	if (WARN_ON((I915_READ(intel_dp->output_reg) & DP_PORT_EN) == 0))
3614e3adcf8fSFrançois Tigeot 		return;
3615e3adcf8fSFrançois Tigeot 
3616e3adcf8fSFrançois Tigeot 	DRM_DEBUG_KMS("\n");
3617e3adcf8fSFrançois Tigeot 
36181e12ee3bSFrançois Tigeot 	if ((IS_GEN7(dev_priv) && port == PORT_A) ||
36191e12ee3bSFrançois Tigeot 	    (HAS_PCH_CPT(dev_priv) && port != PORT_A)) {
3620e3adcf8fSFrançois Tigeot 		DP &= ~DP_LINK_TRAIN_MASK_CPT;
362119c468b4SFrançois Tigeot 		DP |= DP_LINK_TRAIN_PAT_IDLE_CPT;
3622e3adcf8fSFrançois Tigeot 	} else {
36231e12ee3bSFrançois Tigeot 		if (IS_CHERRYVIEW(dev_priv))
36241b13d190SFrançois Tigeot 			DP &= ~DP_LINK_TRAIN_MASK_CHV;
36251b13d190SFrançois Tigeot 		else
3626e3adcf8fSFrançois Tigeot 			DP &= ~DP_LINK_TRAIN_MASK;
362719c468b4SFrançois Tigeot 		DP |= DP_LINK_TRAIN_PAT_IDLE;
3628e3adcf8fSFrançois Tigeot 	}
362919c468b4SFrançois Tigeot 	I915_WRITE(intel_dp->output_reg, DP);
3630e3adcf8fSFrançois Tigeot 	POSTING_READ(intel_dp->output_reg);
3631e3adcf8fSFrançois Tigeot 
363219c468b4SFrançois Tigeot 	DP &= ~(DP_PORT_EN | DP_AUDIO_OUTPUT_ENABLE);
363319c468b4SFrançois Tigeot 	I915_WRITE(intel_dp->output_reg, DP);
363419c468b4SFrançois Tigeot 	POSTING_READ(intel_dp->output_reg);
363519c468b4SFrançois Tigeot 
363619c468b4SFrançois Tigeot 	/*
363719c468b4SFrançois Tigeot 	 * HW workaround for IBX, we need to move the port
363819c468b4SFrançois Tigeot 	 * to transcoder A after disabling it to allow the
363919c468b4SFrançois Tigeot 	 * matching HDMI port to be enabled on transcoder A.
3640e3adcf8fSFrançois Tigeot 	 */
36411e12ee3bSFrançois Tigeot 	if (HAS_PCH_IBX(dev_priv) && crtc->pipe == PIPE_B && port != PORT_A) {
3642aee94f86SFrançois Tigeot 		/*
3643aee94f86SFrançois Tigeot 		 * We get CPU/PCH FIFO underruns on the other pipe when
3644aee94f86SFrançois Tigeot 		 * doing the workaround. Sweep them under the rug.
3645aee94f86SFrançois Tigeot 		 */
3646aee94f86SFrançois Tigeot 		intel_set_cpu_fifo_underrun_reporting(dev_priv, PIPE_A, false);
3647aee94f86SFrançois Tigeot 		intel_set_pch_fifo_underrun_reporting(dev_priv, PIPE_A, false);
3648aee94f86SFrançois Tigeot 
364919c468b4SFrançois Tigeot 		/* always enable with pattern 1 (as per spec) */
365019c468b4SFrançois Tigeot 		DP &= ~(DP_PIPEB_SELECT | DP_LINK_TRAIN_MASK);
365119c468b4SFrançois Tigeot 		DP |= DP_PORT_EN | DP_LINK_TRAIN_PAT_1;
365219c468b4SFrançois Tigeot 		I915_WRITE(intel_dp->output_reg, DP);
365319c468b4SFrançois Tigeot 		POSTING_READ(intel_dp->output_reg);
365419c468b4SFrançois Tigeot 
365519c468b4SFrançois Tigeot 		DP &= ~DP_PORT_EN;
3656e3adcf8fSFrançois Tigeot 		I915_WRITE(intel_dp->output_reg, DP);
3657e3adcf8fSFrançois Tigeot 		POSTING_READ(intel_dp->output_reg);
3658aee94f86SFrançois Tigeot 
36594be47400SFrançois Tigeot 		intel_wait_for_vblank_if_active(dev_priv, PIPE_A);
3660aee94f86SFrançois Tigeot 		intel_set_cpu_fifo_underrun_reporting(dev_priv, PIPE_A, true);
3661aee94f86SFrançois Tigeot 		intel_set_pch_fifo_underrun_reporting(dev_priv, PIPE_A, true);
3662e3adcf8fSFrançois Tigeot 	}
3663e3adcf8fSFrançois Tigeot 
366419df918dSFrançois Tigeot 	msleep(intel_dp->panel_power_down_delay);
3665aee94f86SFrançois Tigeot 
3666aee94f86SFrançois Tigeot 	intel_dp->DP = DP;
3667a85cb24fSFrançois Tigeot 
3668a85cb24fSFrançois Tigeot 	if (IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv)) {
3669a85cb24fSFrançois Tigeot 		pps_lock(intel_dp);
3670a85cb24fSFrançois Tigeot 		intel_dp->active_pipe = INVALID_PIPE;
3671a85cb24fSFrançois Tigeot 		pps_unlock(intel_dp);
3672a85cb24fSFrançois Tigeot 	}
3673e3adcf8fSFrançois Tigeot }
3674e3adcf8fSFrançois Tigeot 
36754be47400SFrançois Tigeot bool
intel_dp_read_dpcd(struct intel_dp * intel_dp)367671f41f3eSFrançois Tigeot intel_dp_read_dpcd(struct intel_dp *intel_dp)
3677e3adcf8fSFrançois Tigeot {
36788621f407SFrançois Tigeot 	if (drm_dp_dpcd_read(&intel_dp->aux, 0x000, intel_dp->dpcd,
36796b231eabSImre Vadász 			     sizeof(intel_dp->dpcd)) < 0)
368019df918dSFrançois Tigeot 		return false; /* aux transfer failed */
368119df918dSFrançois Tigeot 
36821b13d190SFrançois Tigeot 	DRM_DEBUG_KMS("DPCD: %*ph\n", (int) sizeof(intel_dp->dpcd), intel_dp->dpcd);
3683a2fdbec6SFrançois Tigeot 
368471f41f3eSFrançois Tigeot 	return intel_dp->dpcd[DP_DPCD_REV] != 0;
368571f41f3eSFrançois Tigeot }
368671f41f3eSFrançois Tigeot 
368771f41f3eSFrançois Tigeot static bool
intel_edp_init_dpcd(struct intel_dp * intel_dp)368871f41f3eSFrançois Tigeot intel_edp_init_dpcd(struct intel_dp *intel_dp)
368971f41f3eSFrançois Tigeot {
369071f41f3eSFrançois Tigeot 	struct drm_i915_private *dev_priv =
369171f41f3eSFrançois Tigeot 		to_i915(dp_to_dig_port(intel_dp)->base.base.dev);
369271f41f3eSFrançois Tigeot 
369371f41f3eSFrançois Tigeot 	/* this function is meant to be called only once */
369471f41f3eSFrançois Tigeot 	WARN_ON(intel_dp->dpcd[DP_DPCD_REV] != 0);
369571f41f3eSFrançois Tigeot 
369671f41f3eSFrançois Tigeot 	if (!intel_dp_read_dpcd(intel_dp))
369771f41f3eSFrançois Tigeot 		return false;
369871f41f3eSFrançois Tigeot 
3699a85cb24fSFrançois Tigeot 	drm_dp_read_desc(&intel_dp->aux, &intel_dp->desc,
3700a85cb24fSFrançois Tigeot 			 drm_dp_is_branch(intel_dp->dpcd));
37014be47400SFrançois Tigeot 
370271f41f3eSFrançois Tigeot 	if (intel_dp->dpcd[DP_DPCD_REV] >= 0x11)
370371f41f3eSFrançois Tigeot 		dev_priv->no_aux_handshake = intel_dp->dpcd[DP_MAX_DOWNSPREAD] &
370471f41f3eSFrançois Tigeot 			DP_NO_AUX_HANDSHAKE_LINK_TRAINING;
370571f41f3eSFrançois Tigeot 
370671f41f3eSFrançois Tigeot 	/* Check if the panel supports PSR */
370771f41f3eSFrançois Tigeot 	drm_dp_dpcd_read(&intel_dp->aux, DP_PSR_SUPPORT,
370871f41f3eSFrançois Tigeot 			 intel_dp->psr_dpcd,
370971f41f3eSFrançois Tigeot 			 sizeof(intel_dp->psr_dpcd));
371071f41f3eSFrançois Tigeot 	if (intel_dp->psr_dpcd[0] & DP_PSR_IS_SUPPORTED) {
371171f41f3eSFrançois Tigeot 		dev_priv->psr.sink_support = true;
371271f41f3eSFrançois Tigeot 		DRM_DEBUG_KMS("Detected EDP PSR Panel.\n");
371371f41f3eSFrançois Tigeot 	}
371471f41f3eSFrançois Tigeot 
371571f41f3eSFrançois Tigeot 	if (INTEL_GEN(dev_priv) >= 9 &&
371671f41f3eSFrançois Tigeot 	    (intel_dp->psr_dpcd[0] & DP_PSR2_IS_SUPPORTED)) {
371771f41f3eSFrançois Tigeot 		uint8_t frame_sync_cap;
371871f41f3eSFrançois Tigeot 
371971f41f3eSFrançois Tigeot 		dev_priv->psr.sink_support = true;
3720*3f2dd94aSFrançois Tigeot 		if (drm_dp_dpcd_readb(&intel_dp->aux,
372171f41f3eSFrançois Tigeot 				      DP_SINK_DEVICE_AUX_FRAME_SYNC_CAP,
3722*3f2dd94aSFrançois Tigeot 				      &frame_sync_cap) != 1)
3723*3f2dd94aSFrançois Tigeot 			frame_sync_cap = 0;
372471f41f3eSFrançois Tigeot 		dev_priv->psr.aux_frame_sync = frame_sync_cap ? true : false;
372571f41f3eSFrançois Tigeot 		/* PSR2 needs frame sync as well */
372671f41f3eSFrançois Tigeot 		dev_priv->psr.psr2_support = dev_priv->psr.aux_frame_sync;
372771f41f3eSFrançois Tigeot 		DRM_DEBUG_KMS("PSR2 %s on sink",
372871f41f3eSFrançois Tigeot 			      dev_priv->psr.psr2_support ? "supported" : "not supported");
3729a85cb24fSFrançois Tigeot 
3730a85cb24fSFrançois Tigeot 		if (dev_priv->psr.psr2_support) {
3731a85cb24fSFrançois Tigeot 			dev_priv->psr.y_cord_support =
3732a85cb24fSFrançois Tigeot 				intel_dp_get_y_cord_status(intel_dp);
3733a85cb24fSFrançois Tigeot 			dev_priv->psr.colorimetry_support =
3734a85cb24fSFrançois Tigeot 				intel_dp_get_colorimetry_status(intel_dp);
3735a85cb24fSFrançois Tigeot 			dev_priv->psr.alpm =
3736a85cb24fSFrançois Tigeot 				intel_dp_get_alpm_status(intel_dp);
3737a85cb24fSFrançois Tigeot 		}
3738a85cb24fSFrançois Tigeot 
373971f41f3eSFrançois Tigeot 	}
374071f41f3eSFrançois Tigeot 
374171f41f3eSFrançois Tigeot 	/* Read the eDP Display control capabilities registers */
374271f41f3eSFrançois Tigeot 	if ((intel_dp->dpcd[DP_EDP_CONFIGURATION_CAP] & DP_DPCD_DISPLAY_CONTROL_CAPABLE) &&
374371f41f3eSFrançois Tigeot 	    drm_dp_dpcd_read(&intel_dp->aux, DP_EDP_DPCD_REV,
37441e12ee3bSFrançois Tigeot 			     intel_dp->edp_dpcd, sizeof(intel_dp->edp_dpcd)) ==
37451e12ee3bSFrançois Tigeot 			     sizeof(intel_dp->edp_dpcd))
374671f41f3eSFrançois Tigeot 		DRM_DEBUG_KMS("EDP DPCD : %*ph\n", (int) sizeof(intel_dp->edp_dpcd),
374771f41f3eSFrançois Tigeot 			      intel_dp->edp_dpcd);
374871f41f3eSFrançois Tigeot 
374971f41f3eSFrançois Tigeot 	/* Intermediate frequency support */
375071f41f3eSFrançois Tigeot 	if (intel_dp->edp_dpcd[0] >= 0x03) { /* eDp v1.4 or higher */
375171f41f3eSFrançois Tigeot 		__le16 sink_rates[DP_MAX_SUPPORTED_RATES];
375271f41f3eSFrançois Tigeot 		int i;
375371f41f3eSFrançois Tigeot 
375471f41f3eSFrançois Tigeot 		drm_dp_dpcd_read(&intel_dp->aux, DP_SUPPORTED_LINK_RATES,
375571f41f3eSFrançois Tigeot 				sink_rates, sizeof(sink_rates));
375671f41f3eSFrançois Tigeot 
375771f41f3eSFrançois Tigeot 		for (i = 0; i < ARRAY_SIZE(sink_rates); i++) {
375871f41f3eSFrançois Tigeot 			int val = le16_to_cpu(sink_rates[i]);
375971f41f3eSFrançois Tigeot 
376071f41f3eSFrançois Tigeot 			if (val == 0)
376171f41f3eSFrançois Tigeot 				break;
376271f41f3eSFrançois Tigeot 
3763a85cb24fSFrançois Tigeot 			/* Value read multiplied by 200kHz gives the per-lane
3764a85cb24fSFrançois Tigeot 			 * link rate in kHz. The source rates are, however,
3765a85cb24fSFrançois Tigeot 			 * stored in terms of LS_Clk kHz. The full conversion
3766a85cb24fSFrançois Tigeot 			 * back to symbols is
3767a85cb24fSFrançois Tigeot 			 * (val * 200kHz)*(8/10 ch. encoding)*(1/8 bit to Byte)
3768a85cb24fSFrançois Tigeot 			 */
376971f41f3eSFrançois Tigeot 			intel_dp->sink_rates[i] = (val * 200) / 10;
377071f41f3eSFrançois Tigeot 		}
377171f41f3eSFrançois Tigeot 		intel_dp->num_sink_rates = i;
377271f41f3eSFrançois Tigeot 	}
377371f41f3eSFrançois Tigeot 
3774*3f2dd94aSFrançois Tigeot 	if (intel_dp->num_sink_rates)
3775*3f2dd94aSFrançois Tigeot 		intel_dp->use_rate_select = true;
3776*3f2dd94aSFrançois Tigeot 	else
3777*3f2dd94aSFrançois Tigeot 		intel_dp_set_sink_rates(intel_dp);
3778*3f2dd94aSFrançois Tigeot 
3779*3f2dd94aSFrançois Tigeot 	intel_dp_set_common_rates(intel_dp);
3780*3f2dd94aSFrançois Tigeot 
378171f41f3eSFrançois Tigeot 	return true;
378271f41f3eSFrançois Tigeot }
378371f41f3eSFrançois Tigeot 
378471f41f3eSFrançois Tigeot 
378571f41f3eSFrançois Tigeot static bool
intel_dp_get_dpcd(struct intel_dp * intel_dp)378671f41f3eSFrançois Tigeot intel_dp_get_dpcd(struct intel_dp *intel_dp)
378771f41f3eSFrançois Tigeot {
3788*3f2dd94aSFrançois Tigeot 	u8 sink_count;
3789*3f2dd94aSFrançois Tigeot 
379071f41f3eSFrançois Tigeot 	if (!intel_dp_read_dpcd(intel_dp))
379171f41f3eSFrançois Tigeot 		return false;
379219df918dSFrançois Tigeot 
3793*3f2dd94aSFrançois Tigeot 	/* Don't clobber cached eDP rates. */
3794*3f2dd94aSFrançois Tigeot 	if (!intel_dp_is_edp(intel_dp)) {
3795*3f2dd94aSFrançois Tigeot 		intel_dp_set_sink_rates(intel_dp);
3796*3f2dd94aSFrançois Tigeot 		intel_dp_set_common_rates(intel_dp);
3797*3f2dd94aSFrançois Tigeot 	}
3798*3f2dd94aSFrançois Tigeot 
3799*3f2dd94aSFrançois Tigeot 	if (drm_dp_dpcd_readb(&intel_dp->aux, DP_SINK_COUNT, &sink_count) <= 0)
38008621f407SFrançois Tigeot 		return false;
38018621f407SFrançois Tigeot 
38028621f407SFrançois Tigeot 	/*
38038621f407SFrançois Tigeot 	 * Sink count can change between short pulse hpd hence
38048621f407SFrançois Tigeot 	 * a member variable in intel_dp will track any changes
38058621f407SFrançois Tigeot 	 * between short pulse interrupts.
38068621f407SFrançois Tigeot 	 */
3807*3f2dd94aSFrançois Tigeot 	intel_dp->sink_count = DP_GET_SINK_COUNT(sink_count);
38088621f407SFrançois Tigeot 
38098621f407SFrançois Tigeot 	/*
38108621f407SFrançois Tigeot 	 * SINK_COUNT == 0 and DOWNSTREAM_PORT_PRESENT == 1 implies that
38118621f407SFrançois Tigeot 	 * a dongle is present but no display. Unless we require to know
38128621f407SFrançois Tigeot 	 * if a dongle is present or not, we don't need to update
38138621f407SFrançois Tigeot 	 * downstream port information. So, an early return here saves
38148621f407SFrançois Tigeot 	 * time from performing other operations which are not required.
38158621f407SFrançois Tigeot 	 */
3816*3f2dd94aSFrançois Tigeot 	if (!intel_dp_is_edp(intel_dp) && !intel_dp->sink_count)
38178621f407SFrançois Tigeot 		return false;
38188621f407SFrançois Tigeot 
38194be47400SFrançois Tigeot 	if (!drm_dp_is_branch(intel_dp->dpcd))
382019df918dSFrançois Tigeot 		return true; /* native DP sink */
382119df918dSFrançois Tigeot 
382219df918dSFrançois Tigeot 	if (intel_dp->dpcd[DP_DPCD_REV] == 0x10)
382319df918dSFrançois Tigeot 		return true; /* no per-port downstream info */
382419df918dSFrançois Tigeot 
38258621f407SFrançois Tigeot 	if (drm_dp_dpcd_read(&intel_dp->aux, DP_DOWNSTREAM_PORT_0,
382619df918dSFrançois Tigeot 			     intel_dp->downstream_ports,
38276b231eabSImre Vadász 			     DP_MAX_DOWNSTREAM_PORTS) < 0)
382819df918dSFrançois Tigeot 		return false; /* downstream port status fetch failed */
382919df918dSFrançois Tigeot 
3830e3adcf8fSFrançois Tigeot 	return true;
3831e3adcf8fSFrançois Tigeot }
3832e3adcf8fSFrançois Tigeot 
38332c9916cdSFrançois Tigeot static bool
intel_dp_can_mst(struct intel_dp * intel_dp)383471f41f3eSFrançois Tigeot intel_dp_can_mst(struct intel_dp *intel_dp)
38352c9916cdSFrançois Tigeot {
3836*3f2dd94aSFrançois Tigeot 	u8 mstm_cap;
38372c9916cdSFrançois Tigeot 
3838*3f2dd94aSFrançois Tigeot 	if (!i915_modparams.enable_dp_mst)
38398621f407SFrançois Tigeot 		return false;
38408621f407SFrançois Tigeot 
38412c9916cdSFrançois Tigeot 	if (!intel_dp->can_mst)
38422c9916cdSFrançois Tigeot 		return false;
38432c9916cdSFrançois Tigeot 
38442c9916cdSFrançois Tigeot 	if (intel_dp->dpcd[DP_DPCD_REV] < 0x12)
38452c9916cdSFrançois Tigeot 		return false;
38462c9916cdSFrançois Tigeot 
3847*3f2dd94aSFrançois Tigeot 	if (drm_dp_dpcd_readb(&intel_dp->aux, DP_MSTM_CAP, &mstm_cap) != 1)
384871f41f3eSFrançois Tigeot 		return false;
384971f41f3eSFrançois Tigeot 
3850*3f2dd94aSFrançois Tigeot 	return mstm_cap & DP_MST_CAP;
38512c9916cdSFrançois Tigeot }
38522c9916cdSFrançois Tigeot 
385371f41f3eSFrançois Tigeot static void
intel_dp_configure_mst(struct intel_dp * intel_dp)385471f41f3eSFrançois Tigeot intel_dp_configure_mst(struct intel_dp *intel_dp)
385571f41f3eSFrançois Tigeot {
3856*3f2dd94aSFrançois Tigeot 	if (!i915_modparams.enable_dp_mst)
385771f41f3eSFrançois Tigeot 		return;
385871f41f3eSFrançois Tigeot 
385971f41f3eSFrançois Tigeot 	if (!intel_dp->can_mst)
386071f41f3eSFrançois Tigeot 		return;
386171f41f3eSFrançois Tigeot 
386271f41f3eSFrançois Tigeot 	intel_dp->is_mst = intel_dp_can_mst(intel_dp);
386371f41f3eSFrançois Tigeot 
386471f41f3eSFrançois Tigeot 	if (intel_dp->is_mst)
386571f41f3eSFrançois Tigeot 		DRM_DEBUG_KMS("Sink is MST capable\n");
386671f41f3eSFrançois Tigeot 	else
386771f41f3eSFrançois Tigeot 		DRM_DEBUG_KMS("Sink is not MST capable\n");
386871f41f3eSFrançois Tigeot 
386971f41f3eSFrançois Tigeot 	drm_dp_mst_topology_mgr_set_mst(&intel_dp->mst_mgr,
387071f41f3eSFrançois Tigeot 					intel_dp->is_mst);
387119c468b4SFrançois Tigeot }
38722c9916cdSFrançois Tigeot 
intel_dp_sink_crc_stop(struct intel_dp * intel_dp)3873352ff8bdSFrançois Tigeot static int intel_dp_sink_crc_stop(struct intel_dp *intel_dp)
3874ba55f2f5SFrançois Tigeot {
3875a05eeebfSFrançois Tigeot 	struct intel_digital_port *dig_port = dp_to_dig_port(intel_dp);
38764be47400SFrançois Tigeot 	struct drm_i915_private *dev_priv = to_i915(dig_port->base.base.dev);
3877a05eeebfSFrançois Tigeot 	struct intel_crtc *intel_crtc = to_intel_crtc(dig_port->base.base.crtc);
38782c9916cdSFrançois Tigeot 	u8 buf;
3879352ff8bdSFrançois Tigeot 	int ret = 0;
3880aee94f86SFrançois Tigeot 	int count = 0;
3881aee94f86SFrançois Tigeot 	int attempts = 10;
388219c468b4SFrançois Tigeot 
388319c468b4SFrançois Tigeot 	if (drm_dp_dpcd_readb(&intel_dp->aux, DP_TEST_SINK, &buf) < 0) {
3884a05eeebfSFrançois Tigeot 		DRM_DEBUG_KMS("Sink CRC couldn't be stopped properly\n");
3885352ff8bdSFrançois Tigeot 		ret = -EIO;
3886352ff8bdSFrançois Tigeot 		goto out;
388719c468b4SFrançois Tigeot 	}
3888ba55f2f5SFrançois Tigeot 
38892c9916cdSFrançois Tigeot 	if (drm_dp_dpcd_writeb(&intel_dp->aux, DP_TEST_SINK,
3890352ff8bdSFrançois Tigeot 			       buf & ~DP_TEST_SINK_START) < 0) {
3891a05eeebfSFrançois Tigeot 		DRM_DEBUG_KMS("Sink CRC couldn't be stopped properly\n");
3892352ff8bdSFrançois Tigeot 		ret = -EIO;
3893352ff8bdSFrançois Tigeot 		goto out;
3894352ff8bdSFrançois Tigeot 	}
3895a05eeebfSFrançois Tigeot 
3896aee94f86SFrançois Tigeot 	do {
38974be47400SFrançois Tigeot 		intel_wait_for_vblank(dev_priv, intel_crtc->pipe);
3898aee94f86SFrançois Tigeot 
3899aee94f86SFrançois Tigeot 		if (drm_dp_dpcd_readb(&intel_dp->aux,
3900aee94f86SFrançois Tigeot 				      DP_TEST_SINK_MISC, &buf) < 0) {
3901aee94f86SFrançois Tigeot 			ret = -EIO;
3902aee94f86SFrançois Tigeot 			goto out;
3903aee94f86SFrançois Tigeot 		}
3904aee94f86SFrançois Tigeot 		count = buf & DP_TEST_COUNT_MASK;
3905aee94f86SFrançois Tigeot 	} while (--attempts && count);
3906aee94f86SFrançois Tigeot 
3907aee94f86SFrançois Tigeot 	if (attempts == 0) {
3908c0e85e96SFrançois Tigeot 		DRM_DEBUG_KMS("TIMEOUT: Sink CRC counter is not zeroed after calculation is stopped\n");
3909aee94f86SFrançois Tigeot 		ret = -ETIMEDOUT;
3910aee94f86SFrançois Tigeot 	}
3911aee94f86SFrançois Tigeot 
3912352ff8bdSFrançois Tigeot  out:
3913a05eeebfSFrançois Tigeot 	hsw_enable_ips(intel_crtc);
3914352ff8bdSFrançois Tigeot 	return ret;
391519c468b4SFrançois Tigeot }
39162c9916cdSFrançois Tigeot 
intel_dp_sink_crc_start(struct intel_dp * intel_dp)3917a05eeebfSFrançois Tigeot static int intel_dp_sink_crc_start(struct intel_dp *intel_dp)
3918a05eeebfSFrançois Tigeot {
3919a05eeebfSFrançois Tigeot 	struct intel_digital_port *dig_port = dp_to_dig_port(intel_dp);
39204be47400SFrançois Tigeot 	struct drm_i915_private *dev_priv = to_i915(dig_port->base.base.dev);
3921a05eeebfSFrançois Tigeot 	struct intel_crtc *intel_crtc = to_intel_crtc(dig_port->base.base.crtc);
3922a05eeebfSFrançois Tigeot 	u8 buf;
3923352ff8bdSFrançois Tigeot 	int ret;
3924352ff8bdSFrançois Tigeot 
3925a05eeebfSFrançois Tigeot 	if (drm_dp_dpcd_readb(&intel_dp->aux, DP_TEST_SINK_MISC, &buf) < 0)
3926a05eeebfSFrançois Tigeot 		return -EIO;
3927a05eeebfSFrançois Tigeot 
3928a05eeebfSFrançois Tigeot 	if (!(buf & DP_TEST_CRC_SUPPORTED))
3929a05eeebfSFrançois Tigeot 		return -ENOTTY;
3930a05eeebfSFrançois Tigeot 
3931a05eeebfSFrançois Tigeot 	if (drm_dp_dpcd_readb(&intel_dp->aux, DP_TEST_SINK, &buf) < 0)
3932a05eeebfSFrançois Tigeot 		return -EIO;
3933a05eeebfSFrançois Tigeot 
3934aee94f86SFrançois Tigeot 	if (buf & DP_TEST_SINK_START) {
3935aee94f86SFrançois Tigeot 		ret = intel_dp_sink_crc_stop(intel_dp);
3936aee94f86SFrançois Tigeot 		if (ret)
3937aee94f86SFrançois Tigeot 			return ret;
3938aee94f86SFrançois Tigeot 	}
3939aee94f86SFrançois Tigeot 
3940a05eeebfSFrançois Tigeot 	hsw_disable_ips(intel_crtc);
3941a05eeebfSFrançois Tigeot 
3942a05eeebfSFrançois Tigeot 	if (drm_dp_dpcd_writeb(&intel_dp->aux, DP_TEST_SINK,
3943a05eeebfSFrançois Tigeot 			       buf | DP_TEST_SINK_START) < 0) {
3944a05eeebfSFrançois Tigeot 		hsw_enable_ips(intel_crtc);
3945a05eeebfSFrançois Tigeot 		return -EIO;
3946a05eeebfSFrançois Tigeot 	}
3947a05eeebfSFrançois Tigeot 
39484be47400SFrançois Tigeot 	intel_wait_for_vblank(dev_priv, intel_crtc->pipe);
3949a05eeebfSFrançois Tigeot 	return 0;
3950a05eeebfSFrançois Tigeot }
3951a05eeebfSFrançois Tigeot 
intel_dp_sink_crc(struct intel_dp * intel_dp,u8 * crc)3952a05eeebfSFrançois Tigeot int intel_dp_sink_crc(struct intel_dp *intel_dp, u8 *crc)
3953a05eeebfSFrançois Tigeot {
3954a05eeebfSFrançois Tigeot 	struct intel_digital_port *dig_port = dp_to_dig_port(intel_dp);
39554be47400SFrançois Tigeot 	struct drm_i915_private *dev_priv = to_i915(dig_port->base.base.dev);
3956a05eeebfSFrançois Tigeot 	struct intel_crtc *intel_crtc = to_intel_crtc(dig_port->base.base.crtc);
3957a05eeebfSFrançois Tigeot 	u8 buf;
3958352ff8bdSFrançois Tigeot 	int count, ret;
3959a05eeebfSFrançois Tigeot 	int attempts = 6;
3960a05eeebfSFrançois Tigeot 
3961a05eeebfSFrançois Tigeot 	ret = intel_dp_sink_crc_start(intel_dp);
3962a05eeebfSFrançois Tigeot 	if (ret)
3963a05eeebfSFrançois Tigeot 		return ret;
3964a05eeebfSFrançois Tigeot 
39652c9916cdSFrançois Tigeot 	do {
39664be47400SFrançois Tigeot 		intel_wait_for_vblank(dev_priv, intel_crtc->pipe);
3967352ff8bdSFrançois Tigeot 
39682c9916cdSFrançois Tigeot 		if (drm_dp_dpcd_readb(&intel_dp->aux,
396919c468b4SFrançois Tigeot 				      DP_TEST_SINK_MISC, &buf) < 0) {
397019c468b4SFrançois Tigeot 			ret = -EIO;
3971a05eeebfSFrançois Tigeot 			goto stop;
397219c468b4SFrançois Tigeot 		}
3973352ff8bdSFrançois Tigeot 		count = buf & DP_TEST_COUNT_MASK;
39742c9916cdSFrançois Tigeot 
3975aee94f86SFrançois Tigeot 	} while (--attempts && count == 0);
3976352ff8bdSFrançois Tigeot 
3977352ff8bdSFrançois Tigeot 	if (attempts == 0) {
3978352ff8bdSFrançois Tigeot 		DRM_ERROR("Panel is unable to calculate any CRC after 6 vblanks\n");
3979352ff8bdSFrançois Tigeot 		ret = -ETIMEDOUT;
3980352ff8bdSFrançois Tigeot 		goto stop;
3981352ff8bdSFrançois Tigeot 	}
3982aee94f86SFrançois Tigeot 
3983aee94f86SFrançois Tigeot 	if (drm_dp_dpcd_read(&intel_dp->aux, DP_TEST_CRC_R_CR, crc, 6) < 0) {
3984aee94f86SFrançois Tigeot 		ret = -EIO;
3985aee94f86SFrançois Tigeot 		goto stop;
3986352ff8bdSFrançois Tigeot 	}
3987352ff8bdSFrançois Tigeot 
3988a05eeebfSFrançois Tigeot stop:
3989a05eeebfSFrançois Tigeot 	intel_dp_sink_crc_stop(intel_dp);
399019c468b4SFrançois Tigeot 	return ret;
3991e3adcf8fSFrançois Tigeot }
3992e3adcf8fSFrançois Tigeot 
3993e3adcf8fSFrançois Tigeot static bool
intel_dp_get_sink_irq(struct intel_dp * intel_dp,u8 * sink_irq_vector)3994e3adcf8fSFrançois Tigeot intel_dp_get_sink_irq(struct intel_dp *intel_dp, u8 *sink_irq_vector)
3995e3adcf8fSFrançois Tigeot {
3996*3f2dd94aSFrançois Tigeot 	return drm_dp_dpcd_readb(&intel_dp->aux, DP_DEVICE_SERVICE_IRQ_VECTOR,
3997*3f2dd94aSFrançois Tigeot 				 sink_irq_vector) == 1;
3998e3adcf8fSFrançois Tigeot }
3999e3adcf8fSFrançois Tigeot 
4000a05eeebfSFrançois Tigeot static bool
intel_dp_get_sink_irq_esi(struct intel_dp * intel_dp,u8 * sink_irq_vector)4001a05eeebfSFrançois Tigeot intel_dp_get_sink_irq_esi(struct intel_dp *intel_dp, u8 *sink_irq_vector)
4002a05eeebfSFrançois Tigeot {
4003*3f2dd94aSFrançois Tigeot 	return drm_dp_dpcd_read(&intel_dp->aux, DP_SINK_COUNT_ESI,
4004*3f2dd94aSFrançois Tigeot 				sink_irq_vector, DP_DPRX_ESI_LEN) ==
4005*3f2dd94aSFrançois Tigeot 		DP_DPRX_ESI_LEN;
4006a05eeebfSFrançois Tigeot }
4007a05eeebfSFrançois Tigeot 
intel_dp_autotest_link_training(struct intel_dp * intel_dp)400819c468b4SFrançois Tigeot static uint8_t intel_dp_autotest_link_training(struct intel_dp *intel_dp)
4009e3adcf8fSFrançois Tigeot {
4010a85cb24fSFrançois Tigeot 	int status = 0;
4011*3f2dd94aSFrançois Tigeot 	int test_link_rate;
4012a85cb24fSFrançois Tigeot 	uint8_t test_lane_count, test_link_bw;
4013a85cb24fSFrançois Tigeot 	/* (DP CTS 1.2)
4014a85cb24fSFrançois Tigeot 	 * 4.3.1.11
4015a85cb24fSFrançois Tigeot 	 */
4016a85cb24fSFrançois Tigeot 	/* Read the TEST_LANE_COUNT and TEST_LINK_RTAE fields (DP CTS 3.1.4) */
4017a85cb24fSFrançois Tigeot 	status = drm_dp_dpcd_readb(&intel_dp->aux, DP_TEST_LANE_COUNT,
4018a85cb24fSFrançois Tigeot 				   &test_lane_count);
4019a85cb24fSFrançois Tigeot 
4020a85cb24fSFrançois Tigeot 	if (status <= 0) {
4021a85cb24fSFrançois Tigeot 		DRM_DEBUG_KMS("Lane count read failed\n");
4022a85cb24fSFrançois Tigeot 		return DP_TEST_NAK;
4023a85cb24fSFrançois Tigeot 	}
4024a85cb24fSFrançois Tigeot 	test_lane_count &= DP_MAX_LANE_COUNT_MASK;
4025a85cb24fSFrançois Tigeot 
4026a85cb24fSFrançois Tigeot 	status = drm_dp_dpcd_readb(&intel_dp->aux, DP_TEST_LINK_RATE,
4027a85cb24fSFrançois Tigeot 				   &test_link_bw);
4028a85cb24fSFrançois Tigeot 	if (status <= 0) {
4029a85cb24fSFrançois Tigeot 		DRM_DEBUG_KMS("Link Rate read failed\n");
4030a85cb24fSFrançois Tigeot 		return DP_TEST_NAK;
4031a85cb24fSFrançois Tigeot 	}
4032a85cb24fSFrançois Tigeot 	test_link_rate = drm_dp_bw_code_to_link_rate(test_link_bw);
4033*3f2dd94aSFrançois Tigeot 
4034*3f2dd94aSFrançois Tigeot 	/* Validate the requested link rate and lane count */
4035*3f2dd94aSFrançois Tigeot 	if (!intel_dp_link_params_valid(intel_dp, test_link_rate,
4036*3f2dd94aSFrançois Tigeot 					test_lane_count))
4037a85cb24fSFrançois Tigeot 		return DP_TEST_NAK;
4038a85cb24fSFrançois Tigeot 
4039a85cb24fSFrançois Tigeot 	intel_dp->compliance.test_lane_count = test_lane_count;
4040a85cb24fSFrançois Tigeot 	intel_dp->compliance.test_link_rate = test_link_rate;
4041a85cb24fSFrançois Tigeot 
4042a85cb24fSFrançois Tigeot 	return DP_TEST_ACK;
404319c468b4SFrançois Tigeot }
404419c468b4SFrançois Tigeot 
intel_dp_autotest_video_pattern(struct intel_dp * intel_dp)404519c468b4SFrançois Tigeot static uint8_t intel_dp_autotest_video_pattern(struct intel_dp *intel_dp)
404619c468b4SFrançois Tigeot {
4047a85cb24fSFrançois Tigeot 	uint8_t test_pattern;
4048*3f2dd94aSFrançois Tigeot 	uint8_t test_misc;
4049a85cb24fSFrançois Tigeot 	__be16 h_width, v_height;
4050a85cb24fSFrançois Tigeot 	int status = 0;
4051a85cb24fSFrançois Tigeot 
4052a85cb24fSFrançois Tigeot 	/* Read the TEST_PATTERN (DP CTS 3.1.5) */
4053*3f2dd94aSFrançois Tigeot 	status = drm_dp_dpcd_readb(&intel_dp->aux, DP_TEST_PATTERN,
4054*3f2dd94aSFrançois Tigeot 				   &test_pattern);
4055a85cb24fSFrançois Tigeot 	if (status <= 0) {
4056a85cb24fSFrançois Tigeot 		DRM_DEBUG_KMS("Test pattern read failed\n");
4057a85cb24fSFrançois Tigeot 		return DP_TEST_NAK;
4058a85cb24fSFrançois Tigeot 	}
4059a85cb24fSFrançois Tigeot 	if (test_pattern != DP_COLOR_RAMP)
4060a85cb24fSFrançois Tigeot 		return DP_TEST_NAK;
4061a85cb24fSFrançois Tigeot 
4062a85cb24fSFrançois Tigeot 	status = drm_dp_dpcd_read(&intel_dp->aux, DP_TEST_H_WIDTH_HI,
4063a85cb24fSFrançois Tigeot 				  &h_width, 2);
4064a85cb24fSFrançois Tigeot 	if (status <= 0) {
4065a85cb24fSFrançois Tigeot 		DRM_DEBUG_KMS("H Width read failed\n");
4066a85cb24fSFrançois Tigeot 		return DP_TEST_NAK;
4067a85cb24fSFrançois Tigeot 	}
4068a85cb24fSFrançois Tigeot 
4069a85cb24fSFrançois Tigeot 	status = drm_dp_dpcd_read(&intel_dp->aux, DP_TEST_V_HEIGHT_HI,
4070a85cb24fSFrançois Tigeot 				  &v_height, 2);
4071a85cb24fSFrançois Tigeot 	if (status <= 0) {
4072a85cb24fSFrançois Tigeot 		DRM_DEBUG_KMS("V Height read failed\n");
4073a85cb24fSFrançois Tigeot 		return DP_TEST_NAK;
4074a85cb24fSFrançois Tigeot 	}
4075a85cb24fSFrançois Tigeot 
4076*3f2dd94aSFrançois Tigeot 	status = drm_dp_dpcd_readb(&intel_dp->aux, DP_TEST_MISC0,
4077*3f2dd94aSFrançois Tigeot 				   &test_misc);
4078a85cb24fSFrançois Tigeot 	if (status <= 0) {
4079a85cb24fSFrançois Tigeot 		DRM_DEBUG_KMS("TEST MISC read failed\n");
4080a85cb24fSFrançois Tigeot 		return DP_TEST_NAK;
4081a85cb24fSFrançois Tigeot 	}
4082a85cb24fSFrançois Tigeot 	if ((test_misc & DP_TEST_COLOR_FORMAT_MASK) != DP_COLOR_FORMAT_RGB)
4083a85cb24fSFrançois Tigeot 		return DP_TEST_NAK;
4084a85cb24fSFrançois Tigeot 	if (test_misc & DP_TEST_DYNAMIC_RANGE_CEA)
4085a85cb24fSFrançois Tigeot 		return DP_TEST_NAK;
4086a85cb24fSFrançois Tigeot 	switch (test_misc & DP_TEST_BIT_DEPTH_MASK) {
4087a85cb24fSFrançois Tigeot 	case DP_TEST_BIT_DEPTH_6:
4088a85cb24fSFrançois Tigeot 		intel_dp->compliance.test_data.bpc = 6;
4089a85cb24fSFrançois Tigeot 		break;
4090a85cb24fSFrançois Tigeot 	case DP_TEST_BIT_DEPTH_8:
4091a85cb24fSFrançois Tigeot 		intel_dp->compliance.test_data.bpc = 8;
4092a85cb24fSFrançois Tigeot 		break;
4093a85cb24fSFrançois Tigeot 	default:
4094a85cb24fSFrançois Tigeot 		return DP_TEST_NAK;
4095a85cb24fSFrançois Tigeot 	}
4096a85cb24fSFrançois Tigeot 
4097a85cb24fSFrançois Tigeot 	intel_dp->compliance.test_data.video_pattern = test_pattern;
4098a85cb24fSFrançois Tigeot 	intel_dp->compliance.test_data.hdisplay = be16_to_cpu(h_width);
4099a85cb24fSFrançois Tigeot 	intel_dp->compliance.test_data.vdisplay = be16_to_cpu(v_height);
4100a85cb24fSFrançois Tigeot 	/* Set test active flag here so userspace doesn't interrupt things */
4101a85cb24fSFrançois Tigeot 	intel_dp->compliance.test_active = 1;
4102a85cb24fSFrançois Tigeot 
4103a85cb24fSFrançois Tigeot 	return DP_TEST_ACK;
410419c468b4SFrançois Tigeot }
410519c468b4SFrançois Tigeot 
intel_dp_autotest_edid(struct intel_dp * intel_dp)410619c468b4SFrançois Tigeot static uint8_t intel_dp_autotest_edid(struct intel_dp *intel_dp)
410719c468b4SFrançois Tigeot {
4108a85cb24fSFrançois Tigeot 	uint8_t test_result = DP_TEST_ACK;
410919c468b4SFrançois Tigeot 	struct intel_connector *intel_connector = intel_dp->attached_connector;
411019c468b4SFrançois Tigeot 	struct drm_connector *connector = &intel_connector->base;
411119c468b4SFrançois Tigeot 
411219c468b4SFrançois Tigeot 	if (intel_connector->detect_edid == NULL ||
411319c468b4SFrançois Tigeot 	    connector->edid_corrupt ||
411419c468b4SFrançois Tigeot 	    intel_dp->aux.i2c_defer_count > 6) {
411519c468b4SFrançois Tigeot 		/* Check EDID read for NACKs, DEFERs and corruption
411619c468b4SFrançois Tigeot 		 * (DP CTS 1.2 Core r1.1)
411719c468b4SFrançois Tigeot 		 *    4.2.2.4 : Failed EDID read, I2C_NAK
411819c468b4SFrançois Tigeot 		 *    4.2.2.5 : Failed EDID read, I2C_DEFER
411919c468b4SFrançois Tigeot 		 *    4.2.2.6 : EDID corruption detected
412019c468b4SFrançois Tigeot 		 * Use failsafe mode for all cases
412119c468b4SFrançois Tigeot 		 */
412219c468b4SFrançois Tigeot 		if (intel_dp->aux.i2c_nack_count > 0 ||
412319c468b4SFrançois Tigeot 			intel_dp->aux.i2c_defer_count > 0)
412419c468b4SFrançois Tigeot 			DRM_DEBUG_KMS("EDID read had %d NACKs, %d DEFERs\n",
412519c468b4SFrançois Tigeot 				      intel_dp->aux.i2c_nack_count,
412619c468b4SFrançois Tigeot 				      intel_dp->aux.i2c_defer_count);
4127a85cb24fSFrançois Tigeot 		intel_dp->compliance.test_data.edid = INTEL_DP_RESOLUTION_FAILSAFE;
412819c468b4SFrançois Tigeot 	} else {
4129a05eeebfSFrançois Tigeot 		struct edid *block = intel_connector->detect_edid;
4130a05eeebfSFrançois Tigeot 
4131a05eeebfSFrançois Tigeot 		/* We have to write the checksum
4132a05eeebfSFrançois Tigeot 		 * of the last block read
4133a05eeebfSFrançois Tigeot 		 */
4134a05eeebfSFrançois Tigeot 		block += intel_connector->detect_edid->extensions;
4135a05eeebfSFrançois Tigeot 
4136*3f2dd94aSFrançois Tigeot 		if (drm_dp_dpcd_writeb(&intel_dp->aux, DP_TEST_EDID_CHECKSUM,
4137*3f2dd94aSFrançois Tigeot 				       block->checksum) <= 0)
413819c468b4SFrançois Tigeot 			DRM_DEBUG_KMS("Failed to write EDID checksum\n");
413919c468b4SFrançois Tigeot 
414019c468b4SFrançois Tigeot 		test_result = DP_TEST_ACK | DP_TEST_EDID_CHECKSUM_WRITE;
4141a85cb24fSFrançois Tigeot 		intel_dp->compliance.test_data.edid = INTEL_DP_RESOLUTION_PREFERRED;
414219c468b4SFrançois Tigeot 	}
414319c468b4SFrançois Tigeot 
414419c468b4SFrançois Tigeot 	/* Set test active flag here so userspace doesn't interrupt things */
4145a85cb24fSFrançois Tigeot 	intel_dp->compliance.test_active = 1;
414619c468b4SFrançois Tigeot 
414719c468b4SFrançois Tigeot 	return test_result;
414819c468b4SFrançois Tigeot }
414919c468b4SFrançois Tigeot 
intel_dp_autotest_phy_pattern(struct intel_dp * intel_dp)415019c468b4SFrançois Tigeot static uint8_t intel_dp_autotest_phy_pattern(struct intel_dp *intel_dp)
415119c468b4SFrançois Tigeot {
415219c468b4SFrançois Tigeot 	uint8_t test_result = DP_TEST_NAK;
415319c468b4SFrançois Tigeot 	return test_result;
415419c468b4SFrançois Tigeot }
415519c468b4SFrançois Tigeot 
intel_dp_handle_test_request(struct intel_dp * intel_dp)415619c468b4SFrançois Tigeot static void intel_dp_handle_test_request(struct intel_dp *intel_dp)
415719c468b4SFrançois Tigeot {
415819c468b4SFrançois Tigeot 	uint8_t response = DP_TEST_NAK;
4159a85cb24fSFrançois Tigeot 	uint8_t request = 0;
4160a85cb24fSFrançois Tigeot 	int status;
416119c468b4SFrançois Tigeot 
4162a85cb24fSFrançois Tigeot 	status = drm_dp_dpcd_readb(&intel_dp->aux, DP_TEST_REQUEST, &request);
416319c468b4SFrançois Tigeot 	if (status <= 0) {
416419c468b4SFrançois Tigeot 		DRM_DEBUG_KMS("Could not read test request from sink\n");
416519c468b4SFrançois Tigeot 		goto update_status;
416619c468b4SFrançois Tigeot 	}
416719c468b4SFrançois Tigeot 
4168a85cb24fSFrançois Tigeot 	switch (request) {
416919c468b4SFrançois Tigeot 	case DP_TEST_LINK_TRAINING:
417019c468b4SFrançois Tigeot 		DRM_DEBUG_KMS("LINK_TRAINING test requested\n");
417119c468b4SFrançois Tigeot 		response = intel_dp_autotest_link_training(intel_dp);
417219c468b4SFrançois Tigeot 		break;
417319c468b4SFrançois Tigeot 	case DP_TEST_LINK_VIDEO_PATTERN:
417419c468b4SFrançois Tigeot 		DRM_DEBUG_KMS("TEST_PATTERN test requested\n");
417519c468b4SFrançois Tigeot 		response = intel_dp_autotest_video_pattern(intel_dp);
417619c468b4SFrançois Tigeot 		break;
417719c468b4SFrançois Tigeot 	case DP_TEST_LINK_EDID_READ:
417819c468b4SFrançois Tigeot 		DRM_DEBUG_KMS("EDID test requested\n");
417919c468b4SFrançois Tigeot 		response = intel_dp_autotest_edid(intel_dp);
418019c468b4SFrançois Tigeot 		break;
418119c468b4SFrançois Tigeot 	case DP_TEST_LINK_PHY_TEST_PATTERN:
418219c468b4SFrançois Tigeot 		DRM_DEBUG_KMS("PHY_PATTERN test requested\n");
418319c468b4SFrançois Tigeot 		response = intel_dp_autotest_phy_pattern(intel_dp);
418419c468b4SFrançois Tigeot 		break;
418519c468b4SFrançois Tigeot 	default:
4186a85cb24fSFrançois Tigeot 		DRM_DEBUG_KMS("Invalid test request '%02x'\n", request);
418719c468b4SFrançois Tigeot 		break;
418819c468b4SFrançois Tigeot 	}
418919c468b4SFrançois Tigeot 
4190a85cb24fSFrançois Tigeot 	if (response & DP_TEST_ACK)
4191a85cb24fSFrançois Tigeot 		intel_dp->compliance.test_type = request;
4192a85cb24fSFrançois Tigeot 
419319c468b4SFrançois Tigeot update_status:
4194a85cb24fSFrançois Tigeot 	status = drm_dp_dpcd_writeb(&intel_dp->aux, DP_TEST_RESPONSE, response);
419519c468b4SFrançois Tigeot 	if (status <= 0)
419619c468b4SFrançois Tigeot 		DRM_DEBUG_KMS("Could not write test response to sink\n");
4197e3adcf8fSFrançois Tigeot }
4198e3adcf8fSFrançois Tigeot 
41992c9916cdSFrançois Tigeot static int
intel_dp_check_mst_status(struct intel_dp * intel_dp)42002c9916cdSFrançois Tigeot intel_dp_check_mst_status(struct intel_dp *intel_dp)
42012c9916cdSFrançois Tigeot {
42022c9916cdSFrançois Tigeot 	bool bret;
42032c9916cdSFrançois Tigeot 
42042c9916cdSFrançois Tigeot 	if (intel_dp->is_mst) {
4205*3f2dd94aSFrançois Tigeot 		u8 esi[DP_DPRX_ESI_LEN] = { 0 };
42062c9916cdSFrançois Tigeot 		int ret = 0;
42072c9916cdSFrançois Tigeot 		int retry;
42082c9916cdSFrançois Tigeot 		bool handled;
42092c9916cdSFrançois Tigeot 		bret = intel_dp_get_sink_irq_esi(intel_dp, esi);
42102c9916cdSFrançois Tigeot go_again:
42112c9916cdSFrançois Tigeot 		if (bret == true) {
42122c9916cdSFrançois Tigeot 
42132c9916cdSFrançois Tigeot 			/* check link status - esi[10] = 0x200c */
4214352ff8bdSFrançois Tigeot 			if (intel_dp->active_mst_links &&
4215352ff8bdSFrançois Tigeot 			    !drm_dp_channel_eq_ok(&esi[10], intel_dp->lane_count)) {
42162c9916cdSFrançois Tigeot 				DRM_DEBUG_KMS("channel EQ not ok, retraining\n");
42172c9916cdSFrançois Tigeot 				intel_dp_start_link_train(intel_dp);
42182c9916cdSFrançois Tigeot 				intel_dp_stop_link_train(intel_dp);
42192c9916cdSFrançois Tigeot 			}
42202c9916cdSFrançois Tigeot 
42212c9916cdSFrançois Tigeot 			DRM_DEBUG_KMS("got esi %3ph\n", esi);
42222c9916cdSFrançois Tigeot 			ret = drm_dp_mst_hpd_irq(&intel_dp->mst_mgr, esi, &handled);
42232c9916cdSFrançois Tigeot 
42242c9916cdSFrançois Tigeot 			if (handled) {
42252c9916cdSFrançois Tigeot 				for (retry = 0; retry < 3; retry++) {
42262c9916cdSFrançois Tigeot 					int wret;
42272c9916cdSFrançois Tigeot 					wret = drm_dp_dpcd_write(&intel_dp->aux,
42282c9916cdSFrançois Tigeot 								 DP_SINK_COUNT_ESI+1,
42292c9916cdSFrançois Tigeot 								 &esi[1], 3);
42302c9916cdSFrançois Tigeot 					if (wret == 3) {
42312c9916cdSFrançois Tigeot 						break;
42322c9916cdSFrançois Tigeot 					}
42332c9916cdSFrançois Tigeot 				}
42342c9916cdSFrançois Tigeot 
42352c9916cdSFrançois Tigeot 				bret = intel_dp_get_sink_irq_esi(intel_dp, esi);
42362c9916cdSFrançois Tigeot 				if (bret == true) {
42372c9916cdSFrançois Tigeot 					DRM_DEBUG_KMS("got esi2 %3ph\n", esi);
42382c9916cdSFrançois Tigeot 					goto go_again;
42392c9916cdSFrançois Tigeot 				}
42402c9916cdSFrançois Tigeot 			} else
42412c9916cdSFrançois Tigeot 				ret = 0;
42422c9916cdSFrançois Tigeot 
42432c9916cdSFrançois Tigeot 			return ret;
42442c9916cdSFrançois Tigeot 		} else {
42452c9916cdSFrançois Tigeot 			struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp);
42462c9916cdSFrançois Tigeot 			DRM_DEBUG_KMS("failed to get ESI - device may have failed\n");
42472c9916cdSFrançois Tigeot 			intel_dp->is_mst = false;
42482c9916cdSFrançois Tigeot 			drm_dp_mst_topology_mgr_set_mst(&intel_dp->mst_mgr, intel_dp->is_mst);
42492c9916cdSFrançois Tigeot 			/* send a hotplug event */
42502c9916cdSFrançois Tigeot 			drm_kms_helper_hotplug_event(intel_dig_port->base.base.dev);
42512c9916cdSFrançois Tigeot 		}
42522c9916cdSFrançois Tigeot 	}
42532c9916cdSFrançois Tigeot 	return -EINVAL;
42542c9916cdSFrançois Tigeot }
42552c9916cdSFrançois Tigeot 
42568621f407SFrançois Tigeot static void
intel_dp_retrain_link(struct intel_dp * intel_dp)42571e12ee3bSFrançois Tigeot intel_dp_retrain_link(struct intel_dp *intel_dp)
42581e12ee3bSFrançois Tigeot {
42591e12ee3bSFrançois Tigeot 	struct intel_encoder *encoder = &dp_to_dig_port(intel_dp)->base;
42601e12ee3bSFrançois Tigeot 	struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
42611e12ee3bSFrançois Tigeot 	struct intel_crtc *crtc = to_intel_crtc(encoder->base.crtc);
42621e12ee3bSFrançois Tigeot 
42631e12ee3bSFrançois Tigeot 	/* Suppress underruns caused by re-training */
42641e12ee3bSFrançois Tigeot 	intel_set_cpu_fifo_underrun_reporting(dev_priv, crtc->pipe, false);
42651e12ee3bSFrançois Tigeot 	if (crtc->config->has_pch_encoder)
42661e12ee3bSFrançois Tigeot 		intel_set_pch_fifo_underrun_reporting(dev_priv,
42671e12ee3bSFrançois Tigeot 						      intel_crtc_pch_transcoder(crtc), false);
42681e12ee3bSFrançois Tigeot 
42691e12ee3bSFrançois Tigeot 	intel_dp_start_link_train(intel_dp);
42701e12ee3bSFrançois Tigeot 	intel_dp_stop_link_train(intel_dp);
42711e12ee3bSFrançois Tigeot 
42721e12ee3bSFrançois Tigeot 	/* Keep underrun reporting disabled until things are stable */
42734be47400SFrançois Tigeot 	intel_wait_for_vblank(dev_priv, crtc->pipe);
42741e12ee3bSFrançois Tigeot 
42751e12ee3bSFrançois Tigeot 	intel_set_cpu_fifo_underrun_reporting(dev_priv, crtc->pipe, true);
42761e12ee3bSFrançois Tigeot 	if (crtc->config->has_pch_encoder)
42771e12ee3bSFrançois Tigeot 		intel_set_pch_fifo_underrun_reporting(dev_priv,
42781e12ee3bSFrançois Tigeot 						      intel_crtc_pch_transcoder(crtc), true);
42791e12ee3bSFrançois Tigeot }
42801e12ee3bSFrançois Tigeot 
42811e12ee3bSFrançois Tigeot static void
intel_dp_check_link_status(struct intel_dp * intel_dp)42828621f407SFrançois Tigeot intel_dp_check_link_status(struct intel_dp *intel_dp)
42838621f407SFrançois Tigeot {
42848621f407SFrançois Tigeot 	struct intel_encoder *intel_encoder = &dp_to_dig_port(intel_dp)->base;
42858621f407SFrançois Tigeot 	struct drm_device *dev = intel_dp_to_dev(intel_dp);
42868621f407SFrançois Tigeot 	u8 link_status[DP_LINK_STATUS_SIZE];
42878621f407SFrançois Tigeot 
42888621f407SFrançois Tigeot 	WARN_ON(!drm_modeset_is_locked(&dev->mode_config.connection_mutex));
42898621f407SFrançois Tigeot 
42908621f407SFrançois Tigeot 	if (!intel_dp_get_link_status(intel_dp, link_status)) {
42918621f407SFrançois Tigeot 		DRM_ERROR("Failed to get link status\n");
42928621f407SFrançois Tigeot 		return;
42938621f407SFrançois Tigeot 	}
42948621f407SFrançois Tigeot 
42958621f407SFrançois Tigeot 	if (!intel_encoder->base.crtc)
42968621f407SFrançois Tigeot 		return;
42978621f407SFrançois Tigeot 
42988621f407SFrançois Tigeot 	if (!to_intel_crtc(intel_encoder->base.crtc)->active)
42998621f407SFrançois Tigeot 		return;
43008621f407SFrançois Tigeot 
4301*3f2dd94aSFrançois Tigeot 	/*
4302*3f2dd94aSFrançois Tigeot 	 * Validate the cached values of intel_dp->link_rate and
4303*3f2dd94aSFrançois Tigeot 	 * intel_dp->lane_count before attempting to retrain.
4304*3f2dd94aSFrançois Tigeot 	 */
4305*3f2dd94aSFrançois Tigeot 	if (!intel_dp_link_params_valid(intel_dp, intel_dp->link_rate,
4306*3f2dd94aSFrançois Tigeot 					intel_dp->lane_count))
43071e12ee3bSFrançois Tigeot 		return;
43081e12ee3bSFrançois Tigeot 
4309a85cb24fSFrançois Tigeot 	/* Retrain if Channel EQ or CR not ok */
4310a85cb24fSFrançois Tigeot 	if (!drm_dp_channel_eq_ok(link_status, intel_dp->lane_count)) {
43118621f407SFrançois Tigeot 		DRM_DEBUG_KMS("%s: channel EQ not ok, retraining\n",
43128621f407SFrançois Tigeot 			      intel_encoder->base.name);
43131e12ee3bSFrançois Tigeot 
43141e12ee3bSFrançois Tigeot 		intel_dp_retrain_link(intel_dp);
43158621f407SFrançois Tigeot 	}
43168621f407SFrançois Tigeot }
43178621f407SFrançois Tigeot 
4318e3adcf8fSFrançois Tigeot /*
4319e3adcf8fSFrançois Tigeot  * According to DP spec
4320e3adcf8fSFrançois Tigeot  * 5.1.2:
4321e3adcf8fSFrançois Tigeot  *  1. Read DPCD
4322e3adcf8fSFrançois Tigeot  *  2. Configure link according to Receiver Capabilities
4323e3adcf8fSFrançois Tigeot  *  3. Use Link Training from 2.5.3.3 and 3.5.1.3
4324e3adcf8fSFrançois Tigeot  *  4. Check link status on receipt of hot-plug interrupt
43258621f407SFrançois Tigeot  *
43268621f407SFrançois Tigeot  * intel_dp_short_pulse -  handles short pulse interrupts
43278621f407SFrançois Tigeot  * when full detection is not required.
43288621f407SFrançois Tigeot  * Returns %true if short pulse is handled and full detection
43298621f407SFrançois Tigeot  * is NOT required and %false otherwise.
4330e3adcf8fSFrançois Tigeot  */
43318621f407SFrançois Tigeot static bool
intel_dp_short_pulse(struct intel_dp * intel_dp)43328621f407SFrançois Tigeot intel_dp_short_pulse(struct intel_dp *intel_dp)
4333e3adcf8fSFrançois Tigeot {
433424edb884SFrançois Tigeot 	struct drm_device *dev = intel_dp_to_dev(intel_dp);
4335a85cb24fSFrançois Tigeot 	struct intel_encoder *intel_encoder = &dp_to_dig_port(intel_dp)->base;
433671f41f3eSFrançois Tigeot 	u8 sink_irq_vector = 0;
43378621f407SFrançois Tigeot 	u8 old_sink_count = intel_dp->sink_count;
43388621f407SFrançois Tigeot 	bool ret;
433924edb884SFrançois Tigeot 
4340aee94f86SFrançois Tigeot 	/*
4341aee94f86SFrançois Tigeot 	 * Clearing compliance test variables to allow capturing
4342aee94f86SFrançois Tigeot 	 * of values for next automated test request.
4343aee94f86SFrançois Tigeot 	 */
4344a85cb24fSFrançois Tigeot 	memset(&intel_dp->compliance, 0, sizeof(intel_dp->compliance));
4345aee94f86SFrançois Tigeot 
43468621f407SFrançois Tigeot 	/*
43478621f407SFrançois Tigeot 	 * Now read the DPCD to see if it's actually running
43488621f407SFrançois Tigeot 	 * If the current value of sink count doesn't match with
43498621f407SFrançois Tigeot 	 * the value that was stored earlier or dpcd read failed
43508621f407SFrançois Tigeot 	 * we need to do full detection
43518621f407SFrançois Tigeot 	 */
43528621f407SFrançois Tigeot 	ret = intel_dp_get_dpcd(intel_dp);
4353e3adcf8fSFrançois Tigeot 
43548621f407SFrançois Tigeot 	if ((old_sink_count != intel_dp->sink_count) || !ret) {
43558621f407SFrançois Tigeot 		/* No need to proceed if we are going to do full detect */
43568621f407SFrançois Tigeot 		return false;
4357e3adcf8fSFrançois Tigeot 	}
4358e3adcf8fSFrançois Tigeot 
4359e3adcf8fSFrançois Tigeot 	/* Try to read the source of the interrupt */
4360e3adcf8fSFrançois Tigeot 	if (intel_dp->dpcd[DP_DPCD_REV] >= 0x11 &&
436171f41f3eSFrançois Tigeot 	    intel_dp_get_sink_irq(intel_dp, &sink_irq_vector) &&
436271f41f3eSFrançois Tigeot 	    sink_irq_vector != 0) {
4363e3adcf8fSFrançois Tigeot 		/* Clear interrupt source */
43646b231eabSImre Vadász 		drm_dp_dpcd_writeb(&intel_dp->aux,
4365e3adcf8fSFrançois Tigeot 				   DP_DEVICE_SERVICE_IRQ_VECTOR,
4366e3adcf8fSFrançois Tigeot 				   sink_irq_vector);
4367e3adcf8fSFrançois Tigeot 
4368e3adcf8fSFrançois Tigeot 		if (sink_irq_vector & DP_AUTOMATED_TEST_REQUEST)
4369a85cb24fSFrançois Tigeot 			intel_dp_handle_test_request(intel_dp);
4370e3adcf8fSFrançois Tigeot 		if (sink_irq_vector & (DP_CP_IRQ | DP_SINK_SPECIFIC_IRQ))
4371e3440f96SFrançois Tigeot 			DRM_DEBUG_DRIVER("CP or sink specific irq unhandled\n");
4372e3adcf8fSFrançois Tigeot 	}
4373e3adcf8fSFrançois Tigeot 
43748621f407SFrançois Tigeot 	drm_modeset_lock(&dev->mode_config.connection_mutex, NULL);
43758621f407SFrançois Tigeot 	intel_dp_check_link_status(intel_dp);
43768621f407SFrançois Tigeot 	drm_modeset_unlock(&dev->mode_config.connection_mutex);
4377a85cb24fSFrançois Tigeot 	if (intel_dp->compliance.test_type == DP_TEST_LINK_TRAINING) {
4378a85cb24fSFrançois Tigeot 		DRM_DEBUG_KMS("Link Training Compliance Test requested\n");
4379a85cb24fSFrançois Tigeot 		/* Send a Hotplug Uevent to userspace to start modeset */
4380a85cb24fSFrançois Tigeot 		drm_kms_helper_hotplug_event(intel_encoder->base.dev);
4381a85cb24fSFrançois Tigeot 	}
43828621f407SFrançois Tigeot 
43838621f407SFrançois Tigeot 	return true;
4384e3adcf8fSFrançois Tigeot }
4385e3adcf8fSFrançois Tigeot 
438619df918dSFrançois Tigeot /* XXX this is probably wrong for multiple downstream ports */
4387e3adcf8fSFrançois Tigeot static enum drm_connector_status
intel_dp_detect_dpcd(struct intel_dp * intel_dp)4388e3adcf8fSFrançois Tigeot intel_dp_detect_dpcd(struct intel_dp *intel_dp)
4389e3adcf8fSFrançois Tigeot {
4390a85cb24fSFrançois Tigeot 	struct intel_lspcon *lspcon = dp_to_lspcon(intel_dp);
439119df918dSFrançois Tigeot 	uint8_t *dpcd = intel_dp->dpcd;
439219df918dSFrançois Tigeot 	uint8_t type;
439319df918dSFrançois Tigeot 
4394a85cb24fSFrançois Tigeot 	if (lspcon->active)
4395a85cb24fSFrançois Tigeot 		lspcon_resume(lspcon);
4396a85cb24fSFrançois Tigeot 
439719df918dSFrançois Tigeot 	if (!intel_dp_get_dpcd(intel_dp))
439819df918dSFrançois Tigeot 		return connector_status_disconnected;
439919df918dSFrançois Tigeot 
4400*3f2dd94aSFrançois Tigeot 	if (intel_dp_is_edp(intel_dp))
44018621f407SFrançois Tigeot 		return connector_status_connected;
44028621f407SFrançois Tigeot 
440319df918dSFrançois Tigeot 	/* if there's no downstream port, we're done */
44044be47400SFrançois Tigeot 	if (!drm_dp_is_branch(dpcd))
4405e3adcf8fSFrançois Tigeot 		return connector_status_connected;
440619df918dSFrançois Tigeot 
440719df918dSFrançois Tigeot 	/* If we're HPD-aware, SINK_COUNT changes dynamically */
44089edbd4a0SFrançois Tigeot 	if (intel_dp->dpcd[DP_DPCD_REV] >= 0x11 &&
44099edbd4a0SFrançois Tigeot 	    intel_dp->downstream_ports[0] & DP_DS_PORT_HPD) {
44106b231eabSImre Vadász 
44118621f407SFrançois Tigeot 		return intel_dp->sink_count ?
44128621f407SFrançois Tigeot 		connector_status_connected : connector_status_disconnected;
441319df918dSFrançois Tigeot 	}
441419df918dSFrançois Tigeot 
441571f41f3eSFrançois Tigeot 	if (intel_dp_can_mst(intel_dp))
441671f41f3eSFrançois Tigeot 		return connector_status_connected;
441771f41f3eSFrançois Tigeot 
441819df918dSFrançois Tigeot 	/* If no HPD, poke DDC gently */
44199f4ca867SFrançois Tigeot 	if (drm_probe_ddc(&intel_dp->aux.ddc))
442019df918dSFrançois Tigeot 		return connector_status_connected;
442119df918dSFrançois Tigeot 
442219df918dSFrançois Tigeot 	/* Well we tried, say unknown for unreliable port types */
44239edbd4a0SFrançois Tigeot 	if (intel_dp->dpcd[DP_DPCD_REV] >= 0x11) {
442419df918dSFrançois Tigeot 		type = intel_dp->downstream_ports[0] & DP_DS_PORT_TYPE_MASK;
44259edbd4a0SFrançois Tigeot 		if (type == DP_DS_PORT_TYPE_VGA ||
44269edbd4a0SFrançois Tigeot 		    type == DP_DS_PORT_TYPE_NON_EDID)
442719df918dSFrançois Tigeot 			return connector_status_unknown;
44289edbd4a0SFrançois Tigeot 	} else {
44299edbd4a0SFrançois Tigeot 		type = intel_dp->dpcd[DP_DOWNSTREAMPORT_PRESENT] &
44309edbd4a0SFrançois Tigeot 			DP_DWN_STRM_PORT_TYPE_MASK;
44319edbd4a0SFrançois Tigeot 		if (type == DP_DWN_STRM_PORT_TYPE_ANALOG ||
44329edbd4a0SFrançois Tigeot 		    type == DP_DWN_STRM_PORT_TYPE_OTHER)
44339edbd4a0SFrançois Tigeot 			return connector_status_unknown;
44349edbd4a0SFrançois Tigeot 	}
443519df918dSFrançois Tigeot 
443619df918dSFrançois Tigeot 	/* Anything else is out of spec, warn and ignore */
443719df918dSFrançois Tigeot 	DRM_DEBUG_KMS("Broken DP branch device, ignoring\n");
4438e3adcf8fSFrançois Tigeot 	return connector_status_disconnected;
4439e3adcf8fSFrançois Tigeot }
4440e3adcf8fSFrançois Tigeot 
4441e3adcf8fSFrançois Tigeot static enum drm_connector_status
edp_detect(struct intel_dp * intel_dp)44421b13d190SFrançois Tigeot edp_detect(struct intel_dp *intel_dp)
44431b13d190SFrançois Tigeot {
44441b13d190SFrançois Tigeot 	struct drm_device *dev = intel_dp_to_dev(intel_dp);
4445a85cb24fSFrançois Tigeot 	struct drm_i915_private *dev_priv = to_i915(dev);
44461b13d190SFrançois Tigeot 	enum drm_connector_status status;
44471b13d190SFrançois Tigeot 
4448a85cb24fSFrançois Tigeot 	status = intel_panel_detect(dev_priv);
44491b13d190SFrançois Tigeot 	if (status == connector_status_unknown)
44501b13d190SFrançois Tigeot 		status = connector_status_connected;
44511b13d190SFrançois Tigeot 
44521b13d190SFrançois Tigeot 	return status;
44531b13d190SFrançois Tigeot }
44541b13d190SFrançois Tigeot 
ibx_digital_port_connected(struct drm_i915_private * dev_priv,struct intel_digital_port * port)4455352ff8bdSFrançois Tigeot static bool ibx_digital_port_connected(struct drm_i915_private *dev_priv,
4456352ff8bdSFrançois Tigeot 				       struct intel_digital_port *port)
4457e3adcf8fSFrançois Tigeot {
4458352ff8bdSFrançois Tigeot 	u32 bit;
4459e3adcf8fSFrançois Tigeot 
4460352ff8bdSFrançois Tigeot 	switch (port->port) {
44612c9916cdSFrançois Tigeot 	case PORT_B:
4462352ff8bdSFrançois Tigeot 		bit = SDE_PORTB_HOTPLUG;
44632c9916cdSFrançois Tigeot 		break;
44642c9916cdSFrançois Tigeot 	case PORT_C:
4465352ff8bdSFrançois Tigeot 		bit = SDE_PORTC_HOTPLUG;
44662c9916cdSFrançois Tigeot 		break;
44672c9916cdSFrançois Tigeot 	case PORT_D:
4468352ff8bdSFrançois Tigeot 		bit = SDE_PORTD_HOTPLUG;
44692c9916cdSFrançois Tigeot 		break;
44702c9916cdSFrançois Tigeot 	default:
4471352ff8bdSFrançois Tigeot 		MISSING_CASE(port->port);
4472352ff8bdSFrançois Tigeot 		return false;
44732c9916cdSFrançois Tigeot 	}
4474352ff8bdSFrançois Tigeot 
4475352ff8bdSFrançois Tigeot 	return I915_READ(SDEISR) & bit;
4476352ff8bdSFrançois Tigeot }
4477352ff8bdSFrançois Tigeot 
cpt_digital_port_connected(struct drm_i915_private * dev_priv,struct intel_digital_port * port)4478352ff8bdSFrançois Tigeot static bool cpt_digital_port_connected(struct drm_i915_private *dev_priv,
4479352ff8bdSFrançois Tigeot 				       struct intel_digital_port *port)
4480352ff8bdSFrançois Tigeot {
4481352ff8bdSFrançois Tigeot 	u32 bit;
4482352ff8bdSFrançois Tigeot 
4483352ff8bdSFrançois Tigeot 	switch (port->port) {
4484352ff8bdSFrançois Tigeot 	case PORT_B:
4485352ff8bdSFrançois Tigeot 		bit = SDE_PORTB_HOTPLUG_CPT;
4486352ff8bdSFrançois Tigeot 		break;
4487352ff8bdSFrançois Tigeot 	case PORT_C:
4488352ff8bdSFrançois Tigeot 		bit = SDE_PORTC_HOTPLUG_CPT;
4489352ff8bdSFrançois Tigeot 		break;
4490352ff8bdSFrançois Tigeot 	case PORT_D:
4491352ff8bdSFrançois Tigeot 		bit = SDE_PORTD_HOTPLUG_CPT;
4492352ff8bdSFrançois Tigeot 		break;
4493*3f2dd94aSFrançois Tigeot 	default:
4494*3f2dd94aSFrançois Tigeot 		MISSING_CASE(port->port);
4495*3f2dd94aSFrançois Tigeot 		return false;
4496*3f2dd94aSFrançois Tigeot 	}
4497*3f2dd94aSFrançois Tigeot 
4498*3f2dd94aSFrançois Tigeot 	return I915_READ(SDEISR) & bit;
4499*3f2dd94aSFrançois Tigeot }
4500*3f2dd94aSFrançois Tigeot 
spt_digital_port_connected(struct drm_i915_private * dev_priv,struct intel_digital_port * port)4501*3f2dd94aSFrançois Tigeot static bool spt_digital_port_connected(struct drm_i915_private *dev_priv,
4502*3f2dd94aSFrançois Tigeot 				       struct intel_digital_port *port)
4503*3f2dd94aSFrançois Tigeot {
4504*3f2dd94aSFrançois Tigeot 	u32 bit;
4505*3f2dd94aSFrançois Tigeot 
4506*3f2dd94aSFrançois Tigeot 	switch (port->port) {
4507*3f2dd94aSFrançois Tigeot 	case PORT_A:
4508*3f2dd94aSFrançois Tigeot 		bit = SDE_PORTA_HOTPLUG_SPT;
4509*3f2dd94aSFrançois Tigeot 		break;
4510352ff8bdSFrançois Tigeot 	case PORT_E:
4511352ff8bdSFrançois Tigeot 		bit = SDE_PORTE_HOTPLUG_SPT;
4512352ff8bdSFrançois Tigeot 		break;
4513352ff8bdSFrançois Tigeot 	default:
4514*3f2dd94aSFrançois Tigeot 		return cpt_digital_port_connected(dev_priv, port);
4515352ff8bdSFrançois Tigeot 	}
4516352ff8bdSFrançois Tigeot 
4517352ff8bdSFrançois Tigeot 	return I915_READ(SDEISR) & bit;
4518352ff8bdSFrançois Tigeot }
4519352ff8bdSFrançois Tigeot 
g4x_digital_port_connected(struct drm_i915_private * dev_priv,struct intel_digital_port * port)4520352ff8bdSFrançois Tigeot static bool g4x_digital_port_connected(struct drm_i915_private *dev_priv,
4521352ff8bdSFrançois Tigeot 				       struct intel_digital_port *port)
4522352ff8bdSFrançois Tigeot {
4523352ff8bdSFrançois Tigeot 	u32 bit;
4524352ff8bdSFrançois Tigeot 
4525352ff8bdSFrançois Tigeot 	switch (port->port) {
45262c9916cdSFrançois Tigeot 	case PORT_B:
45272c9916cdSFrançois Tigeot 		bit = PORTB_HOTPLUG_LIVE_STATUS_G4X;
45282c9916cdSFrançois Tigeot 		break;
45292c9916cdSFrançois Tigeot 	case PORT_C:
45302c9916cdSFrançois Tigeot 		bit = PORTC_HOTPLUG_LIVE_STATUS_G4X;
45312c9916cdSFrançois Tigeot 		break;
45322c9916cdSFrançois Tigeot 	case PORT_D:
45332c9916cdSFrançois Tigeot 		bit = PORTD_HOTPLUG_LIVE_STATUS_G4X;
45342c9916cdSFrançois Tigeot 		break;
45352c9916cdSFrançois Tigeot 	default:
4536352ff8bdSFrançois Tigeot 		MISSING_CASE(port->port);
4537352ff8bdSFrançois Tigeot 		return false;
45382c9916cdSFrançois Tigeot 	}
45392c9916cdSFrançois Tigeot 
4540352ff8bdSFrançois Tigeot 	return I915_READ(PORT_HOTPLUG_STAT) & bit;
4541352ff8bdSFrançois Tigeot }
4542352ff8bdSFrançois Tigeot 
gm45_digital_port_connected(struct drm_i915_private * dev_priv,struct intel_digital_port * port)4543aee94f86SFrançois Tigeot static bool gm45_digital_port_connected(struct drm_i915_private *dev_priv,
4544352ff8bdSFrançois Tigeot 					struct intel_digital_port *port)
4545352ff8bdSFrançois Tigeot {
4546352ff8bdSFrançois Tigeot 	u32 bit;
4547352ff8bdSFrançois Tigeot 
4548352ff8bdSFrançois Tigeot 	switch (port->port) {
4549352ff8bdSFrançois Tigeot 	case PORT_B:
4550aee94f86SFrançois Tigeot 		bit = PORTB_HOTPLUG_LIVE_STATUS_GM45;
4551352ff8bdSFrançois Tigeot 		break;
4552352ff8bdSFrançois Tigeot 	case PORT_C:
4553aee94f86SFrançois Tigeot 		bit = PORTC_HOTPLUG_LIVE_STATUS_GM45;
4554352ff8bdSFrançois Tigeot 		break;
4555352ff8bdSFrançois Tigeot 	case PORT_D:
4556aee94f86SFrançois Tigeot 		bit = PORTD_HOTPLUG_LIVE_STATUS_GM45;
4557352ff8bdSFrançois Tigeot 		break;
4558352ff8bdSFrançois Tigeot 	default:
4559352ff8bdSFrançois Tigeot 		MISSING_CASE(port->port);
4560352ff8bdSFrançois Tigeot 		return false;
4561352ff8bdSFrançois Tigeot 	}
4562352ff8bdSFrançois Tigeot 
4563352ff8bdSFrançois Tigeot 	return I915_READ(PORT_HOTPLUG_STAT) & bit;
4564352ff8bdSFrançois Tigeot }
4565352ff8bdSFrançois Tigeot 
ilk_digital_port_connected(struct drm_i915_private * dev_priv,struct intel_digital_port * port)4566*3f2dd94aSFrançois Tigeot static bool ilk_digital_port_connected(struct drm_i915_private *dev_priv,
4567*3f2dd94aSFrançois Tigeot 				       struct intel_digital_port *port)
4568*3f2dd94aSFrançois Tigeot {
4569*3f2dd94aSFrançois Tigeot 	if (port->port == PORT_A)
4570*3f2dd94aSFrançois Tigeot 		return I915_READ(DEISR) & DE_DP_A_HOTPLUG;
4571*3f2dd94aSFrançois Tigeot 	else
4572*3f2dd94aSFrançois Tigeot 		return ibx_digital_port_connected(dev_priv, port);
4573*3f2dd94aSFrançois Tigeot }
4574*3f2dd94aSFrançois Tigeot 
snb_digital_port_connected(struct drm_i915_private * dev_priv,struct intel_digital_port * port)4575*3f2dd94aSFrançois Tigeot static bool snb_digital_port_connected(struct drm_i915_private *dev_priv,
4576*3f2dd94aSFrançois Tigeot 				       struct intel_digital_port *port)
4577*3f2dd94aSFrançois Tigeot {
4578*3f2dd94aSFrançois Tigeot 	if (port->port == PORT_A)
4579*3f2dd94aSFrançois Tigeot 		return I915_READ(DEISR) & DE_DP_A_HOTPLUG;
4580*3f2dd94aSFrançois Tigeot 	else
4581*3f2dd94aSFrançois Tigeot 		return cpt_digital_port_connected(dev_priv, port);
4582*3f2dd94aSFrançois Tigeot }
4583*3f2dd94aSFrançois Tigeot 
ivb_digital_port_connected(struct drm_i915_private * dev_priv,struct intel_digital_port * port)4584*3f2dd94aSFrançois Tigeot static bool ivb_digital_port_connected(struct drm_i915_private *dev_priv,
4585*3f2dd94aSFrançois Tigeot 				       struct intel_digital_port *port)
4586*3f2dd94aSFrançois Tigeot {
4587*3f2dd94aSFrançois Tigeot 	if (port->port == PORT_A)
4588*3f2dd94aSFrançois Tigeot 		return I915_READ(DEISR) & DE_DP_A_HOTPLUG_IVB;
4589*3f2dd94aSFrançois Tigeot 	else
4590*3f2dd94aSFrançois Tigeot 		return cpt_digital_port_connected(dev_priv, port);
4591*3f2dd94aSFrançois Tigeot }
4592*3f2dd94aSFrançois Tigeot 
bdw_digital_port_connected(struct drm_i915_private * dev_priv,struct intel_digital_port * port)4593*3f2dd94aSFrançois Tigeot static bool bdw_digital_port_connected(struct drm_i915_private *dev_priv,
4594*3f2dd94aSFrançois Tigeot 				       struct intel_digital_port *port)
4595*3f2dd94aSFrançois Tigeot {
4596*3f2dd94aSFrançois Tigeot 	if (port->port == PORT_A)
4597*3f2dd94aSFrançois Tigeot 		return I915_READ(GEN8_DE_PORT_ISR) & GEN8_PORT_DP_A_HOTPLUG;
4598*3f2dd94aSFrançois Tigeot 	else
4599*3f2dd94aSFrançois Tigeot 		return cpt_digital_port_connected(dev_priv, port);
4600*3f2dd94aSFrançois Tigeot }
4601*3f2dd94aSFrançois Tigeot 
bxt_digital_port_connected(struct drm_i915_private * dev_priv,struct intel_digital_port * intel_dig_port)4602352ff8bdSFrançois Tigeot static bool bxt_digital_port_connected(struct drm_i915_private *dev_priv,
4603352ff8bdSFrançois Tigeot 				       struct intel_digital_port *intel_dig_port)
4604352ff8bdSFrançois Tigeot {
4605352ff8bdSFrançois Tigeot 	struct intel_encoder *intel_encoder = &intel_dig_port->base;
4606352ff8bdSFrançois Tigeot 	enum port port;
4607352ff8bdSFrançois Tigeot 	u32 bit;
4608352ff8bdSFrançois Tigeot 
4609*3f2dd94aSFrançois Tigeot 	port = intel_hpd_pin_to_port(intel_encoder->hpd_pin);
4610352ff8bdSFrançois Tigeot 	switch (port) {
4611352ff8bdSFrançois Tigeot 	case PORT_A:
4612352ff8bdSFrançois Tigeot 		bit = BXT_DE_PORT_HP_DDIA;
4613352ff8bdSFrançois Tigeot 		break;
4614352ff8bdSFrançois Tigeot 	case PORT_B:
4615352ff8bdSFrançois Tigeot 		bit = BXT_DE_PORT_HP_DDIB;
4616352ff8bdSFrançois Tigeot 		break;
4617352ff8bdSFrançois Tigeot 	case PORT_C:
4618352ff8bdSFrançois Tigeot 		bit = BXT_DE_PORT_HP_DDIC;
4619352ff8bdSFrançois Tigeot 		break;
4620352ff8bdSFrançois Tigeot 	default:
4621352ff8bdSFrançois Tigeot 		MISSING_CASE(port);
4622352ff8bdSFrançois Tigeot 		return false;
4623352ff8bdSFrançois Tigeot 	}
4624352ff8bdSFrançois Tigeot 
4625352ff8bdSFrançois Tigeot 	return I915_READ(GEN8_DE_PORT_ISR) & bit;
4626352ff8bdSFrançois Tigeot }
4627352ff8bdSFrançois Tigeot 
4628352ff8bdSFrançois Tigeot /*
4629352ff8bdSFrançois Tigeot  * intel_digital_port_connected - is the specified port connected?
4630352ff8bdSFrançois Tigeot  * @dev_priv: i915 private structure
4631352ff8bdSFrançois Tigeot  * @port: the port to test
4632352ff8bdSFrançois Tigeot  *
4633352ff8bdSFrançois Tigeot  * Return %true if @port is connected, %false otherwise.
4634352ff8bdSFrançois Tigeot  */
intel_digital_port_connected(struct drm_i915_private * dev_priv,struct intel_digital_port * port)46354be47400SFrançois Tigeot bool intel_digital_port_connected(struct drm_i915_private *dev_priv,
4636352ff8bdSFrançois Tigeot 				  struct intel_digital_port *port)
4637352ff8bdSFrançois Tigeot {
4638*3f2dd94aSFrançois Tigeot 	if (HAS_GMCH_DISPLAY(dev_priv)) {
4639*3f2dd94aSFrançois Tigeot 		if (IS_GM45(dev_priv))
4640aee94f86SFrançois Tigeot 			return gm45_digital_port_connected(dev_priv, port);
4641352ff8bdSFrançois Tigeot 		else
4642352ff8bdSFrançois Tigeot 			return g4x_digital_port_connected(dev_priv, port);
4643352ff8bdSFrançois Tigeot 	}
4644352ff8bdSFrançois Tigeot 
4645*3f2dd94aSFrançois Tigeot 	if (IS_GEN5(dev_priv))
4646*3f2dd94aSFrançois Tigeot 		return ilk_digital_port_connected(dev_priv, port);
4647*3f2dd94aSFrançois Tigeot 	else if (IS_GEN6(dev_priv))
4648*3f2dd94aSFrançois Tigeot 		return snb_digital_port_connected(dev_priv, port);
4649*3f2dd94aSFrançois Tigeot 	else if (IS_GEN7(dev_priv))
4650*3f2dd94aSFrançois Tigeot 		return ivb_digital_port_connected(dev_priv, port);
4651*3f2dd94aSFrançois Tigeot 	else if (IS_GEN8(dev_priv))
4652*3f2dd94aSFrançois Tigeot 		return bdw_digital_port_connected(dev_priv, port);
4653*3f2dd94aSFrançois Tigeot 	else if (IS_GEN9_LP(dev_priv))
4654*3f2dd94aSFrançois Tigeot 		return bxt_digital_port_connected(dev_priv, port);
4655*3f2dd94aSFrançois Tigeot 	else
4656*3f2dd94aSFrançois Tigeot 		return spt_digital_port_connected(dev_priv, port);
4657*3f2dd94aSFrançois Tigeot }
4658*3f2dd94aSFrançois Tigeot 
4659e3adcf8fSFrançois Tigeot static struct edid *
intel_dp_get_edid(struct intel_dp * intel_dp)46601b13d190SFrançois Tigeot intel_dp_get_edid(struct intel_dp *intel_dp)
4661e3adcf8fSFrançois Tigeot {
46621b13d190SFrançois Tigeot 	struct intel_connector *intel_connector = intel_dp->attached_connector;
4663e3adcf8fSFrançois Tigeot 
466419df918dSFrançois Tigeot 	/* use cached edid if we have one */
466519df918dSFrançois Tigeot 	if (intel_connector->edid) {
466619df918dSFrançois Tigeot 		/* invalid edid */
466719df918dSFrançois Tigeot 		if (IS_ERR(intel_connector->edid))
466819df918dSFrançois Tigeot 			return NULL;
466919df918dSFrançois Tigeot 
46709edbd4a0SFrançois Tigeot 		return drm_edid_duplicate(intel_connector->edid);
46711b13d190SFrançois Tigeot 	} else
46721b13d190SFrançois Tigeot 		return drm_get_edid(&intel_connector->base,
46739f4ca867SFrançois Tigeot 				    &intel_dp->aux.ddc);
4674e3adcf8fSFrançois Tigeot }
4675e3adcf8fSFrançois Tigeot 
46761b13d190SFrançois Tigeot static void
intel_dp_set_edid(struct intel_dp * intel_dp)46771b13d190SFrançois Tigeot intel_dp_set_edid(struct intel_dp *intel_dp)
467819df918dSFrançois Tigeot {
46791b13d190SFrançois Tigeot 	struct intel_connector *intel_connector = intel_dp->attached_connector;
46801b13d190SFrançois Tigeot 	struct edid *edid;
468119df918dSFrançois Tigeot 
46828621f407SFrançois Tigeot 	intel_dp_unset_edid(intel_dp);
46831b13d190SFrançois Tigeot 	edid = intel_dp_get_edid(intel_dp);
46841b13d190SFrançois Tigeot 	intel_connector->detect_edid = edid;
468519df918dSFrançois Tigeot 
46861b13d190SFrançois Tigeot 	intel_dp->has_audio = drm_detect_monitor_audio(edid);
468719df918dSFrançois Tigeot }
468819df918dSFrançois Tigeot 
46891b13d190SFrançois Tigeot static void
intel_dp_unset_edid(struct intel_dp * intel_dp)46901b13d190SFrançois Tigeot intel_dp_unset_edid(struct intel_dp *intel_dp)
46911b13d190SFrançois Tigeot {
46921b13d190SFrançois Tigeot 	struct intel_connector *intel_connector = intel_dp->attached_connector;
46931b13d190SFrançois Tigeot 
46941b13d190SFrançois Tigeot 	kfree(intel_connector->detect_edid);
46951b13d190SFrançois Tigeot 	intel_connector->detect_edid = NULL;
46961b13d190SFrançois Tigeot 
46971b13d190SFrançois Tigeot 	intel_dp->has_audio = false;
46981b13d190SFrançois Tigeot }
46991b13d190SFrançois Tigeot 
4700a85cb24fSFrançois Tigeot static int
intel_dp_long_pulse(struct intel_connector * intel_connector)47018621f407SFrançois Tigeot intel_dp_long_pulse(struct intel_connector *intel_connector)
4702e3adcf8fSFrançois Tigeot {
47038621f407SFrançois Tigeot 	struct drm_connector *connector = &intel_connector->base;
4704e3adcf8fSFrançois Tigeot 	struct intel_dp *intel_dp = intel_attached_dp(connector);
470519df918dSFrançois Tigeot 	struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp);
470619df918dSFrançois Tigeot 	struct intel_encoder *intel_encoder = &intel_dig_port->base;
470719df918dSFrançois Tigeot 	struct drm_device *dev = connector->dev;
4708e3adcf8fSFrançois Tigeot 	enum drm_connector_status status;
470971f41f3eSFrançois Tigeot 	u8 sink_irq_vector = 0;
4710ba55f2f5SFrançois Tigeot 
4711a85cb24fSFrançois Tigeot 	WARN_ON(!drm_modeset_is_locked(&connector->dev->mode_config.connection_mutex));
4712a85cb24fSFrançois Tigeot 
4713a85cb24fSFrançois Tigeot 	intel_display_power_get(to_i915(dev), intel_dp->aux_power_domain);
47141b13d190SFrançois Tigeot 
47151b13d190SFrançois Tigeot 	/* Can't disconnect eDP, but you can close the lid... */
4716*3f2dd94aSFrançois Tigeot 	if (intel_dp_is_edp(intel_dp))
47171b13d190SFrançois Tigeot 		status = edp_detect(intel_dp);
4718aee94f86SFrançois Tigeot 	else if (intel_digital_port_connected(to_i915(dev),
4719aee94f86SFrançois Tigeot 					      dp_to_dig_port(intel_dp)))
4720aee94f86SFrançois Tigeot 		status = intel_dp_detect_dpcd(intel_dp);
4721e3adcf8fSFrançois Tigeot 	else
4722aee94f86SFrançois Tigeot 		status = connector_status_disconnected;
4723aee94f86SFrançois Tigeot 
4724bf017597SFrançois Tigeot 	if (status == connector_status_disconnected) {
4725a85cb24fSFrançois Tigeot 		memset(&intel_dp->compliance, 0, sizeof(intel_dp->compliance));
4726aee94f86SFrançois Tigeot 
47278621f407SFrançois Tigeot 		if (intel_dp->is_mst) {
47288621f407SFrançois Tigeot 			DRM_DEBUG_KMS("MST device may have disappeared %d vs %d\n",
47298621f407SFrançois Tigeot 				      intel_dp->is_mst,
47308621f407SFrançois Tigeot 				      intel_dp->mst_mgr.mst_state);
47318621f407SFrançois Tigeot 			intel_dp->is_mst = false;
47328621f407SFrançois Tigeot 			drm_dp_mst_topology_mgr_set_mst(&intel_dp->mst_mgr,
47338621f407SFrançois Tigeot 							intel_dp->is_mst);
47348621f407SFrançois Tigeot 		}
47358621f407SFrançois Tigeot 
47369edbd4a0SFrançois Tigeot 		goto out;
4737aee94f86SFrançois Tigeot 	}
4738e3adcf8fSFrançois Tigeot 
47398621f407SFrançois Tigeot 	if (intel_encoder->type != INTEL_OUTPUT_EDP)
4740303bf270SFrançois Tigeot 		intel_encoder->type = INTEL_OUTPUT_DP;
47418621f407SFrançois Tigeot 
4742a85cb24fSFrançois Tigeot 	if (intel_dp->reset_link_params) {
4743*3f2dd94aSFrançois Tigeot 		/* Initial max link lane count */
4744*3f2dd94aSFrançois Tigeot 		intel_dp->max_link_lane_count = intel_dp_max_common_lane_count(intel_dp);
4745a85cb24fSFrançois Tigeot 
4746*3f2dd94aSFrançois Tigeot 		/* Initial max link rate */
4747*3f2dd94aSFrançois Tigeot 		intel_dp->max_link_rate = intel_dp_max_common_rate(intel_dp);
4748a85cb24fSFrançois Tigeot 
4749a85cb24fSFrançois Tigeot 		intel_dp->reset_link_params = false;
4750a85cb24fSFrançois Tigeot 	}
4751a85cb24fSFrançois Tigeot 
475271f41f3eSFrançois Tigeot 	intel_dp_print_rates(intel_dp);
475371f41f3eSFrançois Tigeot 
4754a85cb24fSFrançois Tigeot 	drm_dp_read_desc(&intel_dp->aux, &intel_dp->desc,
4755a85cb24fSFrançois Tigeot 			 drm_dp_is_branch(intel_dp->dpcd));
47561e12ee3bSFrançois Tigeot 
475771f41f3eSFrançois Tigeot 	intel_dp_configure_mst(intel_dp);
475871f41f3eSFrançois Tigeot 
475971f41f3eSFrançois Tigeot 	if (intel_dp->is_mst) {
47608621f407SFrançois Tigeot 		/*
47618621f407SFrançois Tigeot 		 * If we are in MST mode then this connector
47628621f407SFrançois Tigeot 		 * won't appear connected or have anything
47638621f407SFrançois Tigeot 		 * with EDID on it
47648621f407SFrançois Tigeot 		 */
47651b13d190SFrançois Tigeot 		status = connector_status_disconnected;
47661b13d190SFrançois Tigeot 		goto out;
4767a85cb24fSFrançois Tigeot 	} else {
47688621f407SFrançois Tigeot 		/*
4769a85cb24fSFrançois Tigeot 		 * If display is now connected check links status,
4770a85cb24fSFrançois Tigeot 		 * there has been known issues of link loss triggerring
4771a85cb24fSFrançois Tigeot 		 * long pulse.
4772a85cb24fSFrançois Tigeot 		 *
4773a85cb24fSFrançois Tigeot 		 * Some sinks (eg. ASUS PB287Q) seem to perform some
4774a85cb24fSFrançois Tigeot 		 * weird HPD ping pong during modesets. So we can apparently
4775a85cb24fSFrançois Tigeot 		 * end up with HPD going low during a modeset, and then
4776a85cb24fSFrançois Tigeot 		 * going back up soon after. And once that happens we must
4777a85cb24fSFrançois Tigeot 		 * retrain the link to get a picture. That's in case no
4778a85cb24fSFrançois Tigeot 		 * userspace component reacted to intermittent HPD dip.
47798621f407SFrançois Tigeot 		 */
47808621f407SFrançois Tigeot 		intel_dp_check_link_status(intel_dp);
4781e3adcf8fSFrançois Tigeot 	}
47821b13d190SFrançois Tigeot 
4783aee94f86SFrançois Tigeot 	/*
4784aee94f86SFrançois Tigeot 	 * Clearing NACK and defer counts to get their exact values
4785aee94f86SFrançois Tigeot 	 * while reading EDID which are required by Compliance tests
4786aee94f86SFrançois Tigeot 	 * 4.2.2.4 and 4.2.2.5
4787aee94f86SFrançois Tigeot 	 */
4788aee94f86SFrançois Tigeot 	intel_dp->aux.i2c_nack_count = 0;
4789aee94f86SFrançois Tigeot 	intel_dp->aux.i2c_defer_count = 0;
4790aee94f86SFrançois Tigeot 
47911b13d190SFrançois Tigeot 	intel_dp_set_edid(intel_dp);
4792*3f2dd94aSFrançois Tigeot 	if (intel_dp_is_edp(intel_dp) || intel_connector->detect_edid)
47939edbd4a0SFrançois Tigeot 		status = connector_status_connected;
47948621f407SFrançois Tigeot 	intel_dp->detect_done = true;
47959edbd4a0SFrançois Tigeot 
479619c468b4SFrançois Tigeot 	/* Try to read the source of the interrupt */
479719c468b4SFrançois Tigeot 	if (intel_dp->dpcd[DP_DPCD_REV] >= 0x11 &&
479871f41f3eSFrançois Tigeot 	    intel_dp_get_sink_irq(intel_dp, &sink_irq_vector) &&
479971f41f3eSFrançois Tigeot 	    sink_irq_vector != 0) {
480019c468b4SFrançois Tigeot 		/* Clear interrupt source */
480119c468b4SFrançois Tigeot 		drm_dp_dpcd_writeb(&intel_dp->aux,
480219c468b4SFrançois Tigeot 				   DP_DEVICE_SERVICE_IRQ_VECTOR,
480319c468b4SFrançois Tigeot 				   sink_irq_vector);
480419c468b4SFrançois Tigeot 
480519c468b4SFrançois Tigeot 		if (sink_irq_vector & DP_AUTOMATED_TEST_REQUEST)
480619c468b4SFrançois Tigeot 			intel_dp_handle_test_request(intel_dp);
480719c468b4SFrançois Tigeot 		if (sink_irq_vector & (DP_CP_IRQ | DP_SINK_SPECIFIC_IRQ))
480819c468b4SFrançois Tigeot 			DRM_DEBUG_DRIVER("CP or sink specific irq unhandled\n");
480919c468b4SFrançois Tigeot 	}
481019c468b4SFrançois Tigeot 
48119edbd4a0SFrançois Tigeot out:
4812bf017597SFrançois Tigeot 	if (status != connector_status_connected && !intel_dp->is_mst)
48138621f407SFrançois Tigeot 		intel_dp_unset_edid(intel_dp);
48148621f407SFrançois Tigeot 
4815a85cb24fSFrançois Tigeot 	intel_display_power_put(to_i915(dev), intel_dp->aux_power_domain);
4816bf017597SFrançois Tigeot 	return status;
48178621f407SFrançois Tigeot }
48188621f407SFrançois Tigeot 
4819a85cb24fSFrançois Tigeot static int
intel_dp_detect(struct drm_connector * connector,struct drm_modeset_acquire_ctx * ctx,bool force)4820a85cb24fSFrançois Tigeot intel_dp_detect(struct drm_connector *connector,
4821a85cb24fSFrançois Tigeot 		struct drm_modeset_acquire_ctx *ctx,
4822a85cb24fSFrançois Tigeot 		bool force)
48238621f407SFrançois Tigeot {
48248621f407SFrançois Tigeot 	struct intel_dp *intel_dp = intel_attached_dp(connector);
4825a85cb24fSFrançois Tigeot 	int status = connector->status;
48268621f407SFrançois Tigeot 
48278621f407SFrançois Tigeot 	DRM_DEBUG_KMS("[CONNECTOR:%d:%s]\n",
48288621f407SFrançois Tigeot 		      connector->base.id, connector->name);
48298621f407SFrançois Tigeot 
48308621f407SFrançois Tigeot 	/* If full detect is not performed yet, do a full detect */
48318621f407SFrançois Tigeot 	if (!intel_dp->detect_done)
4832bf017597SFrançois Tigeot 		status = intel_dp_long_pulse(intel_dp->attached_connector);
48338621f407SFrançois Tigeot 
48348621f407SFrançois Tigeot 	intel_dp->detect_done = false;
48358621f407SFrançois Tigeot 
4836bf017597SFrançois Tigeot 	return status;
4837e3adcf8fSFrançois Tigeot }
4838e3adcf8fSFrançois Tigeot 
48391b13d190SFrançois Tigeot static void
intel_dp_force(struct drm_connector * connector)48401b13d190SFrançois Tigeot intel_dp_force(struct drm_connector *connector)
48411b13d190SFrançois Tigeot {
48421b13d190SFrançois Tigeot 	struct intel_dp *intel_dp = intel_attached_dp(connector);
48431b13d190SFrançois Tigeot 	struct intel_encoder *intel_encoder = &dp_to_dig_port(intel_dp)->base;
4844352ff8bdSFrançois Tigeot 	struct drm_i915_private *dev_priv = to_i915(intel_encoder->base.dev);
48451b13d190SFrançois Tigeot 
48461b13d190SFrançois Tigeot 	DRM_DEBUG_KMS("[CONNECTOR:%d:%s]\n",
48471b13d190SFrançois Tigeot 		      connector->base.id, connector->name);
48481b13d190SFrançois Tigeot 	intel_dp_unset_edid(intel_dp);
48491b13d190SFrançois Tigeot 
48501b13d190SFrançois Tigeot 	if (connector->status != connector_status_connected)
48511b13d190SFrançois Tigeot 		return;
48521b13d190SFrançois Tigeot 
4853a85cb24fSFrançois Tigeot 	intel_display_power_get(dev_priv, intel_dp->aux_power_domain);
48541b13d190SFrançois Tigeot 
48551b13d190SFrançois Tigeot 	intel_dp_set_edid(intel_dp);
48561b13d190SFrançois Tigeot 
4857a85cb24fSFrançois Tigeot 	intel_display_power_put(dev_priv, intel_dp->aux_power_domain);
48581b13d190SFrançois Tigeot 
48591b13d190SFrançois Tigeot 	if (intel_encoder->type != INTEL_OUTPUT_EDP)
4860303bf270SFrançois Tigeot 		intel_encoder->type = INTEL_OUTPUT_DP;
48611b13d190SFrançois Tigeot }
48621b13d190SFrançois Tigeot 
intel_dp_get_modes(struct drm_connector * connector)4863e3adcf8fSFrançois Tigeot static int intel_dp_get_modes(struct drm_connector *connector)
4864e3adcf8fSFrançois Tigeot {
486519df918dSFrançois Tigeot 	struct intel_connector *intel_connector = to_intel_connector(connector);
48661b13d190SFrançois Tigeot 	struct edid *edid;
4867e3adcf8fSFrançois Tigeot 
48681b13d190SFrançois Tigeot 	edid = intel_connector->detect_edid;
48691b13d190SFrançois Tigeot 	if (edid) {
48701b13d190SFrançois Tigeot 		int ret = intel_connector_update_modes(connector, edid);
487119df918dSFrançois Tigeot 		if (ret)
4872e3adcf8fSFrançois Tigeot 			return ret;
48731b13d190SFrançois Tigeot 	}
4874e3adcf8fSFrançois Tigeot 
487519df918dSFrançois Tigeot 	/* if eDP has no EDID, fall back to fixed mode */
4876*3f2dd94aSFrançois Tigeot 	if (intel_dp_is_edp(intel_attached_dp(connector)) &&
48771b13d190SFrançois Tigeot 	    intel_connector->panel.fixed_mode) {
4878e3adcf8fSFrançois Tigeot 		struct drm_display_mode *mode;
48791b13d190SFrançois Tigeot 
48801b13d190SFrançois Tigeot 		mode = drm_mode_duplicate(connector->dev,
488119df918dSFrançois Tigeot 					  intel_connector->panel.fixed_mode);
488219df918dSFrançois Tigeot 		if (mode) {
4883e3adcf8fSFrançois Tigeot 			drm_mode_probed_add(connector, mode);
4884e3adcf8fSFrançois Tigeot 			return 1;
4885e3adcf8fSFrançois Tigeot 		}
4886e3adcf8fSFrançois Tigeot 	}
48871b13d190SFrançois Tigeot 
4888e3adcf8fSFrançois Tigeot 	return 0;
4889e3adcf8fSFrançois Tigeot }
4890e3adcf8fSFrançois Tigeot 
48911487f786SFrançois Tigeot static int
intel_dp_connector_register(struct drm_connector * connector)48921487f786SFrançois Tigeot intel_dp_connector_register(struct drm_connector *connector)
48931487f786SFrançois Tigeot {
48941487f786SFrançois Tigeot 	struct intel_dp *intel_dp = intel_attached_dp(connector);
48951487f786SFrançois Tigeot 	int ret;
48961487f786SFrançois Tigeot 
48971487f786SFrançois Tigeot 	ret = intel_connector_register(connector);
48981487f786SFrançois Tigeot 	if (ret)
48991487f786SFrançois Tigeot 		return ret;
49001487f786SFrançois Tigeot 
49011487f786SFrançois Tigeot 	i915_debugfs_connector_add(connector);
49021487f786SFrançois Tigeot 
49031487f786SFrançois Tigeot 	DRM_DEBUG_KMS("registering %s bus for %s\n",
49041487f786SFrançois Tigeot 		      intel_dp->aux.name, connector->kdev->kobj.name);
49051487f786SFrançois Tigeot 
49061487f786SFrançois Tigeot 	intel_dp->aux.dev = connector->kdev;
49071487f786SFrançois Tigeot 	return drm_dp_aux_register(&intel_dp->aux);
49081487f786SFrançois Tigeot }
49091487f786SFrançois Tigeot 
49101487f786SFrançois Tigeot static void
intel_dp_connector_unregister(struct drm_connector * connector)49111487f786SFrançois Tigeot intel_dp_connector_unregister(struct drm_connector *connector)
49121487f786SFrançois Tigeot {
49131487f786SFrançois Tigeot 	drm_dp_aux_unregister(&intel_attached_dp(connector)->aux);
49141487f786SFrançois Tigeot 	intel_connector_unregister(connector);
49151487f786SFrançois Tigeot }
49161487f786SFrançois Tigeot 
4917e3adcf8fSFrançois Tigeot static void
intel_dp_connector_destroy(struct drm_connector * connector)49185d0b1887SFrançois Tigeot intel_dp_connector_destroy(struct drm_connector *connector)
4919e3adcf8fSFrançois Tigeot {
492019df918dSFrançois Tigeot 	struct intel_connector *intel_connector = to_intel_connector(connector);
4921e3adcf8fSFrançois Tigeot 
49221b13d190SFrançois Tigeot 	kfree(intel_connector->detect_edid);
49231b13d190SFrançois Tigeot 
492419df918dSFrançois Tigeot 	if (!IS_ERR_OR_NULL(intel_connector->edid))
4925158486a6SFrançois Tigeot 		kfree(intel_connector->edid);
492619df918dSFrançois Tigeot 
4927*3f2dd94aSFrançois Tigeot 	/*
4928*3f2dd94aSFrançois Tigeot 	 * Can't call intel_dp_is_edp() since the encoder may have been
4929*3f2dd94aSFrançois Tigeot 	 * destroyed already.
4930*3f2dd94aSFrançois Tigeot 	 */
49315d0b1887SFrançois Tigeot 	if (connector->connector_type == DRM_MODE_CONNECTOR_eDP)
493219df918dSFrançois Tigeot 		intel_panel_fini(&intel_connector->panel);
4933e3adcf8fSFrançois Tigeot 
4934e3adcf8fSFrançois Tigeot 	drm_connector_cleanup(connector);
4935158486a6SFrançois Tigeot 	kfree(connector);
4936e3adcf8fSFrançois Tigeot }
4937e3adcf8fSFrançois Tigeot 
intel_dp_encoder_destroy(struct drm_encoder * encoder)493819df918dSFrançois Tigeot void intel_dp_encoder_destroy(struct drm_encoder *encoder)
4939e3adcf8fSFrançois Tigeot {
494019df918dSFrançois Tigeot 	struct intel_digital_port *intel_dig_port = enc_to_dig_port(encoder);
494119df918dSFrançois Tigeot 	struct intel_dp *intel_dp = &intel_dig_port->dp;
4942e3adcf8fSFrançois Tigeot 
49431b13d190SFrançois Tigeot 	intel_dp_mst_encoder_cleanup(intel_dig_port);
4944*3f2dd94aSFrançois Tigeot 	if (intel_dp_is_edp(intel_dp)) {
4945abf1f4f4SFrançois Tigeot 		cancel_delayed_work_sync(&intel_dp->panel_vdd_work);
49461b13d190SFrançois Tigeot 		/*
49471b13d190SFrançois Tigeot 		 * vdd might still be enabled do to the delayed vdd off.
49481b13d190SFrançois Tigeot 		 * Make sure vdd is actually turned off here.
49491b13d190SFrançois Tigeot 		 */
49501b13d190SFrançois Tigeot 		pps_lock(intel_dp);
4951ba55f2f5SFrançois Tigeot 		edp_panel_vdd_off_sync(intel_dp);
49521b13d190SFrançois Tigeot 		pps_unlock(intel_dp);
49531b13d190SFrançois Tigeot 
4954ba55f2f5SFrançois Tigeot 		if (intel_dp->edp_notifier.notifier_call) {
4955ba55f2f5SFrançois Tigeot 			unregister_reboot_notifier(&intel_dp->edp_notifier);
4956ba55f2f5SFrançois Tigeot 			intel_dp->edp_notifier.notifier_call = NULL;
4957ba55f2f5SFrançois Tigeot 		}
4958e3adcf8fSFrançois Tigeot 	}
49591487f786SFrançois Tigeot 
49601487f786SFrançois Tigeot 	intel_dp_aux_fini(intel_dp);
49611487f786SFrançois Tigeot 
49622c9916cdSFrançois Tigeot 	drm_encoder_cleanup(encoder);
4963158486a6SFrançois Tigeot 	kfree(intel_dig_port);
4964e3adcf8fSFrançois Tigeot }
4965e3adcf8fSFrançois Tigeot 
intel_dp_encoder_suspend(struct intel_encoder * intel_encoder)4966c0e85e96SFrançois Tigeot void intel_dp_encoder_suspend(struct intel_encoder *intel_encoder)
496724edb884SFrançois Tigeot {
496824edb884SFrançois Tigeot 	struct intel_dp *intel_dp = enc_to_intel_dp(&intel_encoder->base);
496924edb884SFrançois Tigeot 
4970*3f2dd94aSFrançois Tigeot 	if (!intel_dp_is_edp(intel_dp))
497124edb884SFrançois Tigeot 		return;
497224edb884SFrançois Tigeot 
49731b13d190SFrançois Tigeot 	/*
49741b13d190SFrançois Tigeot 	 * vdd might still be enabled do to the delayed vdd off.
49751b13d190SFrançois Tigeot 	 * Make sure vdd is actually turned off here.
49761b13d190SFrançois Tigeot 	 */
49771b13d190SFrançois Tigeot 	cancel_delayed_work_sync(&intel_dp->panel_vdd_work);
49781b13d190SFrançois Tigeot 	pps_lock(intel_dp);
497924edb884SFrançois Tigeot 	edp_panel_vdd_off_sync(intel_dp);
49801b13d190SFrançois Tigeot 	pps_unlock(intel_dp);
498124edb884SFrançois Tigeot }
498224edb884SFrançois Tigeot 
intel_edp_panel_vdd_sanitize(struct intel_dp * intel_dp)49832c9916cdSFrançois Tigeot static void intel_edp_panel_vdd_sanitize(struct intel_dp *intel_dp)
49842c9916cdSFrançois Tigeot {
49852c9916cdSFrançois Tigeot 	struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp);
49862c9916cdSFrançois Tigeot 	struct drm_device *dev = intel_dig_port->base.base.dev;
4987303bf270SFrançois Tigeot 	struct drm_i915_private *dev_priv = to_i915(dev);
49882c9916cdSFrançois Tigeot 
49892c9916cdSFrançois Tigeot 	lockdep_assert_held(&dev_priv->pps_mutex);
49902c9916cdSFrançois Tigeot 
49912c9916cdSFrançois Tigeot 	if (!edp_have_panel_vdd(intel_dp))
49922c9916cdSFrançois Tigeot 		return;
49932c9916cdSFrançois Tigeot 
49942c9916cdSFrançois Tigeot 	/*
49952c9916cdSFrançois Tigeot 	 * The VDD bit needs a power domain reference, so if the bit is
49962c9916cdSFrançois Tigeot 	 * already enabled when we boot or resume, grab this reference and
49972c9916cdSFrançois Tigeot 	 * schedule a vdd off, so we don't hold on to the reference
49982c9916cdSFrançois Tigeot 	 * indefinitely.
49992c9916cdSFrançois Tigeot 	 */
50002c9916cdSFrançois Tigeot 	DRM_DEBUG_KMS("VDD left on by BIOS, adjusting state tracking\n");
5001a85cb24fSFrançois Tigeot 	intel_display_power_get(dev_priv, intel_dp->aux_power_domain);
50022c9916cdSFrançois Tigeot 
50032c9916cdSFrançois Tigeot 	edp_panel_vdd_schedule_off(intel_dp);
50042c9916cdSFrançois Tigeot }
50052c9916cdSFrançois Tigeot 
vlv_active_pipe(struct intel_dp * intel_dp)5006a85cb24fSFrançois Tigeot static enum i915_pipe vlv_active_pipe(struct intel_dp *intel_dp)
5007a85cb24fSFrançois Tigeot {
5008a85cb24fSFrançois Tigeot 	struct drm_i915_private *dev_priv = to_i915(intel_dp_to_dev(intel_dp));
5009a85cb24fSFrançois Tigeot 
5010a85cb24fSFrançois Tigeot 	if ((intel_dp->DP & DP_PORT_EN) == 0)
5011a85cb24fSFrançois Tigeot 		return INVALID_PIPE;
5012a85cb24fSFrançois Tigeot 
5013a85cb24fSFrançois Tigeot 	if (IS_CHERRYVIEW(dev_priv))
5014a85cb24fSFrançois Tigeot 		return DP_PORT_TO_PIPE_CHV(intel_dp->DP);
5015a85cb24fSFrançois Tigeot 	else
5016a85cb24fSFrançois Tigeot 		return PORT_TO_PIPE(intel_dp->DP);
5017a85cb24fSFrançois Tigeot }
5018a85cb24fSFrançois Tigeot 
intel_dp_encoder_reset(struct drm_encoder * encoder)5019c0e85e96SFrançois Tigeot void intel_dp_encoder_reset(struct drm_encoder *encoder)
502024edb884SFrançois Tigeot {
50218621f407SFrançois Tigeot 	struct drm_i915_private *dev_priv = to_i915(encoder->dev);
5022a85cb24fSFrançois Tigeot 	struct intel_dp *intel_dp = enc_to_intel_dp(encoder);
5023a85cb24fSFrançois Tigeot 	struct intel_lspcon *lspcon = dp_to_lspcon(intel_dp);
50248621f407SFrançois Tigeot 
50258621f407SFrançois Tigeot 	if (!HAS_DDI(dev_priv))
50268621f407SFrançois Tigeot 		intel_dp->DP = I915_READ(intel_dp->output_reg);
50272c9916cdSFrançois Tigeot 
5028a85cb24fSFrançois Tigeot 	if (lspcon->active)
50291e12ee3bSFrançois Tigeot 		lspcon_resume(lspcon);
50301e12ee3bSFrançois Tigeot 
5031a85cb24fSFrançois Tigeot 	intel_dp->reset_link_params = true;
50322c9916cdSFrançois Tigeot 
50332c9916cdSFrançois Tigeot 	pps_lock(intel_dp);
50342c9916cdSFrançois Tigeot 
5035a85cb24fSFrançois Tigeot 	if (IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv))
5036a85cb24fSFrançois Tigeot 		intel_dp->active_pipe = vlv_active_pipe(intel_dp);
5037a85cb24fSFrançois Tigeot 
5038*3f2dd94aSFrançois Tigeot 	if (intel_dp_is_edp(intel_dp)) {
50391e12ee3bSFrançois Tigeot 		/* Reinit the power sequencer, in case BIOS did something with it. */
50401e12ee3bSFrançois Tigeot 		intel_dp_pps_init(encoder->dev, intel_dp);
50412c9916cdSFrançois Tigeot 		intel_edp_panel_vdd_sanitize(intel_dp);
5042a85cb24fSFrançois Tigeot 	}
50432c9916cdSFrançois Tigeot 
50442c9916cdSFrançois Tigeot 	pps_unlock(intel_dp);
504524edb884SFrançois Tigeot }
504624edb884SFrançois Tigeot 
5047e3adcf8fSFrançois Tigeot static const struct drm_connector_funcs intel_dp_connector_funcs = {
50481b13d190SFrançois Tigeot 	.force = intel_dp_force,
5049e3adcf8fSFrançois Tigeot 	.fill_modes = drm_helper_probe_single_connector_modes,
5050*3f2dd94aSFrançois Tigeot 	.atomic_get_property = intel_digital_connector_atomic_get_property,
5051*3f2dd94aSFrançois Tigeot 	.atomic_set_property = intel_digital_connector_atomic_set_property,
50521487f786SFrançois Tigeot 	.late_register = intel_dp_connector_register,
50531487f786SFrançois Tigeot 	.early_unregister = intel_dp_connector_unregister,
50545d0b1887SFrançois Tigeot 	.destroy = intel_dp_connector_destroy,
50552c9916cdSFrançois Tigeot 	.atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
5056*3f2dd94aSFrançois Tigeot 	.atomic_duplicate_state = intel_digital_connector_duplicate_state,
5057e3adcf8fSFrançois Tigeot };
5058e3adcf8fSFrançois Tigeot 
5059e3adcf8fSFrançois Tigeot static const struct drm_connector_helper_funcs intel_dp_connector_helper_funcs = {
5060a85cb24fSFrançois Tigeot 	.detect_ctx = intel_dp_detect,
5061e3adcf8fSFrançois Tigeot 	.get_modes = intel_dp_get_modes,
5062e3adcf8fSFrançois Tigeot 	.mode_valid = intel_dp_mode_valid,
5063*3f2dd94aSFrançois Tigeot 	.atomic_check = intel_digital_connector_atomic_check,
5064e3adcf8fSFrançois Tigeot };
5065e3adcf8fSFrançois Tigeot 
5066e3adcf8fSFrançois Tigeot static const struct drm_encoder_funcs intel_dp_enc_funcs = {
506724edb884SFrançois Tigeot 	.reset = intel_dp_encoder_reset,
5068e3adcf8fSFrançois Tigeot 	.destroy = intel_dp_encoder_destroy,
5069e3adcf8fSFrançois Tigeot };
5070e3adcf8fSFrançois Tigeot 
5071fae244afSFrançois Tigeot enum irqreturn
intel_dp_hpd_pulse(struct intel_digital_port * intel_dig_port,bool long_hpd)507224edb884SFrançois Tigeot intel_dp_hpd_pulse(struct intel_digital_port *intel_dig_port, bool long_hpd)
507324edb884SFrançois Tigeot {
507424edb884SFrançois Tigeot 	struct intel_dp *intel_dp = &intel_dig_port->dp;
507524edb884SFrançois Tigeot 	struct drm_device *dev = intel_dig_port->base.base.dev;
5076303bf270SFrançois Tigeot 	struct drm_i915_private *dev_priv = to_i915(dev);
5077fae244afSFrançois Tigeot 	enum irqreturn ret = IRQ_NONE;
507824edb884SFrançois Tigeot 
50798621f407SFrançois Tigeot 	if (intel_dig_port->base.type != INTEL_OUTPUT_EDP &&
50808621f407SFrançois Tigeot 	    intel_dig_port->base.type != INTEL_OUTPUT_HDMI)
5081303bf270SFrançois Tigeot 		intel_dig_port->base.type = INTEL_OUTPUT_DP;
508224edb884SFrançois Tigeot 
50831b13d190SFrançois Tigeot 	if (long_hpd && intel_dig_port->base.type == INTEL_OUTPUT_EDP) {
50841b13d190SFrançois Tigeot 		/*
50851b13d190SFrançois Tigeot 		 * vdd off can generate a long pulse on eDP which
50861b13d190SFrançois Tigeot 		 * would require vdd on to handle it, and thus we
50871b13d190SFrançois Tigeot 		 * would end up in an endless cycle of
50881b13d190SFrançois Tigeot 		 * "vdd off -> long hpd -> vdd on -> detect -> vdd off -> ..."
50891b13d190SFrançois Tigeot 		 */
50901b13d190SFrançois Tigeot 		DRM_DEBUG_KMS("ignoring long hpd on eDP port %c\n",
50911b13d190SFrançois Tigeot 			      port_name(intel_dig_port->port));
5092fae244afSFrançois Tigeot 		return IRQ_HANDLED;
50931b13d190SFrançois Tigeot 	}
50941b13d190SFrançois Tigeot 
50951b13d190SFrançois Tigeot 	DRM_DEBUG_KMS("got hpd irq on port %c - %s\n",
50961b13d190SFrançois Tigeot 		      port_name(intel_dig_port->port),
509724edb884SFrançois Tigeot 		      long_hpd ? "long" : "short");
509824edb884SFrançois Tigeot 
5099bf017597SFrançois Tigeot 	if (long_hpd) {
5100a85cb24fSFrançois Tigeot 		intel_dp->reset_link_params = true;
5101bf017597SFrançois Tigeot 		intel_dp->detect_done = false;
5102bf017597SFrançois Tigeot 		return IRQ_NONE;
5103bf017597SFrançois Tigeot 	}
5104bf017597SFrançois Tigeot 
5105a85cb24fSFrançois Tigeot 	intel_display_power_get(dev_priv, intel_dp->aux_power_domain);
510624edb884SFrançois Tigeot 
5107477eb7f9SFrançois Tigeot 	if (intel_dp->is_mst) {
51088621f407SFrançois Tigeot 		if (intel_dp_check_mst_status(intel_dp) == -EINVAL) {
51098621f407SFrançois Tigeot 			/*
51108621f407SFrançois Tigeot 			 * If we were in MST mode, and device is not
51118621f407SFrançois Tigeot 			 * there, get out of MST mode
51128621f407SFrançois Tigeot 			 */
51138621f407SFrançois Tigeot 			DRM_DEBUG_KMS("MST device may have disappeared %d vs %d\n",
51148621f407SFrançois Tigeot 				      intel_dp->is_mst, intel_dp->mst_mgr.mst_state);
51158621f407SFrançois Tigeot 			intel_dp->is_mst = false;
51168621f407SFrançois Tigeot 			drm_dp_mst_topology_mgr_set_mst(&intel_dp->mst_mgr,
51178621f407SFrançois Tigeot 							intel_dp->is_mst);
5118bf017597SFrançois Tigeot 			intel_dp->detect_done = false;
51198621f407SFrançois Tigeot 			goto put_power;
51208621f407SFrançois Tigeot 		}
512124edb884SFrançois Tigeot 	}
512224edb884SFrançois Tigeot 
5123477eb7f9SFrançois Tigeot 	if (!intel_dp->is_mst) {
51248621f407SFrançois Tigeot 		if (!intel_dp_short_pulse(intel_dp)) {
5125bf017597SFrançois Tigeot 			intel_dp->detect_done = false;
51268621f407SFrançois Tigeot 			goto put_power;
51278621f407SFrançois Tigeot 		}
5128477eb7f9SFrançois Tigeot 	}
512924edb884SFrançois Tigeot 
5130fae244afSFrançois Tigeot 	ret = IRQ_HANDLED;
513119c468b4SFrançois Tigeot 
513224edb884SFrançois Tigeot put_power:
5133a85cb24fSFrançois Tigeot 	intel_display_power_put(dev_priv, intel_dp->aux_power_domain);
513424edb884SFrançois Tigeot 
513524edb884SFrançois Tigeot 	return ret;
513624edb884SFrançois Tigeot }
513724edb884SFrançois Tigeot 
5138a05eeebfSFrançois Tigeot /* check the VBT to see whether the eDP is on another port */
intel_dp_is_port_edp(struct drm_i915_private * dev_priv,enum port port)5139*3f2dd94aSFrançois Tigeot bool intel_dp_is_port_edp(struct drm_i915_private *dev_priv, enum port port)
5140e3adcf8fSFrançois Tigeot {
5141352ff8bdSFrançois Tigeot 	/*
5142352ff8bdSFrançois Tigeot 	 * eDP not supported on g4x. so bail out early just
5143352ff8bdSFrançois Tigeot 	 * for a bit extra safety in case the VBT is bonkers.
5144352ff8bdSFrançois Tigeot 	 */
51454be47400SFrançois Tigeot 	if (INTEL_GEN(dev_priv) < 5)
5146352ff8bdSFrançois Tigeot 		return false;
5147352ff8bdSFrançois Tigeot 
5148a85cb24fSFrançois Tigeot 	if (INTEL_GEN(dev_priv) < 9 && port == PORT_A)
51499edbd4a0SFrançois Tigeot 		return true;
5150e3adcf8fSFrançois Tigeot 
51518621f407SFrançois Tigeot 	return intel_bios_is_port_edp(dev_priv, port);
5152e3adcf8fSFrançois Tigeot }
5153e3adcf8fSFrançois Tigeot 
5154*3f2dd94aSFrançois Tigeot static void
intel_dp_add_properties(struct intel_dp * intel_dp,struct drm_connector * connector)5155e3adcf8fSFrançois Tigeot intel_dp_add_properties(struct intel_dp *intel_dp, struct drm_connector *connector)
5156e3adcf8fSFrançois Tigeot {
5157*3f2dd94aSFrançois Tigeot 	struct drm_i915_private *dev_priv = to_i915(connector->dev);
515819df918dSFrançois Tigeot 
5159e3adcf8fSFrançois Tigeot 	intel_attach_force_audio_property(connector);
5160e3adcf8fSFrançois Tigeot 	intel_attach_broadcast_rgb_property(connector);
516119df918dSFrançois Tigeot 
5162*3f2dd94aSFrançois Tigeot 	if (intel_dp_is_edp(intel_dp)) {
5163*3f2dd94aSFrançois Tigeot 		u32 allowed_scalers;
5164*3f2dd94aSFrançois Tigeot 
5165*3f2dd94aSFrançois Tigeot 		allowed_scalers = BIT(DRM_MODE_SCALE_ASPECT) | BIT(DRM_MODE_SCALE_FULLSCREEN);
5166*3f2dd94aSFrançois Tigeot 		if (!HAS_GMCH_DISPLAY(dev_priv))
5167*3f2dd94aSFrançois Tigeot 			allowed_scalers |= BIT(DRM_MODE_SCALE_CENTER);
5168*3f2dd94aSFrançois Tigeot 
5169*3f2dd94aSFrançois Tigeot 		drm_connector_attach_scaling_mode_property(connector, allowed_scalers);
5170*3f2dd94aSFrançois Tigeot 
5171*3f2dd94aSFrançois Tigeot 		connector->state->scaling_mode = DRM_MODE_SCALE_ASPECT;
5172*3f2dd94aSFrançois Tigeot 
517319df918dSFrançois Tigeot 	}
5174e3adcf8fSFrançois Tigeot }
5175e3adcf8fSFrançois Tigeot 
intel_dp_init_panel_power_timestamps(struct intel_dp * intel_dp)5176ba55f2f5SFrançois Tigeot static void intel_dp_init_panel_power_timestamps(struct intel_dp *intel_dp)
5177ba55f2f5SFrançois Tigeot {
5178c0e85e96SFrançois Tigeot 	intel_dp->panel_power_off_time = ktime_get_boottime();
5179ba55f2f5SFrançois Tigeot 	intel_dp->last_power_on = jiffies;
5180ba55f2f5SFrançois Tigeot 	intel_dp->last_backlight_off = jiffies;
5181ba55f2f5SFrançois Tigeot }
5182ba55f2f5SFrançois Tigeot 
518319df918dSFrançois Tigeot static void
intel_pps_readout_hw_state(struct drm_i915_private * dev_priv,struct intel_dp * intel_dp,struct edp_power_seq * seq)51841487f786SFrançois Tigeot intel_pps_readout_hw_state(struct drm_i915_private *dev_priv,
51851487f786SFrançois Tigeot 			   struct intel_dp *intel_dp, struct edp_power_seq *seq)
51861487f786SFrançois Tigeot {
51871487f786SFrançois Tigeot 	u32 pp_on, pp_off, pp_div = 0, pp_ctl = 0;
51881487f786SFrançois Tigeot 	struct pps_registers regs;
51891487f786SFrançois Tigeot 
51901487f786SFrançois Tigeot 	intel_pps_get_registers(dev_priv, intel_dp, &regs);
51911487f786SFrançois Tigeot 
51921487f786SFrançois Tigeot 	/* Workaround: Need to write PP_CONTROL with the unlock key as
51931487f786SFrançois Tigeot 	 * the very first thing. */
51941487f786SFrançois Tigeot 	pp_ctl = ironlake_get_pp_control(intel_dp);
51951487f786SFrançois Tigeot 
51961487f786SFrançois Tigeot 	pp_on = I915_READ(regs.pp_on);
51971487f786SFrançois Tigeot 	pp_off = I915_READ(regs.pp_off);
5198*3f2dd94aSFrançois Tigeot 	if (!IS_GEN9_LP(dev_priv) && !HAS_PCH_CNP(dev_priv)) {
51991487f786SFrançois Tigeot 		I915_WRITE(regs.pp_ctrl, pp_ctl);
52001487f786SFrançois Tigeot 		pp_div = I915_READ(regs.pp_div);
52011487f786SFrançois Tigeot 	}
52021487f786SFrançois Tigeot 
52031487f786SFrançois Tigeot 	/* Pull timing values out of registers */
52041487f786SFrançois Tigeot 	seq->t1_t3 = (pp_on & PANEL_POWER_UP_DELAY_MASK) >>
52051487f786SFrançois Tigeot 		     PANEL_POWER_UP_DELAY_SHIFT;
52061487f786SFrançois Tigeot 
52071487f786SFrançois Tigeot 	seq->t8 = (pp_on & PANEL_LIGHT_ON_DELAY_MASK) >>
52081487f786SFrançois Tigeot 		  PANEL_LIGHT_ON_DELAY_SHIFT;
52091487f786SFrançois Tigeot 
52101487f786SFrançois Tigeot 	seq->t9 = (pp_off & PANEL_LIGHT_OFF_DELAY_MASK) >>
52111487f786SFrançois Tigeot 		  PANEL_LIGHT_OFF_DELAY_SHIFT;
52121487f786SFrançois Tigeot 
52131487f786SFrançois Tigeot 	seq->t10 = (pp_off & PANEL_POWER_DOWN_DELAY_MASK) >>
52141487f786SFrançois Tigeot 		   PANEL_POWER_DOWN_DELAY_SHIFT;
52151487f786SFrançois Tigeot 
5216*3f2dd94aSFrançois Tigeot 	if (IS_GEN9_LP(dev_priv) || HAS_PCH_CNP(dev_priv)) {
5217*3f2dd94aSFrançois Tigeot 		seq->t11_t12 = ((pp_ctl & BXT_POWER_CYCLE_DELAY_MASK) >>
5218*3f2dd94aSFrançois Tigeot 				BXT_POWER_CYCLE_DELAY_SHIFT) * 1000;
52191487f786SFrançois Tigeot 	} else {
52201487f786SFrançois Tigeot 		seq->t11_t12 = ((pp_div & PANEL_POWER_CYCLE_DELAY_MASK) >>
52211487f786SFrançois Tigeot 		       PANEL_POWER_CYCLE_DELAY_SHIFT) * 1000;
52221487f786SFrançois Tigeot 	}
52231487f786SFrançois Tigeot }
52241487f786SFrançois Tigeot 
52251487f786SFrançois Tigeot static void
intel_pps_dump_state(const char * state_name,const struct edp_power_seq * seq)52261487f786SFrançois Tigeot intel_pps_dump_state(const char *state_name, const struct edp_power_seq *seq)
52271487f786SFrançois Tigeot {
52281487f786SFrançois Tigeot 	DRM_DEBUG_KMS("%s t1_t3 %d t8 %d t9 %d t10 %d t11_t12 %d\n",
52291487f786SFrançois Tigeot 		      state_name,
52301487f786SFrançois Tigeot 		      seq->t1_t3, seq->t8, seq->t9, seq->t10, seq->t11_t12);
52311487f786SFrançois Tigeot }
52321487f786SFrançois Tigeot 
52331487f786SFrançois Tigeot static void
intel_pps_verify_state(struct drm_i915_private * dev_priv,struct intel_dp * intel_dp)52341487f786SFrançois Tigeot intel_pps_verify_state(struct drm_i915_private *dev_priv,
52351487f786SFrançois Tigeot 		       struct intel_dp *intel_dp)
52361487f786SFrançois Tigeot {
52371487f786SFrançois Tigeot 	struct edp_power_seq hw;
52381487f786SFrançois Tigeot 	struct edp_power_seq *sw = &intel_dp->pps_delays;
52391487f786SFrançois Tigeot 
52401487f786SFrançois Tigeot 	intel_pps_readout_hw_state(dev_priv, intel_dp, &hw);
52411487f786SFrançois Tigeot 
52421487f786SFrançois Tigeot 	if (hw.t1_t3 != sw->t1_t3 || hw.t8 != sw->t8 || hw.t9 != sw->t9 ||
52431487f786SFrançois Tigeot 	    hw.t10 != sw->t10 || hw.t11_t12 != sw->t11_t12) {
52441487f786SFrançois Tigeot 		DRM_ERROR("PPS state mismatch\n");
52451487f786SFrançois Tigeot 		intel_pps_dump_state("sw", sw);
52461487f786SFrançois Tigeot 		intel_pps_dump_state("hw", &hw);
52471487f786SFrançois Tigeot 	}
52481487f786SFrançois Tigeot }
52491487f786SFrançois Tigeot 
52501487f786SFrançois Tigeot static void
intel_dp_init_panel_power_sequencer(struct drm_device * dev,struct intel_dp * intel_dp)525119df918dSFrançois Tigeot intel_dp_init_panel_power_sequencer(struct drm_device *dev,
52522c9916cdSFrançois Tigeot 				    struct intel_dp *intel_dp)
5253e3adcf8fSFrançois Tigeot {
5254303bf270SFrançois Tigeot 	struct drm_i915_private *dev_priv = to_i915(dev);
52552c9916cdSFrançois Tigeot 	struct edp_power_seq cur, vbt, spec,
52562c9916cdSFrançois Tigeot 		*final = &intel_dp->pps_delays;
52578e26cdf6SFrançois Tigeot 
52581b13d190SFrançois Tigeot 	lockdep_assert_held(&dev_priv->pps_mutex);
52591b13d190SFrançois Tigeot 
52602c9916cdSFrançois Tigeot 	/* already initialized? */
52612c9916cdSFrançois Tigeot 	if (final->t11_t12 != 0)
52622c9916cdSFrançois Tigeot 		return;
52632c9916cdSFrançois Tigeot 
52641487f786SFrançois Tigeot 	intel_pps_readout_hw_state(dev_priv, intel_dp, &cur);
52659edbd4a0SFrançois Tigeot 
52661487f786SFrançois Tigeot 	intel_pps_dump_state("cur", &cur);
5267e3adcf8fSFrançois Tigeot 
52688621f407SFrançois Tigeot 	vbt = dev_priv->vbt.edp.pps;
5269*3f2dd94aSFrançois Tigeot 	/* On Toshiba Satellite P50-C-18C system the VBT T12 delay
5270*3f2dd94aSFrançois Tigeot 	 * of 500ms appears to be too short. Ocassionally the panel
5271*3f2dd94aSFrançois Tigeot 	 * just fails to power back on. Increasing the delay to 800ms
5272*3f2dd94aSFrançois Tigeot 	 * seems sufficient to avoid this problem.
5273*3f2dd94aSFrançois Tigeot 	 */
5274*3f2dd94aSFrançois Tigeot 	if (dev_priv->quirks & QUIRK_INCREASE_T12_DELAY) {
5275*3f2dd94aSFrançois Tigeot 		vbt.t11_t12 = max_t(u16, vbt.t11_t12, 1300 * 10);
5276*3f2dd94aSFrançois Tigeot 		DRM_DEBUG_KMS("Increasing T12 panel delay as per the quirk to %d\n",
5277*3f2dd94aSFrançois Tigeot 			      vbt.t11_t12);
5278*3f2dd94aSFrançois Tigeot 	}
5279*3f2dd94aSFrançois Tigeot 	/* T11_T12 delay is special and actually in units of 100ms, but zero
5280*3f2dd94aSFrançois Tigeot 	 * based in the hw (so we need to add 100 ms). But the sw vbt
5281*3f2dd94aSFrançois Tigeot 	 * table multiplies it with 1000 to make it in units of 100usec,
5282*3f2dd94aSFrançois Tigeot 	 * too. */
5283*3f2dd94aSFrançois Tigeot 	vbt.t11_t12 += 100 * 10;
5284e3adcf8fSFrançois Tigeot 
528519df918dSFrançois Tigeot 	/* Upper limits from eDP 1.3 spec. Note that we use the clunky units of
528619df918dSFrançois Tigeot 	 * our hw here, which are all in 100usec. */
528719df918dSFrançois Tigeot 	spec.t1_t3 = 210 * 10;
528819df918dSFrançois Tigeot 	spec.t8 = 50 * 10; /* no limit for t8, use t7 instead */
528919df918dSFrançois Tigeot 	spec.t9 = 50 * 10; /* no limit for t9, make it symmetric with t8 */
529019df918dSFrançois Tigeot 	spec.t10 = 500 * 10;
529119df918dSFrançois Tigeot 	/* This one is special and actually in units of 100ms, but zero
529219df918dSFrançois Tigeot 	 * based in the hw (so we need to add 100 ms). But the sw vbt
529319df918dSFrançois Tigeot 	 * table multiplies it with 1000 to make it in units of 100usec,
529419df918dSFrançois Tigeot 	 * too. */
529519df918dSFrançois Tigeot 	spec.t11_t12 = (510 + 100) * 10;
529619df918dSFrançois Tigeot 
52971487f786SFrançois Tigeot 	intel_pps_dump_state("vbt", &vbt);
5298e3adcf8fSFrançois Tigeot 
529919df918dSFrançois Tigeot 	/* Use the max of the register settings and vbt. If both are
530019df918dSFrançois Tigeot 	 * unset, fall back to the spec limits. */
53012c9916cdSFrançois Tigeot #define assign_final(field)	final->field = (max(cur.field, vbt.field) == 0 ? \
530219df918dSFrançois Tigeot 				       spec.field : \
530319df918dSFrançois Tigeot 				       max(cur.field, vbt.field))
530419df918dSFrançois Tigeot 	assign_final(t1_t3);
530519df918dSFrançois Tigeot 	assign_final(t8);
530619df918dSFrançois Tigeot 	assign_final(t9);
530719df918dSFrançois Tigeot 	assign_final(t10);
530819df918dSFrançois Tigeot 	assign_final(t11_t12);
530919df918dSFrançois Tigeot #undef assign_final
5310e3adcf8fSFrançois Tigeot 
53112c9916cdSFrançois Tigeot #define get_delay(field)	(DIV_ROUND_UP(final->field, 10))
5312e3adcf8fSFrançois Tigeot 	intel_dp->panel_power_up_delay = get_delay(t1_t3);
5313e3adcf8fSFrançois Tigeot 	intel_dp->backlight_on_delay = get_delay(t8);
5314e3adcf8fSFrançois Tigeot 	intel_dp->backlight_off_delay = get_delay(t9);
5315e3adcf8fSFrançois Tigeot 	intel_dp->panel_power_down_delay = get_delay(t10);
5316e3adcf8fSFrançois Tigeot 	intel_dp->panel_power_cycle_delay = get_delay(t11_t12);
531719df918dSFrançois Tigeot #undef get_delay
5318e3adcf8fSFrançois Tigeot 
5319e3adcf8fSFrançois Tigeot 	DRM_DEBUG_KMS("panel power up delay %d, power down delay %d, power cycle delay %d\n",
5320e3adcf8fSFrançois Tigeot 		      intel_dp->panel_power_up_delay, intel_dp->panel_power_down_delay,
5321e3adcf8fSFrançois Tigeot 		      intel_dp->panel_power_cycle_delay);
5322e3adcf8fSFrançois Tigeot 
5323e3adcf8fSFrançois Tigeot 	DRM_DEBUG_KMS("backlight on delay %d, off delay %d\n",
5324e3adcf8fSFrançois Tigeot 		      intel_dp->backlight_on_delay, intel_dp->backlight_off_delay);
53251487f786SFrançois Tigeot 
53261487f786SFrançois Tigeot 	/*
53271487f786SFrançois Tigeot 	 * We override the HW backlight delays to 1 because we do manual waits
53281487f786SFrançois Tigeot 	 * on them. For T8, even BSpec recommends doing it. For T9, if we
53291487f786SFrançois Tigeot 	 * don't do this, we'll end up waiting for the backlight off delay
53301487f786SFrançois Tigeot 	 * twice: once when we do the manual sleep, and once when we disable
53311487f786SFrançois Tigeot 	 * the panel and wait for the PP_STATUS bit to become zero.
53321487f786SFrançois Tigeot 	 */
53331487f786SFrançois Tigeot 	final->t8 = 1;
53341487f786SFrançois Tigeot 	final->t9 = 1;
5335*3f2dd94aSFrançois Tigeot 
5336*3f2dd94aSFrançois Tigeot 	/*
5337*3f2dd94aSFrançois Tigeot 	 * HW has only a 100msec granularity for t11_t12 so round it up
5338*3f2dd94aSFrançois Tigeot 	 * accordingly.
5339*3f2dd94aSFrançois Tigeot 	 */
5340*3f2dd94aSFrançois Tigeot 	final->t11_t12 = roundup(final->t11_t12, 100 * 10);
534119df918dSFrançois Tigeot }
534219df918dSFrançois Tigeot 
534319df918dSFrançois Tigeot static void
intel_dp_init_panel_power_sequencer_registers(struct drm_device * dev,struct intel_dp * intel_dp,bool force_disable_vdd)534419df918dSFrançois Tigeot intel_dp_init_panel_power_sequencer_registers(struct drm_device *dev,
53454be47400SFrançois Tigeot 					      struct intel_dp *intel_dp,
53464be47400SFrançois Tigeot 					      bool force_disable_vdd)
534719df918dSFrançois Tigeot {
5348303bf270SFrançois Tigeot 	struct drm_i915_private *dev_priv = to_i915(dev);
53498e26cdf6SFrançois Tigeot 	u32 pp_on, pp_off, pp_div, port_sel = 0;
53508621f407SFrançois Tigeot 	int div = dev_priv->rawclk_freq / 1000;
53511487f786SFrançois Tigeot 	struct pps_registers regs;
53521b13d190SFrançois Tigeot 	enum port port = dp_to_dig_port(intel_dp)->port;
53532c9916cdSFrançois Tigeot 	const struct edp_power_seq *seq = &intel_dp->pps_delays;
53541b13d190SFrançois Tigeot 
53551b13d190SFrançois Tigeot 	lockdep_assert_held(&dev_priv->pps_mutex);
53568e26cdf6SFrançois Tigeot 
53571487f786SFrançois Tigeot 	intel_pps_get_registers(dev_priv, intel_dp, &regs);
5358a05eeebfSFrançois Tigeot 
53594be47400SFrançois Tigeot 	/*
53604be47400SFrançois Tigeot 	 * On some VLV machines the BIOS can leave the VDD
53614be47400SFrançois Tigeot 	 * enabled even on power seqeuencers which aren't
53624be47400SFrançois Tigeot 	 * hooked up to any port. This would mess up the
53634be47400SFrançois Tigeot 	 * power domain tracking the first time we pick
53644be47400SFrançois Tigeot 	 * one of these power sequencers for use since
53654be47400SFrançois Tigeot 	 * edp_panel_vdd_on() would notice that the VDD was
53664be47400SFrançois Tigeot 	 * already on and therefore wouldn't grab the power
53674be47400SFrançois Tigeot 	 * domain reference. Disable VDD first to avoid this.
53684be47400SFrançois Tigeot 	 * This also avoids spuriously turning the VDD on as
53694be47400SFrançois Tigeot 	 * soon as the new power seqeuencer gets initialized.
53704be47400SFrançois Tigeot 	 */
53714be47400SFrançois Tigeot 	if (force_disable_vdd) {
53724be47400SFrançois Tigeot 		u32 pp = ironlake_get_pp_control(intel_dp);
53734be47400SFrançois Tigeot 
53744be47400SFrançois Tigeot 		WARN(pp & PANEL_POWER_ON, "Panel power already on\n");
53754be47400SFrançois Tigeot 
53764be47400SFrançois Tigeot 		if (pp & EDP_FORCE_VDD)
53774be47400SFrançois Tigeot 			DRM_DEBUG_KMS("VDD already on, disabling first\n");
53784be47400SFrançois Tigeot 
53794be47400SFrançois Tigeot 		pp &= ~EDP_FORCE_VDD;
53804be47400SFrançois Tigeot 
53814be47400SFrançois Tigeot 		I915_WRITE(regs.pp_ctrl, pp);
53824be47400SFrançois Tigeot 	}
53834be47400SFrançois Tigeot 
538419df918dSFrançois Tigeot 	pp_on = (seq->t1_t3 << PANEL_POWER_UP_DELAY_SHIFT) |
53851487f786SFrançois Tigeot 		(seq->t8 << PANEL_LIGHT_ON_DELAY_SHIFT);
53861487f786SFrançois Tigeot 	pp_off = (seq->t9 << PANEL_LIGHT_OFF_DELAY_SHIFT) |
538719df918dSFrançois Tigeot 		 (seq->t10 << PANEL_POWER_DOWN_DELAY_SHIFT);
538819df918dSFrançois Tigeot 	/* Compute the divisor for the pp clock, simply match the Bspec
538919df918dSFrançois Tigeot 	 * formula. */
5390*3f2dd94aSFrançois Tigeot 	if (IS_GEN9_LP(dev_priv) || HAS_PCH_CNP(dev_priv)) {
53911487f786SFrançois Tigeot 		pp_div = I915_READ(regs.pp_ctrl);
5392a05eeebfSFrançois Tigeot 		pp_div &= ~BXT_POWER_CYCLE_DELAY_MASK;
5393*3f2dd94aSFrançois Tigeot 		pp_div |= (DIV_ROUND_UP(seq->t11_t12, 1000)
5394a05eeebfSFrançois Tigeot 				<< BXT_POWER_CYCLE_DELAY_SHIFT);
5395a05eeebfSFrançois Tigeot 	} else {
53968e26cdf6SFrançois Tigeot 		pp_div = ((100 * div)/2 - 1) << PP_REFERENCE_DIVIDER_SHIFT;
539719df918dSFrançois Tigeot 		pp_div |= (DIV_ROUND_UP(seq->t11_t12, 1000)
539819df918dSFrançois Tigeot 				<< PANEL_POWER_CYCLE_DELAY_SHIFT);
5399a05eeebfSFrançois Tigeot 	}
540019df918dSFrançois Tigeot 
540119df918dSFrançois Tigeot 	/* Haswell doesn't have any port selection bits for the panel
540219df918dSFrançois Tigeot 	 * power sequencer any more. */
54031e12ee3bSFrançois Tigeot 	if (IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv)) {
54041b13d190SFrançois Tigeot 		port_sel = PANEL_PORT_SELECT_VLV(port);
54051e12ee3bSFrançois Tigeot 	} else if (HAS_PCH_IBX(dev_priv) || HAS_PCH_CPT(dev_priv)) {
54061b13d190SFrançois Tigeot 		if (port == PORT_A)
54079edbd4a0SFrançois Tigeot 			port_sel = PANEL_PORT_SELECT_DPA;
540819df918dSFrançois Tigeot 		else
54099edbd4a0SFrançois Tigeot 			port_sel = PANEL_PORT_SELECT_DPD;
541019df918dSFrançois Tigeot 	}
541119df918dSFrançois Tigeot 
54128e26cdf6SFrançois Tigeot 	pp_on |= port_sel;
54138e26cdf6SFrançois Tigeot 
54141487f786SFrançois Tigeot 	I915_WRITE(regs.pp_on, pp_on);
54151487f786SFrançois Tigeot 	I915_WRITE(regs.pp_off, pp_off);
5416*3f2dd94aSFrançois Tigeot 	if (IS_GEN9_LP(dev_priv) || HAS_PCH_CNP(dev_priv))
54171487f786SFrançois Tigeot 		I915_WRITE(regs.pp_ctrl, pp_div);
5418a05eeebfSFrançois Tigeot 	else
54191487f786SFrançois Tigeot 		I915_WRITE(regs.pp_div, pp_div);
542019df918dSFrançois Tigeot 
542119df918dSFrançois Tigeot 	DRM_DEBUG_KMS("panel power sequencer register settings: PP_ON %#x, PP_OFF %#x, PP_DIV %#x\n",
54221487f786SFrançois Tigeot 		      I915_READ(regs.pp_on),
54231487f786SFrançois Tigeot 		      I915_READ(regs.pp_off),
5424*3f2dd94aSFrançois Tigeot 		      (IS_GEN9_LP(dev_priv) || HAS_PCH_CNP(dev_priv)) ?
54251487f786SFrançois Tigeot 		      (I915_READ(regs.pp_ctrl) & BXT_POWER_CYCLE_DELAY_MASK) :
54261487f786SFrançois Tigeot 		      I915_READ(regs.pp_div));
542719df918dSFrançois Tigeot }
542819df918dSFrançois Tigeot 
intel_dp_pps_init(struct drm_device * dev,struct intel_dp * intel_dp)54291e12ee3bSFrançois Tigeot static void intel_dp_pps_init(struct drm_device *dev,
54301e12ee3bSFrançois Tigeot 			      struct intel_dp *intel_dp)
54311e12ee3bSFrançois Tigeot {
54321e12ee3bSFrançois Tigeot 	struct drm_i915_private *dev_priv = to_i915(dev);
54331e12ee3bSFrançois Tigeot 
54341e12ee3bSFrançois Tigeot 	if (IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv)) {
54351e12ee3bSFrançois Tigeot 		vlv_initial_power_sequencer_setup(intel_dp);
54361e12ee3bSFrançois Tigeot 	} else {
54371e12ee3bSFrançois Tigeot 		intel_dp_init_panel_power_sequencer(dev, intel_dp);
54384be47400SFrançois Tigeot 		intel_dp_init_panel_power_sequencer_registers(dev, intel_dp, false);
54391e12ee3bSFrançois Tigeot 	}
54401e12ee3bSFrançois Tigeot }
54411e12ee3bSFrançois Tigeot 
5442477eb7f9SFrançois Tigeot /**
5443477eb7f9SFrançois Tigeot  * intel_dp_set_drrs_state - program registers for RR switch to take effect
54441e12ee3bSFrançois Tigeot  * @dev_priv: i915 device
54451e12ee3bSFrançois Tigeot  * @crtc_state: a pointer to the active intel_crtc_state
5446477eb7f9SFrançois Tigeot  * @refresh_rate: RR to be programmed
5447477eb7f9SFrançois Tigeot  *
5448477eb7f9SFrançois Tigeot  * This function gets called when refresh rate (RR) has to be changed from
5449477eb7f9SFrançois Tigeot  * one frequency to another. Switches can be between high and low RR
5450477eb7f9SFrançois Tigeot  * supported by the panel or to any other RR based on media playback (in
5451477eb7f9SFrançois Tigeot  * this case, RR value needs to be passed from user space).
5452477eb7f9SFrançois Tigeot  *
5453477eb7f9SFrançois Tigeot  * The caller of this function needs to take a lock on dev_priv->drrs.
5454477eb7f9SFrançois Tigeot  */
intel_dp_set_drrs_state(struct drm_i915_private * dev_priv,const struct intel_crtc_state * crtc_state,int refresh_rate)54551e12ee3bSFrançois Tigeot static void intel_dp_set_drrs_state(struct drm_i915_private *dev_priv,
5456*3f2dd94aSFrançois Tigeot 				    const struct intel_crtc_state *crtc_state,
54571e12ee3bSFrançois Tigeot 				    int refresh_rate)
5458ba55f2f5SFrançois Tigeot {
5459ba55f2f5SFrançois Tigeot 	struct intel_encoder *encoder;
54602c9916cdSFrançois Tigeot 	struct intel_digital_port *dig_port = NULL;
54612c9916cdSFrançois Tigeot 	struct intel_dp *intel_dp = dev_priv->drrs.dp;
54621e12ee3bSFrançois Tigeot 	struct intel_crtc *intel_crtc = to_intel_crtc(crtc_state->base.crtc);
54632c9916cdSFrançois Tigeot 	enum drrs_refresh_rate_type index = DRRS_HIGH_RR;
5464ba55f2f5SFrançois Tigeot 
5465ba55f2f5SFrançois Tigeot 	if (refresh_rate <= 0) {
5466ba55f2f5SFrançois Tigeot 		DRM_DEBUG_KMS("Refresh rate should be positive non-zero.\n");
5467ba55f2f5SFrançois Tigeot 		return;
5468ba55f2f5SFrançois Tigeot 	}
5469ba55f2f5SFrançois Tigeot 
54702c9916cdSFrançois Tigeot 	if (intel_dp == NULL) {
54712c9916cdSFrançois Tigeot 		DRM_DEBUG_KMS("DRRS not supported.\n");
5472ba55f2f5SFrançois Tigeot 		return;
5473ba55f2f5SFrançois Tigeot 	}
5474ba55f2f5SFrançois Tigeot 
54752c9916cdSFrançois Tigeot 	dig_port = dp_to_dig_port(intel_dp);
54762c9916cdSFrançois Tigeot 	encoder = &dig_port->base;
5477477eb7f9SFrançois Tigeot 	intel_crtc = to_intel_crtc(encoder->base.crtc);
5478ba55f2f5SFrançois Tigeot 
5479ba55f2f5SFrançois Tigeot 	if (!intel_crtc) {
5480ba55f2f5SFrançois Tigeot 		DRM_DEBUG_KMS("DRRS: intel_crtc not initialized\n");
5481ba55f2f5SFrançois Tigeot 		return;
5482ba55f2f5SFrançois Tigeot 	}
5483ba55f2f5SFrançois Tigeot 
54842c9916cdSFrançois Tigeot 	if (dev_priv->drrs.type < SEAMLESS_DRRS_SUPPORT) {
5485ba55f2f5SFrançois Tigeot 		DRM_DEBUG_KMS("Only Seamless DRRS supported.\n");
5486ba55f2f5SFrançois Tigeot 		return;
5487ba55f2f5SFrançois Tigeot 	}
5488ba55f2f5SFrançois Tigeot 
54892c9916cdSFrançois Tigeot 	if (intel_dp->attached_connector->panel.downclock_mode->vrefresh ==
54902c9916cdSFrançois Tigeot 			refresh_rate)
5491ba55f2f5SFrançois Tigeot 		index = DRRS_LOW_RR;
5492ba55f2f5SFrançois Tigeot 
54932c9916cdSFrançois Tigeot 	if (index == dev_priv->drrs.refresh_rate_type) {
5494ba55f2f5SFrançois Tigeot 		DRM_DEBUG_KMS(
5495ba55f2f5SFrançois Tigeot 			"DRRS requested for previously set RR...ignoring\n");
5496ba55f2f5SFrançois Tigeot 		return;
5497ba55f2f5SFrançois Tigeot 	}
5498ba55f2f5SFrançois Tigeot 
54991e12ee3bSFrançois Tigeot 	if (!crtc_state->base.active) {
5500ba55f2f5SFrançois Tigeot 		DRM_DEBUG_KMS("eDP encoder disabled. CRTC not Active\n");
5501ba55f2f5SFrançois Tigeot 		return;
5502ba55f2f5SFrançois Tigeot 	}
5503ba55f2f5SFrançois Tigeot 
55041e12ee3bSFrançois Tigeot 	if (INTEL_GEN(dev_priv) >= 8 && !IS_CHERRYVIEW(dev_priv)) {
5505477eb7f9SFrançois Tigeot 		switch (index) {
5506477eb7f9SFrançois Tigeot 		case DRRS_HIGH_RR:
5507477eb7f9SFrançois Tigeot 			intel_dp_set_m_n(intel_crtc, M1_N1);
5508477eb7f9SFrançois Tigeot 			break;
5509477eb7f9SFrançois Tigeot 		case DRRS_LOW_RR:
5510477eb7f9SFrançois Tigeot 			intel_dp_set_m_n(intel_crtc, M2_N2);
5511477eb7f9SFrançois Tigeot 			break;
5512477eb7f9SFrançois Tigeot 		case DRRS_MAX_RR:
5513477eb7f9SFrançois Tigeot 		default:
5514477eb7f9SFrançois Tigeot 			DRM_ERROR("Unsupported refreshrate type\n");
5515477eb7f9SFrançois Tigeot 		}
55161e12ee3bSFrançois Tigeot 	} else if (INTEL_GEN(dev_priv) > 6) {
55171e12ee3bSFrançois Tigeot 		i915_reg_t reg = PIPECONF(crtc_state->cpu_transcoder);
5518352ff8bdSFrançois Tigeot 		u32 val;
5519477eb7f9SFrançois Tigeot 
5520352ff8bdSFrançois Tigeot 		val = I915_READ(reg);
5521ba55f2f5SFrançois Tigeot 		if (index > DRRS_HIGH_RR) {
55221e12ee3bSFrançois Tigeot 			if (IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv))
5523477eb7f9SFrançois Tigeot 				val |= PIPECONF_EDP_RR_MODE_SWITCH_VLV;
5524477eb7f9SFrançois Tigeot 			else
5525ba55f2f5SFrançois Tigeot 				val |= PIPECONF_EDP_RR_MODE_SWITCH;
5526ba55f2f5SFrançois Tigeot 		} else {
55271e12ee3bSFrançois Tigeot 			if (IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv))
5528477eb7f9SFrançois Tigeot 				val &= ~PIPECONF_EDP_RR_MODE_SWITCH_VLV;
5529477eb7f9SFrançois Tigeot 			else
5530ba55f2f5SFrançois Tigeot 				val &= ~PIPECONF_EDP_RR_MODE_SWITCH;
5531ba55f2f5SFrançois Tigeot 		}
5532ba55f2f5SFrançois Tigeot 		I915_WRITE(reg, val);
5533ba55f2f5SFrançois Tigeot 	}
5534ba55f2f5SFrançois Tigeot 
55352c9916cdSFrançois Tigeot 	dev_priv->drrs.refresh_rate_type = index;
5536ba55f2f5SFrançois Tigeot 
5537ba55f2f5SFrançois Tigeot 	DRM_DEBUG_KMS("eDP Refresh Rate set to : %dHz\n", refresh_rate);
5538ba55f2f5SFrançois Tigeot }
5539ba55f2f5SFrançois Tigeot 
5540477eb7f9SFrançois Tigeot /**
5541477eb7f9SFrançois Tigeot  * intel_edp_drrs_enable - init drrs struct if supported
5542477eb7f9SFrançois Tigeot  * @intel_dp: DP struct
55431e12ee3bSFrançois Tigeot  * @crtc_state: A pointer to the active crtc state.
5544477eb7f9SFrançois Tigeot  *
5545477eb7f9SFrançois Tigeot  * Initializes frontbuffer_bits and drrs.dp
5546477eb7f9SFrançois Tigeot  */
intel_edp_drrs_enable(struct intel_dp * intel_dp,const struct intel_crtc_state * crtc_state)55471e12ee3bSFrançois Tigeot void intel_edp_drrs_enable(struct intel_dp *intel_dp,
5548*3f2dd94aSFrançois Tigeot 			   const struct intel_crtc_state *crtc_state)
55492c9916cdSFrançois Tigeot {
55502c9916cdSFrançois Tigeot 	struct drm_device *dev = intel_dp_to_dev(intel_dp);
5551303bf270SFrançois Tigeot 	struct drm_i915_private *dev_priv = to_i915(dev);
55522c9916cdSFrançois Tigeot 
55531e12ee3bSFrançois Tigeot 	if (!crtc_state->has_drrs) {
55542c9916cdSFrançois Tigeot 		DRM_DEBUG_KMS("Panel doesn't support DRRS\n");
55552c9916cdSFrançois Tigeot 		return;
55562c9916cdSFrançois Tigeot 	}
55572c9916cdSFrançois Tigeot 
5558*3f2dd94aSFrançois Tigeot 	if (dev_priv->psr.enabled) {
5559*3f2dd94aSFrançois Tigeot 		DRM_DEBUG_KMS("PSR enabled. Not enabling DRRS.\n");
5560*3f2dd94aSFrançois Tigeot 		return;
5561*3f2dd94aSFrançois Tigeot 	}
5562*3f2dd94aSFrançois Tigeot 
55632c9916cdSFrançois Tigeot 	mutex_lock(&dev_priv->drrs.mutex);
55642c9916cdSFrançois Tigeot 	if (WARN_ON(dev_priv->drrs.dp)) {
55652c9916cdSFrançois Tigeot 		DRM_ERROR("DRRS already enabled\n");
55662c9916cdSFrançois Tigeot 		goto unlock;
55672c9916cdSFrançois Tigeot 	}
55682c9916cdSFrançois Tigeot 
55692c9916cdSFrançois Tigeot 	dev_priv->drrs.busy_frontbuffer_bits = 0;
55702c9916cdSFrançois Tigeot 
55712c9916cdSFrançois Tigeot 	dev_priv->drrs.dp = intel_dp;
55722c9916cdSFrançois Tigeot 
55732c9916cdSFrançois Tigeot unlock:
55742c9916cdSFrançois Tigeot 	mutex_unlock(&dev_priv->drrs.mutex);
55752c9916cdSFrançois Tigeot }
55762c9916cdSFrançois Tigeot 
5577477eb7f9SFrançois Tigeot /**
5578477eb7f9SFrançois Tigeot  * intel_edp_drrs_disable - Disable DRRS
5579477eb7f9SFrançois Tigeot  * @intel_dp: DP struct
55801e12ee3bSFrançois Tigeot  * @old_crtc_state: Pointer to old crtc_state.
5581477eb7f9SFrançois Tigeot  *
5582477eb7f9SFrançois Tigeot  */
intel_edp_drrs_disable(struct intel_dp * intel_dp,const struct intel_crtc_state * old_crtc_state)55831e12ee3bSFrançois Tigeot void intel_edp_drrs_disable(struct intel_dp *intel_dp,
5584*3f2dd94aSFrançois Tigeot 			    const struct intel_crtc_state *old_crtc_state)
55852c9916cdSFrançois Tigeot {
55862c9916cdSFrançois Tigeot 	struct drm_device *dev = intel_dp_to_dev(intel_dp);
5587303bf270SFrançois Tigeot 	struct drm_i915_private *dev_priv = to_i915(dev);
55882c9916cdSFrançois Tigeot 
55891e12ee3bSFrançois Tigeot 	if (!old_crtc_state->has_drrs)
55902c9916cdSFrançois Tigeot 		return;
55912c9916cdSFrançois Tigeot 
55922c9916cdSFrançois Tigeot 	mutex_lock(&dev_priv->drrs.mutex);
55932c9916cdSFrançois Tigeot 	if (!dev_priv->drrs.dp) {
55942c9916cdSFrançois Tigeot 		mutex_unlock(&dev_priv->drrs.mutex);
55952c9916cdSFrançois Tigeot 		return;
55962c9916cdSFrançois Tigeot 	}
55972c9916cdSFrançois Tigeot 
55982c9916cdSFrançois Tigeot 	if (dev_priv->drrs.refresh_rate_type == DRRS_LOW_RR)
55991e12ee3bSFrançois Tigeot 		intel_dp_set_drrs_state(dev_priv, old_crtc_state,
56001e12ee3bSFrançois Tigeot 			intel_dp->attached_connector->panel.fixed_mode->vrefresh);
56012c9916cdSFrançois Tigeot 
56022c9916cdSFrançois Tigeot 	dev_priv->drrs.dp = NULL;
56032c9916cdSFrançois Tigeot 	mutex_unlock(&dev_priv->drrs.mutex);
56042c9916cdSFrançois Tigeot 
56052c9916cdSFrançois Tigeot 	cancel_delayed_work_sync(&dev_priv->drrs.work);
56062c9916cdSFrançois Tigeot }
56072c9916cdSFrançois Tigeot 
intel_edp_drrs_downclock_work(struct work_struct * work)56082c9916cdSFrançois Tigeot static void intel_edp_drrs_downclock_work(struct work_struct *work)
56092c9916cdSFrançois Tigeot {
56102c9916cdSFrançois Tigeot 	struct drm_i915_private *dev_priv =
56112c9916cdSFrançois Tigeot 		container_of(work, typeof(*dev_priv), drrs.work.work);
56122c9916cdSFrançois Tigeot 	struct intel_dp *intel_dp;
56132c9916cdSFrançois Tigeot 
56142c9916cdSFrançois Tigeot 	mutex_lock(&dev_priv->drrs.mutex);
56152c9916cdSFrançois Tigeot 
56162c9916cdSFrançois Tigeot 	intel_dp = dev_priv->drrs.dp;
56172c9916cdSFrançois Tigeot 
56182c9916cdSFrançois Tigeot 	if (!intel_dp)
56192c9916cdSFrançois Tigeot 		goto unlock;
56202c9916cdSFrançois Tigeot 
56212c9916cdSFrançois Tigeot 	/*
56222c9916cdSFrançois Tigeot 	 * The delayed work can race with an invalidate hence we need to
56232c9916cdSFrançois Tigeot 	 * recheck.
56242c9916cdSFrançois Tigeot 	 */
56252c9916cdSFrançois Tigeot 
56262c9916cdSFrançois Tigeot 	if (dev_priv->drrs.busy_frontbuffer_bits)
56272c9916cdSFrançois Tigeot 		goto unlock;
56282c9916cdSFrançois Tigeot 
56291e12ee3bSFrançois Tigeot 	if (dev_priv->drrs.refresh_rate_type != DRRS_LOW_RR) {
56301e12ee3bSFrançois Tigeot 		struct drm_crtc *crtc = dp_to_dig_port(intel_dp)->base.base.crtc;
56311e12ee3bSFrançois Tigeot 
56321e12ee3bSFrançois Tigeot 		intel_dp_set_drrs_state(dev_priv, to_intel_crtc(crtc)->config,
56331e12ee3bSFrançois Tigeot 			intel_dp->attached_connector->panel.downclock_mode->vrefresh);
56341e12ee3bSFrançois Tigeot 	}
56352c9916cdSFrançois Tigeot 
56362c9916cdSFrançois Tigeot unlock:
56372c9916cdSFrançois Tigeot 	mutex_unlock(&dev_priv->drrs.mutex);
56382c9916cdSFrançois Tigeot }
56392c9916cdSFrançois Tigeot 
5640477eb7f9SFrançois Tigeot /**
5641a05eeebfSFrançois Tigeot  * intel_edp_drrs_invalidate - Disable Idleness DRRS
564271f41f3eSFrançois Tigeot  * @dev_priv: i915 device
5643477eb7f9SFrançois Tigeot  * @frontbuffer_bits: frontbuffer plane tracking bits
5644477eb7f9SFrançois Tigeot  *
5645a05eeebfSFrançois Tigeot  * This function gets called everytime rendering on the given planes start.
5646a05eeebfSFrançois Tigeot  * Hence DRRS needs to be Upclocked, i.e. (LOW_RR -> HIGH_RR).
5647477eb7f9SFrançois Tigeot  *
5648477eb7f9SFrançois Tigeot  * Dirty frontbuffers relevant to DRRS are tracked in busy_frontbuffer_bits.
5649477eb7f9SFrançois Tigeot  */
intel_edp_drrs_invalidate(struct drm_i915_private * dev_priv,unsigned int frontbuffer_bits)565071f41f3eSFrançois Tigeot void intel_edp_drrs_invalidate(struct drm_i915_private *dev_priv,
565171f41f3eSFrançois Tigeot 			       unsigned int frontbuffer_bits)
56522c9916cdSFrançois Tigeot {
56532c9916cdSFrançois Tigeot 	struct drm_crtc *crtc;
56542c9916cdSFrançois Tigeot 	enum i915_pipe pipe;
56552c9916cdSFrançois Tigeot 
5656477eb7f9SFrançois Tigeot 	if (dev_priv->drrs.type == DRRS_NOT_SUPPORTED)
56572c9916cdSFrançois Tigeot 		return;
56582c9916cdSFrançois Tigeot 
5659477eb7f9SFrançois Tigeot 	cancel_delayed_work(&dev_priv->drrs.work);
5660477eb7f9SFrançois Tigeot 
56612c9916cdSFrançois Tigeot 	mutex_lock(&dev_priv->drrs.mutex);
5662477eb7f9SFrançois Tigeot 	if (!dev_priv->drrs.dp) {
5663477eb7f9SFrançois Tigeot 		mutex_unlock(&dev_priv->drrs.mutex);
5664477eb7f9SFrançois Tigeot 		return;
5665477eb7f9SFrançois Tigeot 	}
5666477eb7f9SFrançois Tigeot 
56672c9916cdSFrançois Tigeot 	crtc = dp_to_dig_port(dev_priv->drrs.dp)->base.base.crtc;
56682c9916cdSFrançois Tigeot 	pipe = to_intel_crtc(crtc)->pipe;
56692c9916cdSFrançois Tigeot 
5670a05eeebfSFrançois Tigeot 	frontbuffer_bits &= INTEL_FRONTBUFFER_ALL_MASK(pipe);
5671a05eeebfSFrançois Tigeot 	dev_priv->drrs.busy_frontbuffer_bits |= frontbuffer_bits;
5672a05eeebfSFrançois Tigeot 
5673a05eeebfSFrançois Tigeot 	/* invalidate means busy screen hence upclock */
5674a05eeebfSFrançois Tigeot 	if (frontbuffer_bits && dev_priv->drrs.refresh_rate_type == DRRS_LOW_RR)
56751e12ee3bSFrançois Tigeot 		intel_dp_set_drrs_state(dev_priv, to_intel_crtc(crtc)->config,
56761e12ee3bSFrançois Tigeot 			dev_priv->drrs.dp->attached_connector->panel.fixed_mode->vrefresh);
56772c9916cdSFrançois Tigeot 
56782c9916cdSFrançois Tigeot 	mutex_unlock(&dev_priv->drrs.mutex);
56792c9916cdSFrançois Tigeot }
56802c9916cdSFrançois Tigeot 
5681477eb7f9SFrançois Tigeot /**
5682a05eeebfSFrançois Tigeot  * intel_edp_drrs_flush - Restart Idleness DRRS
568371f41f3eSFrançois Tigeot  * @dev_priv: i915 device
5684477eb7f9SFrançois Tigeot  * @frontbuffer_bits: frontbuffer plane tracking bits
5685477eb7f9SFrançois Tigeot  *
5686a05eeebfSFrançois Tigeot  * This function gets called every time rendering on the given planes has
5687a05eeebfSFrançois Tigeot  * completed or flip on a crtc is completed. So DRRS should be upclocked
5688a05eeebfSFrançois Tigeot  * (LOW_RR -> HIGH_RR). And also Idleness detection should be started again,
5689a05eeebfSFrançois Tigeot  * if no other planes are dirty.
5690477eb7f9SFrançois Tigeot  *
5691477eb7f9SFrançois Tigeot  * Dirty frontbuffers relevant to DRRS are tracked in busy_frontbuffer_bits.
5692477eb7f9SFrançois Tigeot  */
intel_edp_drrs_flush(struct drm_i915_private * dev_priv,unsigned int frontbuffer_bits)569371f41f3eSFrançois Tigeot void intel_edp_drrs_flush(struct drm_i915_private *dev_priv,
569471f41f3eSFrançois Tigeot 			  unsigned int frontbuffer_bits)
56952c9916cdSFrançois Tigeot {
56962c9916cdSFrançois Tigeot 	struct drm_crtc *crtc;
56972c9916cdSFrançois Tigeot 	enum i915_pipe pipe;
56982c9916cdSFrançois Tigeot 
5699477eb7f9SFrançois Tigeot 	if (dev_priv->drrs.type == DRRS_NOT_SUPPORTED)
57002c9916cdSFrançois Tigeot 		return;
57012c9916cdSFrançois Tigeot 
5702477eb7f9SFrançois Tigeot 	cancel_delayed_work(&dev_priv->drrs.work);
5703477eb7f9SFrançois Tigeot 
57042c9916cdSFrançois Tigeot 	mutex_lock(&dev_priv->drrs.mutex);
5705477eb7f9SFrançois Tigeot 	if (!dev_priv->drrs.dp) {
5706477eb7f9SFrançois Tigeot 		mutex_unlock(&dev_priv->drrs.mutex);
5707477eb7f9SFrançois Tigeot 		return;
5708477eb7f9SFrançois Tigeot 	}
5709477eb7f9SFrançois Tigeot 
57102c9916cdSFrançois Tigeot 	crtc = dp_to_dig_port(dev_priv->drrs.dp)->base.base.crtc;
57112c9916cdSFrançois Tigeot 	pipe = to_intel_crtc(crtc)->pipe;
5712a05eeebfSFrançois Tigeot 
5713a05eeebfSFrançois Tigeot 	frontbuffer_bits &= INTEL_FRONTBUFFER_ALL_MASK(pipe);
57142c9916cdSFrançois Tigeot 	dev_priv->drrs.busy_frontbuffer_bits &= ~frontbuffer_bits;
57152c9916cdSFrançois Tigeot 
5716a05eeebfSFrançois Tigeot 	/* flush means busy screen hence upclock */
5717a05eeebfSFrançois Tigeot 	if (frontbuffer_bits && dev_priv->drrs.refresh_rate_type == DRRS_LOW_RR)
57181e12ee3bSFrançois Tigeot 		intel_dp_set_drrs_state(dev_priv, to_intel_crtc(crtc)->config,
57191e12ee3bSFrançois Tigeot 				dev_priv->drrs.dp->attached_connector->panel.fixed_mode->vrefresh);
5720a05eeebfSFrançois Tigeot 
5721a05eeebfSFrançois Tigeot 	/*
5722a05eeebfSFrançois Tigeot 	 * flush also means no more activity hence schedule downclock, if all
5723a05eeebfSFrançois Tigeot 	 * other fbs are quiescent too
5724a05eeebfSFrançois Tigeot 	 */
5725a05eeebfSFrançois Tigeot 	if (!dev_priv->drrs.busy_frontbuffer_bits)
57262c9916cdSFrançois Tigeot 		schedule_delayed_work(&dev_priv->drrs.work,
57272c9916cdSFrançois Tigeot 				msecs_to_jiffies(1000));
57282c9916cdSFrançois Tigeot 	mutex_unlock(&dev_priv->drrs.mutex);
57292c9916cdSFrançois Tigeot }
57302c9916cdSFrançois Tigeot 
5731477eb7f9SFrançois Tigeot /**
5732477eb7f9SFrançois Tigeot  * DOC: Display Refresh Rate Switching (DRRS)
5733477eb7f9SFrançois Tigeot  *
5734477eb7f9SFrançois Tigeot  * Display Refresh Rate Switching (DRRS) is a power conservation feature
5735477eb7f9SFrançois Tigeot  * which enables swtching between low and high refresh rates,
5736477eb7f9SFrançois Tigeot  * dynamically, based on the usage scenario. This feature is applicable
5737477eb7f9SFrançois Tigeot  * for internal panels.
5738477eb7f9SFrançois Tigeot  *
5739477eb7f9SFrançois Tigeot  * Indication that the panel supports DRRS is given by the panel EDID, which
5740477eb7f9SFrançois Tigeot  * would list multiple refresh rates for one resolution.
5741477eb7f9SFrançois Tigeot  *
5742477eb7f9SFrançois Tigeot  * DRRS is of 2 types - static and seamless.
5743477eb7f9SFrançois Tigeot  * Static DRRS involves changing refresh rate (RR) by doing a full modeset
5744477eb7f9SFrançois Tigeot  * (may appear as a blink on screen) and is used in dock-undock scenario.
5745477eb7f9SFrançois Tigeot  * Seamless DRRS involves changing RR without any visual effect to the user
5746477eb7f9SFrançois Tigeot  * and can be used during normal system usage. This is done by programming
5747477eb7f9SFrançois Tigeot  * certain registers.
5748477eb7f9SFrançois Tigeot  *
5749477eb7f9SFrançois Tigeot  * Support for static/seamless DRRS may be indicated in the VBT based on
5750477eb7f9SFrançois Tigeot  * inputs from the panel spec.
5751477eb7f9SFrançois Tigeot  *
5752477eb7f9SFrançois Tigeot  * DRRS saves power by switching to low RR based on usage scenarios.
5753477eb7f9SFrançois Tigeot  *
57541487f786SFrançois Tigeot  * The implementation is based on frontbuffer tracking implementation.  When
57551487f786SFrançois Tigeot  * there is a disturbance on the screen triggered by user activity or a periodic
57561487f786SFrançois Tigeot  * system activity, DRRS is disabled (RR is changed to high RR).  When there is
57571487f786SFrançois Tigeot  * no movement on screen, after a timeout of 1 second, a switch to low RR is
57581487f786SFrançois Tigeot  * made.
57591487f786SFrançois Tigeot  *
57601487f786SFrançois Tigeot  * For integration with frontbuffer tracking code, intel_edp_drrs_invalidate()
57611487f786SFrançois Tigeot  * and intel_edp_drrs_flush() are called.
5762477eb7f9SFrançois Tigeot  *
5763477eb7f9SFrançois Tigeot  * DRRS can be further extended to support other internal panels and also
5764477eb7f9SFrançois Tigeot  * the scenario of video playback wherein RR is set based on the rate
5765477eb7f9SFrançois Tigeot  * requested by userspace.
5766477eb7f9SFrançois Tigeot  */
5767477eb7f9SFrançois Tigeot 
5768477eb7f9SFrançois Tigeot /**
5769477eb7f9SFrançois Tigeot  * intel_dp_drrs_init - Init basic DRRS work and mutex.
5770477eb7f9SFrançois Tigeot  * @intel_connector: eDP connector
5771477eb7f9SFrançois Tigeot  * @fixed_mode: preferred mode of panel
5772477eb7f9SFrançois Tigeot  *
5773477eb7f9SFrançois Tigeot  * This function is  called only once at driver load to initialize basic
5774477eb7f9SFrançois Tigeot  * DRRS stuff.
5775477eb7f9SFrançois Tigeot  *
5776477eb7f9SFrançois Tigeot  * Returns:
5777477eb7f9SFrançois Tigeot  * Downclock mode if panel supports it, else return NULL.
5778477eb7f9SFrançois Tigeot  * DRRS support is determined by the presence of downclock mode (apart
5779477eb7f9SFrançois Tigeot  * from VBT setting).
5780477eb7f9SFrançois Tigeot  */
5781ba55f2f5SFrançois Tigeot static struct drm_display_mode *
intel_dp_drrs_init(struct intel_connector * intel_connector,struct drm_display_mode * fixed_mode)57822c9916cdSFrançois Tigeot intel_dp_drrs_init(struct intel_connector *intel_connector,
5783ba55f2f5SFrançois Tigeot 		struct drm_display_mode *fixed_mode)
5784ba55f2f5SFrançois Tigeot {
5785ba55f2f5SFrançois Tigeot 	struct drm_connector *connector = &intel_connector->base;
57862c9916cdSFrançois Tigeot 	struct drm_device *dev = connector->dev;
5787303bf270SFrançois Tigeot 	struct drm_i915_private *dev_priv = to_i915(dev);
5788ba55f2f5SFrançois Tigeot 	struct drm_display_mode *downclock_mode = NULL;
5789ba55f2f5SFrançois Tigeot 
5790477eb7f9SFrançois Tigeot 	INIT_DELAYED_WORK(&dev_priv->drrs.work, intel_edp_drrs_downclock_work);
5791477eb7f9SFrançois Tigeot 	lockinit(&dev_priv->drrs.mutex, "i915dm", 0, LK_CANRECURSE);
5792477eb7f9SFrançois Tigeot 
57934be47400SFrançois Tigeot 	if (INTEL_GEN(dev_priv) <= 6) {
5794ba55f2f5SFrançois Tigeot 		DRM_DEBUG_KMS("DRRS supported for Gen7 and above\n");
5795ba55f2f5SFrançois Tigeot 		return NULL;
5796ba55f2f5SFrançois Tigeot 	}
5797ba55f2f5SFrançois Tigeot 
5798ba55f2f5SFrançois Tigeot 	if (dev_priv->vbt.drrs_type != SEAMLESS_DRRS_SUPPORT) {
57991b13d190SFrançois Tigeot 		DRM_DEBUG_KMS("VBT doesn't support DRRS\n");
5800ba55f2f5SFrançois Tigeot 		return NULL;
5801ba55f2f5SFrançois Tigeot 	}
5802ba55f2f5SFrançois Tigeot 
5803ba55f2f5SFrançois Tigeot 	downclock_mode = intel_find_panel_downclock
5804a85cb24fSFrançois Tigeot 					(dev_priv, fixed_mode, connector);
5805ba55f2f5SFrançois Tigeot 
5806ba55f2f5SFrançois Tigeot 	if (!downclock_mode) {
5807477eb7f9SFrançois Tigeot 		DRM_DEBUG_KMS("Downclock mode is not found. DRRS not supported\n");
5808ba55f2f5SFrançois Tigeot 		return NULL;
5809ba55f2f5SFrançois Tigeot 	}
5810ba55f2f5SFrançois Tigeot 
58112c9916cdSFrançois Tigeot 	dev_priv->drrs.type = dev_priv->vbt.drrs_type;
5812ba55f2f5SFrançois Tigeot 
58132c9916cdSFrançois Tigeot 	dev_priv->drrs.refresh_rate_type = DRRS_HIGH_RR;
58141b13d190SFrançois Tigeot 	DRM_DEBUG_KMS("seamless DRRS supported for eDP panel.\n");
5815ba55f2f5SFrançois Tigeot 	return downclock_mode;
5816ba55f2f5SFrançois Tigeot }
5817ba55f2f5SFrançois Tigeot 
intel_edp_init_connector(struct intel_dp * intel_dp,struct intel_connector * intel_connector)58185d0b1887SFrançois Tigeot static bool intel_edp_init_connector(struct intel_dp *intel_dp,
58192c9916cdSFrançois Tigeot 				     struct intel_connector *intel_connector)
58205d0b1887SFrançois Tigeot {
58215d0b1887SFrançois Tigeot 	struct drm_connector *connector = &intel_connector->base;
58225d0b1887SFrançois Tigeot 	struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp);
5823ba55f2f5SFrançois Tigeot 	struct intel_encoder *intel_encoder = &intel_dig_port->base;
5824ba55f2f5SFrançois Tigeot 	struct drm_device *dev = intel_encoder->base.dev;
5825303bf270SFrançois Tigeot 	struct drm_i915_private *dev_priv = to_i915(dev);
58265d0b1887SFrançois Tigeot 	struct drm_display_mode *fixed_mode = NULL;
5827*3f2dd94aSFrançois Tigeot 	struct drm_display_mode *alt_fixed_mode = NULL;
5828ba55f2f5SFrançois Tigeot 	struct drm_display_mode *downclock_mode = NULL;
58295d0b1887SFrançois Tigeot 	bool has_dpcd;
58305d0b1887SFrançois Tigeot 	struct drm_display_mode *scan;
58315d0b1887SFrançois Tigeot 	struct edid *edid;
58322c9916cdSFrançois Tigeot 	enum i915_pipe pipe = INVALID_PIPE;
58335d0b1887SFrançois Tigeot 
5834*3f2dd94aSFrançois Tigeot 	if (!intel_dp_is_edp(intel_dp))
58355d0b1887SFrançois Tigeot 		return true;
58365d0b1887SFrançois Tigeot 
58371487f786SFrançois Tigeot 	/*
58381487f786SFrançois Tigeot 	 * On IBX/CPT we may get here with LVDS already registered. Since the
58391487f786SFrançois Tigeot 	 * driver uses the only internal power sequencer available for both
58401487f786SFrançois Tigeot 	 * eDP and LVDS bail out early in this case to prevent interfering
58411487f786SFrançois Tigeot 	 * with an already powered-on LVDS power sequencer.
58421487f786SFrançois Tigeot 	 */
58431487f786SFrançois Tigeot 	if (intel_get_lvds_encoder(dev)) {
58441487f786SFrançois Tigeot 		WARN_ON(!(HAS_PCH_IBX(dev_priv) || HAS_PCH_CPT(dev_priv)));
58451487f786SFrançois Tigeot 		DRM_INFO("LVDS was detected, not registering eDP\n");
58461487f786SFrançois Tigeot 
58471487f786SFrançois Tigeot 		return false;
58481487f786SFrançois Tigeot 	}
58491487f786SFrançois Tigeot 
58502c9916cdSFrançois Tigeot 	pps_lock(intel_dp);
58511487f786SFrançois Tigeot 
58521487f786SFrançois Tigeot 	intel_dp_init_panel_power_timestamps(intel_dp);
58531e12ee3bSFrançois Tigeot 	intel_dp_pps_init(dev, intel_dp);
58542c9916cdSFrançois Tigeot 	intel_edp_panel_vdd_sanitize(intel_dp);
58551487f786SFrançois Tigeot 
58562c9916cdSFrançois Tigeot 	pps_unlock(intel_dp);
58575d0b1887SFrançois Tigeot 
58585d0b1887SFrançois Tigeot 	/* Cache DPCD and EDID for edp. */
585971f41f3eSFrançois Tigeot 	has_dpcd = intel_edp_init_dpcd(intel_dp);
58605d0b1887SFrançois Tigeot 
586171f41f3eSFrançois Tigeot 	if (!has_dpcd) {
58625d0b1887SFrançois Tigeot 		/* if this fails, presume the device is a ghost */
58635d0b1887SFrançois Tigeot 		DRM_INFO("failed to retrieve link info, disabling eDP\n");
58641487f786SFrançois Tigeot 		goto out_vdd_off;
58655d0b1887SFrançois Tigeot 	}
58665d0b1887SFrançois Tigeot 
5867ba55f2f5SFrançois Tigeot 	mutex_lock(&dev->mode_config.mutex);
58689f4ca867SFrançois Tigeot 	edid = drm_get_edid(connector, &intel_dp->aux.ddc);
58695d0b1887SFrançois Tigeot 	if (edid) {
58705d0b1887SFrançois Tigeot 		if (drm_add_edid_modes(connector, edid)) {
58715d0b1887SFrançois Tigeot 			drm_mode_connector_update_edid_property(connector,
58725d0b1887SFrançois Tigeot 								edid);
58735d0b1887SFrançois Tigeot 			drm_edid_to_eld(connector, edid);
58745d0b1887SFrançois Tigeot 		} else {
58755d0b1887SFrançois Tigeot 			kfree(edid);
58765d0b1887SFrançois Tigeot 			edid = ERR_PTR(-EINVAL);
58775d0b1887SFrançois Tigeot 		}
58785d0b1887SFrançois Tigeot 	} else {
58795d0b1887SFrançois Tigeot 		edid = ERR_PTR(-ENOENT);
58805d0b1887SFrançois Tigeot 	}
58815d0b1887SFrançois Tigeot 	intel_connector->edid = edid;
58825d0b1887SFrançois Tigeot 
5883*3f2dd94aSFrançois Tigeot 	/* prefer fixed mode from EDID if available, save an alt mode also */
58845d0b1887SFrançois Tigeot 	list_for_each_entry(scan, &connector->probed_modes, head) {
58855d0b1887SFrançois Tigeot 		if ((scan->type & DRM_MODE_TYPE_PREFERRED)) {
58865d0b1887SFrançois Tigeot 			fixed_mode = drm_mode_duplicate(dev, scan);
5887ba55f2f5SFrançois Tigeot 			downclock_mode = intel_dp_drrs_init(
5888ba55f2f5SFrançois Tigeot 						intel_connector, fixed_mode);
5889*3f2dd94aSFrançois Tigeot 		} else if (!alt_fixed_mode) {
5890*3f2dd94aSFrançois Tigeot 			alt_fixed_mode = drm_mode_duplicate(dev, scan);
58915d0b1887SFrançois Tigeot 		}
58925d0b1887SFrançois Tigeot 	}
58935d0b1887SFrançois Tigeot 
58945d0b1887SFrançois Tigeot 	/* fallback to VBT if available for eDP */
58955d0b1887SFrançois Tigeot 	if (!fixed_mode && dev_priv->vbt.lfp_lvds_vbt_mode) {
58965d0b1887SFrançois Tigeot 		fixed_mode = drm_mode_duplicate(dev,
58975d0b1887SFrançois Tigeot 					dev_priv->vbt.lfp_lvds_vbt_mode);
58988621f407SFrançois Tigeot 		if (fixed_mode) {
58995d0b1887SFrançois Tigeot 			fixed_mode->type |= DRM_MODE_TYPE_PREFERRED;
59008621f407SFrançois Tigeot 			connector->display_info.width_mm = fixed_mode->width_mm;
59018621f407SFrançois Tigeot 			connector->display_info.height_mm = fixed_mode->height_mm;
59028621f407SFrançois Tigeot 		}
59035d0b1887SFrançois Tigeot 	}
5904ba55f2f5SFrançois Tigeot 	mutex_unlock(&dev->mode_config.mutex);
59055d0b1887SFrançois Tigeot 
59061e12ee3bSFrançois Tigeot 	if (IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv)) {
5907ba55f2f5SFrançois Tigeot 		intel_dp->edp_notifier.notifier_call = edp_notify_handler;
5908ba55f2f5SFrançois Tigeot 		register_reboot_notifier(&intel_dp->edp_notifier);
59092c9916cdSFrançois Tigeot 
59102c9916cdSFrançois Tigeot 		/*
59112c9916cdSFrançois Tigeot 		 * Figure out the current pipe for the initial backlight setup.
59122c9916cdSFrançois Tigeot 		 * If the current pipe isn't valid, try the PPS pipe, and if that
59132c9916cdSFrançois Tigeot 		 * fails just assume pipe A.
59142c9916cdSFrançois Tigeot 		 */
5915a85cb24fSFrançois Tigeot 		pipe = vlv_active_pipe(intel_dp);
59162c9916cdSFrançois Tigeot 
59172c9916cdSFrançois Tigeot 		if (pipe != PIPE_A && pipe != PIPE_B)
59182c9916cdSFrançois Tigeot 			pipe = intel_dp->pps_pipe;
59192c9916cdSFrançois Tigeot 
59202c9916cdSFrançois Tigeot 		if (pipe != PIPE_A && pipe != PIPE_B)
59212c9916cdSFrançois Tigeot 			pipe = PIPE_A;
59222c9916cdSFrançois Tigeot 
59232c9916cdSFrançois Tigeot 		DRM_DEBUG_KMS("using pipe %c for initial backlight setup\n",
59242c9916cdSFrançois Tigeot 			      pipe_name(pipe));
59251b13d190SFrançois Tigeot 	}
5926ba55f2f5SFrançois Tigeot 
5927*3f2dd94aSFrançois Tigeot 	intel_panel_init(&intel_connector->panel, fixed_mode, alt_fixed_mode,
5928*3f2dd94aSFrançois Tigeot 			 downclock_mode);
5929352ff8bdSFrançois Tigeot 	intel_connector->panel.backlight.power = intel_edp_backlight_power;
59302c9916cdSFrançois Tigeot 	intel_panel_setup_backlight(connector, pipe);
59315d0b1887SFrançois Tigeot 
59325d0b1887SFrançois Tigeot 	return true;
59331487f786SFrançois Tigeot 
59341487f786SFrançois Tigeot out_vdd_off:
59351487f786SFrançois Tigeot 	cancel_delayed_work_sync(&intel_dp->panel_vdd_work);
59361487f786SFrançois Tigeot 	/*
59371487f786SFrançois Tigeot 	 * vdd might still be enabled do to the delayed vdd off.
59381487f786SFrançois Tigeot 	 * Make sure vdd is actually turned off here.
59391487f786SFrançois Tigeot 	 */
59401487f786SFrançois Tigeot 	pps_lock(intel_dp);
59411487f786SFrançois Tigeot 	edp_panel_vdd_off_sync(intel_dp);
59421487f786SFrançois Tigeot 	pps_unlock(intel_dp);
59431487f786SFrançois Tigeot 
59441487f786SFrançois Tigeot 	return false;
59455d0b1887SFrançois Tigeot }
59465d0b1887SFrançois Tigeot 
5947a85cb24fSFrançois Tigeot /* Set up the hotplug pin and aux power domain. */
5948a85cb24fSFrançois Tigeot static void
intel_dp_init_connector_port_info(struct intel_digital_port * intel_dig_port)5949a85cb24fSFrançois Tigeot intel_dp_init_connector_port_info(struct intel_digital_port *intel_dig_port)
5950a85cb24fSFrançois Tigeot {
5951a85cb24fSFrançois Tigeot 	struct intel_encoder *encoder = &intel_dig_port->base;
5952a85cb24fSFrançois Tigeot 	struct intel_dp *intel_dp = &intel_dig_port->dp;
5953a85cb24fSFrançois Tigeot 
5954*3f2dd94aSFrançois Tigeot 	encoder->hpd_pin = intel_hpd_pin(intel_dig_port->port);
5955*3f2dd94aSFrançois Tigeot 
5956a85cb24fSFrançois Tigeot 	switch (intel_dig_port->port) {
5957a85cb24fSFrançois Tigeot 	case PORT_A:
5958a85cb24fSFrançois Tigeot 		intel_dp->aux_power_domain = POWER_DOMAIN_AUX_A;
5959a85cb24fSFrançois Tigeot 		break;
5960a85cb24fSFrançois Tigeot 	case PORT_B:
5961a85cb24fSFrançois Tigeot 		intel_dp->aux_power_domain = POWER_DOMAIN_AUX_B;
5962a85cb24fSFrançois Tigeot 		break;
5963a85cb24fSFrançois Tigeot 	case PORT_C:
5964a85cb24fSFrançois Tigeot 		intel_dp->aux_power_domain = POWER_DOMAIN_AUX_C;
5965a85cb24fSFrançois Tigeot 		break;
5966a85cb24fSFrançois Tigeot 	case PORT_D:
5967a85cb24fSFrançois Tigeot 		intel_dp->aux_power_domain = POWER_DOMAIN_AUX_D;
5968a85cb24fSFrançois Tigeot 		break;
5969a85cb24fSFrançois Tigeot 	case PORT_E:
5970a85cb24fSFrançois Tigeot 		/* FIXME: Check VBT for actual wiring of PORT E */
5971a85cb24fSFrançois Tigeot 		intel_dp->aux_power_domain = POWER_DOMAIN_AUX_D;
5972a85cb24fSFrançois Tigeot 		break;
5973a85cb24fSFrançois Tigeot 	default:
5974a85cb24fSFrançois Tigeot 		MISSING_CASE(intel_dig_port->port);
5975a85cb24fSFrançois Tigeot 	}
5976a85cb24fSFrançois Tigeot }
5977a85cb24fSFrançois Tigeot 
intel_dp_modeset_retry_work_fn(struct work_struct * work)5978*3f2dd94aSFrançois Tigeot static void intel_dp_modeset_retry_work_fn(struct work_struct *work)
5979*3f2dd94aSFrançois Tigeot {
5980*3f2dd94aSFrançois Tigeot 	struct intel_connector *intel_connector;
5981*3f2dd94aSFrançois Tigeot 	struct drm_connector *connector;
5982*3f2dd94aSFrançois Tigeot 
5983*3f2dd94aSFrançois Tigeot 	intel_connector = container_of(work, typeof(*intel_connector),
5984*3f2dd94aSFrançois Tigeot 				       modeset_retry_work);
5985*3f2dd94aSFrançois Tigeot 	connector = &intel_connector->base;
5986*3f2dd94aSFrançois Tigeot 	DRM_DEBUG_KMS("[CONNECTOR:%d:%s]\n", connector->base.id,
5987*3f2dd94aSFrançois Tigeot 		      connector->name);
5988*3f2dd94aSFrançois Tigeot 
5989*3f2dd94aSFrançois Tigeot 	/* Grab the locks before changing connector property*/
5990*3f2dd94aSFrançois Tigeot 	mutex_lock(&connector->dev->mode_config.mutex);
5991*3f2dd94aSFrançois Tigeot 	/* Set connector link status to BAD and send a Uevent to notify
5992*3f2dd94aSFrançois Tigeot 	 * userspace to do a modeset.
5993*3f2dd94aSFrançois Tigeot 	 */
5994*3f2dd94aSFrançois Tigeot 	drm_mode_connector_set_link_status_property(connector,
5995*3f2dd94aSFrançois Tigeot 						    DRM_MODE_LINK_STATUS_BAD);
5996*3f2dd94aSFrançois Tigeot 	mutex_unlock(&connector->dev->mode_config.mutex);
5997*3f2dd94aSFrançois Tigeot 	/* Send Hotplug uevent so userspace can reprobe */
5998*3f2dd94aSFrançois Tigeot 	drm_kms_helper_hotplug_event(connector->dev);
5999*3f2dd94aSFrançois Tigeot }
6000*3f2dd94aSFrançois Tigeot 
60015d0b1887SFrançois Tigeot bool
intel_dp_init_connector(struct intel_digital_port * intel_dig_port,struct intel_connector * intel_connector)600219df918dSFrançois Tigeot intel_dp_init_connector(struct intel_digital_port *intel_dig_port,
600319df918dSFrançois Tigeot 			struct intel_connector *intel_connector)
600419df918dSFrançois Tigeot {
600519df918dSFrançois Tigeot 	struct drm_connector *connector = &intel_connector->base;
600619df918dSFrançois Tigeot 	struct intel_dp *intel_dp = &intel_dig_port->dp;
600719df918dSFrançois Tigeot 	struct intel_encoder *intel_encoder = &intel_dig_port->base;
600819df918dSFrançois Tigeot 	struct drm_device *dev = intel_encoder->base.dev;
6009303bf270SFrançois Tigeot 	struct drm_i915_private *dev_priv = to_i915(dev);
601019df918dSFrançois Tigeot 	enum port port = intel_dig_port->port;
60111487f786SFrançois Tigeot 	int type;
601219df918dSFrançois Tigeot 
6013*3f2dd94aSFrançois Tigeot 	/* Initialize the work for modeset in case of link train failure */
6014*3f2dd94aSFrançois Tigeot 	INIT_WORK(&intel_connector->modeset_retry_work,
6015*3f2dd94aSFrançois Tigeot 		  intel_dp_modeset_retry_work_fn);
6016*3f2dd94aSFrançois Tigeot 
6017c0e85e96SFrançois Tigeot 	if (WARN(intel_dig_port->max_lanes < 1,
6018c0e85e96SFrançois Tigeot 		 "Not enough lanes (%d) for DP on port %c\n",
6019c0e85e96SFrançois Tigeot 		 intel_dig_port->max_lanes, port_name(port)))
6020c0e85e96SFrançois Tigeot 		return false;
6021c0e85e96SFrançois Tigeot 
6022*3f2dd94aSFrançois Tigeot 	intel_dp_set_source_rates(intel_dp);
6023*3f2dd94aSFrançois Tigeot 
6024a85cb24fSFrançois Tigeot 	intel_dp->reset_link_params = true;
60251b13d190SFrançois Tigeot 	intel_dp->pps_pipe = INVALID_PIPE;
6026a85cb24fSFrançois Tigeot 	intel_dp->active_pipe = INVALID_PIPE;
60271b13d190SFrançois Tigeot 
6028ba55f2f5SFrançois Tigeot 	/* intel_dp vfuncs */
60294be47400SFrançois Tigeot 	if (INTEL_GEN(dev_priv) >= 9)
60302c9916cdSFrançois Tigeot 		intel_dp->get_aux_clock_divider = skl_get_aux_clock_divider;
60311e12ee3bSFrançois Tigeot 	else if (IS_HASWELL(dev_priv) || IS_BROADWELL(dev_priv))
6032ba55f2f5SFrançois Tigeot 		intel_dp->get_aux_clock_divider = hsw_get_aux_clock_divider;
60331e12ee3bSFrançois Tigeot 	else if (HAS_PCH_SPLIT(dev_priv))
6034ba55f2f5SFrançois Tigeot 		intel_dp->get_aux_clock_divider = ilk_get_aux_clock_divider;
6035ba55f2f5SFrançois Tigeot 	else
60368621f407SFrançois Tigeot 		intel_dp->get_aux_clock_divider = g4x_get_aux_clock_divider;
6037ba55f2f5SFrançois Tigeot 
60384be47400SFrançois Tigeot 	if (INTEL_GEN(dev_priv) >= 9)
60392c9916cdSFrançois Tigeot 		intel_dp->get_aux_send_ctl = skl_get_aux_send_ctl;
60402c9916cdSFrançois Tigeot 	else
60418621f407SFrançois Tigeot 		intel_dp->get_aux_send_ctl = g4x_get_aux_send_ctl;
6042ba55f2f5SFrançois Tigeot 
60431e12ee3bSFrançois Tigeot 	if (HAS_DDI(dev_priv))
6044aee94f86SFrançois Tigeot 		intel_dp->prepare_link_retrain = intel_ddi_prepare_link_retrain;
6045aee94f86SFrançois Tigeot 
604619df918dSFrançois Tigeot 	/* Preserve the current hw state. */
604719df918dSFrançois Tigeot 	intel_dp->DP = I915_READ(intel_dp->output_reg);
604819df918dSFrançois Tigeot 	intel_dp->attached_connector = intel_connector;
604919df918dSFrançois Tigeot 
6050*3f2dd94aSFrançois Tigeot 	if (intel_dp_is_port_edp(dev_priv, port))
60519edbd4a0SFrançois Tigeot 		type = DRM_MODE_CONNECTOR_eDP;
60529edbd4a0SFrançois Tigeot 	else
60535d0b1887SFrançois Tigeot 		type = DRM_MODE_CONNECTOR_DisplayPort;
605419df918dSFrançois Tigeot 
6055a85cb24fSFrançois Tigeot 	if (IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv))
6056a85cb24fSFrançois Tigeot 		intel_dp->active_pipe = vlv_active_pipe(intel_dp);
6057a85cb24fSFrançois Tigeot 
60585d0b1887SFrançois Tigeot 	/*
60595d0b1887SFrançois Tigeot 	 * For eDP we always set the encoder type to INTEL_OUTPUT_EDP, but
60605d0b1887SFrançois Tigeot 	 * for DP the encoder type can be set by the caller to
60615d0b1887SFrançois Tigeot 	 * INTEL_OUTPUT_UNKNOWN for DDI, so don't rewrite it.
60625d0b1887SFrançois Tigeot 	 */
60635d0b1887SFrançois Tigeot 	if (type == DRM_MODE_CONNECTOR_eDP)
60645d0b1887SFrançois Tigeot 		intel_encoder->type = INTEL_OUTPUT_EDP;
60655d0b1887SFrançois Tigeot 
60662c9916cdSFrançois Tigeot 	/* eDP only on port B and/or C on vlv/chv */
60671e12ee3bSFrançois Tigeot 	if (WARN_ON((IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv)) &&
6068*3f2dd94aSFrançois Tigeot 		    intel_dp_is_edp(intel_dp) &&
6069*3f2dd94aSFrançois Tigeot 		    port != PORT_B && port != PORT_C))
60702c9916cdSFrançois Tigeot 		return false;
60712c9916cdSFrançois Tigeot 
60725d0b1887SFrançois Tigeot 	DRM_DEBUG_KMS("Adding %s connector on port %c\n",
60735d0b1887SFrançois Tigeot 			type == DRM_MODE_CONNECTOR_eDP ? "eDP" : "DP",
60745d0b1887SFrançois Tigeot 			port_name(port));
60755d0b1887SFrançois Tigeot 
607619df918dSFrançois Tigeot 	drm_connector_init(dev, connector, &intel_dp_connector_funcs, type);
607719df918dSFrançois Tigeot 	drm_connector_helper_add(connector, &intel_dp_connector_helper_funcs);
607819df918dSFrançois Tigeot 
607919df918dSFrançois Tigeot 	connector->interlace_allowed = true;
608019df918dSFrançois Tigeot 	connector->doublescan_allowed = 0;
608119df918dSFrançois Tigeot 
6082a85cb24fSFrançois Tigeot 	intel_dp_init_connector_port_info(intel_dig_port);
6083a85cb24fSFrançois Tigeot 
60841e12ee3bSFrançois Tigeot 	intel_dp_aux_init(intel_dp);
60851487f786SFrançois Tigeot 
608619df918dSFrançois Tigeot 	INIT_DELAYED_WORK(&intel_dp->panel_vdd_work,
6087ba55f2f5SFrançois Tigeot 			  edp_panel_vdd_work);
608819df918dSFrançois Tigeot 
608919df918dSFrançois Tigeot 	intel_connector_attach_encoder(intel_connector, intel_encoder);
609019df918dSFrançois Tigeot 
60911e12ee3bSFrançois Tigeot 	if (HAS_DDI(dev_priv))
609219df918dSFrançois Tigeot 		intel_connector->get_hw_state = intel_ddi_connector_get_hw_state;
609319df918dSFrançois Tigeot 	else
609419df918dSFrançois Tigeot 		intel_connector->get_hw_state = intel_connector_get_hw_state;
609519df918dSFrançois Tigeot 
60961b13d190SFrançois Tigeot 	/* init MST on ports that can support it */
6097*3f2dd94aSFrançois Tigeot 	if (HAS_DP_MST(dev_priv) && !intel_dp_is_edp(intel_dp) &&
609819c468b4SFrançois Tigeot 	    (port == PORT_B || port == PORT_C || port == PORT_D))
60991b13d190SFrançois Tigeot 		intel_dp_mst_encoder_init(intel_dig_port,
61001b13d190SFrançois Tigeot 					  intel_connector->base.base.id);
61011b13d190SFrançois Tigeot 
61022c9916cdSFrançois Tigeot 	if (!intel_edp_init_connector(intel_dp, intel_connector)) {
6103aee94f86SFrançois Tigeot 		intel_dp_aux_fini(intel_dp);
6104aee94f86SFrançois Tigeot 		intel_dp_mst_encoder_cleanup(intel_dig_port);
6105aee94f86SFrançois Tigeot 		goto fail;
6106e3adcf8fSFrançois Tigeot 	}
6107e3adcf8fSFrançois Tigeot 
6108e3adcf8fSFrançois Tigeot 	intel_dp_add_properties(intel_dp, connector);
6109e3adcf8fSFrançois Tigeot 
6110e3adcf8fSFrançois Tigeot 	/* For G4X desktop chip, PEG_BAND_GAP_DATA 3:0 must first be written
6111e3adcf8fSFrançois Tigeot 	 * 0xd.  Failure to do so will result in spurious interrupts being
6112e3adcf8fSFrançois Tigeot 	 * generated on the port when a cable is not attached.
6113e3adcf8fSFrançois Tigeot 	 */
61141e12ee3bSFrançois Tigeot 	if (IS_G4X(dev_priv) && !IS_GM45(dev_priv)) {
6115e3adcf8fSFrançois Tigeot 		u32 temp = I915_READ(PEG_BAND_GAP_DATA);
6116e3adcf8fSFrançois Tigeot 		I915_WRITE(PEG_BAND_GAP_DATA, (temp & ~0xf) | 0xd);
6117e3adcf8fSFrançois Tigeot 	}
61185d0b1887SFrançois Tigeot 
61195d0b1887SFrançois Tigeot 	return true;
6120aee94f86SFrançois Tigeot 
6121aee94f86SFrançois Tigeot fail:
6122aee94f86SFrançois Tigeot 	drm_connector_cleanup(connector);
6123aee94f86SFrançois Tigeot 
6124aee94f86SFrançois Tigeot 	return false;
6125e3adcf8fSFrançois Tigeot }
612619df918dSFrançois Tigeot 
intel_dp_init(struct drm_i915_private * dev_priv,i915_reg_t output_reg,enum port port)6127a85cb24fSFrançois Tigeot bool intel_dp_init(struct drm_i915_private *dev_priv,
61288621f407SFrançois Tigeot 		   i915_reg_t output_reg,
61298621f407SFrançois Tigeot 		   enum port port)
613019df918dSFrançois Tigeot {
613119df918dSFrançois Tigeot 	struct intel_digital_port *intel_dig_port;
613219df918dSFrançois Tigeot 	struct intel_encoder *intel_encoder;
613319df918dSFrançois Tigeot 	struct drm_encoder *encoder;
613419df918dSFrançois Tigeot 	struct intel_connector *intel_connector;
613519df918dSFrançois Tigeot 
61369edbd4a0SFrançois Tigeot 	intel_dig_port = kzalloc(sizeof(*intel_dig_port), GFP_KERNEL);
613719df918dSFrançois Tigeot 	if (!intel_dig_port)
61388621f407SFrançois Tigeot 		return false;
613919df918dSFrançois Tigeot 
6140477eb7f9SFrançois Tigeot 	intel_connector = intel_connector_alloc();
6141352ff8bdSFrançois Tigeot 	if (!intel_connector)
6142352ff8bdSFrançois Tigeot 		goto err_connector_alloc;
614319df918dSFrançois Tigeot 
614419df918dSFrançois Tigeot 	intel_encoder = &intel_dig_port->base;
614519df918dSFrançois Tigeot 	encoder = &intel_encoder->base;
614619df918dSFrançois Tigeot 
6147a85cb24fSFrançois Tigeot 	if (drm_encoder_init(&dev_priv->drm, &intel_encoder->base,
6148a85cb24fSFrançois Tigeot 			     &intel_dp_enc_funcs, DRM_MODE_ENCODER_TMDS,
6149a85cb24fSFrançois Tigeot 			     "DP %c", port_name(port)))
61508621f407SFrançois Tigeot 		goto err_encoder_init;
615119df918dSFrançois Tigeot 
61528e26cdf6SFrançois Tigeot 	intel_encoder->compute_config = intel_dp_compute_config;
615319df918dSFrançois Tigeot 	intel_encoder->get_hw_state = intel_dp_get_hw_state;
61545d0b1887SFrançois Tigeot 	intel_encoder->get_config = intel_dp_get_config;
615524edb884SFrançois Tigeot 	intel_encoder->suspend = intel_dp_encoder_suspend;
61561e12ee3bSFrançois Tigeot 	if (IS_CHERRYVIEW(dev_priv)) {
615724edb884SFrançois Tigeot 		intel_encoder->pre_pll_enable = chv_dp_pre_pll_enable;
6158ba55f2f5SFrançois Tigeot 		intel_encoder->pre_enable = chv_pre_enable_dp;
6159ba55f2f5SFrançois Tigeot 		intel_encoder->enable = vlv_enable_dp;
6160*3f2dd94aSFrançois Tigeot 		intel_encoder->disable = vlv_disable_dp;
6161ba55f2f5SFrançois Tigeot 		intel_encoder->post_disable = chv_post_disable_dp;
6162352ff8bdSFrançois Tigeot 		intel_encoder->post_pll_disable = chv_dp_post_pll_disable;
61631e12ee3bSFrançois Tigeot 	} else if (IS_VALLEYVIEW(dev_priv)) {
61649edbd4a0SFrançois Tigeot 		intel_encoder->pre_pll_enable = vlv_dp_pre_pll_enable;
61659edbd4a0SFrançois Tigeot 		intel_encoder->pre_enable = vlv_pre_enable_dp;
61669edbd4a0SFrançois Tigeot 		intel_encoder->enable = vlv_enable_dp;
6167*3f2dd94aSFrançois Tigeot 		intel_encoder->disable = vlv_disable_dp;
6168ba55f2f5SFrançois Tigeot 		intel_encoder->post_disable = vlv_post_disable_dp;
6169*3f2dd94aSFrançois Tigeot 	} else if (INTEL_GEN(dev_priv) >= 5) {
6170*3f2dd94aSFrançois Tigeot 		intel_encoder->pre_enable = g4x_pre_enable_dp;
6171*3f2dd94aSFrançois Tigeot 		intel_encoder->enable = g4x_enable_dp;
6172*3f2dd94aSFrançois Tigeot 		intel_encoder->disable = ilk_disable_dp;
6173*3f2dd94aSFrançois Tigeot 		intel_encoder->post_disable = ilk_post_disable_dp;
61749edbd4a0SFrançois Tigeot 	} else {
61759edbd4a0SFrançois Tigeot 		intel_encoder->pre_enable = g4x_pre_enable_dp;
61769edbd4a0SFrançois Tigeot 		intel_encoder->enable = g4x_enable_dp;
6177*3f2dd94aSFrançois Tigeot 		intel_encoder->disable = g4x_disable_dp;
61789edbd4a0SFrançois Tigeot 	}
617919df918dSFrançois Tigeot 
618019df918dSFrançois Tigeot 	intel_dig_port->port = port;
618119df918dSFrançois Tigeot 	intel_dig_port->dp.output_reg = output_reg;
6182c0e85e96SFrançois Tigeot 	intel_dig_port->max_lanes = 4;
618319df918dSFrançois Tigeot 
6184303bf270SFrançois Tigeot 	intel_encoder->type = INTEL_OUTPUT_DP;
6185a85cb24fSFrançois Tigeot 	intel_encoder->power_domain = intel_port_to_power_domain(port);
61861e12ee3bSFrançois Tigeot 	if (IS_CHERRYVIEW(dev_priv)) {
6187ba55f2f5SFrançois Tigeot 		if (port == PORT_D)
6188ba55f2f5SFrançois Tigeot 			intel_encoder->crtc_mask = 1 << 2;
6189ba55f2f5SFrançois Tigeot 		else
6190ba55f2f5SFrançois Tigeot 			intel_encoder->crtc_mask = (1 << 0) | (1 << 1);
6191ba55f2f5SFrançois Tigeot 	} else {
619219df918dSFrançois Tigeot 		intel_encoder->crtc_mask = (1 << 0) | (1 << 1) | (1 << 2);
6193ba55f2f5SFrançois Tigeot 	}
6194ba55f2f5SFrançois Tigeot 	intel_encoder->cloneable = 0;
61951e12ee3bSFrançois Tigeot 	intel_encoder->port = port;
619619df918dSFrançois Tigeot 
619724edb884SFrançois Tigeot 	intel_dig_port->hpd_pulse = intel_dp_hpd_pulse;
6198a05eeebfSFrançois Tigeot 	dev_priv->hotplug.irq_port[port] = intel_dig_port;
619924edb884SFrançois Tigeot 
6200*3f2dd94aSFrançois Tigeot 	if (port != PORT_A)
6201*3f2dd94aSFrançois Tigeot 		intel_infoframe_init(intel_dig_port);
6202*3f2dd94aSFrançois Tigeot 
6203352ff8bdSFrançois Tigeot 	if (!intel_dp_init_connector(intel_dig_port, intel_connector))
6204352ff8bdSFrançois Tigeot 		goto err_init_connector;
6205352ff8bdSFrançois Tigeot 
62068621f407SFrançois Tigeot 	return true;
6207352ff8bdSFrançois Tigeot 
6208352ff8bdSFrançois Tigeot err_init_connector:
62095d0b1887SFrançois Tigeot 	drm_encoder_cleanup(encoder);
62108621f407SFrançois Tigeot err_encoder_init:
62115d0b1887SFrançois Tigeot 	kfree(intel_connector);
6212352ff8bdSFrançois Tigeot err_connector_alloc:
6213352ff8bdSFrançois Tigeot 	kfree(intel_dig_port);
62148621f407SFrançois Tigeot 	return false;
621519df918dSFrançois Tigeot }
62162c9916cdSFrançois Tigeot 
intel_dp_mst_suspend(struct drm_device * dev)6217477eb7f9SFrançois Tigeot void intel_dp_mst_suspend(struct drm_device *dev)
6218477eb7f9SFrançois Tigeot {
6219303bf270SFrançois Tigeot 	struct drm_i915_private *dev_priv = to_i915(dev);
6220477eb7f9SFrançois Tigeot 	int i;
6221477eb7f9SFrançois Tigeot 
6222477eb7f9SFrançois Tigeot 	/* disable MST */
6223477eb7f9SFrançois Tigeot 	for (i = 0; i < I915_MAX_PORTS; i++) {
6224a05eeebfSFrançois Tigeot 		struct intel_digital_port *intel_dig_port = dev_priv->hotplug.irq_port[i];
6225303bf270SFrançois Tigeot 
6226303bf270SFrançois Tigeot 		if (!intel_dig_port || !intel_dig_port->dp.can_mst)
6227477eb7f9SFrançois Tigeot 			continue;
6228477eb7f9SFrançois Tigeot 
6229477eb7f9SFrançois Tigeot 		if (intel_dig_port->dp.is_mst)
6230477eb7f9SFrançois Tigeot 			drm_dp_mst_topology_mgr_suspend(&intel_dig_port->dp.mst_mgr);
6231477eb7f9SFrançois Tigeot 	}
6232477eb7f9SFrançois Tigeot }
6233477eb7f9SFrançois Tigeot 
intel_dp_mst_resume(struct drm_device * dev)62342c9916cdSFrançois Tigeot void intel_dp_mst_resume(struct drm_device *dev)
62352c9916cdSFrançois Tigeot {
6236303bf270SFrançois Tigeot 	struct drm_i915_private *dev_priv = to_i915(dev);
62372c9916cdSFrançois Tigeot 	int i;
62382c9916cdSFrançois Tigeot 
62392c9916cdSFrançois Tigeot 	for (i = 0; i < I915_MAX_PORTS; i++) {
6240a05eeebfSFrançois Tigeot 		struct intel_digital_port *intel_dig_port = dev_priv->hotplug.irq_port[i];
62412c9916cdSFrançois Tigeot 		int ret;
62422c9916cdSFrançois Tigeot 
6243303bf270SFrançois Tigeot 		if (!intel_dig_port || !intel_dig_port->dp.can_mst)
62442c9916cdSFrançois Tigeot 			continue;
62452c9916cdSFrançois Tigeot 
62462c9916cdSFrançois Tigeot 		ret = drm_dp_mst_topology_mgr_resume(&intel_dig_port->dp.mst_mgr);
6247303bf270SFrançois Tigeot 		if (ret)
62482c9916cdSFrançois Tigeot 			intel_dp_check_mst_status(&intel_dig_port->dp);
62492c9916cdSFrançois Tigeot 	}
62502c9916cdSFrançois Tigeot }
6251