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 ®s);
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 ®s);
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, ®s);
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, ®s);
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