| 
									
										
										
										
											2016-04-27 15:44:17 +03:00
										 |  |  | /*
 | 
					
						
							|  |  |  |  * Copyright © 2014-2016 Intel Corporation | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * Permission is hereby granted, free of charge, to any person obtaining a | 
					
						
							|  |  |  |  * copy of this software and associated documentation files (the "Software"), | 
					
						
							|  |  |  |  * to deal in the Software without restriction, including without limitation | 
					
						
							|  |  |  |  * the rights to use, copy, modify, merge, publish, distribute, sublicense, | 
					
						
							|  |  |  |  * and/or sell copies of the Software, and to permit persons to whom the | 
					
						
							|  |  |  |  * Software is furnished to do so, subject to the following conditions: | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * The above copyright notice and this permission notice (including the next | 
					
						
							|  |  |  |  * paragraph) shall be included in all copies or substantial portions of the | 
					
						
							|  |  |  |  * Software. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | 
					
						
							|  |  |  |  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | 
					
						
							|  |  |  |  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL | 
					
						
							|  |  |  |  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | 
					
						
							|  |  |  |  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING | 
					
						
							|  |  |  |  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER | 
					
						
							|  |  |  |  * DEALINGS IN THE SOFTWARE. | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-05 14:00:17 +03:00
										 |  |  | #include "intel_dp.h"
 | 
					
						
							| 
									
										
										
										
											2019-05-02 18:02:40 +03:00
										 |  |  | #include "intel_dpio_phy.h"
 | 
					
						
							| 
									
										
										
										
											2016-04-27 15:44:17 +03:00
										 |  |  | #include "intel_drv.h"
 | 
					
						
							| 
									
										
										
										
											2019-04-26 09:17:22 +01:00
										 |  |  | #include "intel_sideband.h"
 | 
					
						
							| 
									
										
										
										
											2016-04-27 15:44:17 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-10-06 19:22:18 +03:00
										 |  |  | /**
 | 
					
						
							|  |  |  |  * DOC: DPIO | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * VLV, CHV and BXT have slightly peculiar display PHYs for driving DP/HDMI | 
					
						
							|  |  |  |  * ports. DPIO is the name given to such a display PHY. These PHYs | 
					
						
							|  |  |  |  * don't follow the standard programming model using direct MMIO | 
					
						
							|  |  |  |  * registers, and instead their registers must be accessed trough IOSF | 
					
						
							|  |  |  |  * sideband. VLV has one such PHY for driving ports B and C, and CHV | 
					
						
							|  |  |  |  * adds another PHY for driving port D. Each PHY responds to specific | 
					
						
							|  |  |  |  * IOSF-SB port. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * Each display PHY is made up of one or two channels. Each channel | 
					
						
							|  |  |  |  * houses a common lane part which contains the PLL and other common | 
					
						
							|  |  |  |  * logic. CH0 common lane also contains the IOSF-SB logic for the | 
					
						
							|  |  |  |  * Common Register Interface (CRI) ie. the DPIO registers. CRI clock | 
					
						
							|  |  |  |  * must be running when any DPIO registers are accessed. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * In addition to having their own registers, the PHYs are also | 
					
						
							|  |  |  |  * controlled through some dedicated signals from the display | 
					
						
							|  |  |  |  * controller. These include PLL reference clock enable, PLL enable, | 
					
						
							|  |  |  |  * and CRI clock selection, for example. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * Eeach channel also has two splines (also called data lanes), and | 
					
						
							|  |  |  |  * each spline is made up of one Physical Access Coding Sub-Layer | 
					
						
							|  |  |  |  * (PCS) block and two TX lanes. So each channel has two PCS blocks | 
					
						
							|  |  |  |  * and four TX lanes. The TX lanes are used as DP lanes or TMDS | 
					
						
							|  |  |  |  * data/clock pairs depending on the output type. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * Additionally the PHY also contains an AUX lane with AUX blocks | 
					
						
							|  |  |  |  * for each channel. This is used for DP AUX communication, but | 
					
						
							|  |  |  |  * this fact isn't really relevant for the driver since AUX is | 
					
						
							|  |  |  |  * controlled from the display controller side. No DPIO registers | 
					
						
							|  |  |  |  * need to be accessed during AUX communication, | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * Generally on VLV/CHV the common lane corresponds to the pipe and | 
					
						
							|  |  |  |  * the spline (PCS/TX) corresponds to the port. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * For dual channel PHY (VLV/CHV): | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  *  pipe A == CMN/PLL/REF CH0 | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  *  pipe B == CMN/PLL/REF CH1 | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  *  port B == PCS/TX CH0 | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  *  port C == PCS/TX CH1 | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * This is especially important when we cross the streams | 
					
						
							|  |  |  |  * ie. drive port B with pipe B, or port C with pipe A. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * For single channel PHY (CHV): | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  *  pipe C == CMN/PLL/REF CH0 | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  *  port D == PCS/TX CH0 | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * On BXT the entire PHY channel corresponds to the port. That means | 
					
						
							|  |  |  |  * the PLL is also now associated with the port rather than the pipe, | 
					
						
							|  |  |  |  * and so the clock needs to be routed to the appropriate transcoder. | 
					
						
							|  |  |  |  * Port A PLL is directly connected to transcoder EDP and port B/C | 
					
						
							|  |  |  |  * PLLs can be routed to any transcoder A/B/C. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * Note: DDI0 is digital port B, DD1 is digital port C, and DDI2 is | 
					
						
							|  |  |  |  * digital port D (CHV) or port A (BXT). :: | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  *     Dual channel PHY (VLV/CHV/BXT) | 
					
						
							|  |  |  |  *     --------------------------------- | 
					
						
							|  |  |  |  *     |      CH0      |      CH1      | | 
					
						
							|  |  |  |  *     |  CMN/PLL/REF  |  CMN/PLL/REF  | | 
					
						
							|  |  |  |  *     |---------------|---------------| Display PHY | 
					
						
							|  |  |  |  *     | PCS01 | PCS23 | PCS01 | PCS23 | | 
					
						
							|  |  |  |  *     |-------|-------|-------|-------| | 
					
						
							|  |  |  |  *     |TX0|TX1|TX2|TX3|TX0|TX1|TX2|TX3| | 
					
						
							|  |  |  |  *     --------------------------------- | 
					
						
							|  |  |  |  *     |     DDI0      |     DDI1      | DP/HDMI ports | 
					
						
							|  |  |  |  *     --------------------------------- | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  *     Single channel PHY (CHV/BXT) | 
					
						
							|  |  |  |  *     ----------------- | 
					
						
							|  |  |  |  *     |      CH0      | | 
					
						
							|  |  |  |  *     |  CMN/PLL/REF  | | 
					
						
							|  |  |  |  *     |---------------| Display PHY | 
					
						
							|  |  |  |  *     | PCS01 | PCS23 | | 
					
						
							|  |  |  |  *     |-------|-------| | 
					
						
							|  |  |  |  *     |TX0|TX1|TX2|TX3| | 
					
						
							|  |  |  |  *     ----------------- | 
					
						
							|  |  |  |  *     |     DDI2      | DP/HDMI port | 
					
						
							|  |  |  |  *     ----------------- | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-10-06 19:22:20 +03:00
										 |  |  | /**
 | 
					
						
							|  |  |  |  * struct bxt_ddi_phy_info - Hold info for a broxton DDI phy | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | struct bxt_ddi_phy_info { | 
					
						
							|  |  |  | 	/**
 | 
					
						
							|  |  |  | 	 * @dual_channel: true if this phy has a second channel. | 
					
						
							|  |  |  | 	 */ | 
					
						
							|  |  |  | 	bool dual_channel; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-10-06 19:22:21 +03:00
										 |  |  | 	/**
 | 
					
						
							|  |  |  | 	 * @rcomp_phy: If -1, indicates this phy has its own rcomp resistor. | 
					
						
							|  |  |  | 	 * Otherwise the GRC value will be copied from the phy indicated by | 
					
						
							|  |  |  | 	 * this field. | 
					
						
							|  |  |  | 	 */ | 
					
						
							|  |  |  | 	enum dpio_phy rcomp_phy; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-12-02 10:23:51 +02:00
										 |  |  | 	/**
 | 
					
						
							|  |  |  | 	 * @reset_delay: delay in us to wait before setting the common reset | 
					
						
							|  |  |  | 	 * bit in BXT_PHY_CTL_FAMILY, which effectively enables the phy. | 
					
						
							|  |  |  | 	 */ | 
					
						
							|  |  |  | 	int reset_delay; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/**
 | 
					
						
							|  |  |  | 	 * @pwron_mask: Mask with the appropriate bit set that would cause the | 
					
						
							|  |  |  | 	 * punit to power this phy if written to BXT_P_CR_GT_DISP_PWRON. | 
					
						
							|  |  |  | 	 */ | 
					
						
							|  |  |  | 	u32 pwron_mask; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-10-06 19:22:20 +03:00
										 |  |  | 	/**
 | 
					
						
							|  |  |  | 	 * @channel: struct containing per channel information. | 
					
						
							|  |  |  | 	 */ | 
					
						
							|  |  |  | 	struct { | 
					
						
							|  |  |  | 		/**
 | 
					
						
							| 
									
										
										
										
											2018-02-16 11:48:20 -02:00
										 |  |  | 		 * @channel.port: which port maps to this channel. | 
					
						
							| 
									
										
										
										
											2016-10-06 19:22:20 +03:00
										 |  |  | 		 */ | 
					
						
							|  |  |  | 		enum port port; | 
					
						
							|  |  |  | 	} channel[2]; | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static const struct bxt_ddi_phy_info bxt_ddi_phy_info[] = { | 
					
						
							|  |  |  | 	[DPIO_PHY0] = { | 
					
						
							|  |  |  | 		.dual_channel = true, | 
					
						
							| 
									
										
										
										
											2016-10-06 19:22:21 +03:00
										 |  |  | 		.rcomp_phy = DPIO_PHY1, | 
					
						
							| 
									
										
										
										
											2016-12-02 10:23:51 +02:00
										 |  |  | 		.pwron_mask = BIT(0), | 
					
						
							| 
									
										
										
										
											2016-10-06 19:22:20 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 		.channel = { | 
					
						
							|  |  |  | 			[DPIO_CH0] = { .port = PORT_B }, | 
					
						
							|  |  |  | 			[DPIO_CH1] = { .port = PORT_C }, | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	}, | 
					
						
							|  |  |  | 	[DPIO_PHY1] = { | 
					
						
							|  |  |  | 		.dual_channel = false, | 
					
						
							| 
									
										
										
										
											2016-10-06 19:22:21 +03:00
										 |  |  | 		.rcomp_phy = -1, | 
					
						
							| 
									
										
										
										
											2016-12-02 10:23:51 +02:00
										 |  |  | 		.pwron_mask = BIT(1), | 
					
						
							| 
									
										
										
										
											2016-10-06 19:22:20 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 		.channel = { | 
					
						
							|  |  |  | 			[DPIO_CH0] = { .port = PORT_A }, | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	}, | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-12-02 10:23:51 +02:00
										 |  |  | static const struct bxt_ddi_phy_info glk_ddi_phy_info[] = { | 
					
						
							|  |  |  | 	[DPIO_PHY0] = { | 
					
						
							|  |  |  | 		.dual_channel = false, | 
					
						
							|  |  |  | 		.rcomp_phy = DPIO_PHY1, | 
					
						
							|  |  |  | 		.pwron_mask = BIT(0), | 
					
						
							|  |  |  | 		.reset_delay = 20, | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		.channel = { | 
					
						
							|  |  |  | 			[DPIO_CH0] = { .port = PORT_B }, | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	}, | 
					
						
							|  |  |  | 	[DPIO_PHY1] = { | 
					
						
							|  |  |  | 		.dual_channel = false, | 
					
						
							|  |  |  | 		.rcomp_phy = -1, | 
					
						
							|  |  |  | 		.pwron_mask = BIT(3), | 
					
						
							|  |  |  | 		.reset_delay = 20, | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		.channel = { | 
					
						
							|  |  |  | 			[DPIO_CH0] = { .port = PORT_A }, | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	}, | 
					
						
							|  |  |  | 	[DPIO_PHY2] = { | 
					
						
							|  |  |  | 		.dual_channel = false, | 
					
						
							|  |  |  | 		.rcomp_phy = DPIO_PHY1, | 
					
						
							|  |  |  | 		.pwron_mask = BIT(1), | 
					
						
							|  |  |  | 		.reset_delay = 20, | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		.channel = { | 
					
						
							|  |  |  | 			[DPIO_CH0] = { .port = PORT_C }, | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	}, | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static const struct bxt_ddi_phy_info * | 
					
						
							|  |  |  | bxt_get_phy_list(struct drm_i915_private *dev_priv, int *count) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	if (IS_GEMINILAKE(dev_priv)) { | 
					
						
							|  |  |  | 		*count =  ARRAY_SIZE(glk_ddi_phy_info); | 
					
						
							|  |  |  | 		return glk_ddi_phy_info; | 
					
						
							|  |  |  | 	} else { | 
					
						
							|  |  |  | 		*count =  ARRAY_SIZE(bxt_ddi_phy_info); | 
					
						
							|  |  |  | 		return bxt_ddi_phy_info; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static const struct bxt_ddi_phy_info * | 
					
						
							|  |  |  | bxt_get_phy_info(struct drm_i915_private *dev_priv, enum dpio_phy phy) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	int count; | 
					
						
							|  |  |  | 	const struct bxt_ddi_phy_info *phy_list = | 
					
						
							|  |  |  | 		bxt_get_phy_list(dev_priv, &count); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return &phy_list[phy]; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void bxt_port_to_phy_channel(struct drm_i915_private *dev_priv, enum port port, | 
					
						
							| 
									
										
										
										
											2016-10-19 10:59:00 +03:00
										 |  |  | 			     enum dpio_phy *phy, enum dpio_channel *ch) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2016-12-02 10:23:51 +02:00
										 |  |  | 	const struct bxt_ddi_phy_info *phy_info, *phys; | 
					
						
							|  |  |  | 	int i, count; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	phys = bxt_get_phy_list(dev_priv, &count); | 
					
						
							| 
									
										
										
										
											2016-10-19 10:59:00 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-12-02 10:23:51 +02:00
										 |  |  | 	for (i = 0; i < count; i++) { | 
					
						
							|  |  |  | 		phy_info = &phys[i]; | 
					
						
							| 
									
										
										
										
											2016-10-19 10:59:00 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 		if (port == phy_info->channel[DPIO_CH0].port) { | 
					
						
							|  |  |  | 			*phy = i; | 
					
						
							|  |  |  | 			*ch = DPIO_CH0; | 
					
						
							|  |  |  | 			return; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		if (phy_info->dual_channel && | 
					
						
							|  |  |  | 		    port == phy_info->channel[DPIO_CH1].port) { | 
					
						
							|  |  |  | 			*phy = i; | 
					
						
							|  |  |  | 			*ch = DPIO_CH1; | 
					
						
							|  |  |  | 			return; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	WARN(1, "PHY not found for PORT %c", port_name(port)); | 
					
						
							|  |  |  | 	*phy = DPIO_PHY0; | 
					
						
							|  |  |  | 	*ch = DPIO_CH0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-10-06 19:22:19 +03:00
										 |  |  | void bxt_ddi_phy_set_signal_level(struct drm_i915_private *dev_priv, | 
					
						
							|  |  |  | 				  enum port port, u32 margin, u32 scale, | 
					
						
							|  |  |  | 				  u32 enable, u32 deemphasis) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	u32 val; | 
					
						
							| 
									
										
										
										
											2016-10-19 10:59:00 +03:00
										 |  |  | 	enum dpio_phy phy; | 
					
						
							|  |  |  | 	enum dpio_channel ch; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-12-02 10:23:51 +02:00
										 |  |  | 	bxt_port_to_phy_channel(dev_priv, port, &phy, &ch); | 
					
						
							| 
									
										
										
										
											2016-10-06 19:22:19 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	/*
 | 
					
						
							|  |  |  | 	 * While we write to the group register to program all lanes at once we | 
					
						
							|  |  |  | 	 * can read only lane registers and we pick lanes 0/1 for that. | 
					
						
							|  |  |  | 	 */ | 
					
						
							| 
									
										
										
										
											2016-10-19 10:59:00 +03:00
										 |  |  | 	val = I915_READ(BXT_PORT_PCS_DW10_LN01(phy, ch)); | 
					
						
							| 
									
										
										
										
											2016-10-06 19:22:19 +03:00
										 |  |  | 	val &= ~(TX2_SWING_CALC_INIT | TX1_SWING_CALC_INIT); | 
					
						
							| 
									
										
										
										
											2016-10-19 10:59:00 +03:00
										 |  |  | 	I915_WRITE(BXT_PORT_PCS_DW10_GRP(phy, ch), val); | 
					
						
							| 
									
										
										
										
											2016-10-06 19:22:19 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-10-19 10:59:00 +03:00
										 |  |  | 	val = I915_READ(BXT_PORT_TX_DW2_LN0(phy, ch)); | 
					
						
							| 
									
										
										
										
											2016-10-06 19:22:19 +03:00
										 |  |  | 	val &= ~(MARGIN_000 | UNIQ_TRANS_SCALE); | 
					
						
							|  |  |  | 	val |= margin << MARGIN_000_SHIFT | scale << UNIQ_TRANS_SCALE_SHIFT; | 
					
						
							| 
									
										
										
										
											2016-10-19 10:59:00 +03:00
										 |  |  | 	I915_WRITE(BXT_PORT_TX_DW2_GRP(phy, ch), val); | 
					
						
							| 
									
										
										
										
											2016-10-06 19:22:19 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-10-19 10:59:00 +03:00
										 |  |  | 	val = I915_READ(BXT_PORT_TX_DW3_LN0(phy, ch)); | 
					
						
							| 
									
										
										
										
											2016-10-06 19:22:19 +03:00
										 |  |  | 	val &= ~SCALE_DCOMP_METHOD; | 
					
						
							|  |  |  | 	if (enable) | 
					
						
							|  |  |  | 		val |= SCALE_DCOMP_METHOD; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if ((val & UNIQUE_TRANGE_EN_METHOD) && !(val & SCALE_DCOMP_METHOD)) | 
					
						
							|  |  |  | 		DRM_ERROR("Disabled scaling while ouniqetrangenmethod was set"); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-10-19 10:59:00 +03:00
										 |  |  | 	I915_WRITE(BXT_PORT_TX_DW3_GRP(phy, ch), val); | 
					
						
							| 
									
										
										
										
											2016-10-06 19:22:19 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-10-19 10:59:00 +03:00
										 |  |  | 	val = I915_READ(BXT_PORT_TX_DW4_LN0(phy, ch)); | 
					
						
							| 
									
										
										
										
											2016-10-06 19:22:19 +03:00
										 |  |  | 	val &= ~DE_EMPHASIS; | 
					
						
							|  |  |  | 	val |= deemphasis << DEEMPH_SHIFT; | 
					
						
							| 
									
										
										
										
											2016-10-19 10:59:00 +03:00
										 |  |  | 	I915_WRITE(BXT_PORT_TX_DW4_GRP(phy, ch), val); | 
					
						
							| 
									
										
										
										
											2016-10-06 19:22:19 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-10-19 10:59:00 +03:00
										 |  |  | 	val = I915_READ(BXT_PORT_PCS_DW10_LN01(phy, ch)); | 
					
						
							| 
									
										
										
										
											2016-10-06 19:22:19 +03:00
										 |  |  | 	val |= TX2_SWING_CALC_INIT | TX1_SWING_CALC_INIT; | 
					
						
							| 
									
										
										
										
											2016-10-19 10:59:00 +03:00
										 |  |  | 	I915_WRITE(BXT_PORT_PCS_DW10_GRP(phy, ch), val); | 
					
						
							| 
									
										
										
										
											2016-10-06 19:22:19 +03:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-10-06 19:22:17 +03:00
										 |  |  | bool bxt_ddi_phy_is_enabled(struct drm_i915_private *dev_priv, | 
					
						
							|  |  |  | 			    enum dpio_phy phy) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2016-12-02 10:23:51 +02:00
										 |  |  | 	const struct bxt_ddi_phy_info *phy_info; | 
					
						
							| 
									
										
										
										
											2016-10-06 19:22:17 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-12-02 10:23:51 +02:00
										 |  |  | 	phy_info = bxt_get_phy_info(dev_priv, phy); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (!(I915_READ(BXT_P_CR_GT_DISP_PWRON) & phy_info->pwron_mask)) | 
					
						
							| 
									
										
										
										
											2016-10-06 19:22:17 +03:00
										 |  |  | 		return false; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if ((I915_READ(BXT_PORT_CL1CM_DW0(phy)) & | 
					
						
							|  |  |  | 	     (PHY_POWER_GOOD | PHY_RESERVED)) != PHY_POWER_GOOD) { | 
					
						
							|  |  |  | 		DRM_DEBUG_DRIVER("DDI PHY %d powered, but power hasn't settled\n", | 
					
						
							|  |  |  | 				 phy); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		return false; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (!(I915_READ(BXT_PHY_CTL_FAMILY(phy)) & COMMON_RESET_DIS)) { | 
					
						
							|  |  |  | 		DRM_DEBUG_DRIVER("DDI PHY %d powered, but still in reset\n", | 
					
						
							|  |  |  | 				 phy); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		return false; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return true; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static u32 bxt_get_grc(struct drm_i915_private *dev_priv, enum dpio_phy phy) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	u32 val = I915_READ(BXT_PORT_REF_DW6(phy)); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return (val & GRC_CODE_MASK) >> GRC_CODE_SHIFT; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static void bxt_phy_wait_grc_done(struct drm_i915_private *dev_priv, | 
					
						
							|  |  |  | 				  enum dpio_phy phy) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2019-03-25 14:49:39 -07:00
										 |  |  | 	if (intel_wait_for_register(&dev_priv->uncore, | 
					
						
							| 
									
										
										
										
											2016-10-06 19:22:17 +03:00
										 |  |  | 				    BXT_PORT_REF_DW3(phy), | 
					
						
							|  |  |  | 				    GRC_DONE, GRC_DONE, | 
					
						
							|  |  |  | 				    10)) | 
					
						
							|  |  |  | 		DRM_ERROR("timeout waiting for PHY%d GRC\n", phy); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-10-06 19:22:21 +03:00
										 |  |  | static void _bxt_ddi_phy_init(struct drm_i915_private *dev_priv, | 
					
						
							|  |  |  | 			      enum dpio_phy phy) | 
					
						
							| 
									
										
										
										
											2016-10-06 19:22:17 +03:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2016-12-02 10:23:51 +02:00
										 |  |  | 	const struct bxt_ddi_phy_info *phy_info; | 
					
						
							| 
									
										
										
										
											2016-10-06 19:22:17 +03:00
										 |  |  | 	u32 val; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-12-02 10:23:51 +02:00
										 |  |  | 	phy_info = bxt_get_phy_info(dev_priv, phy); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-10-06 19:22:17 +03:00
										 |  |  | 	if (bxt_ddi_phy_is_enabled(dev_priv, phy)) { | 
					
						
							|  |  |  | 		/* Still read out the GRC value for state verification */ | 
					
						
							| 
									
										
										
										
											2016-10-06 19:22:21 +03:00
										 |  |  | 		if (phy_info->rcomp_phy != -1) | 
					
						
							| 
									
										
										
										
											2016-10-06 19:22:17 +03:00
										 |  |  | 			dev_priv->bxt_phy_grc = bxt_get_grc(dev_priv, phy); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		if (bxt_ddi_phy_verify_state(dev_priv, phy)) { | 
					
						
							|  |  |  | 			DRM_DEBUG_DRIVER("DDI PHY %d already enabled, " | 
					
						
							|  |  |  | 					 "won't reprogram it\n", phy); | 
					
						
							|  |  |  | 			return; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		DRM_DEBUG_DRIVER("DDI PHY %d enabled with invalid state, " | 
					
						
							|  |  |  | 				 "force reprogramming it\n", phy); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	val = I915_READ(BXT_P_CR_GT_DISP_PWRON); | 
					
						
							| 
									
										
										
										
											2016-12-02 10:23:51 +02:00
										 |  |  | 	val |= phy_info->pwron_mask; | 
					
						
							| 
									
										
										
										
											2016-10-06 19:22:17 +03:00
										 |  |  | 	I915_WRITE(BXT_P_CR_GT_DISP_PWRON, val); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/*
 | 
					
						
							|  |  |  | 	 * The PHY registers start out inaccessible and respond to reads with | 
					
						
							|  |  |  | 	 * all 1s.  Eventually they become accessible as they power up, then | 
					
						
							|  |  |  | 	 * the reserved bit will give the default 0.  Poll on the reserved bit | 
					
						
							|  |  |  | 	 * becoming 0 to find when the PHY is accessible. | 
					
						
							| 
									
										
										
										
											2018-04-09 15:27:16 +03:00
										 |  |  | 	 * The flag should get set in 100us according to the HW team, but | 
					
						
							|  |  |  | 	 * use 1ms due to occasional timeouts observed with that. | 
					
						
							| 
									
										
										
										
											2016-10-06 19:22:17 +03:00
										 |  |  | 	 */ | 
					
						
							| 
									
										
										
										
											2019-03-25 14:49:38 -07:00
										 |  |  | 	if (intel_wait_for_register_fw(&dev_priv->uncore, | 
					
						
							|  |  |  | 				       BXT_PORT_CL1CM_DW0(phy), | 
					
						
							| 
									
										
										
										
											2018-04-09 15:27:16 +03:00
										 |  |  | 				       PHY_RESERVED | PHY_POWER_GOOD, | 
					
						
							|  |  |  | 				       PHY_POWER_GOOD, | 
					
						
							|  |  |  | 				       1)) | 
					
						
							| 
									
										
										
										
											2016-10-06 19:22:17 +03:00
										 |  |  | 		DRM_ERROR("timeout during PHY%d power on\n", phy); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/* Program PLL Rcomp code offset */ | 
					
						
							|  |  |  | 	val = I915_READ(BXT_PORT_CL1CM_DW9(phy)); | 
					
						
							|  |  |  | 	val &= ~IREF0RC_OFFSET_MASK; | 
					
						
							|  |  |  | 	val |= 0xE4 << IREF0RC_OFFSET_SHIFT; | 
					
						
							|  |  |  | 	I915_WRITE(BXT_PORT_CL1CM_DW9(phy), val); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	val = I915_READ(BXT_PORT_CL1CM_DW10(phy)); | 
					
						
							|  |  |  | 	val &= ~IREF1RC_OFFSET_MASK; | 
					
						
							|  |  |  | 	val |= 0xE4 << IREF1RC_OFFSET_SHIFT; | 
					
						
							|  |  |  | 	I915_WRITE(BXT_PORT_CL1CM_DW10(phy), val); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/* Program power gating */ | 
					
						
							|  |  |  | 	val = I915_READ(BXT_PORT_CL1CM_DW28(phy)); | 
					
						
							|  |  |  | 	val |= OCL1_POWER_DOWN_EN | DW28_OLDO_DYN_PWR_DOWN_EN | | 
					
						
							|  |  |  | 		SUS_CLK_CONFIG; | 
					
						
							|  |  |  | 	I915_WRITE(BXT_PORT_CL1CM_DW28(phy), val); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-10-06 19:22:20 +03:00
										 |  |  | 	if (phy_info->dual_channel) { | 
					
						
							|  |  |  | 		val = I915_READ(BXT_PORT_CL2CM_DW6(phy)); | 
					
						
							| 
									
										
										
										
											2016-10-06 19:22:17 +03:00
										 |  |  | 		val |= DW6_OLDO_DYN_PWR_DOWN_EN; | 
					
						
							| 
									
										
										
										
											2016-10-06 19:22:20 +03:00
										 |  |  | 		I915_WRITE(BXT_PORT_CL2CM_DW6(phy), val); | 
					
						
							| 
									
										
										
										
											2016-10-06 19:22:17 +03:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-10-06 19:22:21 +03:00
										 |  |  | 	if (phy_info->rcomp_phy != -1) { | 
					
						
							| 
									
										
										
										
											2019-01-16 11:15:19 +02:00
										 |  |  | 		u32 grc_code; | 
					
						
							| 
									
										
										
										
											2016-11-17 11:17:36 -08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 		bxt_phy_wait_grc_done(dev_priv, phy_info->rcomp_phy); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-10-06 19:22:17 +03:00
										 |  |  | 		/*
 | 
					
						
							|  |  |  | 		 * PHY0 isn't connected to an RCOMP resistor so copy over | 
					
						
							|  |  |  | 		 * the corresponding calibrated value from PHY1, and disable | 
					
						
							|  |  |  | 		 * the automatic calibration on PHY0. | 
					
						
							|  |  |  | 		 */ | 
					
						
							| 
									
										
										
										
											2016-10-06 19:22:21 +03:00
										 |  |  | 		val = dev_priv->bxt_phy_grc = bxt_get_grc(dev_priv, | 
					
						
							|  |  |  | 							  phy_info->rcomp_phy); | 
					
						
							| 
									
										
										
										
											2016-10-06 19:22:17 +03:00
										 |  |  | 		grc_code = val << GRC_CODE_FAST_SHIFT | | 
					
						
							|  |  |  | 			   val << GRC_CODE_SLOW_SHIFT | | 
					
						
							|  |  |  | 			   val; | 
					
						
							| 
									
										
										
										
											2016-10-06 19:22:21 +03:00
										 |  |  | 		I915_WRITE(BXT_PORT_REF_DW6(phy), grc_code); | 
					
						
							| 
									
										
										
										
											2016-10-06 19:22:17 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-10-06 19:22:21 +03:00
										 |  |  | 		val = I915_READ(BXT_PORT_REF_DW8(phy)); | 
					
						
							| 
									
										
										
										
											2016-10-06 19:22:17 +03:00
										 |  |  | 		val |= GRC_DIS | GRC_RDY_OVRD; | 
					
						
							| 
									
										
										
										
											2016-10-06 19:22:21 +03:00
										 |  |  | 		I915_WRITE(BXT_PORT_REF_DW8(phy), val); | 
					
						
							| 
									
										
										
										
											2016-10-06 19:22:17 +03:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-12-02 10:23:51 +02:00
										 |  |  | 	if (phy_info->reset_delay) | 
					
						
							|  |  |  | 		udelay(phy_info->reset_delay); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-10-06 19:22:17 +03:00
										 |  |  | 	val = I915_READ(BXT_PHY_CTL_FAMILY(phy)); | 
					
						
							|  |  |  | 	val |= COMMON_RESET_DIS; | 
					
						
							|  |  |  | 	I915_WRITE(BXT_PHY_CTL_FAMILY(phy), val); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void bxt_ddi_phy_uninit(struct drm_i915_private *dev_priv, enum dpio_phy phy) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2016-12-02 10:23:51 +02:00
										 |  |  | 	const struct bxt_ddi_phy_info *phy_info; | 
					
						
							| 
									
										
										
										
											2019-01-16 11:15:19 +02:00
										 |  |  | 	u32 val; | 
					
						
							| 
									
										
										
										
											2016-10-06 19:22:17 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-12-02 10:23:51 +02:00
										 |  |  | 	phy_info = bxt_get_phy_info(dev_priv, phy); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-10-06 19:22:17 +03:00
										 |  |  | 	val = I915_READ(BXT_PHY_CTL_FAMILY(phy)); | 
					
						
							|  |  |  | 	val &= ~COMMON_RESET_DIS; | 
					
						
							|  |  |  | 	I915_WRITE(BXT_PHY_CTL_FAMILY(phy), val); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	val = I915_READ(BXT_P_CR_GT_DISP_PWRON); | 
					
						
							| 
									
										
										
										
											2016-12-02 10:23:51 +02:00
										 |  |  | 	val &= ~phy_info->pwron_mask; | 
					
						
							| 
									
										
										
										
											2016-10-06 19:22:17 +03:00
										 |  |  | 	I915_WRITE(BXT_P_CR_GT_DISP_PWRON, val); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-10-06 19:22:21 +03:00
										 |  |  | void bxt_ddi_phy_init(struct drm_i915_private *dev_priv, enum dpio_phy phy) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2016-12-02 10:23:51 +02:00
										 |  |  | 	const struct bxt_ddi_phy_info *phy_info = | 
					
						
							|  |  |  | 		bxt_get_phy_info(dev_priv, phy); | 
					
						
							| 
									
										
										
										
											2016-10-06 19:22:21 +03:00
										 |  |  | 	enum dpio_phy rcomp_phy = phy_info->rcomp_phy; | 
					
						
							|  |  |  | 	bool was_enabled; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	lockdep_assert_held(&dev_priv->power_domains.lock); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-11-07 13:53:24 +00:00
										 |  |  | 	was_enabled = true; | 
					
						
							|  |  |  | 	if (rcomp_phy != -1) | 
					
						
							| 
									
										
										
										
											2016-10-06 19:22:21 +03:00
										 |  |  | 		was_enabled = bxt_ddi_phy_is_enabled(dev_priv, rcomp_phy); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-11-07 13:53:24 +00:00
										 |  |  | 	/*
 | 
					
						
							|  |  |  | 	 * We need to copy the GRC calibration value from rcomp_phy, | 
					
						
							|  |  |  | 	 * so make sure it's powered up. | 
					
						
							|  |  |  | 	 */ | 
					
						
							|  |  |  | 	if (!was_enabled) | 
					
						
							|  |  |  | 		_bxt_ddi_phy_init(dev_priv, rcomp_phy); | 
					
						
							| 
									
										
										
										
											2016-10-06 19:22:21 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	_bxt_ddi_phy_init(dev_priv, phy); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-11-07 13:53:24 +00:00
										 |  |  | 	if (!was_enabled) | 
					
						
							|  |  |  | 		bxt_ddi_phy_uninit(dev_priv, rcomp_phy); | 
					
						
							| 
									
										
										
										
											2016-10-06 19:22:21 +03:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-10-06 19:22:17 +03:00
										 |  |  | 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, ...) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	struct va_format vaf; | 
					
						
							|  |  |  | 	va_list args; | 
					
						
							|  |  |  | 	u32 val; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	val = I915_READ(reg); | 
					
						
							|  |  |  | 	if ((val & mask) == expected) | 
					
						
							|  |  |  | 		return true; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	va_start(args, reg_fmt); | 
					
						
							|  |  |  | 	vaf.fmt = reg_fmt; | 
					
						
							|  |  |  | 	vaf.va = &args; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	DRM_DEBUG_DRIVER("DDI PHY %d reg %pV [%08x] state mismatch: " | 
					
						
							|  |  |  | 			 "current %08x, expected %08x (mask %08x)\n", | 
					
						
							|  |  |  | 			 phy, &vaf, reg.reg, val, (val & ~mask) | expected, | 
					
						
							|  |  |  | 			 mask); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	va_end(args); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return false; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | bool bxt_ddi_phy_verify_state(struct drm_i915_private *dev_priv, | 
					
						
							|  |  |  | 			      enum dpio_phy phy) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2016-12-02 10:23:51 +02:00
										 |  |  | 	const struct bxt_ddi_phy_info *phy_info; | 
					
						
							| 
									
										
										
										
											2019-01-16 11:15:19 +02:00
										 |  |  | 	u32 mask; | 
					
						
							| 
									
										
										
										
											2016-10-06 19:22:17 +03:00
										 |  |  | 	bool ok; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-12-02 10:23:51 +02:00
										 |  |  | 	phy_info = bxt_get_phy_info(dev_priv, phy); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-10-06 19:22:17 +03:00
										 |  |  | #define _CHK(reg, mask, exp, fmt, ...)					\
 | 
					
						
							|  |  |  | 	__phy_reg_verify_state(dev_priv, phy, reg, mask, exp, fmt,	\ | 
					
						
							|  |  |  | 			       ## __VA_ARGS__)
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (!bxt_ddi_phy_is_enabled(dev_priv, phy)) | 
					
						
							|  |  |  | 		return false; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	ok = true; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/* PLL Rcomp code offset */ | 
					
						
							|  |  |  | 	ok &= _CHK(BXT_PORT_CL1CM_DW9(phy), | 
					
						
							|  |  |  | 		    IREF0RC_OFFSET_MASK, 0xe4 << IREF0RC_OFFSET_SHIFT, | 
					
						
							|  |  |  | 		    "BXT_PORT_CL1CM_DW9(%d)", phy); | 
					
						
							|  |  |  | 	ok &= _CHK(BXT_PORT_CL1CM_DW10(phy), | 
					
						
							|  |  |  | 		    IREF1RC_OFFSET_MASK, 0xe4 << IREF1RC_OFFSET_SHIFT, | 
					
						
							|  |  |  | 		    "BXT_PORT_CL1CM_DW10(%d)", phy); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/* Power gating */ | 
					
						
							|  |  |  | 	mask = OCL1_POWER_DOWN_EN | DW28_OLDO_DYN_PWR_DOWN_EN | SUS_CLK_CONFIG; | 
					
						
							|  |  |  | 	ok &= _CHK(BXT_PORT_CL1CM_DW28(phy), mask, mask, | 
					
						
							|  |  |  | 		    "BXT_PORT_CL1CM_DW28(%d)", phy); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-10-06 19:22:20 +03:00
										 |  |  | 	if (phy_info->dual_channel) | 
					
						
							|  |  |  | 		ok &= _CHK(BXT_PORT_CL2CM_DW6(phy), | 
					
						
							| 
									
										
										
										
											2016-10-06 19:22:17 +03:00
										 |  |  | 			   DW6_OLDO_DYN_PWR_DOWN_EN, DW6_OLDO_DYN_PWR_DOWN_EN, | 
					
						
							| 
									
										
										
										
											2016-10-06 19:22:20 +03:00
										 |  |  | 			   "BXT_PORT_CL2CM_DW6(%d)", phy); | 
					
						
							| 
									
										
										
										
											2016-10-06 19:22:17 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-10-06 19:22:21 +03:00
										 |  |  | 	if (phy_info->rcomp_phy != -1) { | 
					
						
							| 
									
										
										
										
											2016-10-06 19:22:17 +03:00
										 |  |  | 		u32 grc_code = dev_priv->bxt_phy_grc; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		grc_code = grc_code << GRC_CODE_FAST_SHIFT | | 
					
						
							|  |  |  | 			   grc_code << GRC_CODE_SLOW_SHIFT | | 
					
						
							|  |  |  | 			   grc_code; | 
					
						
							|  |  |  | 		mask = GRC_CODE_FAST_MASK | GRC_CODE_SLOW_MASK | | 
					
						
							|  |  |  | 		       GRC_CODE_NOM_MASK; | 
					
						
							| 
									
										
										
										
											2016-10-06 19:22:21 +03:00
										 |  |  | 		ok &= _CHK(BXT_PORT_REF_DW6(phy), mask, grc_code, | 
					
						
							| 
									
										
										
										
											2016-10-19 10:59:00 +03:00
										 |  |  | 			   "BXT_PORT_REF_DW6(%d)", phy); | 
					
						
							| 
									
										
										
										
											2016-10-06 19:22:17 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 		mask = GRC_DIS | GRC_RDY_OVRD; | 
					
						
							| 
									
										
										
										
											2016-10-06 19:22:21 +03:00
										 |  |  | 		ok &= _CHK(BXT_PORT_REF_DW8(phy), mask, mask, | 
					
						
							|  |  |  | 			    "BXT_PORT_REF_DW8(%d)", phy); | 
					
						
							| 
									
										
										
										
											2016-10-06 19:22:17 +03:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return ok; | 
					
						
							|  |  |  | #undef _CHK
 | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-01-16 11:15:19 +02:00
										 |  |  | u8 | 
					
						
							|  |  |  | bxt_ddi_phy_calc_lane_lat_optim_mask(u8 lane_count) | 
					
						
							| 
									
										
										
										
											2016-10-06 19:22:17 +03:00
										 |  |  | { | 
					
						
							|  |  |  | 	switch (lane_count) { | 
					
						
							|  |  |  | 	case 1: | 
					
						
							|  |  |  | 		return 0; | 
					
						
							|  |  |  | 	case 2: | 
					
						
							|  |  |  | 		return BIT(2) | BIT(0); | 
					
						
							|  |  |  | 	case 4: | 
					
						
							|  |  |  | 		return BIT(3) | BIT(2) | BIT(0); | 
					
						
							|  |  |  | 	default: | 
					
						
							|  |  |  | 		MISSING_CASE(lane_count); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		return 0; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void bxt_ddi_phy_set_lane_optim_mask(struct intel_encoder *encoder, | 
					
						
							| 
									
										
										
										
											2019-01-16 11:15:19 +02:00
										 |  |  | 				     u8 lane_lat_optim_mask) | 
					
						
							| 
									
										
										
										
											2016-10-06 19:22:17 +03:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2017-11-09 17:24:34 +02:00
										 |  |  | 	struct drm_i915_private *dev_priv = to_i915(encoder->base.dev); | 
					
						
							|  |  |  | 	enum port port = encoder->port; | 
					
						
							| 
									
										
										
										
											2016-10-19 10:59:00 +03:00
										 |  |  | 	enum dpio_phy phy; | 
					
						
							|  |  |  | 	enum dpio_channel ch; | 
					
						
							| 
									
										
										
										
											2016-10-06 19:22:17 +03:00
										 |  |  | 	int lane; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-12-02 10:23:51 +02:00
										 |  |  | 	bxt_port_to_phy_channel(dev_priv, port, &phy, &ch); | 
					
						
							| 
									
										
										
										
											2016-10-19 10:59:00 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-10-06 19:22:17 +03:00
										 |  |  | 	for (lane = 0; lane < 4; lane++) { | 
					
						
							| 
									
										
										
										
											2016-10-19 10:59:00 +03:00
										 |  |  | 		u32 val = I915_READ(BXT_PORT_TX_DW14_LN(phy, ch, lane)); | 
					
						
							| 
									
										
										
										
											2016-10-06 19:22:17 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 		/*
 | 
					
						
							|  |  |  | 		 * Note that on CHV this flag is called UPAR, but has | 
					
						
							|  |  |  | 		 * the same function. | 
					
						
							|  |  |  | 		 */ | 
					
						
							|  |  |  | 		val &= ~LATENCY_OPTIM; | 
					
						
							|  |  |  | 		if (lane_lat_optim_mask & BIT(lane)) | 
					
						
							|  |  |  | 			val |= LATENCY_OPTIM; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-10-19 10:59:00 +03:00
										 |  |  | 		I915_WRITE(BXT_PORT_TX_DW14_LN(phy, ch, lane), val); | 
					
						
							| 
									
										
										
										
											2016-10-06 19:22:17 +03:00
										 |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-01-16 11:15:19 +02:00
										 |  |  | u8 | 
					
						
							| 
									
										
										
										
											2016-10-06 19:22:17 +03:00
										 |  |  | bxt_ddi_phy_get_lane_lat_optim_mask(struct intel_encoder *encoder) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2017-11-09 17:24:34 +02:00
										 |  |  | 	struct drm_i915_private *dev_priv = to_i915(encoder->base.dev); | 
					
						
							|  |  |  | 	enum port port = encoder->port; | 
					
						
							| 
									
										
										
										
											2016-10-19 10:59:00 +03:00
										 |  |  | 	enum dpio_phy phy; | 
					
						
							|  |  |  | 	enum dpio_channel ch; | 
					
						
							| 
									
										
										
										
											2016-10-06 19:22:17 +03:00
										 |  |  | 	int lane; | 
					
						
							| 
									
										
										
										
											2019-01-16 11:15:19 +02:00
										 |  |  | 	u8 mask; | 
					
						
							| 
									
										
										
										
											2016-10-06 19:22:17 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-12-02 10:23:51 +02:00
										 |  |  | 	bxt_port_to_phy_channel(dev_priv, port, &phy, &ch); | 
					
						
							| 
									
										
										
										
											2016-10-19 10:59:00 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-10-06 19:22:17 +03:00
										 |  |  | 	mask = 0; | 
					
						
							|  |  |  | 	for (lane = 0; lane < 4; lane++) { | 
					
						
							| 
									
										
										
										
											2016-10-19 10:59:00 +03:00
										 |  |  | 		u32 val = I915_READ(BXT_PORT_TX_DW14_LN(phy, ch, lane)); | 
					
						
							| 
									
										
										
										
											2016-10-06 19:22:17 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 		if (val & LATENCY_OPTIM) | 
					
						
							|  |  |  | 			mask |= BIT(lane); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return mask; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-04-27 15:44:17 +03:00
										 |  |  | void chv_set_phy_signal_level(struct intel_encoder *encoder, | 
					
						
							|  |  |  | 			      u32 deemph_reg_value, u32 margin_reg_value, | 
					
						
							|  |  |  | 			      bool uniq_trans_scale) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	struct drm_i915_private *dev_priv = to_i915(encoder->base.dev); | 
					
						
							|  |  |  | 	struct intel_digital_port *dport = enc_to_dig_port(&encoder->base); | 
					
						
							| 
									
										
										
										
											2017-11-09 17:24:34 +02:00
										 |  |  | 	struct intel_crtc *intel_crtc = to_intel_crtc(encoder->base.crtc); | 
					
						
							| 
									
										
										
										
											2016-04-27 15:44:17 +03:00
										 |  |  | 	enum dpio_channel ch = vlv_dport_to_channel(dport); | 
					
						
							|  |  |  | 	enum pipe pipe = intel_crtc->pipe; | 
					
						
							|  |  |  | 	u32 val; | 
					
						
							|  |  |  | 	int i; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-26 09:17:19 +01:00
										 |  |  | 	vlv_dpio_get(dev_priv); | 
					
						
							| 
									
										
										
										
											2016-04-27 15:44:17 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	/* Clear calc init */ | 
					
						
							|  |  |  | 	val = vlv_dpio_read(dev_priv, pipe, VLV_PCS01_DW10(ch)); | 
					
						
							|  |  |  | 	val &= ~(DPIO_PCS_SWING_CALC_TX0_TX2 | DPIO_PCS_SWING_CALC_TX1_TX3); | 
					
						
							|  |  |  | 	val &= ~(DPIO_PCS_TX1DEEMP_MASK | DPIO_PCS_TX2DEEMP_MASK); | 
					
						
							|  |  |  | 	val |= DPIO_PCS_TX1DEEMP_9P5 | DPIO_PCS_TX2DEEMP_9P5; | 
					
						
							|  |  |  | 	vlv_dpio_write(dev_priv, pipe, VLV_PCS01_DW10(ch), val); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (intel_crtc->config->lane_count > 2) { | 
					
						
							|  |  |  | 		val = vlv_dpio_read(dev_priv, pipe, VLV_PCS23_DW10(ch)); | 
					
						
							|  |  |  | 		val &= ~(DPIO_PCS_SWING_CALC_TX0_TX2 | DPIO_PCS_SWING_CALC_TX1_TX3); | 
					
						
							|  |  |  | 		val &= ~(DPIO_PCS_TX1DEEMP_MASK | DPIO_PCS_TX2DEEMP_MASK); | 
					
						
							|  |  |  | 		val |= DPIO_PCS_TX1DEEMP_9P5 | DPIO_PCS_TX2DEEMP_9P5; | 
					
						
							|  |  |  | 		vlv_dpio_write(dev_priv, pipe, VLV_PCS23_DW10(ch), val); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	val = vlv_dpio_read(dev_priv, pipe, VLV_PCS01_DW9(ch)); | 
					
						
							|  |  |  | 	val &= ~(DPIO_PCS_TX1MARGIN_MASK | DPIO_PCS_TX2MARGIN_MASK); | 
					
						
							|  |  |  | 	val |= DPIO_PCS_TX1MARGIN_000 | DPIO_PCS_TX2MARGIN_000; | 
					
						
							|  |  |  | 	vlv_dpio_write(dev_priv, pipe, VLV_PCS01_DW9(ch), val); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (intel_crtc->config->lane_count > 2) { | 
					
						
							|  |  |  | 		val = vlv_dpio_read(dev_priv, pipe, VLV_PCS23_DW9(ch)); | 
					
						
							|  |  |  | 		val &= ~(DPIO_PCS_TX1MARGIN_MASK | DPIO_PCS_TX2MARGIN_MASK); | 
					
						
							|  |  |  | 		val |= DPIO_PCS_TX1MARGIN_000 | DPIO_PCS_TX2MARGIN_000; | 
					
						
							|  |  |  | 		vlv_dpio_write(dev_priv, pipe, VLV_PCS23_DW9(ch), val); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/* Program swing deemph */ | 
					
						
							|  |  |  | 	for (i = 0; i < intel_crtc->config->lane_count; i++) { | 
					
						
							|  |  |  | 		val = vlv_dpio_read(dev_priv, pipe, CHV_TX_DW4(ch, i)); | 
					
						
							|  |  |  | 		val &= ~DPIO_SWING_DEEMPH9P5_MASK; | 
					
						
							|  |  |  | 		val |= deemph_reg_value << DPIO_SWING_DEEMPH9P5_SHIFT; | 
					
						
							|  |  |  | 		vlv_dpio_write(dev_priv, pipe, CHV_TX_DW4(ch, i), val); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/* Program swing margin */ | 
					
						
							|  |  |  | 	for (i = 0; i < intel_crtc->config->lane_count; i++) { | 
					
						
							|  |  |  | 		val = vlv_dpio_read(dev_priv, pipe, CHV_TX_DW2(ch, i)); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		val &= ~DPIO_SWING_MARGIN000_MASK; | 
					
						
							|  |  |  | 		val |= margin_reg_value << DPIO_SWING_MARGIN000_SHIFT; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		/*
 | 
					
						
							|  |  |  | 		 * Supposedly this value shouldn't matter when unique transition | 
					
						
							|  |  |  | 		 * scale is disabled, but in fact it does matter. Let's just | 
					
						
							|  |  |  | 		 * always program the same value and hope it's OK. | 
					
						
							|  |  |  | 		 */ | 
					
						
							|  |  |  | 		val &= ~(0xff << DPIO_UNIQ_TRANS_SCALE_SHIFT); | 
					
						
							|  |  |  | 		val |= 0x9a << DPIO_UNIQ_TRANS_SCALE_SHIFT; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		vlv_dpio_write(dev_priv, pipe, CHV_TX_DW2(ch, i), val); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/*
 | 
					
						
							|  |  |  | 	 * The document said it needs to set bit 27 for ch0 and bit 26 | 
					
						
							|  |  |  | 	 * for ch1. Might be a typo in the doc. | 
					
						
							|  |  |  | 	 * For now, for this unique transition scale selection, set bit | 
					
						
							|  |  |  | 	 * 27 for ch0 and ch1. | 
					
						
							|  |  |  | 	 */ | 
					
						
							|  |  |  | 	for (i = 0; i < intel_crtc->config->lane_count; i++) { | 
					
						
							|  |  |  | 		val = vlv_dpio_read(dev_priv, pipe, CHV_TX_DW3(ch, i)); | 
					
						
							|  |  |  | 		if (uniq_trans_scale) | 
					
						
							|  |  |  | 			val |= DPIO_TX_UNIQ_TRANS_SCALE_EN; | 
					
						
							|  |  |  | 		else | 
					
						
							|  |  |  | 			val &= ~DPIO_TX_UNIQ_TRANS_SCALE_EN; | 
					
						
							|  |  |  | 		vlv_dpio_write(dev_priv, pipe, CHV_TX_DW3(ch, i), val); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/* Start swing calculation */ | 
					
						
							|  |  |  | 	val = vlv_dpio_read(dev_priv, pipe, VLV_PCS01_DW10(ch)); | 
					
						
							|  |  |  | 	val |= DPIO_PCS_SWING_CALC_TX0_TX2 | DPIO_PCS_SWING_CALC_TX1_TX3; | 
					
						
							|  |  |  | 	vlv_dpio_write(dev_priv, pipe, VLV_PCS01_DW10(ch), val); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (intel_crtc->config->lane_count > 2) { | 
					
						
							|  |  |  | 		val = vlv_dpio_read(dev_priv, pipe, VLV_PCS23_DW10(ch)); | 
					
						
							|  |  |  | 		val |= DPIO_PCS_SWING_CALC_TX0_TX2 | DPIO_PCS_SWING_CALC_TX1_TX3; | 
					
						
							|  |  |  | 		vlv_dpio_write(dev_priv, pipe, VLV_PCS23_DW10(ch), val); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-26 09:17:19 +01:00
										 |  |  | 	vlv_dpio_put(dev_priv); | 
					
						
							| 
									
										
										
										
											2016-04-27 15:44:17 +03:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-04-27 15:44:18 +03:00
										 |  |  | void chv_data_lane_soft_reset(struct intel_encoder *encoder, | 
					
						
							| 
									
										
										
										
											2017-10-31 22:51:18 +02:00
										 |  |  | 			      const struct intel_crtc_state *crtc_state, | 
					
						
							| 
									
										
										
										
											2016-04-27 15:44:18 +03:00
										 |  |  | 			      bool reset) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	struct drm_i915_private *dev_priv = to_i915(encoder->base.dev); | 
					
						
							|  |  |  | 	enum dpio_channel ch = vlv_dport_to_channel(enc_to_dig_port(&encoder->base)); | 
					
						
							| 
									
										
										
										
											2017-10-31 22:51:18 +02:00
										 |  |  | 	struct intel_crtc *crtc = to_intel_crtc(crtc_state->base.crtc); | 
					
						
							| 
									
										
										
										
											2016-04-27 15:44:18 +03:00
										 |  |  | 	enum pipe pipe = crtc->pipe; | 
					
						
							| 
									
										
										
										
											2019-01-16 11:15:19 +02:00
										 |  |  | 	u32 val; | 
					
						
							| 
									
										
										
										
											2016-04-27 15:44:18 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	val = vlv_dpio_read(dev_priv, pipe, VLV_PCS01_DW0(ch)); | 
					
						
							|  |  |  | 	if (reset) | 
					
						
							|  |  |  | 		val &= ~(DPIO_PCS_TX_LANE2_RESET | DPIO_PCS_TX_LANE1_RESET); | 
					
						
							|  |  |  | 	else | 
					
						
							|  |  |  | 		val |= DPIO_PCS_TX_LANE2_RESET | DPIO_PCS_TX_LANE1_RESET; | 
					
						
							|  |  |  | 	vlv_dpio_write(dev_priv, pipe, VLV_PCS01_DW0(ch), val); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-10-04 11:46:03 +02:00
										 |  |  | 	if (crtc_state->lane_count > 2) { | 
					
						
							| 
									
										
										
										
											2016-04-27 15:44:18 +03:00
										 |  |  | 		val = vlv_dpio_read(dev_priv, pipe, VLV_PCS23_DW0(ch)); | 
					
						
							|  |  |  | 		if (reset) | 
					
						
							|  |  |  | 			val &= ~(DPIO_PCS_TX_LANE2_RESET | DPIO_PCS_TX_LANE1_RESET); | 
					
						
							|  |  |  | 		else | 
					
						
							|  |  |  | 			val |= DPIO_PCS_TX_LANE2_RESET | DPIO_PCS_TX_LANE1_RESET; | 
					
						
							|  |  |  | 		vlv_dpio_write(dev_priv, pipe, VLV_PCS23_DW0(ch), val); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	val = vlv_dpio_read(dev_priv, pipe, VLV_PCS01_DW1(ch)); | 
					
						
							|  |  |  | 	val |= CHV_PCS_REQ_SOFTRESET_EN; | 
					
						
							|  |  |  | 	if (reset) | 
					
						
							|  |  |  | 		val &= ~DPIO_PCS_CLK_SOFT_RESET; | 
					
						
							|  |  |  | 	else | 
					
						
							|  |  |  | 		val |= DPIO_PCS_CLK_SOFT_RESET; | 
					
						
							|  |  |  | 	vlv_dpio_write(dev_priv, pipe, VLV_PCS01_DW1(ch), val); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-10-04 11:46:03 +02:00
										 |  |  | 	if (crtc_state->lane_count > 2) { | 
					
						
							| 
									
										
										
										
											2016-04-27 15:44:18 +03:00
										 |  |  | 		val = vlv_dpio_read(dev_priv, pipe, VLV_PCS23_DW1(ch)); | 
					
						
							|  |  |  | 		val |= CHV_PCS_REQ_SOFTRESET_EN; | 
					
						
							|  |  |  | 		if (reset) | 
					
						
							|  |  |  | 			val &= ~DPIO_PCS_CLK_SOFT_RESET; | 
					
						
							|  |  |  | 		else | 
					
						
							|  |  |  | 			val |= DPIO_PCS_CLK_SOFT_RESET; | 
					
						
							|  |  |  | 		vlv_dpio_write(dev_priv, pipe, VLV_PCS23_DW1(ch), val); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2016-04-27 15:44:19 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-10-31 22:51:18 +02:00
										 |  |  | void chv_phy_pre_pll_enable(struct intel_encoder *encoder, | 
					
						
							|  |  |  | 			    const struct intel_crtc_state *crtc_state) | 
					
						
							| 
									
										
										
										
											2016-04-27 15:44:19 +03:00
										 |  |  | { | 
					
						
							|  |  |  | 	struct intel_digital_port *dport = enc_to_dig_port(&encoder->base); | 
					
						
							| 
									
										
										
										
											2017-10-31 22:51:18 +02:00
										 |  |  | 	struct drm_i915_private *dev_priv = to_i915(encoder->base.dev); | 
					
						
							|  |  |  | 	struct intel_crtc *crtc = to_intel_crtc(crtc_state->base.crtc); | 
					
						
							| 
									
										
										
										
											2016-04-27 15:44:19 +03:00
										 |  |  | 	enum dpio_channel ch = vlv_dport_to_channel(dport); | 
					
						
							| 
									
										
										
										
											2017-10-31 22:51:18 +02:00
										 |  |  | 	enum pipe pipe = crtc->pipe; | 
					
						
							| 
									
										
										
										
											2016-04-27 15:44:19 +03:00
										 |  |  | 	unsigned int lane_mask = | 
					
						
							| 
									
										
										
										
											2017-10-31 22:51:18 +02:00
										 |  |  | 		intel_dp_unused_lane_mask(crtc_state->lane_count); | 
					
						
							| 
									
										
										
										
											2016-04-27 15:44:19 +03:00
										 |  |  | 	u32 val; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/*
 | 
					
						
							|  |  |  | 	 * Must trick the second common lane into life. | 
					
						
							|  |  |  | 	 * Otherwise we can't even access the PLL. | 
					
						
							|  |  |  | 	 */ | 
					
						
							|  |  |  | 	if (ch == DPIO_CH0 && pipe == PIPE_B) | 
					
						
							|  |  |  | 		dport->release_cl2_override = | 
					
						
							|  |  |  | 			!chv_phy_powergate_ch(dev_priv, DPIO_PHY0, DPIO_CH1, true); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	chv_phy_powergate_lanes(encoder, true, lane_mask); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-26 09:17:19 +01:00
										 |  |  | 	vlv_dpio_get(dev_priv); | 
					
						
							| 
									
										
										
										
											2016-04-27 15:44:19 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	/* Assert data lane reset */ | 
					
						
							| 
									
										
										
										
											2017-10-31 22:51:18 +02:00
										 |  |  | 	chv_data_lane_soft_reset(encoder, crtc_state, true); | 
					
						
							| 
									
										
										
										
											2016-04-27 15:44:19 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	/* program left/right clock distribution */ | 
					
						
							|  |  |  | 	if (pipe != PIPE_B) { | 
					
						
							|  |  |  | 		val = vlv_dpio_read(dev_priv, pipe, _CHV_CMN_DW5_CH0); | 
					
						
							|  |  |  | 		val &= ~(CHV_BUFLEFTENA1_MASK | CHV_BUFRIGHTENA1_MASK); | 
					
						
							|  |  |  | 		if (ch == DPIO_CH0) | 
					
						
							|  |  |  | 			val |= CHV_BUFLEFTENA1_FORCE; | 
					
						
							|  |  |  | 		if (ch == DPIO_CH1) | 
					
						
							|  |  |  | 			val |= CHV_BUFRIGHTENA1_FORCE; | 
					
						
							|  |  |  | 		vlv_dpio_write(dev_priv, pipe, _CHV_CMN_DW5_CH0, val); | 
					
						
							|  |  |  | 	} else { | 
					
						
							|  |  |  | 		val = vlv_dpio_read(dev_priv, pipe, _CHV_CMN_DW1_CH1); | 
					
						
							|  |  |  | 		val &= ~(CHV_BUFLEFTENA2_MASK | CHV_BUFRIGHTENA2_MASK); | 
					
						
							|  |  |  | 		if (ch == DPIO_CH0) | 
					
						
							|  |  |  | 			val |= CHV_BUFLEFTENA2_FORCE; | 
					
						
							|  |  |  | 		if (ch == DPIO_CH1) | 
					
						
							|  |  |  | 			val |= CHV_BUFRIGHTENA2_FORCE; | 
					
						
							|  |  |  | 		vlv_dpio_write(dev_priv, pipe, _CHV_CMN_DW1_CH1, val); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/* program clock channel usage */ | 
					
						
							|  |  |  | 	val = vlv_dpio_read(dev_priv, pipe, VLV_PCS01_DW8(ch)); | 
					
						
							|  |  |  | 	val |= CHV_PCS_USEDCLKCHANNEL_OVRRIDE; | 
					
						
							|  |  |  | 	if (pipe != PIPE_B) | 
					
						
							|  |  |  | 		val &= ~CHV_PCS_USEDCLKCHANNEL; | 
					
						
							|  |  |  | 	else | 
					
						
							|  |  |  | 		val |= CHV_PCS_USEDCLKCHANNEL; | 
					
						
							|  |  |  | 	vlv_dpio_write(dev_priv, pipe, VLV_PCS01_DW8(ch), val); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-10-31 22:51:18 +02:00
										 |  |  | 	if (crtc_state->lane_count > 2) { | 
					
						
							| 
									
										
										
										
											2016-04-27 15:44:19 +03:00
										 |  |  | 		val = vlv_dpio_read(dev_priv, pipe, VLV_PCS23_DW8(ch)); | 
					
						
							|  |  |  | 		val |= CHV_PCS_USEDCLKCHANNEL_OVRRIDE; | 
					
						
							|  |  |  | 		if (pipe != PIPE_B) | 
					
						
							|  |  |  | 			val &= ~CHV_PCS_USEDCLKCHANNEL; | 
					
						
							|  |  |  | 		else | 
					
						
							|  |  |  | 			val |= CHV_PCS_USEDCLKCHANNEL; | 
					
						
							|  |  |  | 		vlv_dpio_write(dev_priv, pipe, VLV_PCS23_DW8(ch), val); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/*
 | 
					
						
							|  |  |  | 	 * This a a bit weird since generally CL | 
					
						
							|  |  |  | 	 * matches the pipe, but here we need to | 
					
						
							|  |  |  | 	 * pick the CL based on the port. | 
					
						
							|  |  |  | 	 */ | 
					
						
							|  |  |  | 	val = vlv_dpio_read(dev_priv, pipe, CHV_CMN_DW19(ch)); | 
					
						
							|  |  |  | 	if (pipe != PIPE_B) | 
					
						
							|  |  |  | 		val &= ~CHV_CMN_USEDCLKCHANNEL; | 
					
						
							|  |  |  | 	else | 
					
						
							|  |  |  | 		val |= CHV_CMN_USEDCLKCHANNEL; | 
					
						
							|  |  |  | 	vlv_dpio_write(dev_priv, pipe, CHV_CMN_DW19(ch), val); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-26 09:17:19 +01:00
										 |  |  | 	vlv_dpio_put(dev_priv); | 
					
						
							| 
									
										
										
										
											2016-04-27 15:44:19 +03:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2016-04-27 15:44:20 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-10-31 22:51:18 +02:00
										 |  |  | void chv_phy_pre_encoder_enable(struct intel_encoder *encoder, | 
					
						
							|  |  |  | 				const struct intel_crtc_state *crtc_state) | 
					
						
							| 
									
										
										
										
											2016-04-27 15:44:20 +03:00
										 |  |  | { | 
					
						
							|  |  |  | 	struct intel_dp *intel_dp = enc_to_intel_dp(&encoder->base); | 
					
						
							|  |  |  | 	struct intel_digital_port *dport = dp_to_dig_port(intel_dp); | 
					
						
							| 
									
										
										
										
											2017-10-31 22:51:18 +02:00
										 |  |  | 	struct drm_i915_private *dev_priv = to_i915(encoder->base.dev); | 
					
						
							|  |  |  | 	struct intel_crtc *crtc = to_intel_crtc(crtc_state->base.crtc); | 
					
						
							| 
									
										
										
										
											2016-04-27 15:44:20 +03:00
										 |  |  | 	enum dpio_channel ch = vlv_dport_to_channel(dport); | 
					
						
							| 
									
										
										
										
											2017-10-31 22:51:18 +02:00
										 |  |  | 	enum pipe pipe = crtc->pipe; | 
					
						
							| 
									
										
										
										
											2016-04-27 15:44:20 +03:00
										 |  |  | 	int data, i, stagger; | 
					
						
							|  |  |  | 	u32 val; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-26 09:17:19 +01:00
										 |  |  | 	vlv_dpio_get(dev_priv); | 
					
						
							| 
									
										
										
										
											2016-04-27 15:44:20 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	/* allow hardware to manage TX FIFO reset source */ | 
					
						
							|  |  |  | 	val = vlv_dpio_read(dev_priv, pipe, VLV_PCS01_DW11(ch)); | 
					
						
							|  |  |  | 	val &= ~DPIO_LANEDESKEW_STRAP_OVRD; | 
					
						
							|  |  |  | 	vlv_dpio_write(dev_priv, pipe, VLV_PCS01_DW11(ch), val); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-10-31 22:51:18 +02:00
										 |  |  | 	if (crtc_state->lane_count > 2) { | 
					
						
							| 
									
										
										
										
											2016-04-27 15:44:20 +03:00
										 |  |  | 		val = vlv_dpio_read(dev_priv, pipe, VLV_PCS23_DW11(ch)); | 
					
						
							|  |  |  | 		val &= ~DPIO_LANEDESKEW_STRAP_OVRD; | 
					
						
							|  |  |  | 		vlv_dpio_write(dev_priv, pipe, VLV_PCS23_DW11(ch), val); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/* Program Tx lane latency optimal setting*/ | 
					
						
							| 
									
										
										
										
											2017-10-31 22:51:18 +02:00
										 |  |  | 	for (i = 0; i < crtc_state->lane_count; i++) { | 
					
						
							| 
									
										
										
										
											2016-04-27 15:44:20 +03:00
										 |  |  | 		/* Set the upar bit */ | 
					
						
							| 
									
										
										
										
											2017-10-31 22:51:18 +02:00
										 |  |  | 		if (crtc_state->lane_count == 1) | 
					
						
							| 
									
										
										
										
											2016-04-27 15:44:20 +03:00
										 |  |  | 			data = 0x0; | 
					
						
							|  |  |  | 		else | 
					
						
							|  |  |  | 			data = (i == 1) ? 0x0 : 0x1; | 
					
						
							|  |  |  | 		vlv_dpio_write(dev_priv, pipe, CHV_TX_DW14(ch, i), | 
					
						
							|  |  |  | 				data << DPIO_UPAR_SHIFT); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/* Data lane stagger programming */ | 
					
						
							| 
									
										
										
										
											2017-10-31 22:51:18 +02:00
										 |  |  | 	if (crtc_state->port_clock > 270000) | 
					
						
							| 
									
										
										
										
											2016-04-27 15:44:20 +03:00
										 |  |  | 		stagger = 0x18; | 
					
						
							| 
									
										
										
										
											2017-10-31 22:51:18 +02:00
										 |  |  | 	else if (crtc_state->port_clock > 135000) | 
					
						
							| 
									
										
										
										
											2016-04-27 15:44:20 +03:00
										 |  |  | 		stagger = 0xd; | 
					
						
							| 
									
										
										
										
											2017-10-31 22:51:18 +02:00
										 |  |  | 	else if (crtc_state->port_clock > 67500) | 
					
						
							| 
									
										
										
										
											2016-04-27 15:44:20 +03:00
										 |  |  | 		stagger = 0x7; | 
					
						
							| 
									
										
										
										
											2017-10-31 22:51:18 +02:00
										 |  |  | 	else if (crtc_state->port_clock > 33750) | 
					
						
							| 
									
										
										
										
											2016-04-27 15:44:20 +03:00
										 |  |  | 		stagger = 0x4; | 
					
						
							|  |  |  | 	else | 
					
						
							|  |  |  | 		stagger = 0x2; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	val = vlv_dpio_read(dev_priv, pipe, VLV_PCS01_DW11(ch)); | 
					
						
							|  |  |  | 	val |= DPIO_TX2_STAGGER_MASK(0x1f); | 
					
						
							|  |  |  | 	vlv_dpio_write(dev_priv, pipe, VLV_PCS01_DW11(ch), val); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-10-31 22:51:18 +02:00
										 |  |  | 	if (crtc_state->lane_count > 2) { | 
					
						
							| 
									
										
										
										
											2016-04-27 15:44:20 +03:00
										 |  |  | 		val = vlv_dpio_read(dev_priv, pipe, VLV_PCS23_DW11(ch)); | 
					
						
							|  |  |  | 		val |= DPIO_TX2_STAGGER_MASK(0x1f); | 
					
						
							|  |  |  | 		vlv_dpio_write(dev_priv, pipe, VLV_PCS23_DW11(ch), val); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	vlv_dpio_write(dev_priv, pipe, VLV_PCS01_DW12(ch), | 
					
						
							|  |  |  | 		       DPIO_LANESTAGGER_STRAP(stagger) | | 
					
						
							|  |  |  | 		       DPIO_LANESTAGGER_STRAP_OVRD | | 
					
						
							|  |  |  | 		       DPIO_TX1_STAGGER_MASK(0x1f) | | 
					
						
							|  |  |  | 		       DPIO_TX1_STAGGER_MULT(6) | | 
					
						
							|  |  |  | 		       DPIO_TX2_STAGGER_MULT(0)); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-10-31 22:51:18 +02:00
										 |  |  | 	if (crtc_state->lane_count > 2) { | 
					
						
							| 
									
										
										
										
											2016-04-27 15:44:20 +03:00
										 |  |  | 		vlv_dpio_write(dev_priv, pipe, VLV_PCS23_DW12(ch), | 
					
						
							|  |  |  | 			       DPIO_LANESTAGGER_STRAP(stagger) | | 
					
						
							|  |  |  | 			       DPIO_LANESTAGGER_STRAP_OVRD | | 
					
						
							|  |  |  | 			       DPIO_TX1_STAGGER_MASK(0x1f) | | 
					
						
							|  |  |  | 			       DPIO_TX1_STAGGER_MULT(7) | | 
					
						
							|  |  |  | 			       DPIO_TX2_STAGGER_MULT(5)); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/* Deassert data lane reset */ | 
					
						
							| 
									
										
										
										
											2017-10-31 22:51:18 +02:00
										 |  |  | 	chv_data_lane_soft_reset(encoder, crtc_state, false); | 
					
						
							| 
									
										
										
										
											2016-04-27 15:44:20 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-26 09:17:19 +01:00
										 |  |  | 	vlv_dpio_put(dev_priv); | 
					
						
							| 
									
										
										
										
											2016-04-27 15:44:20 +03:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void chv_phy_release_cl2_override(struct intel_encoder *encoder) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	struct intel_digital_port *dport = enc_to_dig_port(&encoder->base); | 
					
						
							|  |  |  | 	struct drm_i915_private *dev_priv = to_i915(encoder->base.dev); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (dport->release_cl2_override) { | 
					
						
							|  |  |  | 		chv_phy_powergate_ch(dev_priv, DPIO_PHY0, DPIO_CH1, false); | 
					
						
							|  |  |  | 		dport->release_cl2_override = false; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2016-04-27 15:44:21 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-10-31 22:51:18 +02:00
										 |  |  | void chv_phy_post_pll_disable(struct intel_encoder *encoder, | 
					
						
							|  |  |  | 			      const struct intel_crtc_state *old_crtc_state) | 
					
						
							| 
									
										
										
										
											2016-04-27 15:44:21 +03:00
										 |  |  | { | 
					
						
							|  |  |  | 	struct drm_i915_private *dev_priv = to_i915(encoder->base.dev); | 
					
						
							| 
									
										
										
										
											2017-10-31 22:51:18 +02:00
										 |  |  | 	enum pipe pipe = to_intel_crtc(old_crtc_state->base.crtc)->pipe; | 
					
						
							| 
									
										
										
										
											2016-04-27 15:44:21 +03:00
										 |  |  | 	u32 val; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-26 09:17:19 +01:00
										 |  |  | 	vlv_dpio_get(dev_priv); | 
					
						
							| 
									
										
										
										
											2016-04-27 15:44:21 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	/* disable left/right clock distribution */ | 
					
						
							|  |  |  | 	if (pipe != PIPE_B) { | 
					
						
							|  |  |  | 		val = vlv_dpio_read(dev_priv, pipe, _CHV_CMN_DW5_CH0); | 
					
						
							|  |  |  | 		val &= ~(CHV_BUFLEFTENA1_MASK | CHV_BUFRIGHTENA1_MASK); | 
					
						
							|  |  |  | 		vlv_dpio_write(dev_priv, pipe, _CHV_CMN_DW5_CH0, val); | 
					
						
							|  |  |  | 	} else { | 
					
						
							|  |  |  | 		val = vlv_dpio_read(dev_priv, pipe, _CHV_CMN_DW1_CH1); | 
					
						
							|  |  |  | 		val &= ~(CHV_BUFLEFTENA2_MASK | CHV_BUFRIGHTENA2_MASK); | 
					
						
							|  |  |  | 		vlv_dpio_write(dev_priv, pipe, _CHV_CMN_DW1_CH1, val); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-26 09:17:19 +01:00
										 |  |  | 	vlv_dpio_put(dev_priv); | 
					
						
							| 
									
										
										
										
											2016-04-27 15:44:21 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	/*
 | 
					
						
							|  |  |  | 	 * Leave the power down bit cleared for at least one | 
					
						
							|  |  |  | 	 * lane so that chv_powergate_phy_ch() will power | 
					
						
							|  |  |  | 	 * on something when the channel is otherwise unused. | 
					
						
							|  |  |  | 	 * When the port is off and the override is removed | 
					
						
							|  |  |  | 	 * the lanes power down anyway, so otherwise it doesn't | 
					
						
							|  |  |  | 	 * really matter what the state of power down bits is | 
					
						
							|  |  |  | 	 * after this. | 
					
						
							|  |  |  | 	 */ | 
					
						
							|  |  |  | 	chv_phy_powergate_lanes(encoder, false, 0x0); | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2016-04-27 15:44:22 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | void vlv_set_phy_signal_level(struct intel_encoder *encoder, | 
					
						
							|  |  |  | 			      u32 demph_reg_value, u32 preemph_reg_value, | 
					
						
							|  |  |  | 			      u32 uniqtranscale_reg_value, u32 tx3_demph) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	struct drm_i915_private *dev_priv = to_i915(encoder->base.dev); | 
					
						
							|  |  |  | 	struct intel_crtc *intel_crtc = to_intel_crtc(encoder->base.crtc); | 
					
						
							|  |  |  | 	struct intel_digital_port *dport = enc_to_dig_port(&encoder->base); | 
					
						
							|  |  |  | 	enum dpio_channel port = vlv_dport_to_channel(dport); | 
					
						
							| 
									
										
										
										
											2017-10-31 22:51:18 +02:00
										 |  |  | 	enum pipe pipe = intel_crtc->pipe; | 
					
						
							| 
									
										
										
										
											2016-04-27 15:44:22 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-26 09:17:19 +01:00
										 |  |  | 	vlv_dpio_get(dev_priv); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-04-27 15:44:22 +03:00
										 |  |  | 	vlv_dpio_write(dev_priv, pipe, VLV_TX_DW5(port), 0x00000000); | 
					
						
							|  |  |  | 	vlv_dpio_write(dev_priv, pipe, VLV_TX_DW4(port), demph_reg_value); | 
					
						
							|  |  |  | 	vlv_dpio_write(dev_priv, pipe, VLV_TX_DW2(port), | 
					
						
							|  |  |  | 			 uniqtranscale_reg_value); | 
					
						
							|  |  |  | 	vlv_dpio_write(dev_priv, pipe, VLV_TX_DW3(port), 0x0C782040); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (tx3_demph) | 
					
						
							|  |  |  | 		vlv_dpio_write(dev_priv, pipe, VLV_TX3_DW4(port), tx3_demph); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	vlv_dpio_write(dev_priv, pipe, VLV_PCS_DW11(port), 0x00030000); | 
					
						
							|  |  |  | 	vlv_dpio_write(dev_priv, pipe, VLV_PCS_DW9(port), preemph_reg_value); | 
					
						
							|  |  |  | 	vlv_dpio_write(dev_priv, pipe, VLV_TX_DW5(port), DPIO_TX_OCALINIT_EN); | 
					
						
							| 
									
										
										
										
											2019-04-26 09:17:19 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	vlv_dpio_put(dev_priv); | 
					
						
							| 
									
										
										
										
											2016-04-27 15:44:22 +03:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2016-04-27 15:44:23 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-10-31 22:51:18 +02:00
										 |  |  | void vlv_phy_pre_pll_enable(struct intel_encoder *encoder, | 
					
						
							|  |  |  | 			    const struct intel_crtc_state *crtc_state) | 
					
						
							| 
									
										
										
										
											2016-04-27 15:44:23 +03:00
										 |  |  | { | 
					
						
							|  |  |  | 	struct intel_digital_port *dport = enc_to_dig_port(&encoder->base); | 
					
						
							| 
									
										
										
										
											2017-10-31 22:51:18 +02:00
										 |  |  | 	struct drm_i915_private *dev_priv = to_i915(encoder->base.dev); | 
					
						
							|  |  |  | 	struct intel_crtc *crtc = to_intel_crtc(crtc_state->base.crtc); | 
					
						
							| 
									
										
										
										
											2016-04-27 15:44:23 +03:00
										 |  |  | 	enum dpio_channel port = vlv_dport_to_channel(dport); | 
					
						
							| 
									
										
										
										
											2017-10-31 22:51:18 +02:00
										 |  |  | 	enum pipe pipe = crtc->pipe; | 
					
						
							| 
									
										
										
										
											2016-04-27 15:44:23 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	/* Program Tx lane resets to default */ | 
					
						
							| 
									
										
										
										
											2019-04-26 09:17:19 +01:00
										 |  |  | 	vlv_dpio_get(dev_priv); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-04-27 15:44:23 +03:00
										 |  |  | 	vlv_dpio_write(dev_priv, pipe, VLV_PCS_DW0(port), | 
					
						
							|  |  |  | 			 DPIO_PCS_TX_LANE2_RESET | | 
					
						
							|  |  |  | 			 DPIO_PCS_TX_LANE1_RESET); | 
					
						
							|  |  |  | 	vlv_dpio_write(dev_priv, pipe, VLV_PCS_DW1(port), | 
					
						
							|  |  |  | 			 DPIO_PCS_CLK_CRI_RXEB_EIOS_EN | | 
					
						
							|  |  |  | 			 DPIO_PCS_CLK_CRI_RXDIGFILTSG_EN | | 
					
						
							|  |  |  | 			 (1<<DPIO_PCS_CLK_DATAWIDTH_SHIFT) | | 
					
						
							|  |  |  | 				 DPIO_PCS_CLK_SOFT_RESET); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/* Fix up inter-pair skew failure */ | 
					
						
							|  |  |  | 	vlv_dpio_write(dev_priv, pipe, VLV_PCS_DW12(port), 0x00750f00); | 
					
						
							|  |  |  | 	vlv_dpio_write(dev_priv, pipe, VLV_TX_DW11(port), 0x00001500); | 
					
						
							|  |  |  | 	vlv_dpio_write(dev_priv, pipe, VLV_TX_DW14(port), 0x40400000); | 
					
						
							| 
									
										
										
										
											2019-04-26 09:17:19 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	vlv_dpio_put(dev_priv); | 
					
						
							| 
									
										
										
										
											2016-04-27 15:44:23 +03:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2016-04-27 15:44:24 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-10-31 22:51:18 +02:00
										 |  |  | void vlv_phy_pre_encoder_enable(struct intel_encoder *encoder, | 
					
						
							|  |  |  | 				const struct intel_crtc_state *crtc_state) | 
					
						
							| 
									
										
										
										
											2016-04-27 15:44:24 +03:00
										 |  |  | { | 
					
						
							|  |  |  | 	struct intel_dp *intel_dp = enc_to_intel_dp(&encoder->base); | 
					
						
							|  |  |  | 	struct intel_digital_port *dport = dp_to_dig_port(intel_dp); | 
					
						
							| 
									
										
										
										
											2017-10-31 22:51:18 +02:00
										 |  |  | 	struct drm_i915_private *dev_priv = to_i915(encoder->base.dev); | 
					
						
							|  |  |  | 	struct intel_crtc *crtc = to_intel_crtc(crtc_state->base.crtc); | 
					
						
							| 
									
										
										
										
											2016-04-27 15:44:24 +03:00
										 |  |  | 	enum dpio_channel port = vlv_dport_to_channel(dport); | 
					
						
							| 
									
										
										
										
											2017-10-31 22:51:18 +02:00
										 |  |  | 	enum pipe pipe = crtc->pipe; | 
					
						
							| 
									
										
										
										
											2016-04-27 15:44:24 +03:00
										 |  |  | 	u32 val; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-26 09:17:19 +01:00
										 |  |  | 	vlv_dpio_get(dev_priv); | 
					
						
							| 
									
										
										
										
											2016-04-27 15:44:24 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	/* Enable clock channels for this port */ | 
					
						
							|  |  |  | 	val = vlv_dpio_read(dev_priv, pipe, VLV_PCS01_DW8(port)); | 
					
						
							|  |  |  | 	val = 0; | 
					
						
							|  |  |  | 	if (pipe) | 
					
						
							|  |  |  | 		val |= (1<<21); | 
					
						
							|  |  |  | 	else | 
					
						
							|  |  |  | 		val &= ~(1<<21); | 
					
						
							|  |  |  | 	val |= 0x001000c4; | 
					
						
							|  |  |  | 	vlv_dpio_write(dev_priv, pipe, VLV_PCS_DW8(port), val); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/* Program lane clock */ | 
					
						
							|  |  |  | 	vlv_dpio_write(dev_priv, pipe, VLV_PCS_DW14(port), 0x00760018); | 
					
						
							|  |  |  | 	vlv_dpio_write(dev_priv, pipe, VLV_PCS_DW23(port), 0x00400888); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-26 09:17:19 +01:00
										 |  |  | 	vlv_dpio_put(dev_priv); | 
					
						
							| 
									
										
										
										
											2016-04-27 15:44:24 +03:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2016-04-27 15:44:25 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-10-31 22:51:18 +02:00
										 |  |  | void vlv_phy_reset_lanes(struct intel_encoder *encoder, | 
					
						
							|  |  |  | 			 const struct intel_crtc_state *old_crtc_state) | 
					
						
							| 
									
										
										
										
											2016-04-27 15:44:25 +03:00
										 |  |  | { | 
					
						
							|  |  |  | 	struct intel_digital_port *dport = enc_to_dig_port(&encoder->base); | 
					
						
							| 
									
										
										
										
											2016-07-04 11:34:36 +01:00
										 |  |  | 	struct drm_i915_private *dev_priv = to_i915(encoder->base.dev); | 
					
						
							| 
									
										
										
										
											2017-10-31 22:51:18 +02:00
										 |  |  | 	struct intel_crtc *crtc = to_intel_crtc(old_crtc_state->base.crtc); | 
					
						
							| 
									
										
										
										
											2016-04-27 15:44:25 +03:00
										 |  |  | 	enum dpio_channel port = vlv_dport_to_channel(dport); | 
					
						
							| 
									
										
										
										
											2017-10-31 22:51:18 +02:00
										 |  |  | 	enum pipe pipe = crtc->pipe; | 
					
						
							| 
									
										
										
										
											2016-04-27 15:44:25 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-26 09:17:19 +01:00
										 |  |  | 	vlv_dpio_get(dev_priv); | 
					
						
							| 
									
										
										
										
											2016-04-27 15:44:25 +03:00
										 |  |  | 	vlv_dpio_write(dev_priv, pipe, VLV_PCS_DW0(port), 0x00000000); | 
					
						
							|  |  |  | 	vlv_dpio_write(dev_priv, pipe, VLV_PCS_DW1(port), 0x00e00060); | 
					
						
							| 
									
										
										
										
											2019-04-26 09:17:19 +01:00
										 |  |  | 	vlv_dpio_put(dev_priv); | 
					
						
							| 
									
										
										
										
											2016-04-27 15:44:25 +03:00
										 |  |  | } |