xref: /dragonfly/sys/dev/drm/i915/intel_dpio_phy.c (revision 3f2dd94a)
11487f786SFrançois Tigeot /*
21487f786SFrançois Tigeot  * Copyright © 2014-2016 Intel Corporation
31487f786SFrançois Tigeot  *
41487f786SFrançois Tigeot  * Permission is hereby granted, free of charge, to any person obtaining a
51487f786SFrançois Tigeot  * copy of this software and associated documentation files (the "Software"),
61487f786SFrançois Tigeot  * to deal in the Software without restriction, including without limitation
71487f786SFrançois Tigeot  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
81487f786SFrançois Tigeot  * and/or sell copies of the Software, and to permit persons to whom the
91487f786SFrançois Tigeot  * Software is furnished to do so, subject to the following conditions:
101487f786SFrançois Tigeot  *
111487f786SFrançois Tigeot  * The above copyright notice and this permission notice (including the next
121487f786SFrançois Tigeot  * paragraph) shall be included in all copies or substantial portions of the
131487f786SFrançois Tigeot  * Software.
141487f786SFrançois Tigeot  *
151487f786SFrançois Tigeot  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
161487f786SFrançois Tigeot  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
171487f786SFrançois Tigeot  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
181487f786SFrançois Tigeot  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
191487f786SFrançois Tigeot  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
201487f786SFrançois Tigeot  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
211487f786SFrançois Tigeot  * DEALINGS IN THE SOFTWARE.
221487f786SFrançois Tigeot  */
231487f786SFrançois Tigeot 
241487f786SFrançois Tigeot #include "intel_drv.h"
251487f786SFrançois Tigeot 
264be47400SFrançois Tigeot /**
274be47400SFrançois Tigeot  * DOC: DPIO
284be47400SFrançois Tigeot  *
294be47400SFrançois Tigeot  * VLV, CHV and BXT have slightly peculiar display PHYs for driving DP/HDMI
304be47400SFrançois Tigeot  * ports. DPIO is the name given to such a display PHY. These PHYs
314be47400SFrançois Tigeot  * don't follow the standard programming model using direct MMIO
324be47400SFrançois Tigeot  * registers, and instead their registers must be accessed trough IOSF
334be47400SFrançois Tigeot  * sideband. VLV has one such PHY for driving ports B and C, and CHV
344be47400SFrançois Tigeot  * adds another PHY for driving port D. Each PHY responds to specific
354be47400SFrançois Tigeot  * IOSF-SB port.
364be47400SFrançois Tigeot  *
374be47400SFrançois Tigeot  * Each display PHY is made up of one or two channels. Each channel
384be47400SFrançois Tigeot  * houses a common lane part which contains the PLL and other common
394be47400SFrançois Tigeot  * logic. CH0 common lane also contains the IOSF-SB logic for the
404be47400SFrançois Tigeot  * Common Register Interface (CRI) ie. the DPIO registers. CRI clock
414be47400SFrançois Tigeot  * must be running when any DPIO registers are accessed.
424be47400SFrançois Tigeot  *
434be47400SFrançois Tigeot  * In addition to having their own registers, the PHYs are also
444be47400SFrançois Tigeot  * controlled through some dedicated signals from the display
454be47400SFrançois Tigeot  * controller. These include PLL reference clock enable, PLL enable,
464be47400SFrançois Tigeot  * and CRI clock selection, for example.
474be47400SFrançois Tigeot  *
484be47400SFrançois Tigeot  * Eeach channel also has two splines (also called data lanes), and
494be47400SFrançois Tigeot  * each spline is made up of one Physical Access Coding Sub-Layer
504be47400SFrançois Tigeot  * (PCS) block and two TX lanes. So each channel has two PCS blocks
514be47400SFrançois Tigeot  * and four TX lanes. The TX lanes are used as DP lanes or TMDS
524be47400SFrançois Tigeot  * data/clock pairs depending on the output type.
534be47400SFrançois Tigeot  *
544be47400SFrançois Tigeot  * Additionally the PHY also contains an AUX lane with AUX blocks
554be47400SFrançois Tigeot  * for each channel. This is used for DP AUX communication, but
564be47400SFrançois Tigeot  * this fact isn't really relevant for the driver since AUX is
574be47400SFrançois Tigeot  * controlled from the display controller side. No DPIO registers
584be47400SFrançois Tigeot  * need to be accessed during AUX communication,
594be47400SFrançois Tigeot  *
604be47400SFrançois Tigeot  * Generally on VLV/CHV the common lane corresponds to the pipe and
614be47400SFrançois Tigeot  * the spline (PCS/TX) corresponds to the port.
624be47400SFrançois Tigeot  *
634be47400SFrançois Tigeot  * For dual channel PHY (VLV/CHV):
644be47400SFrançois Tigeot  *
654be47400SFrançois Tigeot  *  pipe A == CMN/PLL/REF CH0
664be47400SFrançois Tigeot  *
674be47400SFrançois Tigeot  *  pipe B == CMN/PLL/REF CH1
684be47400SFrançois Tigeot  *
694be47400SFrançois Tigeot  *  port B == PCS/TX CH0
704be47400SFrançois Tigeot  *
714be47400SFrançois Tigeot  *  port C == PCS/TX CH1
724be47400SFrançois Tigeot  *
734be47400SFrançois Tigeot  * This is especially important when we cross the streams
744be47400SFrançois Tigeot  * ie. drive port B with pipe B, or port C with pipe A.
754be47400SFrançois Tigeot  *
764be47400SFrançois Tigeot  * For single channel PHY (CHV):
774be47400SFrançois Tigeot  *
784be47400SFrançois Tigeot  *  pipe C == CMN/PLL/REF CH0
794be47400SFrançois Tigeot  *
804be47400SFrançois Tigeot  *  port D == PCS/TX CH0
814be47400SFrançois Tigeot  *
824be47400SFrançois Tigeot  * On BXT the entire PHY channel corresponds to the port. That means
834be47400SFrançois Tigeot  * the PLL is also now associated with the port rather than the pipe,
844be47400SFrançois Tigeot  * and so the clock needs to be routed to the appropriate transcoder.
854be47400SFrançois Tigeot  * Port A PLL is directly connected to transcoder EDP and port B/C
864be47400SFrançois Tigeot  * PLLs can be routed to any transcoder A/B/C.
874be47400SFrançois Tigeot  *
884be47400SFrançois Tigeot  * Note: DDI0 is digital port B, DD1 is digital port C, and DDI2 is
894be47400SFrançois Tigeot  * digital port D (CHV) or port A (BXT). ::
904be47400SFrançois Tigeot  *
914be47400SFrançois Tigeot  *
924be47400SFrançois Tigeot  *     Dual channel PHY (VLV/CHV/BXT)
934be47400SFrançois Tigeot  *     ---------------------------------
944be47400SFrançois Tigeot  *     |      CH0      |      CH1      |
954be47400SFrançois Tigeot  *     |  CMN/PLL/REF  |  CMN/PLL/REF  |
964be47400SFrançois Tigeot  *     |---------------|---------------| Display PHY
974be47400SFrançois Tigeot  *     | PCS01 | PCS23 | PCS01 | PCS23 |
984be47400SFrançois Tigeot  *     |-------|-------|-------|-------|
994be47400SFrançois Tigeot  *     |TX0|TX1|TX2|TX3|TX0|TX1|TX2|TX3|
1004be47400SFrançois Tigeot  *     ---------------------------------
1014be47400SFrançois Tigeot  *     |     DDI0      |     DDI1      | DP/HDMI ports
1024be47400SFrançois Tigeot  *     ---------------------------------
1034be47400SFrançois Tigeot  *
1044be47400SFrançois Tigeot  *     Single channel PHY (CHV/BXT)
1054be47400SFrançois Tigeot  *     -----------------
1064be47400SFrançois Tigeot  *     |      CH0      |
1074be47400SFrançois Tigeot  *     |  CMN/PLL/REF  |
1084be47400SFrançois Tigeot  *     |---------------| Display PHY
1094be47400SFrançois Tigeot  *     | PCS01 | PCS23 |
1104be47400SFrançois Tigeot  *     |-------|-------|
1114be47400SFrançois Tigeot  *     |TX0|TX1|TX2|TX3|
1124be47400SFrançois Tigeot  *     -----------------
1134be47400SFrançois Tigeot  *     |     DDI2      | DP/HDMI port
1144be47400SFrançois Tigeot  *     -----------------
1154be47400SFrançois Tigeot  */
1164be47400SFrançois Tigeot 
1174be47400SFrançois Tigeot /**
1184be47400SFrançois Tigeot  * struct bxt_ddi_phy_info - Hold info for a broxton DDI phy
1194be47400SFrançois Tigeot  */
1204be47400SFrançois Tigeot struct bxt_ddi_phy_info {
1214be47400SFrançois Tigeot 	/**
1224be47400SFrançois Tigeot 	 * @dual_channel: true if this phy has a second channel.
1234be47400SFrançois Tigeot 	 */
1244be47400SFrançois Tigeot 	bool dual_channel;
1254be47400SFrançois Tigeot 
1264be47400SFrançois Tigeot 	/**
1274be47400SFrançois Tigeot 	 * @rcomp_phy: If -1, indicates this phy has its own rcomp resistor.
1284be47400SFrançois Tigeot 	 * Otherwise the GRC value will be copied from the phy indicated by
1294be47400SFrançois Tigeot 	 * this field.
1304be47400SFrançois Tigeot 	 */
1314be47400SFrançois Tigeot 	enum dpio_phy rcomp_phy;
1324be47400SFrançois Tigeot 
1334be47400SFrançois Tigeot 	/**
134*a85cb24fSFrançois Tigeot 	 * @reset_delay: delay in us to wait before setting the common reset
135*a85cb24fSFrançois Tigeot 	 * bit in BXT_PHY_CTL_FAMILY, which effectively enables the phy.
136*a85cb24fSFrançois Tigeot 	 */
137*a85cb24fSFrançois Tigeot 	int reset_delay;
138*a85cb24fSFrançois Tigeot 
139*a85cb24fSFrançois Tigeot 	/**
140*a85cb24fSFrançois Tigeot 	 * @pwron_mask: Mask with the appropriate bit set that would cause the
141*a85cb24fSFrançois Tigeot 	 * punit to power this phy if written to BXT_P_CR_GT_DISP_PWRON.
142*a85cb24fSFrançois Tigeot 	 */
143*a85cb24fSFrançois Tigeot 	u32 pwron_mask;
144*a85cb24fSFrançois Tigeot 
145*a85cb24fSFrançois Tigeot 	/**
1464be47400SFrançois Tigeot 	 * @channel: struct containing per channel information.
1474be47400SFrançois Tigeot 	 */
1484be47400SFrançois Tigeot 	struct {
1494be47400SFrançois Tigeot 		/**
1504be47400SFrançois Tigeot 		 * @port: which port maps to this channel.
1514be47400SFrançois Tigeot 		 */
1524be47400SFrançois Tigeot 		enum port port;
1534be47400SFrançois Tigeot 	} channel[2];
1544be47400SFrançois Tigeot };
1554be47400SFrançois Tigeot 
1564be47400SFrançois Tigeot static const struct bxt_ddi_phy_info bxt_ddi_phy_info[] = {
1574be47400SFrançois Tigeot 	[DPIO_PHY0] = {
1584be47400SFrançois Tigeot 		.dual_channel = true,
1594be47400SFrançois Tigeot 		.rcomp_phy = DPIO_PHY1,
160*a85cb24fSFrançois Tigeot 		.pwron_mask = BIT(0),
1614be47400SFrançois Tigeot 
1624be47400SFrançois Tigeot 		.channel = {
1634be47400SFrançois Tigeot 			[DPIO_CH0] = { .port = PORT_B },
1644be47400SFrançois Tigeot 			[DPIO_CH1] = { .port = PORT_C },
1654be47400SFrançois Tigeot 		}
1664be47400SFrançois Tigeot 	},
1674be47400SFrançois Tigeot 	[DPIO_PHY1] = {
1684be47400SFrançois Tigeot 		.dual_channel = false,
1694be47400SFrançois Tigeot 		.rcomp_phy = -1,
170*a85cb24fSFrançois Tigeot 		.pwron_mask = BIT(1),
1714be47400SFrançois Tigeot 
1724be47400SFrançois Tigeot 		.channel = {
1734be47400SFrançois Tigeot 			[DPIO_CH0] = { .port = PORT_A },
1744be47400SFrançois Tigeot 		}
1754be47400SFrançois Tigeot 	},
1764be47400SFrançois Tigeot };
1774be47400SFrançois Tigeot 
178*a85cb24fSFrançois Tigeot static const struct bxt_ddi_phy_info glk_ddi_phy_info[] = {
179*a85cb24fSFrançois Tigeot 	[DPIO_PHY0] = {
180*a85cb24fSFrançois Tigeot 		.dual_channel = false,
181*a85cb24fSFrançois Tigeot 		.rcomp_phy = DPIO_PHY1,
182*a85cb24fSFrançois Tigeot 		.pwron_mask = BIT(0),
183*a85cb24fSFrançois Tigeot 		.reset_delay = 20,
184*a85cb24fSFrançois Tigeot 
185*a85cb24fSFrançois Tigeot 		.channel = {
186*a85cb24fSFrançois Tigeot 			[DPIO_CH0] = { .port = PORT_B },
187*a85cb24fSFrançois Tigeot 		}
188*a85cb24fSFrançois Tigeot 	},
189*a85cb24fSFrançois Tigeot 	[DPIO_PHY1] = {
190*a85cb24fSFrançois Tigeot 		.dual_channel = false,
191*a85cb24fSFrançois Tigeot 		.rcomp_phy = -1,
192*a85cb24fSFrançois Tigeot 		.pwron_mask = BIT(3),
193*a85cb24fSFrançois Tigeot 		.reset_delay = 20,
194*a85cb24fSFrançois Tigeot 
195*a85cb24fSFrançois Tigeot 		.channel = {
196*a85cb24fSFrançois Tigeot 			[DPIO_CH0] = { .port = PORT_A },
197*a85cb24fSFrançois Tigeot 		}
198*a85cb24fSFrançois Tigeot 	},
199*a85cb24fSFrançois Tigeot 	[DPIO_PHY2] = {
200*a85cb24fSFrançois Tigeot 		.dual_channel = false,
201*a85cb24fSFrançois Tigeot 		.rcomp_phy = DPIO_PHY1,
202*a85cb24fSFrançois Tigeot 		.pwron_mask = BIT(1),
203*a85cb24fSFrançois Tigeot 		.reset_delay = 20,
204*a85cb24fSFrançois Tigeot 
205*a85cb24fSFrançois Tigeot 		.channel = {
206*a85cb24fSFrançois Tigeot 			[DPIO_CH0] = { .port = PORT_C },
207*a85cb24fSFrançois Tigeot 		}
208*a85cb24fSFrançois Tigeot 	},
209*a85cb24fSFrançois Tigeot };
210*a85cb24fSFrançois Tigeot 
211*a85cb24fSFrançois Tigeot static const struct bxt_ddi_phy_info *
bxt_get_phy_list(struct drm_i915_private * dev_priv,int * count)212*a85cb24fSFrançois Tigeot bxt_get_phy_list(struct drm_i915_private *dev_priv, int *count)
213*a85cb24fSFrançois Tigeot {
214*a85cb24fSFrançois Tigeot 	if (IS_GEMINILAKE(dev_priv)) {
215*a85cb24fSFrançois Tigeot 		*count =  ARRAY_SIZE(glk_ddi_phy_info);
216*a85cb24fSFrançois Tigeot 		return glk_ddi_phy_info;
217*a85cb24fSFrançois Tigeot 	} else {
218*a85cb24fSFrançois Tigeot 		*count =  ARRAY_SIZE(bxt_ddi_phy_info);
219*a85cb24fSFrançois Tigeot 		return bxt_ddi_phy_info;
220*a85cb24fSFrançois Tigeot 	}
221*a85cb24fSFrançois Tigeot }
222*a85cb24fSFrançois Tigeot 
223*a85cb24fSFrançois Tigeot static const struct bxt_ddi_phy_info *
bxt_get_phy_info(struct drm_i915_private * dev_priv,enum dpio_phy phy)224*a85cb24fSFrançois Tigeot bxt_get_phy_info(struct drm_i915_private *dev_priv, enum dpio_phy phy)
225*a85cb24fSFrançois Tigeot {
226*a85cb24fSFrançois Tigeot 	int count;
227*a85cb24fSFrançois Tigeot 	const struct bxt_ddi_phy_info *phy_list =
228*a85cb24fSFrançois Tigeot 		bxt_get_phy_list(dev_priv, &count);
229*a85cb24fSFrançois Tigeot 
230*a85cb24fSFrançois Tigeot 	return &phy_list[phy];
231*a85cb24fSFrançois Tigeot }
232*a85cb24fSFrançois Tigeot 
bxt_port_to_phy_channel(struct drm_i915_private * dev_priv,enum port port,enum dpio_phy * phy,enum dpio_channel * ch)233*a85cb24fSFrançois Tigeot void bxt_port_to_phy_channel(struct drm_i915_private *dev_priv, enum port port,
2344be47400SFrançois Tigeot 			     enum dpio_phy *phy, enum dpio_channel *ch)
2354be47400SFrançois Tigeot {
236*a85cb24fSFrançois Tigeot 	const struct bxt_ddi_phy_info *phy_info, *phys;
237*a85cb24fSFrançois Tigeot 	int i, count;
2384be47400SFrançois Tigeot 
239*a85cb24fSFrançois Tigeot 	phys = bxt_get_phy_list(dev_priv, &count);
240*a85cb24fSFrançois Tigeot 
241*a85cb24fSFrançois Tigeot 	for (i = 0; i < count; i++) {
242*a85cb24fSFrançois Tigeot 		phy_info = &phys[i];
2434be47400SFrançois Tigeot 
2444be47400SFrançois Tigeot 		if (port == phy_info->channel[DPIO_CH0].port) {
2454be47400SFrançois Tigeot 			*phy = i;
2464be47400SFrançois Tigeot 			*ch = DPIO_CH0;
2474be47400SFrançois Tigeot 			return;
2484be47400SFrançois Tigeot 		}
2494be47400SFrançois Tigeot 
2504be47400SFrançois Tigeot 		if (phy_info->dual_channel &&
2514be47400SFrançois Tigeot 		    port == phy_info->channel[DPIO_CH1].port) {
2524be47400SFrançois Tigeot 			*phy = i;
2534be47400SFrançois Tigeot 			*ch = DPIO_CH1;
2544be47400SFrançois Tigeot 			return;
2554be47400SFrançois Tigeot 		}
2564be47400SFrançois Tigeot 	}
2574be47400SFrançois Tigeot 
2584be47400SFrançois Tigeot 	WARN(1, "PHY not found for PORT %c", port_name(port));
2594be47400SFrançois Tigeot 	*phy = DPIO_PHY0;
2604be47400SFrançois Tigeot 	*ch = DPIO_CH0;
2614be47400SFrançois Tigeot }
2624be47400SFrançois Tigeot 
bxt_ddi_phy_set_signal_level(struct drm_i915_private * dev_priv,enum port port,u32 margin,u32 scale,u32 enable,u32 deemphasis)2634be47400SFrançois Tigeot void bxt_ddi_phy_set_signal_level(struct drm_i915_private *dev_priv,
2644be47400SFrançois Tigeot 				  enum port port, u32 margin, u32 scale,
2654be47400SFrançois Tigeot 				  u32 enable, u32 deemphasis)
2664be47400SFrançois Tigeot {
2674be47400SFrançois Tigeot 	u32 val;
2684be47400SFrançois Tigeot 	enum dpio_phy phy;
2694be47400SFrançois Tigeot 	enum dpio_channel ch;
2704be47400SFrançois Tigeot 
271*a85cb24fSFrançois Tigeot 	bxt_port_to_phy_channel(dev_priv, port, &phy, &ch);
2724be47400SFrançois Tigeot 
2734be47400SFrançois Tigeot 	/*
2744be47400SFrançois Tigeot 	 * While we write to the group register to program all lanes at once we
2754be47400SFrançois Tigeot 	 * can read only lane registers and we pick lanes 0/1 for that.
2764be47400SFrançois Tigeot 	 */
2774be47400SFrançois Tigeot 	val = I915_READ(BXT_PORT_PCS_DW10_LN01(phy, ch));
2784be47400SFrançois Tigeot 	val &= ~(TX2_SWING_CALC_INIT | TX1_SWING_CALC_INIT);
2794be47400SFrançois Tigeot 	I915_WRITE(BXT_PORT_PCS_DW10_GRP(phy, ch), val);
2804be47400SFrançois Tigeot 
2814be47400SFrançois Tigeot 	val = I915_READ(BXT_PORT_TX_DW2_LN0(phy, ch));
2824be47400SFrançois Tigeot 	val &= ~(MARGIN_000 | UNIQ_TRANS_SCALE);
2834be47400SFrançois Tigeot 	val |= margin << MARGIN_000_SHIFT | scale << UNIQ_TRANS_SCALE_SHIFT;
2844be47400SFrançois Tigeot 	I915_WRITE(BXT_PORT_TX_DW2_GRP(phy, ch), val);
2854be47400SFrançois Tigeot 
2864be47400SFrançois Tigeot 	val = I915_READ(BXT_PORT_TX_DW3_LN0(phy, ch));
2874be47400SFrançois Tigeot 	val &= ~SCALE_DCOMP_METHOD;
2884be47400SFrançois Tigeot 	if (enable)
2894be47400SFrançois Tigeot 		val |= SCALE_DCOMP_METHOD;
2904be47400SFrançois Tigeot 
2914be47400SFrançois Tigeot 	if ((val & UNIQUE_TRANGE_EN_METHOD) && !(val & SCALE_DCOMP_METHOD))
2924be47400SFrançois Tigeot 		DRM_ERROR("Disabled scaling while ouniqetrangenmethod was set");
2934be47400SFrançois Tigeot 
2944be47400SFrançois Tigeot 	I915_WRITE(BXT_PORT_TX_DW3_GRP(phy, ch), val);
2954be47400SFrançois Tigeot 
2964be47400SFrançois Tigeot 	val = I915_READ(BXT_PORT_TX_DW4_LN0(phy, ch));
2974be47400SFrançois Tigeot 	val &= ~DE_EMPHASIS;
2984be47400SFrançois Tigeot 	val |= deemphasis << DEEMPH_SHIFT;
2994be47400SFrançois Tigeot 	I915_WRITE(BXT_PORT_TX_DW4_GRP(phy, ch), val);
3004be47400SFrançois Tigeot 
3014be47400SFrançois Tigeot 	val = I915_READ(BXT_PORT_PCS_DW10_LN01(phy, ch));
3024be47400SFrançois Tigeot 	val |= TX2_SWING_CALC_INIT | TX1_SWING_CALC_INIT;
3034be47400SFrançois Tigeot 	I915_WRITE(BXT_PORT_PCS_DW10_GRP(phy, ch), val);
3044be47400SFrançois Tigeot }
3054be47400SFrançois Tigeot 
bxt_ddi_phy_is_enabled(struct drm_i915_private * dev_priv,enum dpio_phy phy)3064be47400SFrançois Tigeot bool bxt_ddi_phy_is_enabled(struct drm_i915_private *dev_priv,
3074be47400SFrançois Tigeot 			    enum dpio_phy phy)
3084be47400SFrançois Tigeot {
309*a85cb24fSFrançois Tigeot 	const struct bxt_ddi_phy_info *phy_info;
3104be47400SFrançois Tigeot 
311*a85cb24fSFrançois Tigeot 	phy_info = bxt_get_phy_info(dev_priv, phy);
312*a85cb24fSFrançois Tigeot 
313*a85cb24fSFrançois Tigeot 	if (!(I915_READ(BXT_P_CR_GT_DISP_PWRON) & phy_info->pwron_mask))
3144be47400SFrançois Tigeot 		return false;
3154be47400SFrançois Tigeot 
3164be47400SFrançois Tigeot 	if ((I915_READ(BXT_PORT_CL1CM_DW0(phy)) &
3174be47400SFrançois Tigeot 	     (PHY_POWER_GOOD | PHY_RESERVED)) != PHY_POWER_GOOD) {
3184be47400SFrançois Tigeot 		DRM_DEBUG_DRIVER("DDI PHY %d powered, but power hasn't settled\n",
3194be47400SFrançois Tigeot 				 phy);
3204be47400SFrançois Tigeot 
3214be47400SFrançois Tigeot 		return false;
3224be47400SFrançois Tigeot 	}
3234be47400SFrançois Tigeot 
3244be47400SFrançois Tigeot 	if (!(I915_READ(BXT_PHY_CTL_FAMILY(phy)) & COMMON_RESET_DIS)) {
3254be47400SFrançois Tigeot 		DRM_DEBUG_DRIVER("DDI PHY %d powered, but still in reset\n",
3264be47400SFrançois Tigeot 				 phy);
3274be47400SFrançois Tigeot 
3284be47400SFrançois Tigeot 		return false;
3294be47400SFrançois Tigeot 	}
3304be47400SFrançois Tigeot 
3314be47400SFrançois Tigeot 	return true;
3324be47400SFrançois Tigeot }
3334be47400SFrançois Tigeot 
bxt_get_grc(struct drm_i915_private * dev_priv,enum dpio_phy phy)3344be47400SFrançois Tigeot static u32 bxt_get_grc(struct drm_i915_private *dev_priv, enum dpio_phy phy)
3354be47400SFrançois Tigeot {
3364be47400SFrançois Tigeot 	u32 val = I915_READ(BXT_PORT_REF_DW6(phy));
3374be47400SFrançois Tigeot 
3384be47400SFrançois Tigeot 	return (val & GRC_CODE_MASK) >> GRC_CODE_SHIFT;
3394be47400SFrançois Tigeot }
3404be47400SFrançois Tigeot 
bxt_phy_wait_grc_done(struct drm_i915_private * dev_priv,enum dpio_phy phy)3414be47400SFrançois Tigeot static void bxt_phy_wait_grc_done(struct drm_i915_private *dev_priv,
3424be47400SFrançois Tigeot 				  enum dpio_phy phy)
3434be47400SFrançois Tigeot {
3444be47400SFrançois Tigeot 	if (intel_wait_for_register(dev_priv,
3454be47400SFrançois Tigeot 				    BXT_PORT_REF_DW3(phy),
3464be47400SFrançois Tigeot 				    GRC_DONE, GRC_DONE,
3474be47400SFrançois Tigeot 				    10))
3484be47400SFrançois Tigeot 		DRM_ERROR("timeout waiting for PHY%d GRC\n", phy);
3494be47400SFrançois Tigeot }
3504be47400SFrançois Tigeot 
_bxt_ddi_phy_init(struct drm_i915_private * dev_priv,enum dpio_phy phy)3514be47400SFrançois Tigeot static void _bxt_ddi_phy_init(struct drm_i915_private *dev_priv,
3524be47400SFrançois Tigeot 			      enum dpio_phy phy)
3534be47400SFrançois Tigeot {
354*a85cb24fSFrançois Tigeot 	const struct bxt_ddi_phy_info *phy_info;
3554be47400SFrançois Tigeot 	u32 val;
3564be47400SFrançois Tigeot 
357*a85cb24fSFrançois Tigeot 	phy_info = bxt_get_phy_info(dev_priv, phy);
358*a85cb24fSFrançois Tigeot 
3594be47400SFrançois Tigeot 	if (bxt_ddi_phy_is_enabled(dev_priv, phy)) {
3604be47400SFrançois Tigeot 		/* Still read out the GRC value for state verification */
3614be47400SFrançois Tigeot 		if (phy_info->rcomp_phy != -1)
3624be47400SFrançois Tigeot 			dev_priv->bxt_phy_grc = bxt_get_grc(dev_priv, phy);
3634be47400SFrançois Tigeot 
3644be47400SFrançois Tigeot 		if (bxt_ddi_phy_verify_state(dev_priv, phy)) {
3654be47400SFrançois Tigeot 			DRM_DEBUG_DRIVER("DDI PHY %d already enabled, "
3664be47400SFrançois Tigeot 					 "won't reprogram it\n", phy);
3674be47400SFrançois Tigeot 			return;
3684be47400SFrançois Tigeot 		}
3694be47400SFrançois Tigeot 
3704be47400SFrançois Tigeot 		DRM_DEBUG_DRIVER("DDI PHY %d enabled with invalid state, "
3714be47400SFrançois Tigeot 				 "force reprogramming it\n", phy);
3724be47400SFrançois Tigeot 	}
3734be47400SFrançois Tigeot 
3744be47400SFrançois Tigeot 	val = I915_READ(BXT_P_CR_GT_DISP_PWRON);
375*a85cb24fSFrançois Tigeot 	val |= phy_info->pwron_mask;
3764be47400SFrançois Tigeot 	I915_WRITE(BXT_P_CR_GT_DISP_PWRON, val);
3774be47400SFrançois Tigeot 
3784be47400SFrançois Tigeot 	/*
3794be47400SFrançois Tigeot 	 * The PHY registers start out inaccessible and respond to reads with
3804be47400SFrançois Tigeot 	 * all 1s.  Eventually they become accessible as they power up, then
3814be47400SFrançois Tigeot 	 * the reserved bit will give the default 0.  Poll on the reserved bit
3824be47400SFrançois Tigeot 	 * becoming 0 to find when the PHY is accessible.
3834be47400SFrançois Tigeot 	 * HW team confirmed that the time to reach phypowergood status is
3844be47400SFrançois Tigeot 	 * anywhere between 50 us and 100us.
3854be47400SFrançois Tigeot 	 */
3864be47400SFrançois Tigeot 	if (wait_for_us(((I915_READ(BXT_PORT_CL1CM_DW0(phy)) &
3874be47400SFrançois Tigeot 		(PHY_RESERVED | PHY_POWER_GOOD)) == PHY_POWER_GOOD), 100)) {
3884be47400SFrançois Tigeot 		DRM_ERROR("timeout during PHY%d power on\n", phy);
3894be47400SFrançois Tigeot 	}
3904be47400SFrançois Tigeot 
3914be47400SFrançois Tigeot 	/* Program PLL Rcomp code offset */
3924be47400SFrançois Tigeot 	val = I915_READ(BXT_PORT_CL1CM_DW9(phy));
3934be47400SFrançois Tigeot 	val &= ~IREF0RC_OFFSET_MASK;
3944be47400SFrançois Tigeot 	val |= 0xE4 << IREF0RC_OFFSET_SHIFT;
3954be47400SFrançois Tigeot 	I915_WRITE(BXT_PORT_CL1CM_DW9(phy), val);
3964be47400SFrançois Tigeot 
3974be47400SFrançois Tigeot 	val = I915_READ(BXT_PORT_CL1CM_DW10(phy));
3984be47400SFrançois Tigeot 	val &= ~IREF1RC_OFFSET_MASK;
3994be47400SFrançois Tigeot 	val |= 0xE4 << IREF1RC_OFFSET_SHIFT;
4004be47400SFrançois Tigeot 	I915_WRITE(BXT_PORT_CL1CM_DW10(phy), val);
4014be47400SFrançois Tigeot 
4024be47400SFrançois Tigeot 	/* Program power gating */
4034be47400SFrançois Tigeot 	val = I915_READ(BXT_PORT_CL1CM_DW28(phy));
4044be47400SFrançois Tigeot 	val |= OCL1_POWER_DOWN_EN | DW28_OLDO_DYN_PWR_DOWN_EN |
4054be47400SFrançois Tigeot 		SUS_CLK_CONFIG;
4064be47400SFrançois Tigeot 	I915_WRITE(BXT_PORT_CL1CM_DW28(phy), val);
4074be47400SFrançois Tigeot 
4084be47400SFrançois Tigeot 	if (phy_info->dual_channel) {
4094be47400SFrançois Tigeot 		val = I915_READ(BXT_PORT_CL2CM_DW6(phy));
4104be47400SFrançois Tigeot 		val |= DW6_OLDO_DYN_PWR_DOWN_EN;
4114be47400SFrançois Tigeot 		I915_WRITE(BXT_PORT_CL2CM_DW6(phy), val);
4124be47400SFrançois Tigeot 	}
4134be47400SFrançois Tigeot 
4144be47400SFrançois Tigeot 	if (phy_info->rcomp_phy != -1) {
4154be47400SFrançois Tigeot 		uint32_t grc_code;
416*a85cb24fSFrançois Tigeot 
417*a85cb24fSFrançois Tigeot 		bxt_phy_wait_grc_done(dev_priv, phy_info->rcomp_phy);
418*a85cb24fSFrançois Tigeot 
4194be47400SFrançois Tigeot 		/*
4204be47400SFrançois Tigeot 		 * PHY0 isn't connected to an RCOMP resistor so copy over
4214be47400SFrançois Tigeot 		 * the corresponding calibrated value from PHY1, and disable
4224be47400SFrançois Tigeot 		 * the automatic calibration on PHY0.
4234be47400SFrançois Tigeot 		 */
4244be47400SFrançois Tigeot 		val = dev_priv->bxt_phy_grc = bxt_get_grc(dev_priv,
4254be47400SFrançois Tigeot 							  phy_info->rcomp_phy);
4264be47400SFrançois Tigeot 		grc_code = val << GRC_CODE_FAST_SHIFT |
4274be47400SFrançois Tigeot 			   val << GRC_CODE_SLOW_SHIFT |
4284be47400SFrançois Tigeot 			   val;
4294be47400SFrançois Tigeot 		I915_WRITE(BXT_PORT_REF_DW6(phy), grc_code);
4304be47400SFrançois Tigeot 
4314be47400SFrançois Tigeot 		val = I915_READ(BXT_PORT_REF_DW8(phy));
4324be47400SFrançois Tigeot 		val |= GRC_DIS | GRC_RDY_OVRD;
4334be47400SFrançois Tigeot 		I915_WRITE(BXT_PORT_REF_DW8(phy), val);
4344be47400SFrançois Tigeot 	}
4354be47400SFrançois Tigeot 
436*a85cb24fSFrançois Tigeot 	if (phy_info->reset_delay)
437*a85cb24fSFrançois Tigeot 		udelay(phy_info->reset_delay);
438*a85cb24fSFrançois Tigeot 
4394be47400SFrançois Tigeot 	val = I915_READ(BXT_PHY_CTL_FAMILY(phy));
4404be47400SFrançois Tigeot 	val |= COMMON_RESET_DIS;
4414be47400SFrançois Tigeot 	I915_WRITE(BXT_PHY_CTL_FAMILY(phy), val);
4424be47400SFrançois Tigeot }
4434be47400SFrançois Tigeot 
bxt_ddi_phy_uninit(struct drm_i915_private * dev_priv,enum dpio_phy phy)4444be47400SFrançois Tigeot void bxt_ddi_phy_uninit(struct drm_i915_private *dev_priv, enum dpio_phy phy)
4454be47400SFrançois Tigeot {
446*a85cb24fSFrançois Tigeot 	const struct bxt_ddi_phy_info *phy_info;
4474be47400SFrançois Tigeot 	uint32_t val;
4484be47400SFrançois Tigeot 
449*a85cb24fSFrançois Tigeot 	phy_info = bxt_get_phy_info(dev_priv, phy);
450*a85cb24fSFrançois Tigeot 
4514be47400SFrançois Tigeot 	val = I915_READ(BXT_PHY_CTL_FAMILY(phy));
4524be47400SFrançois Tigeot 	val &= ~COMMON_RESET_DIS;
4534be47400SFrançois Tigeot 	I915_WRITE(BXT_PHY_CTL_FAMILY(phy), val);
4544be47400SFrançois Tigeot 
4554be47400SFrançois Tigeot 	val = I915_READ(BXT_P_CR_GT_DISP_PWRON);
456*a85cb24fSFrançois Tigeot 	val &= ~phy_info->pwron_mask;
4574be47400SFrançois Tigeot 	I915_WRITE(BXT_P_CR_GT_DISP_PWRON, val);
4584be47400SFrançois Tigeot }
4594be47400SFrançois Tigeot 
bxt_ddi_phy_init(struct drm_i915_private * dev_priv,enum dpio_phy phy)4604be47400SFrançois Tigeot void bxt_ddi_phy_init(struct drm_i915_private *dev_priv, enum dpio_phy phy)
4614be47400SFrançois Tigeot {
462*a85cb24fSFrançois Tigeot 	const struct bxt_ddi_phy_info *phy_info =
463*a85cb24fSFrançois Tigeot 		bxt_get_phy_info(dev_priv, phy);
4644be47400SFrançois Tigeot 	enum dpio_phy rcomp_phy = phy_info->rcomp_phy;
4654be47400SFrançois Tigeot 	bool was_enabled;
4664be47400SFrançois Tigeot 
4674be47400SFrançois Tigeot 	lockdep_assert_held(&dev_priv->power_domains.lock);
4684be47400SFrançois Tigeot 
4694be47400SFrançois Tigeot 	if (rcomp_phy != -1) {
4704be47400SFrançois Tigeot 		was_enabled = bxt_ddi_phy_is_enabled(dev_priv, rcomp_phy);
4714be47400SFrançois Tigeot 
4724be47400SFrançois Tigeot 		/*
4734be47400SFrançois Tigeot 		 * We need to copy the GRC calibration value from rcomp_phy,
4744be47400SFrançois Tigeot 		 * so make sure it's powered up.
4754be47400SFrançois Tigeot 		 */
4764be47400SFrançois Tigeot 		if (!was_enabled)
4774be47400SFrançois Tigeot 			_bxt_ddi_phy_init(dev_priv, rcomp_phy);
4784be47400SFrançois Tigeot 	}
4794be47400SFrançois Tigeot 
4804be47400SFrançois Tigeot 	_bxt_ddi_phy_init(dev_priv, phy);
4814be47400SFrançois Tigeot 
4824be47400SFrançois Tigeot 	if (rcomp_phy != -1 && !was_enabled)
4834be47400SFrançois Tigeot 		bxt_ddi_phy_uninit(dev_priv, phy_info->rcomp_phy);
4844be47400SFrançois Tigeot }
4854be47400SFrançois Tigeot 
4864be47400SFrançois Tigeot static bool __printf(6, 7)
__phy_reg_verify_state(struct drm_i915_private * dev_priv,enum dpio_phy phy,i915_reg_t reg,u32 mask,u32 expected,const char * reg_fmt,...)4874be47400SFrançois Tigeot __phy_reg_verify_state(struct drm_i915_private *dev_priv, enum dpio_phy phy,
4884be47400SFrançois Tigeot 		       i915_reg_t reg, u32 mask, u32 expected,
4894be47400SFrançois Tigeot 		       const char *reg_fmt, ...)
4904be47400SFrançois Tigeot {
4914be47400SFrançois Tigeot 	struct va_format vaf;
4924be47400SFrançois Tigeot 	va_list args;
4934be47400SFrançois Tigeot 	u32 val;
4944be47400SFrançois Tigeot 
4954be47400SFrançois Tigeot 	val = I915_READ(reg);
4964be47400SFrançois Tigeot 	if ((val & mask) == expected)
4974be47400SFrançois Tigeot 		return true;
4984be47400SFrançois Tigeot 
4994be47400SFrançois Tigeot 	va_start(args, reg_fmt);
5004be47400SFrançois Tigeot 	vaf.fmt = reg_fmt;
5014be47400SFrançois Tigeot 	vaf.va = &args;
5024be47400SFrançois Tigeot 
5034be47400SFrançois Tigeot 	DRM_DEBUG_DRIVER("DDI PHY %d reg %pV [%08x] state mismatch: "
5044be47400SFrançois Tigeot 			 "current %08x, expected %08x (mask %08x)\n",
5054be47400SFrançois Tigeot 			 phy, &vaf, reg.reg, val, (val & ~mask) | expected,
5064be47400SFrançois Tigeot 			 mask);
5074be47400SFrançois Tigeot 
5084be47400SFrançois Tigeot 	va_end(args);
5094be47400SFrançois Tigeot 
5104be47400SFrançois Tigeot 	return false;
5114be47400SFrançois Tigeot }
5124be47400SFrançois Tigeot 
bxt_ddi_phy_verify_state(struct drm_i915_private * dev_priv,enum dpio_phy phy)5134be47400SFrançois Tigeot bool bxt_ddi_phy_verify_state(struct drm_i915_private *dev_priv,
5144be47400SFrançois Tigeot 			      enum dpio_phy phy)
5154be47400SFrançois Tigeot {
516*a85cb24fSFrançois Tigeot 	const struct bxt_ddi_phy_info *phy_info;
5174be47400SFrançois Tigeot 	uint32_t mask;
5184be47400SFrançois Tigeot 	bool ok;
5194be47400SFrançois Tigeot 
520*a85cb24fSFrançois Tigeot 	phy_info = bxt_get_phy_info(dev_priv, phy);
521*a85cb24fSFrançois Tigeot 
5224be47400SFrançois Tigeot #define _CHK(reg, mask, exp, fmt, ...)					\
5234be47400SFrançois Tigeot 	__phy_reg_verify_state(dev_priv, phy, reg, mask, exp, fmt,	\
5244be47400SFrançois Tigeot 			       ## __VA_ARGS__)
5254be47400SFrançois Tigeot 
5264be47400SFrançois Tigeot 	if (!bxt_ddi_phy_is_enabled(dev_priv, phy))
5274be47400SFrançois Tigeot 		return false;
5284be47400SFrançois Tigeot 
5294be47400SFrançois Tigeot 	ok = true;
5304be47400SFrançois Tigeot 
5314be47400SFrançois Tigeot 	/* PLL Rcomp code offset */
5324be47400SFrançois Tigeot 	ok &= _CHK(BXT_PORT_CL1CM_DW9(phy),
5334be47400SFrançois Tigeot 		    IREF0RC_OFFSET_MASK, 0xe4 << IREF0RC_OFFSET_SHIFT,
5344be47400SFrançois Tigeot 		    "BXT_PORT_CL1CM_DW9(%d)", phy);
5354be47400SFrançois Tigeot 	ok &= _CHK(BXT_PORT_CL1CM_DW10(phy),
5364be47400SFrançois Tigeot 		    IREF1RC_OFFSET_MASK, 0xe4 << IREF1RC_OFFSET_SHIFT,
5374be47400SFrançois Tigeot 		    "BXT_PORT_CL1CM_DW10(%d)", phy);
5384be47400SFrançois Tigeot 
5394be47400SFrançois Tigeot 	/* Power gating */
5404be47400SFrançois Tigeot 	mask = OCL1_POWER_DOWN_EN | DW28_OLDO_DYN_PWR_DOWN_EN | SUS_CLK_CONFIG;
5414be47400SFrançois Tigeot 	ok &= _CHK(BXT_PORT_CL1CM_DW28(phy), mask, mask,
5424be47400SFrançois Tigeot 		    "BXT_PORT_CL1CM_DW28(%d)", phy);
5434be47400SFrançois Tigeot 
5444be47400SFrançois Tigeot 	if (phy_info->dual_channel)
5454be47400SFrançois Tigeot 		ok &= _CHK(BXT_PORT_CL2CM_DW6(phy),
5464be47400SFrançois Tigeot 			   DW6_OLDO_DYN_PWR_DOWN_EN, DW6_OLDO_DYN_PWR_DOWN_EN,
5474be47400SFrançois Tigeot 			   "BXT_PORT_CL2CM_DW6(%d)", phy);
5484be47400SFrançois Tigeot 
5494be47400SFrançois Tigeot 	if (phy_info->rcomp_phy != -1) {
5504be47400SFrançois Tigeot 		u32 grc_code = dev_priv->bxt_phy_grc;
5514be47400SFrançois Tigeot 
5524be47400SFrançois Tigeot 		grc_code = grc_code << GRC_CODE_FAST_SHIFT |
5534be47400SFrançois Tigeot 			   grc_code << GRC_CODE_SLOW_SHIFT |
5544be47400SFrançois Tigeot 			   grc_code;
5554be47400SFrançois Tigeot 		mask = GRC_CODE_FAST_MASK | GRC_CODE_SLOW_MASK |
5564be47400SFrançois Tigeot 		       GRC_CODE_NOM_MASK;
5574be47400SFrançois Tigeot 		ok &= _CHK(BXT_PORT_REF_DW6(phy), mask, grc_code,
5584be47400SFrançois Tigeot 			   "BXT_PORT_REF_DW6(%d)", phy);
5594be47400SFrançois Tigeot 
5604be47400SFrançois Tigeot 		mask = GRC_DIS | GRC_RDY_OVRD;
5614be47400SFrançois Tigeot 		ok &= _CHK(BXT_PORT_REF_DW8(phy), mask, mask,
5624be47400SFrançois Tigeot 			    "BXT_PORT_REF_DW8(%d)", phy);
5634be47400SFrançois Tigeot 	}
5644be47400SFrançois Tigeot 
5654be47400SFrançois Tigeot 	return ok;
5664be47400SFrançois Tigeot #undef _CHK
5674be47400SFrançois Tigeot }
5684be47400SFrançois Tigeot 
5694be47400SFrançois Tigeot uint8_t
bxt_ddi_phy_calc_lane_lat_optim_mask(struct intel_encoder * encoder,uint8_t lane_count)5704be47400SFrançois Tigeot bxt_ddi_phy_calc_lane_lat_optim_mask(struct intel_encoder *encoder,
5714be47400SFrançois Tigeot 				     uint8_t lane_count)
5724be47400SFrançois Tigeot {
5734be47400SFrançois Tigeot 	switch (lane_count) {
5744be47400SFrançois Tigeot 	case 1:
5754be47400SFrançois Tigeot 		return 0;
5764be47400SFrançois Tigeot 	case 2:
5774be47400SFrançois Tigeot 		return BIT(2) | BIT(0);
5784be47400SFrançois Tigeot 	case 4:
5794be47400SFrançois Tigeot 		return BIT(3) | BIT(2) | BIT(0);
5804be47400SFrançois Tigeot 	default:
5814be47400SFrançois Tigeot 		MISSING_CASE(lane_count);
5824be47400SFrançois Tigeot 
5834be47400SFrançois Tigeot 		return 0;
5844be47400SFrançois Tigeot 	}
5854be47400SFrançois Tigeot }
5864be47400SFrançois Tigeot 
bxt_ddi_phy_set_lane_optim_mask(struct intel_encoder * encoder,uint8_t lane_lat_optim_mask)5874be47400SFrançois Tigeot void bxt_ddi_phy_set_lane_optim_mask(struct intel_encoder *encoder,
5884be47400SFrançois Tigeot 				     uint8_t lane_lat_optim_mask)
5894be47400SFrançois Tigeot {
5904be47400SFrançois Tigeot 	struct intel_digital_port *dport = enc_to_dig_port(&encoder->base);
5914be47400SFrançois Tigeot 	struct drm_i915_private *dev_priv = to_i915(dport->base.base.dev);
5924be47400SFrançois Tigeot 	enum port port = dport->port;
5934be47400SFrançois Tigeot 	enum dpio_phy phy;
5944be47400SFrançois Tigeot 	enum dpio_channel ch;
5954be47400SFrançois Tigeot 	int lane;
5964be47400SFrançois Tigeot 
597*a85cb24fSFrançois Tigeot 	bxt_port_to_phy_channel(dev_priv, port, &phy, &ch);
5984be47400SFrançois Tigeot 
5994be47400SFrançois Tigeot 	for (lane = 0; lane < 4; lane++) {
6004be47400SFrançois Tigeot 		u32 val = I915_READ(BXT_PORT_TX_DW14_LN(phy, ch, lane));
6014be47400SFrançois Tigeot 
6024be47400SFrançois Tigeot 		/*
6034be47400SFrançois Tigeot 		 * Note that on CHV this flag is called UPAR, but has
6044be47400SFrançois Tigeot 		 * the same function.
6054be47400SFrançois Tigeot 		 */
6064be47400SFrançois Tigeot 		val &= ~LATENCY_OPTIM;
6074be47400SFrançois Tigeot 		if (lane_lat_optim_mask & BIT(lane))
6084be47400SFrançois Tigeot 			val |= LATENCY_OPTIM;
6094be47400SFrançois Tigeot 
6104be47400SFrançois Tigeot 		I915_WRITE(BXT_PORT_TX_DW14_LN(phy, ch, lane), val);
6114be47400SFrançois Tigeot 	}
6124be47400SFrançois Tigeot }
6134be47400SFrançois Tigeot 
6144be47400SFrançois Tigeot uint8_t
bxt_ddi_phy_get_lane_lat_optim_mask(struct intel_encoder * encoder)6154be47400SFrançois Tigeot bxt_ddi_phy_get_lane_lat_optim_mask(struct intel_encoder *encoder)
6164be47400SFrançois Tigeot {
6174be47400SFrançois Tigeot 	struct intel_digital_port *dport = enc_to_dig_port(&encoder->base);
6184be47400SFrançois Tigeot 	struct drm_i915_private *dev_priv = to_i915(dport->base.base.dev);
6194be47400SFrançois Tigeot 	enum port port = dport->port;
6204be47400SFrançois Tigeot 	enum dpio_phy phy;
6214be47400SFrançois Tigeot 	enum dpio_channel ch;
6224be47400SFrançois Tigeot 	int lane;
6234be47400SFrançois Tigeot 	uint8_t mask;
6244be47400SFrançois Tigeot 
625*a85cb24fSFrançois Tigeot 	bxt_port_to_phy_channel(dev_priv, port, &phy, &ch);
6264be47400SFrançois Tigeot 
6274be47400SFrançois Tigeot 	mask = 0;
6284be47400SFrançois Tigeot 	for (lane = 0; lane < 4; lane++) {
6294be47400SFrançois Tigeot 		u32 val = I915_READ(BXT_PORT_TX_DW14_LN(phy, ch, lane));
6304be47400SFrançois Tigeot 
6314be47400SFrançois Tigeot 		if (val & LATENCY_OPTIM)
6324be47400SFrançois Tigeot 			mask |= BIT(lane);
6334be47400SFrançois Tigeot 	}
6344be47400SFrançois Tigeot 
6354be47400SFrançois Tigeot 	return mask;
6364be47400SFrançois Tigeot }
6374be47400SFrançois Tigeot 
6384be47400SFrançois Tigeot 
chv_set_phy_signal_level(struct intel_encoder * encoder,u32 deemph_reg_value,u32 margin_reg_value,bool uniq_trans_scale)6391487f786SFrançois Tigeot void chv_set_phy_signal_level(struct intel_encoder *encoder,
6401487f786SFrançois Tigeot 			      u32 deemph_reg_value, u32 margin_reg_value,
6411487f786SFrançois Tigeot 			      bool uniq_trans_scale)
6421487f786SFrançois Tigeot {
6431487f786SFrançois Tigeot 	struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
6441487f786SFrançois Tigeot 	struct intel_digital_port *dport = enc_to_dig_port(&encoder->base);
6451487f786SFrançois Tigeot 	struct intel_crtc *intel_crtc = to_intel_crtc(dport->base.base.crtc);
6461487f786SFrançois Tigeot 	enum dpio_channel ch = vlv_dport_to_channel(dport);
6471487f786SFrançois Tigeot 	enum i915_pipe pipe = intel_crtc->pipe;
6481487f786SFrançois Tigeot 	u32 val;
6491487f786SFrançois Tigeot 	int i;
6501487f786SFrançois Tigeot 
6511487f786SFrançois Tigeot 	mutex_lock(&dev_priv->sb_lock);
6521487f786SFrançois Tigeot 
6531487f786SFrançois Tigeot 	/* Clear calc init */
6541487f786SFrançois Tigeot 	val = vlv_dpio_read(dev_priv, pipe, VLV_PCS01_DW10(ch));
6551487f786SFrançois Tigeot 	val &= ~(DPIO_PCS_SWING_CALC_TX0_TX2 | DPIO_PCS_SWING_CALC_TX1_TX3);
6561487f786SFrançois Tigeot 	val &= ~(DPIO_PCS_TX1DEEMP_MASK | DPIO_PCS_TX2DEEMP_MASK);
6571487f786SFrançois Tigeot 	val |= DPIO_PCS_TX1DEEMP_9P5 | DPIO_PCS_TX2DEEMP_9P5;
6581487f786SFrançois Tigeot 	vlv_dpio_write(dev_priv, pipe, VLV_PCS01_DW10(ch), val);
6591487f786SFrançois Tigeot 
6601487f786SFrançois Tigeot 	if (intel_crtc->config->lane_count > 2) {
6611487f786SFrançois Tigeot 		val = vlv_dpio_read(dev_priv, pipe, VLV_PCS23_DW10(ch));
6621487f786SFrançois Tigeot 		val &= ~(DPIO_PCS_SWING_CALC_TX0_TX2 | DPIO_PCS_SWING_CALC_TX1_TX3);
6631487f786SFrançois Tigeot 		val &= ~(DPIO_PCS_TX1DEEMP_MASK | DPIO_PCS_TX2DEEMP_MASK);
6641487f786SFrançois Tigeot 		val |= DPIO_PCS_TX1DEEMP_9P5 | DPIO_PCS_TX2DEEMP_9P5;
6651487f786SFrançois Tigeot 		vlv_dpio_write(dev_priv, pipe, VLV_PCS23_DW10(ch), val);
6661487f786SFrançois Tigeot 	}
6671487f786SFrançois Tigeot 
6681487f786SFrançois Tigeot 	val = vlv_dpio_read(dev_priv, pipe, VLV_PCS01_DW9(ch));
6691487f786SFrançois Tigeot 	val &= ~(DPIO_PCS_TX1MARGIN_MASK | DPIO_PCS_TX2MARGIN_MASK);
6701487f786SFrançois Tigeot 	val |= DPIO_PCS_TX1MARGIN_000 | DPIO_PCS_TX2MARGIN_000;
6711487f786SFrançois Tigeot 	vlv_dpio_write(dev_priv, pipe, VLV_PCS01_DW9(ch), val);
6721487f786SFrançois Tigeot 
6731487f786SFrançois Tigeot 	if (intel_crtc->config->lane_count > 2) {
6741487f786SFrançois Tigeot 		val = vlv_dpio_read(dev_priv, pipe, VLV_PCS23_DW9(ch));
6751487f786SFrançois Tigeot 		val &= ~(DPIO_PCS_TX1MARGIN_MASK | DPIO_PCS_TX2MARGIN_MASK);
6761487f786SFrançois Tigeot 		val |= DPIO_PCS_TX1MARGIN_000 | DPIO_PCS_TX2MARGIN_000;
6771487f786SFrançois Tigeot 		vlv_dpio_write(dev_priv, pipe, VLV_PCS23_DW9(ch), val);
6781487f786SFrançois Tigeot 	}
6791487f786SFrançois Tigeot 
6801487f786SFrançois Tigeot 	/* Program swing deemph */
6811487f786SFrançois Tigeot 	for (i = 0; i < intel_crtc->config->lane_count; i++) {
6821487f786SFrançois Tigeot 		val = vlv_dpio_read(dev_priv, pipe, CHV_TX_DW4(ch, i));
6831487f786SFrançois Tigeot 		val &= ~DPIO_SWING_DEEMPH9P5_MASK;
6841487f786SFrançois Tigeot 		val |= deemph_reg_value << DPIO_SWING_DEEMPH9P5_SHIFT;
6851487f786SFrançois Tigeot 		vlv_dpio_write(dev_priv, pipe, CHV_TX_DW4(ch, i), val);
6861487f786SFrançois Tigeot 	}
6871487f786SFrançois Tigeot 
6881487f786SFrançois Tigeot 	/* Program swing margin */
6891487f786SFrançois Tigeot 	for (i = 0; i < intel_crtc->config->lane_count; i++) {
6901487f786SFrançois Tigeot 		val = vlv_dpio_read(dev_priv, pipe, CHV_TX_DW2(ch, i));
6911487f786SFrançois Tigeot 
6921487f786SFrançois Tigeot 		val &= ~DPIO_SWING_MARGIN000_MASK;
6931487f786SFrançois Tigeot 		val |= margin_reg_value << DPIO_SWING_MARGIN000_SHIFT;
6941487f786SFrançois Tigeot 
6951487f786SFrançois Tigeot 		/*
6961487f786SFrançois Tigeot 		 * Supposedly this value shouldn't matter when unique transition
6971487f786SFrançois Tigeot 		 * scale is disabled, but in fact it does matter. Let's just
6981487f786SFrançois Tigeot 		 * always program the same value and hope it's OK.
6991487f786SFrançois Tigeot 		 */
7001487f786SFrançois Tigeot 		val &= ~(0xff << DPIO_UNIQ_TRANS_SCALE_SHIFT);
7011487f786SFrançois Tigeot 		val |= 0x9a << DPIO_UNIQ_TRANS_SCALE_SHIFT;
7021487f786SFrançois Tigeot 
7031487f786SFrançois Tigeot 		vlv_dpio_write(dev_priv, pipe, CHV_TX_DW2(ch, i), val);
7041487f786SFrançois Tigeot 	}
7051487f786SFrançois Tigeot 
7061487f786SFrançois Tigeot 	/*
7071487f786SFrançois Tigeot 	 * The document said it needs to set bit 27 for ch0 and bit 26
7081487f786SFrançois Tigeot 	 * for ch1. Might be a typo in the doc.
7091487f786SFrançois Tigeot 	 * For now, for this unique transition scale selection, set bit
7101487f786SFrançois Tigeot 	 * 27 for ch0 and ch1.
7111487f786SFrançois Tigeot 	 */
7121487f786SFrançois Tigeot 	for (i = 0; i < intel_crtc->config->lane_count; i++) {
7131487f786SFrançois Tigeot 		val = vlv_dpio_read(dev_priv, pipe, CHV_TX_DW3(ch, i));
7141487f786SFrançois Tigeot 		if (uniq_trans_scale)
7151487f786SFrançois Tigeot 			val |= DPIO_TX_UNIQ_TRANS_SCALE_EN;
7161487f786SFrançois Tigeot 		else
7171487f786SFrançois Tigeot 			val &= ~DPIO_TX_UNIQ_TRANS_SCALE_EN;
7181487f786SFrançois Tigeot 		vlv_dpio_write(dev_priv, pipe, CHV_TX_DW3(ch, i), val);
7191487f786SFrançois Tigeot 	}
7201487f786SFrançois Tigeot 
7211487f786SFrançois Tigeot 	/* Start swing calculation */
7221487f786SFrançois Tigeot 	val = vlv_dpio_read(dev_priv, pipe, VLV_PCS01_DW10(ch));
7231487f786SFrançois Tigeot 	val |= DPIO_PCS_SWING_CALC_TX0_TX2 | DPIO_PCS_SWING_CALC_TX1_TX3;
7241487f786SFrançois Tigeot 	vlv_dpio_write(dev_priv, pipe, VLV_PCS01_DW10(ch), val);
7251487f786SFrançois Tigeot 
7261487f786SFrançois Tigeot 	if (intel_crtc->config->lane_count > 2) {
7271487f786SFrançois Tigeot 		val = vlv_dpio_read(dev_priv, pipe, VLV_PCS23_DW10(ch));
7281487f786SFrançois Tigeot 		val |= DPIO_PCS_SWING_CALC_TX0_TX2 | DPIO_PCS_SWING_CALC_TX1_TX3;
7291487f786SFrançois Tigeot 		vlv_dpio_write(dev_priv, pipe, VLV_PCS23_DW10(ch), val);
7301487f786SFrançois Tigeot 	}
7311487f786SFrançois Tigeot 
7321487f786SFrançois Tigeot 	mutex_unlock(&dev_priv->sb_lock);
7331487f786SFrançois Tigeot 
7341487f786SFrançois Tigeot }
7351487f786SFrançois Tigeot 
chv_data_lane_soft_reset(struct intel_encoder * encoder,bool reset)7361487f786SFrançois Tigeot void chv_data_lane_soft_reset(struct intel_encoder *encoder,
7371487f786SFrançois Tigeot 			      bool reset)
7381487f786SFrançois Tigeot {
7391487f786SFrançois Tigeot 	struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
7401487f786SFrançois Tigeot 	enum dpio_channel ch = vlv_dport_to_channel(enc_to_dig_port(&encoder->base));
7411487f786SFrançois Tigeot 	struct intel_crtc *crtc = to_intel_crtc(encoder->base.crtc);
7421487f786SFrançois Tigeot 	enum i915_pipe pipe = crtc->pipe;
7431487f786SFrançois Tigeot 	uint32_t val;
7441487f786SFrançois Tigeot 
7451487f786SFrançois Tigeot 	val = vlv_dpio_read(dev_priv, pipe, VLV_PCS01_DW0(ch));
7461487f786SFrançois Tigeot 	if (reset)
7471487f786SFrançois Tigeot 		val &= ~(DPIO_PCS_TX_LANE2_RESET | DPIO_PCS_TX_LANE1_RESET);
7481487f786SFrançois Tigeot 	else
7491487f786SFrançois Tigeot 		val |= DPIO_PCS_TX_LANE2_RESET | DPIO_PCS_TX_LANE1_RESET;
7501487f786SFrançois Tigeot 	vlv_dpio_write(dev_priv, pipe, VLV_PCS01_DW0(ch), val);
7511487f786SFrançois Tigeot 
7521487f786SFrançois Tigeot 	if (crtc->config->lane_count > 2) {
7531487f786SFrançois Tigeot 		val = vlv_dpio_read(dev_priv, pipe, VLV_PCS23_DW0(ch));
7541487f786SFrançois Tigeot 		if (reset)
7551487f786SFrançois Tigeot 			val &= ~(DPIO_PCS_TX_LANE2_RESET | DPIO_PCS_TX_LANE1_RESET);
7561487f786SFrançois Tigeot 		else
7571487f786SFrançois Tigeot 			val |= DPIO_PCS_TX_LANE2_RESET | DPIO_PCS_TX_LANE1_RESET;
7581487f786SFrançois Tigeot 		vlv_dpio_write(dev_priv, pipe, VLV_PCS23_DW0(ch), val);
7591487f786SFrançois Tigeot 	}
7601487f786SFrançois Tigeot 
7611487f786SFrançois Tigeot 	val = vlv_dpio_read(dev_priv, pipe, VLV_PCS01_DW1(ch));
7621487f786SFrançois Tigeot 	val |= CHV_PCS_REQ_SOFTRESET_EN;
7631487f786SFrançois Tigeot 	if (reset)
7641487f786SFrançois Tigeot 		val &= ~DPIO_PCS_CLK_SOFT_RESET;
7651487f786SFrançois Tigeot 	else
7661487f786SFrançois Tigeot 		val |= DPIO_PCS_CLK_SOFT_RESET;
7671487f786SFrançois Tigeot 	vlv_dpio_write(dev_priv, pipe, VLV_PCS01_DW1(ch), val);
7681487f786SFrançois Tigeot 
7691487f786SFrançois Tigeot 	if (crtc->config->lane_count > 2) {
7701487f786SFrançois Tigeot 		val = vlv_dpio_read(dev_priv, pipe, VLV_PCS23_DW1(ch));
7711487f786SFrançois Tigeot 		val |= CHV_PCS_REQ_SOFTRESET_EN;
7721487f786SFrançois Tigeot 		if (reset)
7731487f786SFrançois Tigeot 			val &= ~DPIO_PCS_CLK_SOFT_RESET;
7741487f786SFrançois Tigeot 		else
7751487f786SFrançois Tigeot 			val |= DPIO_PCS_CLK_SOFT_RESET;
7761487f786SFrançois Tigeot 		vlv_dpio_write(dev_priv, pipe, VLV_PCS23_DW1(ch), val);
7771487f786SFrançois Tigeot 	}
7781487f786SFrançois Tigeot }
7791487f786SFrançois Tigeot 
chv_phy_pre_pll_enable(struct intel_encoder * encoder)7801487f786SFrançois Tigeot void chv_phy_pre_pll_enable(struct intel_encoder *encoder)
7811487f786SFrançois Tigeot {
7821487f786SFrançois Tigeot 	struct intel_digital_port *dport = enc_to_dig_port(&encoder->base);
7831487f786SFrançois Tigeot 	struct drm_device *dev = encoder->base.dev;
784303bf270SFrançois Tigeot 	struct drm_i915_private *dev_priv = to_i915(dev);
7851487f786SFrançois Tigeot 	struct intel_crtc *intel_crtc =
7861487f786SFrançois Tigeot 		to_intel_crtc(encoder->base.crtc);
7871487f786SFrançois Tigeot 	enum dpio_channel ch = vlv_dport_to_channel(dport);
7881487f786SFrançois Tigeot 	enum i915_pipe pipe = intel_crtc->pipe;
7891487f786SFrançois Tigeot 	unsigned int lane_mask =
7901487f786SFrançois Tigeot 		intel_dp_unused_lane_mask(intel_crtc->config->lane_count);
7911487f786SFrançois Tigeot 	u32 val;
7921487f786SFrançois Tigeot 
7931487f786SFrançois Tigeot 	/*
7941487f786SFrançois Tigeot 	 * Must trick the second common lane into life.
7951487f786SFrançois Tigeot 	 * Otherwise we can't even access the PLL.
7961487f786SFrançois Tigeot 	 */
7971487f786SFrançois Tigeot 	if (ch == DPIO_CH0 && pipe == PIPE_B)
7981487f786SFrançois Tigeot 		dport->release_cl2_override =
7991487f786SFrançois Tigeot 			!chv_phy_powergate_ch(dev_priv, DPIO_PHY0, DPIO_CH1, true);
8001487f786SFrançois Tigeot 
8011487f786SFrançois Tigeot 	chv_phy_powergate_lanes(encoder, true, lane_mask);
8021487f786SFrançois Tigeot 
8031487f786SFrançois Tigeot 	mutex_lock(&dev_priv->sb_lock);
8041487f786SFrançois Tigeot 
8051487f786SFrançois Tigeot 	/* Assert data lane reset */
8061487f786SFrançois Tigeot 	chv_data_lane_soft_reset(encoder, true);
8071487f786SFrançois Tigeot 
8081487f786SFrançois Tigeot 	/* program left/right clock distribution */
8091487f786SFrançois Tigeot 	if (pipe != PIPE_B) {
8101487f786SFrançois Tigeot 		val = vlv_dpio_read(dev_priv, pipe, _CHV_CMN_DW5_CH0);
8111487f786SFrançois Tigeot 		val &= ~(CHV_BUFLEFTENA1_MASK | CHV_BUFRIGHTENA1_MASK);
8121487f786SFrançois Tigeot 		if (ch == DPIO_CH0)
8131487f786SFrançois Tigeot 			val |= CHV_BUFLEFTENA1_FORCE;
8141487f786SFrançois Tigeot 		if (ch == DPIO_CH1)
8151487f786SFrançois Tigeot 			val |= CHV_BUFRIGHTENA1_FORCE;
8161487f786SFrançois Tigeot 		vlv_dpio_write(dev_priv, pipe, _CHV_CMN_DW5_CH0, val);
8171487f786SFrançois Tigeot 	} else {
8181487f786SFrançois Tigeot 		val = vlv_dpio_read(dev_priv, pipe, _CHV_CMN_DW1_CH1);
8191487f786SFrançois Tigeot 		val &= ~(CHV_BUFLEFTENA2_MASK | CHV_BUFRIGHTENA2_MASK);
8201487f786SFrançois Tigeot 		if (ch == DPIO_CH0)
8211487f786SFrançois Tigeot 			val |= CHV_BUFLEFTENA2_FORCE;
8221487f786SFrançois Tigeot 		if (ch == DPIO_CH1)
8231487f786SFrançois Tigeot 			val |= CHV_BUFRIGHTENA2_FORCE;
8241487f786SFrançois Tigeot 		vlv_dpio_write(dev_priv, pipe, _CHV_CMN_DW1_CH1, val);
8251487f786SFrançois Tigeot 	}
8261487f786SFrançois Tigeot 
8271487f786SFrançois Tigeot 	/* program clock channel usage */
8281487f786SFrançois Tigeot 	val = vlv_dpio_read(dev_priv, pipe, VLV_PCS01_DW8(ch));
8291487f786SFrançois Tigeot 	val |= CHV_PCS_USEDCLKCHANNEL_OVRRIDE;
8301487f786SFrançois Tigeot 	if (pipe != PIPE_B)
8311487f786SFrançois Tigeot 		val &= ~CHV_PCS_USEDCLKCHANNEL;
8321487f786SFrançois Tigeot 	else
8331487f786SFrançois Tigeot 		val |= CHV_PCS_USEDCLKCHANNEL;
8341487f786SFrançois Tigeot 	vlv_dpio_write(dev_priv, pipe, VLV_PCS01_DW8(ch), val);
8351487f786SFrançois Tigeot 
8361487f786SFrançois Tigeot 	if (intel_crtc->config->lane_count > 2) {
8371487f786SFrançois Tigeot 		val = vlv_dpio_read(dev_priv, pipe, VLV_PCS23_DW8(ch));
8381487f786SFrançois Tigeot 		val |= CHV_PCS_USEDCLKCHANNEL_OVRRIDE;
8391487f786SFrançois Tigeot 		if (pipe != PIPE_B)
8401487f786SFrançois Tigeot 			val &= ~CHV_PCS_USEDCLKCHANNEL;
8411487f786SFrançois Tigeot 		else
8421487f786SFrançois Tigeot 			val |= CHV_PCS_USEDCLKCHANNEL;
8431487f786SFrançois Tigeot 		vlv_dpio_write(dev_priv, pipe, VLV_PCS23_DW8(ch), val);
8441487f786SFrançois Tigeot 	}
8451487f786SFrançois Tigeot 
8461487f786SFrançois Tigeot 	/*
8471487f786SFrançois Tigeot 	 * This a a bit weird since generally CL
8481487f786SFrançois Tigeot 	 * matches the pipe, but here we need to
8491487f786SFrançois Tigeot 	 * pick the CL based on the port.
8501487f786SFrançois Tigeot 	 */
8511487f786SFrançois Tigeot 	val = vlv_dpio_read(dev_priv, pipe, CHV_CMN_DW19(ch));
8521487f786SFrançois Tigeot 	if (pipe != PIPE_B)
8531487f786SFrançois Tigeot 		val &= ~CHV_CMN_USEDCLKCHANNEL;
8541487f786SFrançois Tigeot 	else
8551487f786SFrançois Tigeot 		val |= CHV_CMN_USEDCLKCHANNEL;
8561487f786SFrançois Tigeot 	vlv_dpio_write(dev_priv, pipe, CHV_CMN_DW19(ch), val);
8571487f786SFrançois Tigeot 
8581487f786SFrançois Tigeot 	mutex_unlock(&dev_priv->sb_lock);
8591487f786SFrançois Tigeot }
8601487f786SFrançois Tigeot 
chv_phy_pre_encoder_enable(struct intel_encoder * encoder)8611487f786SFrançois Tigeot void chv_phy_pre_encoder_enable(struct intel_encoder *encoder)
8621487f786SFrançois Tigeot {
8631487f786SFrançois Tigeot 	struct intel_dp *intel_dp = enc_to_intel_dp(&encoder->base);
8641487f786SFrançois Tigeot 	struct intel_digital_port *dport = dp_to_dig_port(intel_dp);
8651487f786SFrançois Tigeot 	struct drm_device *dev = encoder->base.dev;
866303bf270SFrançois Tigeot 	struct drm_i915_private *dev_priv = to_i915(dev);
8671487f786SFrançois Tigeot 	struct intel_crtc *intel_crtc =
8681487f786SFrançois Tigeot 		to_intel_crtc(encoder->base.crtc);
8691487f786SFrançois Tigeot 	enum dpio_channel ch = vlv_dport_to_channel(dport);
8701487f786SFrançois Tigeot 	int pipe = intel_crtc->pipe;
8711487f786SFrançois Tigeot 	int data, i, stagger;
8721487f786SFrançois Tigeot 	u32 val;
8731487f786SFrançois Tigeot 
8741487f786SFrançois Tigeot 	mutex_lock(&dev_priv->sb_lock);
8751487f786SFrançois Tigeot 
8761487f786SFrançois Tigeot 	/* allow hardware to manage TX FIFO reset source */
8771487f786SFrançois Tigeot 	val = vlv_dpio_read(dev_priv, pipe, VLV_PCS01_DW11(ch));
8781487f786SFrançois Tigeot 	val &= ~DPIO_LANEDESKEW_STRAP_OVRD;
8791487f786SFrançois Tigeot 	vlv_dpio_write(dev_priv, pipe, VLV_PCS01_DW11(ch), val);
8801487f786SFrançois Tigeot 
8811487f786SFrançois Tigeot 	if (intel_crtc->config->lane_count > 2) {
8821487f786SFrançois Tigeot 		val = vlv_dpio_read(dev_priv, pipe, VLV_PCS23_DW11(ch));
8831487f786SFrançois Tigeot 		val &= ~DPIO_LANEDESKEW_STRAP_OVRD;
8841487f786SFrançois Tigeot 		vlv_dpio_write(dev_priv, pipe, VLV_PCS23_DW11(ch), val);
8851487f786SFrançois Tigeot 	}
8861487f786SFrançois Tigeot 
8871487f786SFrançois Tigeot 	/* Program Tx lane latency optimal setting*/
8881487f786SFrançois Tigeot 	for (i = 0; i < intel_crtc->config->lane_count; i++) {
8891487f786SFrançois Tigeot 		/* Set the upar bit */
8901487f786SFrançois Tigeot 		if (intel_crtc->config->lane_count == 1)
8911487f786SFrançois Tigeot 			data = 0x0;
8921487f786SFrançois Tigeot 		else
8931487f786SFrançois Tigeot 			data = (i == 1) ? 0x0 : 0x1;
8941487f786SFrançois Tigeot 		vlv_dpio_write(dev_priv, pipe, CHV_TX_DW14(ch, i),
8951487f786SFrançois Tigeot 				data << DPIO_UPAR_SHIFT);
8961487f786SFrançois Tigeot 	}
8971487f786SFrançois Tigeot 
8981487f786SFrançois Tigeot 	/* Data lane stagger programming */
8991487f786SFrançois Tigeot 	if (intel_crtc->config->port_clock > 270000)
9001487f786SFrançois Tigeot 		stagger = 0x18;
9011487f786SFrançois Tigeot 	else if (intel_crtc->config->port_clock > 135000)
9021487f786SFrançois Tigeot 		stagger = 0xd;
9031487f786SFrançois Tigeot 	else if (intel_crtc->config->port_clock > 67500)
9041487f786SFrançois Tigeot 		stagger = 0x7;
9051487f786SFrançois Tigeot 	else if (intel_crtc->config->port_clock > 33750)
9061487f786SFrançois Tigeot 		stagger = 0x4;
9071487f786SFrançois Tigeot 	else
9081487f786SFrançois Tigeot 		stagger = 0x2;
9091487f786SFrançois Tigeot 
9101487f786SFrançois Tigeot 	val = vlv_dpio_read(dev_priv, pipe, VLV_PCS01_DW11(ch));
9111487f786SFrançois Tigeot 	val |= DPIO_TX2_STAGGER_MASK(0x1f);
9121487f786SFrançois Tigeot 	vlv_dpio_write(dev_priv, pipe, VLV_PCS01_DW11(ch), val);
9131487f786SFrançois Tigeot 
9141487f786SFrançois Tigeot 	if (intel_crtc->config->lane_count > 2) {
9151487f786SFrançois Tigeot 		val = vlv_dpio_read(dev_priv, pipe, VLV_PCS23_DW11(ch));
9161487f786SFrançois Tigeot 		val |= DPIO_TX2_STAGGER_MASK(0x1f);
9171487f786SFrançois Tigeot 		vlv_dpio_write(dev_priv, pipe, VLV_PCS23_DW11(ch), val);
9181487f786SFrançois Tigeot 	}
9191487f786SFrançois Tigeot 
9201487f786SFrançois Tigeot 	vlv_dpio_write(dev_priv, pipe, VLV_PCS01_DW12(ch),
9211487f786SFrançois Tigeot 		       DPIO_LANESTAGGER_STRAP(stagger) |
9221487f786SFrançois Tigeot 		       DPIO_LANESTAGGER_STRAP_OVRD |
9231487f786SFrançois Tigeot 		       DPIO_TX1_STAGGER_MASK(0x1f) |
9241487f786SFrançois Tigeot 		       DPIO_TX1_STAGGER_MULT(6) |
9251487f786SFrançois Tigeot 		       DPIO_TX2_STAGGER_MULT(0));
9261487f786SFrançois Tigeot 
9271487f786SFrançois Tigeot 	if (intel_crtc->config->lane_count > 2) {
9281487f786SFrançois Tigeot 		vlv_dpio_write(dev_priv, pipe, VLV_PCS23_DW12(ch),
9291487f786SFrançois Tigeot 			       DPIO_LANESTAGGER_STRAP(stagger) |
9301487f786SFrançois Tigeot 			       DPIO_LANESTAGGER_STRAP_OVRD |
9311487f786SFrançois Tigeot 			       DPIO_TX1_STAGGER_MASK(0x1f) |
9321487f786SFrançois Tigeot 			       DPIO_TX1_STAGGER_MULT(7) |
9331487f786SFrançois Tigeot 			       DPIO_TX2_STAGGER_MULT(5));
9341487f786SFrançois Tigeot 	}
9351487f786SFrançois Tigeot 
9361487f786SFrançois Tigeot 	/* Deassert data lane reset */
9371487f786SFrançois Tigeot 	chv_data_lane_soft_reset(encoder, false);
9381487f786SFrançois Tigeot 
9391487f786SFrançois Tigeot 	mutex_unlock(&dev_priv->sb_lock);
9401487f786SFrançois Tigeot }
9411487f786SFrançois Tigeot 
chv_phy_release_cl2_override(struct intel_encoder * encoder)9421487f786SFrançois Tigeot void chv_phy_release_cl2_override(struct intel_encoder *encoder)
9431487f786SFrançois Tigeot {
9441487f786SFrançois Tigeot 	struct intel_digital_port *dport = enc_to_dig_port(&encoder->base);
9451487f786SFrançois Tigeot 	struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
9461487f786SFrançois Tigeot 
9471487f786SFrançois Tigeot 	if (dport->release_cl2_override) {
9481487f786SFrançois Tigeot 		chv_phy_powergate_ch(dev_priv, DPIO_PHY0, DPIO_CH1, false);
9491487f786SFrançois Tigeot 		dport->release_cl2_override = false;
9501487f786SFrançois Tigeot 	}
9511487f786SFrançois Tigeot }
9521487f786SFrançois Tigeot 
chv_phy_post_pll_disable(struct intel_encoder * encoder)9531487f786SFrançois Tigeot void chv_phy_post_pll_disable(struct intel_encoder *encoder)
9541487f786SFrançois Tigeot {
9551487f786SFrançois Tigeot 	struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
9561487f786SFrançois Tigeot 	enum i915_pipe pipe = to_intel_crtc(encoder->base.crtc)->pipe;
9571487f786SFrançois Tigeot 	u32 val;
9581487f786SFrançois Tigeot 
9591487f786SFrançois Tigeot 	mutex_lock(&dev_priv->sb_lock);
9601487f786SFrançois Tigeot 
9611487f786SFrançois Tigeot 	/* disable left/right clock distribution */
9621487f786SFrançois Tigeot 	if (pipe != PIPE_B) {
9631487f786SFrançois Tigeot 		val = vlv_dpio_read(dev_priv, pipe, _CHV_CMN_DW5_CH0);
9641487f786SFrançois Tigeot 		val &= ~(CHV_BUFLEFTENA1_MASK | CHV_BUFRIGHTENA1_MASK);
9651487f786SFrançois Tigeot 		vlv_dpio_write(dev_priv, pipe, _CHV_CMN_DW5_CH0, val);
9661487f786SFrançois Tigeot 	} else {
9671487f786SFrançois Tigeot 		val = vlv_dpio_read(dev_priv, pipe, _CHV_CMN_DW1_CH1);
9681487f786SFrançois Tigeot 		val &= ~(CHV_BUFLEFTENA2_MASK | CHV_BUFRIGHTENA2_MASK);
9691487f786SFrançois Tigeot 		vlv_dpio_write(dev_priv, pipe, _CHV_CMN_DW1_CH1, val);
9701487f786SFrançois Tigeot 	}
9711487f786SFrançois Tigeot 
9721487f786SFrançois Tigeot 	mutex_unlock(&dev_priv->sb_lock);
9731487f786SFrançois Tigeot 
9741487f786SFrançois Tigeot 	/*
9751487f786SFrançois Tigeot 	 * Leave the power down bit cleared for at least one
9761487f786SFrançois Tigeot 	 * lane so that chv_powergate_phy_ch() will power
9771487f786SFrançois Tigeot 	 * on something when the channel is otherwise unused.
9781487f786SFrançois Tigeot 	 * When the port is off and the override is removed
9791487f786SFrançois Tigeot 	 * the lanes power down anyway, so otherwise it doesn't
9801487f786SFrançois Tigeot 	 * really matter what the state of power down bits is
9811487f786SFrançois Tigeot 	 * after this.
9821487f786SFrançois Tigeot 	 */
9831487f786SFrançois Tigeot 	chv_phy_powergate_lanes(encoder, false, 0x0);
9841487f786SFrançois Tigeot }
9851487f786SFrançois Tigeot 
vlv_set_phy_signal_level(struct intel_encoder * encoder,u32 demph_reg_value,u32 preemph_reg_value,u32 uniqtranscale_reg_value,u32 tx3_demph)9861487f786SFrançois Tigeot void vlv_set_phy_signal_level(struct intel_encoder *encoder,
9871487f786SFrançois Tigeot 			      u32 demph_reg_value, u32 preemph_reg_value,
9881487f786SFrançois Tigeot 			      u32 uniqtranscale_reg_value, u32 tx3_demph)
9891487f786SFrançois Tigeot {
9901487f786SFrançois Tigeot 	struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
9911487f786SFrançois Tigeot 	struct intel_crtc *intel_crtc = to_intel_crtc(encoder->base.crtc);
9921487f786SFrançois Tigeot 	struct intel_digital_port *dport = enc_to_dig_port(&encoder->base);
9931487f786SFrançois Tigeot 	enum dpio_channel port = vlv_dport_to_channel(dport);
9941487f786SFrançois Tigeot 	int pipe = intel_crtc->pipe;
9951487f786SFrançois Tigeot 
9961487f786SFrançois Tigeot 	mutex_lock(&dev_priv->sb_lock);
9971487f786SFrançois Tigeot 	vlv_dpio_write(dev_priv, pipe, VLV_TX_DW5(port), 0x00000000);
9981487f786SFrançois Tigeot 	vlv_dpio_write(dev_priv, pipe, VLV_TX_DW4(port), demph_reg_value);
9991487f786SFrançois Tigeot 	vlv_dpio_write(dev_priv, pipe, VLV_TX_DW2(port),
10001487f786SFrançois Tigeot 			 uniqtranscale_reg_value);
10011487f786SFrançois Tigeot 	vlv_dpio_write(dev_priv, pipe, VLV_TX_DW3(port), 0x0C782040);
10021487f786SFrançois Tigeot 
10031487f786SFrançois Tigeot 	if (tx3_demph)
10041487f786SFrançois Tigeot 		vlv_dpio_write(dev_priv, pipe, VLV_TX3_DW4(port), tx3_demph);
10051487f786SFrançois Tigeot 
10061487f786SFrançois Tigeot 	vlv_dpio_write(dev_priv, pipe, VLV_PCS_DW11(port), 0x00030000);
10071487f786SFrançois Tigeot 	vlv_dpio_write(dev_priv, pipe, VLV_PCS_DW9(port), preemph_reg_value);
10081487f786SFrançois Tigeot 	vlv_dpio_write(dev_priv, pipe, VLV_TX_DW5(port), DPIO_TX_OCALINIT_EN);
10091487f786SFrançois Tigeot 	mutex_unlock(&dev_priv->sb_lock);
10101487f786SFrançois Tigeot }
10111487f786SFrançois Tigeot 
vlv_phy_pre_pll_enable(struct intel_encoder * encoder)10121487f786SFrançois Tigeot void vlv_phy_pre_pll_enable(struct intel_encoder *encoder)
10131487f786SFrançois Tigeot {
10141487f786SFrançois Tigeot 	struct intel_digital_port *dport = enc_to_dig_port(&encoder->base);
10151487f786SFrançois Tigeot 	struct drm_device *dev = encoder->base.dev;
1016303bf270SFrançois Tigeot 	struct drm_i915_private *dev_priv = to_i915(dev);
10171487f786SFrançois Tigeot 	struct intel_crtc *intel_crtc =
10181487f786SFrançois Tigeot 		to_intel_crtc(encoder->base.crtc);
10191487f786SFrançois Tigeot 	enum dpio_channel port = vlv_dport_to_channel(dport);
10201487f786SFrançois Tigeot 	int pipe = intel_crtc->pipe;
10211487f786SFrançois Tigeot 
10221487f786SFrançois Tigeot 	/* Program Tx lane resets to default */
10231487f786SFrançois Tigeot 	mutex_lock(&dev_priv->sb_lock);
10241487f786SFrançois Tigeot 	vlv_dpio_write(dev_priv, pipe, VLV_PCS_DW0(port),
10251487f786SFrançois Tigeot 			 DPIO_PCS_TX_LANE2_RESET |
10261487f786SFrançois Tigeot 			 DPIO_PCS_TX_LANE1_RESET);
10271487f786SFrançois Tigeot 	vlv_dpio_write(dev_priv, pipe, VLV_PCS_DW1(port),
10281487f786SFrançois Tigeot 			 DPIO_PCS_CLK_CRI_RXEB_EIOS_EN |
10291487f786SFrançois Tigeot 			 DPIO_PCS_CLK_CRI_RXDIGFILTSG_EN |
10301487f786SFrançois Tigeot 			 (1<<DPIO_PCS_CLK_DATAWIDTH_SHIFT) |
10311487f786SFrançois Tigeot 				 DPIO_PCS_CLK_SOFT_RESET);
10321487f786SFrançois Tigeot 
10331487f786SFrançois Tigeot 	/* Fix up inter-pair skew failure */
10341487f786SFrançois Tigeot 	vlv_dpio_write(dev_priv, pipe, VLV_PCS_DW12(port), 0x00750f00);
10351487f786SFrançois Tigeot 	vlv_dpio_write(dev_priv, pipe, VLV_TX_DW11(port), 0x00001500);
10361487f786SFrançois Tigeot 	vlv_dpio_write(dev_priv, pipe, VLV_TX_DW14(port), 0x40400000);
10371487f786SFrançois Tigeot 	mutex_unlock(&dev_priv->sb_lock);
10381487f786SFrançois Tigeot }
10391487f786SFrançois Tigeot 
vlv_phy_pre_encoder_enable(struct intel_encoder * encoder)10401487f786SFrançois Tigeot void vlv_phy_pre_encoder_enable(struct intel_encoder *encoder)
10411487f786SFrançois Tigeot {
10421487f786SFrançois Tigeot 	struct intel_dp *intel_dp = enc_to_intel_dp(&encoder->base);
10431487f786SFrançois Tigeot 	struct intel_digital_port *dport = dp_to_dig_port(intel_dp);
10441487f786SFrançois Tigeot 	struct drm_device *dev = encoder->base.dev;
1045303bf270SFrançois Tigeot 	struct drm_i915_private *dev_priv = to_i915(dev);
10461487f786SFrançois Tigeot 	struct intel_crtc *intel_crtc = to_intel_crtc(encoder->base.crtc);
10471487f786SFrançois Tigeot 	enum dpio_channel port = vlv_dport_to_channel(dport);
10481487f786SFrançois Tigeot 	int pipe = intel_crtc->pipe;
10491487f786SFrançois Tigeot 	u32 val;
10501487f786SFrançois Tigeot 
10511487f786SFrançois Tigeot 	mutex_lock(&dev_priv->sb_lock);
10521487f786SFrançois Tigeot 
10531487f786SFrançois Tigeot 	/* Enable clock channels for this port */
10541487f786SFrançois Tigeot 	val = vlv_dpio_read(dev_priv, pipe, VLV_PCS01_DW8(port));
10551487f786SFrançois Tigeot 	val = 0;
10561487f786SFrançois Tigeot 	if (pipe)
10571487f786SFrançois Tigeot 		val |= (1<<21);
10581487f786SFrançois Tigeot 	else
10591487f786SFrançois Tigeot 		val &= ~(1<<21);
10601487f786SFrançois Tigeot 	val |= 0x001000c4;
10611487f786SFrançois Tigeot 	vlv_dpio_write(dev_priv, pipe, VLV_PCS_DW8(port), val);
10621487f786SFrançois Tigeot 
10631487f786SFrançois Tigeot 	/* Program lane clock */
10641487f786SFrançois Tigeot 	vlv_dpio_write(dev_priv, pipe, VLV_PCS_DW14(port), 0x00760018);
10651487f786SFrançois Tigeot 	vlv_dpio_write(dev_priv, pipe, VLV_PCS_DW23(port), 0x00400888);
10661487f786SFrançois Tigeot 
10671487f786SFrançois Tigeot 	mutex_unlock(&dev_priv->sb_lock);
10681487f786SFrançois Tigeot }
10691487f786SFrançois Tigeot 
vlv_phy_reset_lanes(struct intel_encoder * encoder)10701487f786SFrançois Tigeot void vlv_phy_reset_lanes(struct intel_encoder *encoder)
10711487f786SFrançois Tigeot {
10721487f786SFrançois Tigeot 	struct intel_digital_port *dport = enc_to_dig_port(&encoder->base);
1073303bf270SFrançois Tigeot 	struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
10741487f786SFrançois Tigeot 	struct intel_crtc *intel_crtc =
10751487f786SFrançois Tigeot 		to_intel_crtc(encoder->base.crtc);
10761487f786SFrançois Tigeot 	enum dpio_channel port = vlv_dport_to_channel(dport);
10771487f786SFrançois Tigeot 	int pipe = intel_crtc->pipe;
10781487f786SFrançois Tigeot 
10791487f786SFrançois Tigeot 	mutex_lock(&dev_priv->sb_lock);
10801487f786SFrançois Tigeot 	vlv_dpio_write(dev_priv, pipe, VLV_PCS_DW0(port), 0x00000000);
10811487f786SFrançois Tigeot 	vlv_dpio_write(dev_priv, pipe, VLV_PCS_DW1(port), 0x00e00060);
10821487f786SFrançois Tigeot 	mutex_unlock(&dev_priv->sb_lock);
10831487f786SFrançois Tigeot }
1084