1aa850fb1SJani Nikula // SPDX-License-Identifier: MIT
2aa850fb1SJani Nikula /*
3aa850fb1SJani Nikula  * Copyright © 2020-2021 Intel Corporation
4aa850fb1SJani Nikula  */
5aa850fb1SJani Nikula 
6aa850fb1SJani Nikula #include "i915_drv.h"
7801543b2SJani Nikula #include "i915_reg.h"
8aa850fb1SJani Nikula #include "i915_trace.h"
9bb45217fSVille Syrjälä #include "intel_bios.h"
10ec2593e3SJani Nikula #include "intel_de.h"
11aa850fb1SJani Nikula #include "intel_display_types.h"
12aa850fb1SJani Nikula #include "intel_dp_aux.h"
1389e790ecSJani Nikula #include "intel_dp_aux_regs.h"
14aa850fb1SJani Nikula #include "intel_pps.h"
15aa850fb1SJani Nikula #include "intel_tc.h"
16aa850fb1SJani Nikula 
intel_dp_aux_pack(const u8 * src,int src_bytes)17a181e940SVille Syrjälä u32 intel_dp_aux_pack(const u8 *src, int src_bytes)
18aa850fb1SJani Nikula {
19aa850fb1SJani Nikula 	int i;
20aa850fb1SJani Nikula 	u32 v = 0;
21aa850fb1SJani Nikula 
22aa850fb1SJani Nikula 	if (src_bytes > 4)
23aa850fb1SJani Nikula 		src_bytes = 4;
24aa850fb1SJani Nikula 	for (i = 0; i < src_bytes; i++)
25aa850fb1SJani Nikula 		v |= ((u32)src[i]) << ((3 - i) * 8);
26aa850fb1SJani Nikula 	return v;
27aa850fb1SJani Nikula }
28aa850fb1SJani Nikula 
intel_dp_aux_unpack(u32 src,u8 * dst,int dst_bytes)292616be2eSJani Nikula static void intel_dp_aux_unpack(u32 src, u8 *dst, int dst_bytes)
30aa850fb1SJani Nikula {
31aa850fb1SJani Nikula 	int i;
32aa850fb1SJani Nikula 
33aa850fb1SJani Nikula 	if (dst_bytes > 4)
34aa850fb1SJani Nikula 		dst_bytes = 4;
35aa850fb1SJani Nikula 	for (i = 0; i < dst_bytes; i++)
36aa850fb1SJani Nikula 		dst[i] = src >> ((3 - i) * 8);
37aa850fb1SJani Nikula }
38aa850fb1SJani Nikula 
39aa850fb1SJani Nikula static u32
intel_dp_aux_wait_done(struct intel_dp * intel_dp)40aa850fb1SJani Nikula intel_dp_aux_wait_done(struct intel_dp *intel_dp)
41aa850fb1SJani Nikula {
42aa850fb1SJani Nikula 	struct drm_i915_private *i915 = dp_to_i915(intel_dp);
43aa850fb1SJani Nikula 	i915_reg_t ch_ctl = intel_dp->aux_ch_ctl_reg(intel_dp);
44aa850fb1SJani Nikula 	const unsigned int timeout_ms = 10;
45aa850fb1SJani Nikula 	u32 status;
465a9b0c74SArun R Murthy 	int ret;
47aa850fb1SJani Nikula 
485a9b0c74SArun R Murthy 	ret = __intel_de_wait_for_register(i915, ch_ctl,
495a9b0c74SArun R Murthy 					   DP_AUX_CH_CTL_SEND_BUSY, 0,
505a9b0c74SArun R Murthy 					   2, timeout_ms, &status);
51aa850fb1SJani Nikula 
525a9b0c74SArun R Murthy 	if (ret == -ETIMEDOUT)
53aa850fb1SJani Nikula 		drm_err(&i915->drm,
54aa850fb1SJani Nikula 			"%s: did not complete or timeout within %ums (status 0x%08x)\n",
55aa850fb1SJani Nikula 			intel_dp->aux.name, timeout_ms, status);
56aa850fb1SJani Nikula 
57aa850fb1SJani Nikula 	return status;
58aa850fb1SJani Nikula }
59aa850fb1SJani Nikula 
g4x_get_aux_clock_divider(struct intel_dp * intel_dp,int index)60aa850fb1SJani Nikula static u32 g4x_get_aux_clock_divider(struct intel_dp *intel_dp, int index)
61aa850fb1SJani Nikula {
62aa850fb1SJani Nikula 	struct drm_i915_private *dev_priv = dp_to_i915(intel_dp);
63aa850fb1SJani Nikula 
64aa850fb1SJani Nikula 	if (index)
65aa850fb1SJani Nikula 		return 0;
66aa850fb1SJani Nikula 
67aa850fb1SJani Nikula 	/*
68aa850fb1SJani Nikula 	 * The clock divider is based off the hrawclk, and would like to run at
69aa850fb1SJani Nikula 	 * 2MHz.  So, take the hrawclk value and divide by 2000 and use that
70aa850fb1SJani Nikula 	 */
71aa850fb1SJani Nikula 	return DIV_ROUND_CLOSEST(RUNTIME_INFO(dev_priv)->rawclk_freq, 2000);
72aa850fb1SJani Nikula }
73aa850fb1SJani Nikula 
ilk_get_aux_clock_divider(struct intel_dp * intel_dp,int index)74aa850fb1SJani Nikula static u32 ilk_get_aux_clock_divider(struct intel_dp *intel_dp, int index)
75aa850fb1SJani Nikula {
76aa850fb1SJani Nikula 	struct drm_i915_private *dev_priv = dp_to_i915(intel_dp);
77aa850fb1SJani Nikula 	struct intel_digital_port *dig_port = dp_to_dig_port(intel_dp);
78aa850fb1SJani Nikula 	u32 freq;
79aa850fb1SJani Nikula 
80aa850fb1SJani Nikula 	if (index)
81aa850fb1SJani Nikula 		return 0;
82aa850fb1SJani Nikula 
83aa850fb1SJani Nikula 	/*
84aa850fb1SJani Nikula 	 * The clock divider is based off the cdclk or PCH rawclk, and would
85aa850fb1SJani Nikula 	 * like to run at 2MHz.  So, take the cdclk or PCH rawclk value and
86aa850fb1SJani Nikula 	 * divide by 2000 and use that
87aa850fb1SJani Nikula 	 */
88aa850fb1SJani Nikula 	if (dig_port->aux_ch == AUX_CH_A)
89d51309b4SJani Nikula 		freq = dev_priv->display.cdclk.hw.cdclk;
90aa850fb1SJani Nikula 	else
91aa850fb1SJani Nikula 		freq = RUNTIME_INFO(dev_priv)->rawclk_freq;
92aa850fb1SJani Nikula 	return DIV_ROUND_CLOSEST(freq, 2000);
93aa850fb1SJani Nikula }
94aa850fb1SJani Nikula 
hsw_get_aux_clock_divider(struct intel_dp * intel_dp,int index)95aa850fb1SJani Nikula static u32 hsw_get_aux_clock_divider(struct intel_dp *intel_dp, int index)
96aa850fb1SJani Nikula {
97aa850fb1SJani Nikula 	struct drm_i915_private *dev_priv = dp_to_i915(intel_dp);
98aa850fb1SJani Nikula 	struct intel_digital_port *dig_port = dp_to_dig_port(intel_dp);
99aa850fb1SJani Nikula 
100aa850fb1SJani Nikula 	if (dig_port->aux_ch != AUX_CH_A && HAS_PCH_LPT_H(dev_priv)) {
101aa850fb1SJani Nikula 		/* Workaround for non-ULT HSW */
102aa850fb1SJani Nikula 		switch (index) {
103aa850fb1SJani Nikula 		case 0: return 63;
104aa850fb1SJani Nikula 		case 1: return 72;
105aa850fb1SJani Nikula 		default: return 0;
106aa850fb1SJani Nikula 		}
107aa850fb1SJani Nikula 	}
108aa850fb1SJani Nikula 
109aa850fb1SJani Nikula 	return ilk_get_aux_clock_divider(intel_dp, index);
110aa850fb1SJani Nikula }
111aa850fb1SJani Nikula 
skl_get_aux_clock_divider(struct intel_dp * intel_dp,int index)112aa850fb1SJani Nikula static u32 skl_get_aux_clock_divider(struct intel_dp *intel_dp, int index)
113aa850fb1SJani Nikula {
114aa850fb1SJani Nikula 	/*
115aa850fb1SJani Nikula 	 * SKL doesn't need us to program the AUX clock divider (Hardware will
116aa850fb1SJani Nikula 	 * derive the clock from CDCLK automatically). We still implement the
117aa850fb1SJani Nikula 	 * get_aux_clock_divider vfunc to plug-in into the existing code.
118aa850fb1SJani Nikula 	 */
119aa850fb1SJani Nikula 	return index ? 0 : 1;
120aa850fb1SJani Nikula }
121aa850fb1SJani Nikula 
intel_dp_aux_sync_len(void)12226bfc3f3SVille Syrjälä static int intel_dp_aux_sync_len(void)
12326bfc3f3SVille Syrjälä {
12426bfc3f3SVille Syrjälä 	int precharge = 16; /* 10-16 */
12526bfc3f3SVille Syrjälä 	int preamble = 16;
12626bfc3f3SVille Syrjälä 
12726bfc3f3SVille Syrjälä 	return precharge + preamble;
12826bfc3f3SVille Syrjälä }
12926bfc3f3SVille Syrjälä 
intel_dp_aux_fw_sync_len(void)13026bfc3f3SVille Syrjälä static int intel_dp_aux_fw_sync_len(void)
13126bfc3f3SVille Syrjälä {
132b29a20f7SJouni Högander 	int precharge = 10; /* 10-16 */
13326bfc3f3SVille Syrjälä 	int preamble = 8;
13426bfc3f3SVille Syrjälä 
13526bfc3f3SVille Syrjälä 	return precharge + preamble;
13626bfc3f3SVille Syrjälä }
13726bfc3f3SVille Syrjälä 
g4x_dp_aux_precharge_len(void)13826bfc3f3SVille Syrjälä static int g4x_dp_aux_precharge_len(void)
13926bfc3f3SVille Syrjälä {
14026bfc3f3SVille Syrjälä 	int precharge_min = 10;
14126bfc3f3SVille Syrjälä 	int preamble = 16;
14226bfc3f3SVille Syrjälä 
14326bfc3f3SVille Syrjälä 	/* HW wants the length of the extra precharge in 2us units */
14426bfc3f3SVille Syrjälä 	return (intel_dp_aux_sync_len() -
14526bfc3f3SVille Syrjälä 		precharge_min - preamble) / 2;
14626bfc3f3SVille Syrjälä }
14726bfc3f3SVille Syrjälä 
g4x_get_aux_send_ctl(struct intel_dp * intel_dp,int send_bytes,u32 aux_clock_divider)148aa850fb1SJani Nikula static u32 g4x_get_aux_send_ctl(struct intel_dp *intel_dp,
149aa850fb1SJani Nikula 				int send_bytes,
150aa850fb1SJani Nikula 				u32 aux_clock_divider)
151aa850fb1SJani Nikula {
152aa850fb1SJani Nikula 	struct intel_digital_port *dig_port = dp_to_dig_port(intel_dp);
153aa850fb1SJani Nikula 	struct drm_i915_private *dev_priv =
154aa850fb1SJani Nikula 			to_i915(dig_port->base.base.dev);
1558ec7d10aSVille Syrjälä 	u32 timeout;
156aa850fb1SJani Nikula 
157984982f3SImre Deak 	/* Max timeout value on G4x-BDW: 1.6ms */
158aa850fb1SJani Nikula 	if (IS_BROADWELL(dev_priv))
159aa850fb1SJani Nikula 		timeout = DP_AUX_CH_CTL_TIME_OUT_600us;
160aa850fb1SJani Nikula 	else
161aa850fb1SJani Nikula 		timeout = DP_AUX_CH_CTL_TIME_OUT_400us;
162aa850fb1SJani Nikula 
163aa850fb1SJani Nikula 	return DP_AUX_CH_CTL_SEND_BUSY |
164aa850fb1SJani Nikula 		DP_AUX_CH_CTL_DONE |
165aa850fb1SJani Nikula 		DP_AUX_CH_CTL_INTERRUPT |
166aa850fb1SJani Nikula 		DP_AUX_CH_CTL_TIME_OUT_ERROR |
167aa850fb1SJani Nikula 		timeout |
168aa850fb1SJani Nikula 		DP_AUX_CH_CTL_RECEIVE_ERROR |
1690cad796aSVille Syrjälä 		DP_AUX_CH_CTL_MESSAGE_SIZE(send_bytes) |
1700cad796aSVille Syrjälä 		DP_AUX_CH_CTL_PRECHARGE_2US(g4x_dp_aux_precharge_len()) |
1710cad796aSVille Syrjälä 		DP_AUX_CH_CTL_BIT_CLOCK_2X(aux_clock_divider);
172aa850fb1SJani Nikula }
173aa850fb1SJani Nikula 
skl_get_aux_send_ctl(struct intel_dp * intel_dp,int send_bytes,u32 unused)174aa850fb1SJani Nikula static u32 skl_get_aux_send_ctl(struct intel_dp *intel_dp,
175aa850fb1SJani Nikula 				int send_bytes,
176aa850fb1SJani Nikula 				u32 unused)
177aa850fb1SJani Nikula {
178aa850fb1SJani Nikula 	struct intel_digital_port *dig_port = dp_to_dig_port(intel_dp);
17940151be7SImre Deak 	struct drm_i915_private *i915 =	to_i915(dig_port->base.base.dev);
180aa850fb1SJani Nikula 	u32 ret;
181aa850fb1SJani Nikula 
182984982f3SImre Deak 	/*
183984982f3SImre Deak 	 * Max timeout values:
184984982f3SImre Deak 	 * SKL-GLK: 1.6ms
185984982f3SImre Deak 	 * ICL+: 4ms
186984982f3SImre Deak 	 */
187aa850fb1SJani Nikula 	ret = DP_AUX_CH_CTL_SEND_BUSY |
188aa850fb1SJani Nikula 		DP_AUX_CH_CTL_DONE |
189aa850fb1SJani Nikula 		DP_AUX_CH_CTL_INTERRUPT |
190aa850fb1SJani Nikula 		DP_AUX_CH_CTL_TIME_OUT_ERROR |
191aa850fb1SJani Nikula 		DP_AUX_CH_CTL_TIME_OUT_MAX |
192aa850fb1SJani Nikula 		DP_AUX_CH_CTL_RECEIVE_ERROR |
1930cad796aSVille Syrjälä 		DP_AUX_CH_CTL_MESSAGE_SIZE(send_bytes) |
19426bfc3f3SVille Syrjälä 		DP_AUX_CH_CTL_FW_SYNC_PULSE_SKL(intel_dp_aux_fw_sync_len()) |
19526bfc3f3SVille Syrjälä 		DP_AUX_CH_CTL_SYNC_PULSE_SKL(intel_dp_aux_sync_len());
196aa850fb1SJani Nikula 
19711a89708SImre Deak 	if (intel_tc_port_in_tbt_alt_mode(dig_port))
198aa850fb1SJani Nikula 		ret |= DP_AUX_CH_CTL_TBT_IO;
199aa850fb1SJani Nikula 
20040151be7SImre Deak 	/*
20140151be7SImre Deak 	 * Power request bit is already set during aux power well enable.
20240151be7SImre Deak 	 * Preserve the bit across aux transactions.
20340151be7SImre Deak 	 */
20440151be7SImre Deak 	if (DISPLAY_VER(i915) >= 14)
20540151be7SImre Deak 		ret |= XELPDP_DP_AUX_CH_CTL_POWER_REQUEST;
20640151be7SImre Deak 
207aa850fb1SJani Nikula 	return ret;
208aa850fb1SJani Nikula }
209aa850fb1SJani Nikula 
210aa850fb1SJani Nikula static int
intel_dp_aux_xfer(struct intel_dp * intel_dp,const u8 * send,int send_bytes,u8 * recv,int recv_size,u32 aux_send_ctl_flags)211aa850fb1SJani Nikula intel_dp_aux_xfer(struct intel_dp *intel_dp,
212aa850fb1SJani Nikula 		  const u8 *send, int send_bytes,
213aa850fb1SJani Nikula 		  u8 *recv, int recv_size,
214aa850fb1SJani Nikula 		  u32 aux_send_ctl_flags)
215aa850fb1SJani Nikula {
216aa850fb1SJani Nikula 	struct intel_digital_port *dig_port = dp_to_dig_port(intel_dp);
217aa850fb1SJani Nikula 	struct drm_i915_private *i915 =
218aa850fb1SJani Nikula 			to_i915(dig_port->base.base.dev);
219aa850fb1SJani Nikula 	enum phy phy = intel_port_to_phy(i915, dig_port->base.port);
220aa850fb1SJani Nikula 	bool is_tc_port = intel_phy_is_tc(i915, phy);
221aa850fb1SJani Nikula 	i915_reg_t ch_ctl, ch_data[5];
222aa850fb1SJani Nikula 	u32 aux_clock_divider;
223aa850fb1SJani Nikula 	enum intel_display_power_domain aux_domain;
224aa850fb1SJani Nikula 	intel_wakeref_t aux_wakeref;
225aa850fb1SJani Nikula 	intel_wakeref_t pps_wakeref;
226aa850fb1SJani Nikula 	int i, ret, recv_bytes;
227aa850fb1SJani Nikula 	int try, clock = 0;
228aa850fb1SJani Nikula 	u32 status;
229aa850fb1SJani Nikula 	bool vdd;
230aa850fb1SJani Nikula 
231aa850fb1SJani Nikula 	ch_ctl = intel_dp->aux_ch_ctl_reg(intel_dp);
232aa850fb1SJani Nikula 	for (i = 0; i < ARRAY_SIZE(ch_data); i++)
233aa850fb1SJani Nikula 		ch_data[i] = intel_dp->aux_ch_data_reg(intel_dp, i);
234aa850fb1SJani Nikula 
235a972cd3fSImre Deak 	if (is_tc_port) {
236aa850fb1SJani Nikula 		intel_tc_port_lock(dig_port);
237a972cd3fSImre Deak 		/*
238a972cd3fSImre Deak 		 * Abort transfers on a disconnected port as required by
239a972cd3fSImre Deak 		 * DP 1.4a link CTS 4.2.1.5, also avoiding the long AUX
240a972cd3fSImre Deak 		 * timeouts that would otherwise happen.
241a972cd3fSImre Deak 		 * TODO: abort the transfer on non-TC ports as well.
242a972cd3fSImre Deak 		 */
243a972cd3fSImre Deak 		if (!intel_tc_port_connected_locked(&dig_port->base)) {
244a972cd3fSImre Deak 			ret = -ENXIO;
245a972cd3fSImre Deak 			goto out_unlock;
246a972cd3fSImre Deak 		}
247a972cd3fSImre Deak 	}
248aa850fb1SJani Nikula 
249aa850fb1SJani Nikula 	aux_domain = intel_aux_power_domain(dig_port);
250aa850fb1SJani Nikula 
251aa850fb1SJani Nikula 	aux_wakeref = intel_display_power_get(i915, aux_domain);
252aa850fb1SJani Nikula 	pps_wakeref = intel_pps_lock(intel_dp);
253aa850fb1SJani Nikula 
254aa850fb1SJani Nikula 	/*
255aa850fb1SJani Nikula 	 * We will be called with VDD already enabled for dpcd/edid/oui reads.
256aa850fb1SJani Nikula 	 * In such cases we want to leave VDD enabled and it's up to upper layers
257aa850fb1SJani Nikula 	 * to turn it off. But for eg. i2c-dev access we need to turn it on/off
258aa850fb1SJani Nikula 	 * ourselves.
259aa850fb1SJani Nikula 	 */
260aa850fb1SJani Nikula 	vdd = intel_pps_vdd_on_unlocked(intel_dp);
261aa850fb1SJani Nikula 
262aa850fb1SJani Nikula 	/*
263aa850fb1SJani Nikula 	 * dp aux is extremely sensitive to irq latency, hence request the
264aa850fb1SJani Nikula 	 * lowest possible wakeup latency and so prevent the cpu from going into
265aa850fb1SJani Nikula 	 * deep sleep states.
266aa850fb1SJani Nikula 	 */
267aa850fb1SJani Nikula 	cpu_latency_qos_update_request(&intel_dp->pm_qos, 0);
268aa850fb1SJani Nikula 
269aa850fb1SJani Nikula 	intel_pps_check_power_unlocked(intel_dp);
270aa850fb1SJani Nikula 
271da57e3d6SVille Syrjälä 	/*
272da57e3d6SVille Syrjälä 	 * FIXME PSR should be disabled here to prevent
273da57e3d6SVille Syrjälä 	 * it using the same AUX CH simultaneously
274da57e3d6SVille Syrjälä 	 */
275da57e3d6SVille Syrjälä 
276aa850fb1SJani Nikula 	/* Try to wait for any previous AUX channel activity */
277aa850fb1SJani Nikula 	for (try = 0; try < 3; try++) {
278ec2593e3SJani Nikula 		status = intel_de_read_notrace(i915, ch_ctl);
279aa850fb1SJani Nikula 		if ((status & DP_AUX_CH_CTL_SEND_BUSY) == 0)
280aa850fb1SJani Nikula 			break;
281aa850fb1SJani Nikula 		msleep(1);
282aa850fb1SJani Nikula 	}
283aa850fb1SJani Nikula 	/* just trace the final value */
284aa850fb1SJani Nikula 	trace_i915_reg_rw(false, ch_ctl, status, sizeof(status), true);
285aa850fb1SJani Nikula 
286aa850fb1SJani Nikula 	if (try == 3) {
287ec2593e3SJani Nikula 		const u32 status = intel_de_read(i915, ch_ctl);
288aa850fb1SJani Nikula 
289aa850fb1SJani Nikula 		if (status != intel_dp->aux_busy_last_status) {
290aa850fb1SJani Nikula 			drm_WARN(&i915->drm, 1,
291aa850fb1SJani Nikula 				 "%s: not started (status 0x%08x)\n",
292aa850fb1SJani Nikula 				 intel_dp->aux.name, status);
293aa850fb1SJani Nikula 			intel_dp->aux_busy_last_status = status;
294aa850fb1SJani Nikula 		}
295aa850fb1SJani Nikula 
296aa850fb1SJani Nikula 		ret = -EBUSY;
297aa850fb1SJani Nikula 		goto out;
298aa850fb1SJani Nikula 	}
299aa850fb1SJani Nikula 
300aa850fb1SJani Nikula 	/* Only 5 data registers! */
301aa850fb1SJani Nikula 	if (drm_WARN_ON(&i915->drm, send_bytes > 20 || recv_size > 20)) {
302aa850fb1SJani Nikula 		ret = -E2BIG;
303aa850fb1SJani Nikula 		goto out;
304aa850fb1SJani Nikula 	}
305aa850fb1SJani Nikula 
306aa850fb1SJani Nikula 	while ((aux_clock_divider = intel_dp->get_aux_clock_divider(intel_dp, clock++))) {
307aa850fb1SJani Nikula 		u32 send_ctl = intel_dp->get_aux_send_ctl(intel_dp,
308aa850fb1SJani Nikula 							  send_bytes,
309aa850fb1SJani Nikula 							  aux_clock_divider);
310aa850fb1SJani Nikula 
311aa850fb1SJani Nikula 		send_ctl |= aux_send_ctl_flags;
312aa850fb1SJani Nikula 
313aa850fb1SJani Nikula 		/* Must try at least 3 times according to DP spec */
314aa850fb1SJani Nikula 		for (try = 0; try < 5; try++) {
315aa850fb1SJani Nikula 			/* Load the send data into the aux channel data registers */
316aa850fb1SJani Nikula 			for (i = 0; i < send_bytes; i += 4)
317ec2593e3SJani Nikula 				intel_de_write(i915, ch_data[i >> 2],
3182616be2eSJani Nikula 					       intel_dp_aux_pack(send + i,
319aa850fb1SJani Nikula 								 send_bytes - i));
320aa850fb1SJani Nikula 
321aa850fb1SJani Nikula 			/* Send the command and wait for it to complete */
322ec2593e3SJani Nikula 			intel_de_write(i915, ch_ctl, send_ctl);
323aa850fb1SJani Nikula 
324aa850fb1SJani Nikula 			status = intel_dp_aux_wait_done(intel_dp);
325aa850fb1SJani Nikula 
326aa850fb1SJani Nikula 			/* Clear done status and any errors */
327ec2593e3SJani Nikula 			intel_de_write(i915, ch_ctl,
328ec2593e3SJani Nikula 				       status | DP_AUX_CH_CTL_DONE |
329aa850fb1SJani Nikula 				       DP_AUX_CH_CTL_TIME_OUT_ERROR |
330aa850fb1SJani Nikula 				       DP_AUX_CH_CTL_RECEIVE_ERROR);
331aa850fb1SJani Nikula 
332aa850fb1SJani Nikula 			/*
333aa850fb1SJani Nikula 			 * DP CTS 1.2 Core Rev 1.1, 4.2.1.1 & 4.2.1.2
334aa850fb1SJani Nikula 			 *   400us delay required for errors and timeouts
335aa850fb1SJani Nikula 			 *   Timeout errors from the HW already meet this
336aa850fb1SJani Nikula 			 *   requirement so skip to next iteration
337aa850fb1SJani Nikula 			 */
338aa850fb1SJani Nikula 			if (status & DP_AUX_CH_CTL_TIME_OUT_ERROR)
339aa850fb1SJani Nikula 				continue;
340aa850fb1SJani Nikula 
341aa850fb1SJani Nikula 			if (status & DP_AUX_CH_CTL_RECEIVE_ERROR) {
342aa850fb1SJani Nikula 				usleep_range(400, 500);
343aa850fb1SJani Nikula 				continue;
344aa850fb1SJani Nikula 			}
345aa850fb1SJani Nikula 			if (status & DP_AUX_CH_CTL_DONE)
346aa850fb1SJani Nikula 				goto done;
347aa850fb1SJani Nikula 		}
348aa850fb1SJani Nikula 	}
349aa850fb1SJani Nikula 
350aa850fb1SJani Nikula 	if ((status & DP_AUX_CH_CTL_DONE) == 0) {
351aa850fb1SJani Nikula 		drm_err(&i915->drm, "%s: not done (status 0x%08x)\n",
352aa850fb1SJani Nikula 			intel_dp->aux.name, status);
353aa850fb1SJani Nikula 		ret = -EBUSY;
354aa850fb1SJani Nikula 		goto out;
355aa850fb1SJani Nikula 	}
356aa850fb1SJani Nikula 
357aa850fb1SJani Nikula done:
358aa850fb1SJani Nikula 	/*
359aa850fb1SJani Nikula 	 * Check for timeout or receive error. Timeouts occur when the sink is
360aa850fb1SJani Nikula 	 * not connected.
361aa850fb1SJani Nikula 	 */
362aa850fb1SJani Nikula 	if (status & DP_AUX_CH_CTL_RECEIVE_ERROR) {
363aa850fb1SJani Nikula 		drm_err(&i915->drm, "%s: receive error (status 0x%08x)\n",
364aa850fb1SJani Nikula 			intel_dp->aux.name, status);
365aa850fb1SJani Nikula 		ret = -EIO;
366aa850fb1SJani Nikula 		goto out;
367aa850fb1SJani Nikula 	}
368aa850fb1SJani Nikula 
369aa850fb1SJani Nikula 	/*
370aa850fb1SJani Nikula 	 * Timeouts occur when the device isn't connected, so they're "normal"
371aa850fb1SJani Nikula 	 * -- don't fill the kernel log with these
372aa850fb1SJani Nikula 	 */
373aa850fb1SJani Nikula 	if (status & DP_AUX_CH_CTL_TIME_OUT_ERROR) {
374aa850fb1SJani Nikula 		drm_dbg_kms(&i915->drm, "%s: timeout (status 0x%08x)\n",
375aa850fb1SJani Nikula 			    intel_dp->aux.name, status);
376aa850fb1SJani Nikula 		ret = -ETIMEDOUT;
377aa850fb1SJani Nikula 		goto out;
378aa850fb1SJani Nikula 	}
379aa850fb1SJani Nikula 
380aa850fb1SJani Nikula 	/* Unload any bytes sent back from the other side */
3810cad796aSVille Syrjälä 	recv_bytes = REG_FIELD_GET(DP_AUX_CH_CTL_MESSAGE_SIZE_MASK, status);
382aa850fb1SJani Nikula 
383aa850fb1SJani Nikula 	/*
384aa850fb1SJani Nikula 	 * By BSpec: "Message sizes of 0 or >20 are not allowed."
385aa850fb1SJani Nikula 	 * We have no idea of what happened so we return -EBUSY so
386aa850fb1SJani Nikula 	 * drm layer takes care for the necessary retries.
387aa850fb1SJani Nikula 	 */
388aa850fb1SJani Nikula 	if (recv_bytes == 0 || recv_bytes > 20) {
389aa850fb1SJani Nikula 		drm_dbg_kms(&i915->drm,
390aa850fb1SJani Nikula 			    "%s: Forbidden recv_bytes = %d on aux transaction\n",
391aa850fb1SJani Nikula 			    intel_dp->aux.name, recv_bytes);
392aa850fb1SJani Nikula 		ret = -EBUSY;
393aa850fb1SJani Nikula 		goto out;
394aa850fb1SJani Nikula 	}
395aa850fb1SJani Nikula 
396aa850fb1SJani Nikula 	if (recv_bytes > recv_size)
397aa850fb1SJani Nikula 		recv_bytes = recv_size;
398aa850fb1SJani Nikula 
399aa850fb1SJani Nikula 	for (i = 0; i < recv_bytes; i += 4)
400ec2593e3SJani Nikula 		intel_dp_aux_unpack(intel_de_read(i915, ch_data[i >> 2]),
401aa850fb1SJani Nikula 				    recv + i, recv_bytes - i);
402aa850fb1SJani Nikula 
403aa850fb1SJani Nikula 	ret = recv_bytes;
404aa850fb1SJani Nikula out:
405aa850fb1SJani Nikula 	cpu_latency_qos_update_request(&intel_dp->pm_qos, PM_QOS_DEFAULT_VALUE);
406aa850fb1SJani Nikula 
407aa850fb1SJani Nikula 	if (vdd)
408aa850fb1SJani Nikula 		intel_pps_vdd_off_unlocked(intel_dp, false);
409aa850fb1SJani Nikula 
410aa850fb1SJani Nikula 	intel_pps_unlock(intel_dp, pps_wakeref);
411aa850fb1SJani Nikula 	intel_display_power_put_async(i915, aux_domain, aux_wakeref);
412a972cd3fSImre Deak out_unlock:
413aa850fb1SJani Nikula 	if (is_tc_port)
414aa850fb1SJani Nikula 		intel_tc_port_unlock(dig_port);
415aa850fb1SJani Nikula 
416aa850fb1SJani Nikula 	return ret;
417aa850fb1SJani Nikula }
418aa850fb1SJani Nikula 
419aa850fb1SJani Nikula #define BARE_ADDRESS_SIZE	3
420aa850fb1SJani Nikula #define HEADER_SIZE		(BARE_ADDRESS_SIZE + 1)
421aa850fb1SJani Nikula 
422aa850fb1SJani Nikula static void
intel_dp_aux_header(u8 txbuf[HEADER_SIZE],const struct drm_dp_aux_msg * msg)423aa850fb1SJani Nikula intel_dp_aux_header(u8 txbuf[HEADER_SIZE],
424aa850fb1SJani Nikula 		    const struct drm_dp_aux_msg *msg)
425aa850fb1SJani Nikula {
426aa850fb1SJani Nikula 	txbuf[0] = (msg->request << 4) | ((msg->address >> 16) & 0xf);
427aa850fb1SJani Nikula 	txbuf[1] = (msg->address >> 8) & 0xff;
428aa850fb1SJani Nikula 	txbuf[2] = msg->address & 0xff;
429aa850fb1SJani Nikula 	txbuf[3] = msg->size - 1;
430aa850fb1SJani Nikula }
431aa850fb1SJani Nikula 
intel_dp_aux_xfer_flags(const struct drm_dp_aux_msg * msg)432aa850fb1SJani Nikula static u32 intel_dp_aux_xfer_flags(const struct drm_dp_aux_msg *msg)
433aa850fb1SJani Nikula {
434aa850fb1SJani Nikula 	/*
435aa850fb1SJani Nikula 	 * If we're trying to send the HDCP Aksv, we need to set a the Aksv
436aa850fb1SJani Nikula 	 * select bit to inform the hardware to send the Aksv after our header
437aa850fb1SJani Nikula 	 * since we can't access that data from software.
438aa850fb1SJani Nikula 	 */
439aa850fb1SJani Nikula 	if ((msg->request & ~DP_AUX_I2C_MOT) == DP_AUX_NATIVE_WRITE &&
440aa850fb1SJani Nikula 	    msg->address == DP_AUX_HDCP_AKSV)
441aa850fb1SJani Nikula 		return DP_AUX_CH_CTL_AUX_AKSV_SELECT;
442aa850fb1SJani Nikula 
443aa850fb1SJani Nikula 	return 0;
444aa850fb1SJani Nikula }
445aa850fb1SJani Nikula 
446aa850fb1SJani Nikula static ssize_t
intel_dp_aux_transfer(struct drm_dp_aux * aux,struct drm_dp_aux_msg * msg)447aa850fb1SJani Nikula intel_dp_aux_transfer(struct drm_dp_aux *aux, struct drm_dp_aux_msg *msg)
448aa850fb1SJani Nikula {
449aa850fb1SJani Nikula 	struct intel_dp *intel_dp = container_of(aux, struct intel_dp, aux);
450aa850fb1SJani Nikula 	struct drm_i915_private *i915 = dp_to_i915(intel_dp);
451aa850fb1SJani Nikula 	u8 txbuf[20], rxbuf[20];
452aa850fb1SJani Nikula 	size_t txsize, rxsize;
453aa850fb1SJani Nikula 	u32 flags = intel_dp_aux_xfer_flags(msg);
454aa850fb1SJani Nikula 	int ret;
455aa850fb1SJani Nikula 
456aa850fb1SJani Nikula 	intel_dp_aux_header(txbuf, msg);
457aa850fb1SJani Nikula 
458aa850fb1SJani Nikula 	switch (msg->request & ~DP_AUX_I2C_MOT) {
459aa850fb1SJani Nikula 	case DP_AUX_NATIVE_WRITE:
460aa850fb1SJani Nikula 	case DP_AUX_I2C_WRITE:
461aa850fb1SJani Nikula 	case DP_AUX_I2C_WRITE_STATUS_UPDATE:
462aa850fb1SJani Nikula 		txsize = msg->size ? HEADER_SIZE + msg->size : BARE_ADDRESS_SIZE;
463aa850fb1SJani Nikula 		rxsize = 2; /* 0 or 1 data bytes */
464aa850fb1SJani Nikula 
465aa850fb1SJani Nikula 		if (drm_WARN_ON(&i915->drm, txsize > 20))
466aa850fb1SJani Nikula 			return -E2BIG;
467aa850fb1SJani Nikula 
468aa850fb1SJani Nikula 		drm_WARN_ON(&i915->drm, !msg->buffer != !msg->size);
469aa850fb1SJani Nikula 
470aa850fb1SJani Nikula 		if (msg->buffer)
471aa850fb1SJani Nikula 			memcpy(txbuf + HEADER_SIZE, msg->buffer, msg->size);
472aa850fb1SJani Nikula 
473aa850fb1SJani Nikula 		ret = intel_dp_aux_xfer(intel_dp, txbuf, txsize,
474aa850fb1SJani Nikula 					rxbuf, rxsize, flags);
475aa850fb1SJani Nikula 		if (ret > 0) {
476aa850fb1SJani Nikula 			msg->reply = rxbuf[0] >> 4;
477aa850fb1SJani Nikula 
478aa850fb1SJani Nikula 			if (ret > 1) {
479aa850fb1SJani Nikula 				/* Number of bytes written in a short write. */
480aa850fb1SJani Nikula 				ret = clamp_t(int, rxbuf[1], 0, msg->size);
481aa850fb1SJani Nikula 			} else {
482aa850fb1SJani Nikula 				/* Return payload size. */
483aa850fb1SJani Nikula 				ret = msg->size;
484aa850fb1SJani Nikula 			}
485aa850fb1SJani Nikula 		}
486aa850fb1SJani Nikula 		break;
487aa850fb1SJani Nikula 
488aa850fb1SJani Nikula 	case DP_AUX_NATIVE_READ:
489aa850fb1SJani Nikula 	case DP_AUX_I2C_READ:
490aa850fb1SJani Nikula 		txsize = msg->size ? HEADER_SIZE : BARE_ADDRESS_SIZE;
491aa850fb1SJani Nikula 		rxsize = msg->size + 1;
492aa850fb1SJani Nikula 
493aa850fb1SJani Nikula 		if (drm_WARN_ON(&i915->drm, rxsize > 20))
494aa850fb1SJani Nikula 			return -E2BIG;
495aa850fb1SJani Nikula 
496aa850fb1SJani Nikula 		ret = intel_dp_aux_xfer(intel_dp, txbuf, txsize,
497aa850fb1SJani Nikula 					rxbuf, rxsize, flags);
498aa850fb1SJani Nikula 		if (ret > 0) {
499aa850fb1SJani Nikula 			msg->reply = rxbuf[0] >> 4;
500aa850fb1SJani Nikula 			/*
501aa850fb1SJani Nikula 			 * Assume happy day, and copy the data. The caller is
502aa850fb1SJani Nikula 			 * expected to check msg->reply before touching it.
503aa850fb1SJani Nikula 			 *
504aa850fb1SJani Nikula 			 * Return payload size.
505aa850fb1SJani Nikula 			 */
506aa850fb1SJani Nikula 			ret--;
507aa850fb1SJani Nikula 			memcpy(msg->buffer, rxbuf + 1, ret);
508aa850fb1SJani Nikula 		}
509aa850fb1SJani Nikula 		break;
510aa850fb1SJani Nikula 
511aa850fb1SJani Nikula 	default:
512aa850fb1SJani Nikula 		ret = -EINVAL;
513aa850fb1SJani Nikula 		break;
514aa850fb1SJani Nikula 	}
515aa850fb1SJani Nikula 
516aa850fb1SJani Nikula 	return ret;
517aa850fb1SJani Nikula }
518aa850fb1SJani Nikula 
g4x_aux_ctl_reg(struct intel_dp * intel_dp)519aa850fb1SJani Nikula static i915_reg_t g4x_aux_ctl_reg(struct intel_dp *intel_dp)
520aa850fb1SJani Nikula {
521aa850fb1SJani Nikula 	struct drm_i915_private *dev_priv = dp_to_i915(intel_dp);
522aa850fb1SJani Nikula 	struct intel_digital_port *dig_port = dp_to_dig_port(intel_dp);
523aa850fb1SJani Nikula 	enum aux_ch aux_ch = dig_port->aux_ch;
524aa850fb1SJani Nikula 
525aa850fb1SJani Nikula 	switch (aux_ch) {
526aa850fb1SJani Nikula 	case AUX_CH_B:
527aa850fb1SJani Nikula 	case AUX_CH_C:
528aa850fb1SJani Nikula 	case AUX_CH_D:
529aa850fb1SJani Nikula 		return DP_AUX_CH_CTL(aux_ch);
530aa850fb1SJani Nikula 	default:
531aa850fb1SJani Nikula 		MISSING_CASE(aux_ch);
532aa850fb1SJani Nikula 		return DP_AUX_CH_CTL(AUX_CH_B);
533aa850fb1SJani Nikula 	}
534aa850fb1SJani Nikula }
535aa850fb1SJani Nikula 
g4x_aux_data_reg(struct intel_dp * intel_dp,int index)536aa850fb1SJani Nikula static i915_reg_t g4x_aux_data_reg(struct intel_dp *intel_dp, int index)
537aa850fb1SJani Nikula {
538aa850fb1SJani Nikula 	struct drm_i915_private *dev_priv = dp_to_i915(intel_dp);
539aa850fb1SJani Nikula 	struct intel_digital_port *dig_port = dp_to_dig_port(intel_dp);
540aa850fb1SJani Nikula 	enum aux_ch aux_ch = dig_port->aux_ch;
541aa850fb1SJani Nikula 
542aa850fb1SJani Nikula 	switch (aux_ch) {
543aa850fb1SJani Nikula 	case AUX_CH_B:
544aa850fb1SJani Nikula 	case AUX_CH_C:
545aa850fb1SJani Nikula 	case AUX_CH_D:
546aa850fb1SJani Nikula 		return DP_AUX_CH_DATA(aux_ch, index);
547aa850fb1SJani Nikula 	default:
548aa850fb1SJani Nikula 		MISSING_CASE(aux_ch);
549aa850fb1SJani Nikula 		return DP_AUX_CH_DATA(AUX_CH_B, index);
550aa850fb1SJani Nikula 	}
551aa850fb1SJani Nikula }
552aa850fb1SJani Nikula 
ilk_aux_ctl_reg(struct intel_dp * intel_dp)553aa850fb1SJani Nikula static i915_reg_t ilk_aux_ctl_reg(struct intel_dp *intel_dp)
554aa850fb1SJani Nikula {
555aa850fb1SJani Nikula 	struct drm_i915_private *dev_priv = dp_to_i915(intel_dp);
556aa850fb1SJani Nikula 	struct intel_digital_port *dig_port = dp_to_dig_port(intel_dp);
557aa850fb1SJani Nikula 	enum aux_ch aux_ch = dig_port->aux_ch;
558aa850fb1SJani Nikula 
559aa850fb1SJani Nikula 	switch (aux_ch) {
560aa850fb1SJani Nikula 	case AUX_CH_A:
561aa850fb1SJani Nikula 		return DP_AUX_CH_CTL(aux_ch);
562aa850fb1SJani Nikula 	case AUX_CH_B:
563aa850fb1SJani Nikula 	case AUX_CH_C:
564aa850fb1SJani Nikula 	case AUX_CH_D:
565aa850fb1SJani Nikula 		return PCH_DP_AUX_CH_CTL(aux_ch);
566aa850fb1SJani Nikula 	default:
567aa850fb1SJani Nikula 		MISSING_CASE(aux_ch);
568aa850fb1SJani Nikula 		return DP_AUX_CH_CTL(AUX_CH_A);
569aa850fb1SJani Nikula 	}
570aa850fb1SJani Nikula }
571aa850fb1SJani Nikula 
ilk_aux_data_reg(struct intel_dp * intel_dp,int index)572aa850fb1SJani Nikula static i915_reg_t ilk_aux_data_reg(struct intel_dp *intel_dp, int index)
573aa850fb1SJani Nikula {
574aa850fb1SJani Nikula 	struct drm_i915_private *dev_priv = dp_to_i915(intel_dp);
575aa850fb1SJani Nikula 	struct intel_digital_port *dig_port = dp_to_dig_port(intel_dp);
576aa850fb1SJani Nikula 	enum aux_ch aux_ch = dig_port->aux_ch;
577aa850fb1SJani Nikula 
578aa850fb1SJani Nikula 	switch (aux_ch) {
579aa850fb1SJani Nikula 	case AUX_CH_A:
580aa850fb1SJani Nikula 		return DP_AUX_CH_DATA(aux_ch, index);
581aa850fb1SJani Nikula 	case AUX_CH_B:
582aa850fb1SJani Nikula 	case AUX_CH_C:
583aa850fb1SJani Nikula 	case AUX_CH_D:
584aa850fb1SJani Nikula 		return PCH_DP_AUX_CH_DATA(aux_ch, index);
585aa850fb1SJani Nikula 	default:
586aa850fb1SJani Nikula 		MISSING_CASE(aux_ch);
587aa850fb1SJani Nikula 		return DP_AUX_CH_DATA(AUX_CH_A, index);
588aa850fb1SJani Nikula 	}
589aa850fb1SJani Nikula }
590aa850fb1SJani Nikula 
skl_aux_ctl_reg(struct intel_dp * intel_dp)591aa850fb1SJani Nikula static i915_reg_t skl_aux_ctl_reg(struct intel_dp *intel_dp)
592aa850fb1SJani Nikula {
593aa850fb1SJani Nikula 	struct drm_i915_private *dev_priv = dp_to_i915(intel_dp);
594aa850fb1SJani Nikula 	struct intel_digital_port *dig_port = dp_to_dig_port(intel_dp);
595aa850fb1SJani Nikula 	enum aux_ch aux_ch = dig_port->aux_ch;
596aa850fb1SJani Nikula 
597aa850fb1SJani Nikula 	switch (aux_ch) {
598aa850fb1SJani Nikula 	case AUX_CH_A:
599aa850fb1SJani Nikula 	case AUX_CH_B:
600aa850fb1SJani Nikula 	case AUX_CH_C:
601aa850fb1SJani Nikula 	case AUX_CH_D:
602aa850fb1SJani Nikula 	case AUX_CH_E:
603aa850fb1SJani Nikula 	case AUX_CH_F:
604aa850fb1SJani Nikula 		return DP_AUX_CH_CTL(aux_ch);
605aa850fb1SJani Nikula 	default:
606aa850fb1SJani Nikula 		MISSING_CASE(aux_ch);
607aa850fb1SJani Nikula 		return DP_AUX_CH_CTL(AUX_CH_A);
608aa850fb1SJani Nikula 	}
609aa850fb1SJani Nikula }
610aa850fb1SJani Nikula 
skl_aux_data_reg(struct intel_dp * intel_dp,int index)611aa850fb1SJani Nikula static i915_reg_t skl_aux_data_reg(struct intel_dp *intel_dp, int index)
612aa850fb1SJani Nikula {
613aa850fb1SJani Nikula 	struct drm_i915_private *dev_priv = dp_to_i915(intel_dp);
614aa850fb1SJani Nikula 	struct intel_digital_port *dig_port = dp_to_dig_port(intel_dp);
615aa850fb1SJani Nikula 	enum aux_ch aux_ch = dig_port->aux_ch;
616aa850fb1SJani Nikula 
617aa850fb1SJani Nikula 	switch (aux_ch) {
618aa850fb1SJani Nikula 	case AUX_CH_A:
619aa850fb1SJani Nikula 	case AUX_CH_B:
620aa850fb1SJani Nikula 	case AUX_CH_C:
621aa850fb1SJani Nikula 	case AUX_CH_D:
622aa850fb1SJani Nikula 	case AUX_CH_E:
623aa850fb1SJani Nikula 	case AUX_CH_F:
624aa850fb1SJani Nikula 		return DP_AUX_CH_DATA(aux_ch, index);
625aa850fb1SJani Nikula 	default:
626aa850fb1SJani Nikula 		MISSING_CASE(aux_ch);
627aa850fb1SJani Nikula 		return DP_AUX_CH_DATA(AUX_CH_A, index);
628aa850fb1SJani Nikula 	}
629aa850fb1SJani Nikula }
630aa850fb1SJani Nikula 
tgl_aux_ctl_reg(struct intel_dp * intel_dp)631aa850fb1SJani Nikula static i915_reg_t tgl_aux_ctl_reg(struct intel_dp *intel_dp)
632aa850fb1SJani Nikula {
633aa850fb1SJani Nikula 	struct drm_i915_private *dev_priv = dp_to_i915(intel_dp);
634aa850fb1SJani Nikula 	struct intel_digital_port *dig_port = dp_to_dig_port(intel_dp);
635aa850fb1SJani Nikula 	enum aux_ch aux_ch = dig_port->aux_ch;
636aa850fb1SJani Nikula 
637aa850fb1SJani Nikula 	switch (aux_ch) {
638aa850fb1SJani Nikula 	case AUX_CH_A:
639aa850fb1SJani Nikula 	case AUX_CH_B:
640aa850fb1SJani Nikula 	case AUX_CH_C:
641aa850fb1SJani Nikula 	case AUX_CH_USBC1:
642aa850fb1SJani Nikula 	case AUX_CH_USBC2:
643aa850fb1SJani Nikula 	case AUX_CH_USBC3:
644aa850fb1SJani Nikula 	case AUX_CH_USBC4:
645ed2615a8SMatt Roper 	case AUX_CH_USBC5:  /* aka AUX_CH_D_XELPD */
646ed2615a8SMatt Roper 	case AUX_CH_USBC6:  /* aka AUX_CH_E_XELPD */
647aa850fb1SJani Nikula 		return DP_AUX_CH_CTL(aux_ch);
648aa850fb1SJani Nikula 	default:
649aa850fb1SJani Nikula 		MISSING_CASE(aux_ch);
650aa850fb1SJani Nikula 		return DP_AUX_CH_CTL(AUX_CH_A);
651aa850fb1SJani Nikula 	}
652aa850fb1SJani Nikula }
653aa850fb1SJani Nikula 
tgl_aux_data_reg(struct intel_dp * intel_dp,int index)654aa850fb1SJani Nikula static i915_reg_t tgl_aux_data_reg(struct intel_dp *intel_dp, int index)
655aa850fb1SJani Nikula {
656aa850fb1SJani Nikula 	struct drm_i915_private *dev_priv = dp_to_i915(intel_dp);
657aa850fb1SJani Nikula 	struct intel_digital_port *dig_port = dp_to_dig_port(intel_dp);
658aa850fb1SJani Nikula 	enum aux_ch aux_ch = dig_port->aux_ch;
659aa850fb1SJani Nikula 
660aa850fb1SJani Nikula 	switch (aux_ch) {
661aa850fb1SJani Nikula 	case AUX_CH_A:
662aa850fb1SJani Nikula 	case AUX_CH_B:
663aa850fb1SJani Nikula 	case AUX_CH_C:
664aa850fb1SJani Nikula 	case AUX_CH_USBC1:
665aa850fb1SJani Nikula 	case AUX_CH_USBC2:
666aa850fb1SJani Nikula 	case AUX_CH_USBC3:
667aa850fb1SJani Nikula 	case AUX_CH_USBC4:
668ed2615a8SMatt Roper 	case AUX_CH_USBC5:  /* aka AUX_CH_D_XELPD */
669ed2615a8SMatt Roper 	case AUX_CH_USBC6:  /* aka AUX_CH_E_XELPD */
670aa850fb1SJani Nikula 		return DP_AUX_CH_DATA(aux_ch, index);
671aa850fb1SJani Nikula 	default:
672aa850fb1SJani Nikula 		MISSING_CASE(aux_ch);
673aa850fb1SJani Nikula 		return DP_AUX_CH_DATA(AUX_CH_A, index);
674aa850fb1SJani Nikula 	}
675aa850fb1SJani Nikula }
676aa850fb1SJani Nikula 
xelpdp_aux_ctl_reg(struct intel_dp * intel_dp)67785d53200SImre Deak static i915_reg_t xelpdp_aux_ctl_reg(struct intel_dp *intel_dp)
67885d53200SImre Deak {
67985d53200SImre Deak 	struct drm_i915_private *dev_priv = dp_to_i915(intel_dp);
68085d53200SImre Deak 	struct intel_digital_port *dig_port = dp_to_dig_port(intel_dp);
68185d53200SImre Deak 	enum aux_ch aux_ch = dig_port->aux_ch;
68285d53200SImre Deak 
68385d53200SImre Deak 	switch (aux_ch) {
68485d53200SImre Deak 	case AUX_CH_A:
68585d53200SImre Deak 	case AUX_CH_B:
68685d53200SImre Deak 	case AUX_CH_USBC1:
68785d53200SImre Deak 	case AUX_CH_USBC2:
68885d53200SImre Deak 	case AUX_CH_USBC3:
68985d53200SImre Deak 	case AUX_CH_USBC4:
69085d53200SImre Deak 		return XELPDP_DP_AUX_CH_CTL(aux_ch);
69185d53200SImre Deak 	default:
69285d53200SImre Deak 		MISSING_CASE(aux_ch);
69385d53200SImre Deak 		return XELPDP_DP_AUX_CH_CTL(AUX_CH_A);
69485d53200SImre Deak 	}
69585d53200SImre Deak }
69685d53200SImre Deak 
xelpdp_aux_data_reg(struct intel_dp * intel_dp,int index)69785d53200SImre Deak static i915_reg_t xelpdp_aux_data_reg(struct intel_dp *intel_dp, int index)
69885d53200SImre Deak {
69985d53200SImre Deak 	struct drm_i915_private *dev_priv = dp_to_i915(intel_dp);
70085d53200SImre Deak 	struct intel_digital_port *dig_port = dp_to_dig_port(intel_dp);
70185d53200SImre Deak 	enum aux_ch aux_ch = dig_port->aux_ch;
70285d53200SImre Deak 
70385d53200SImre Deak 	switch (aux_ch) {
70485d53200SImre Deak 	case AUX_CH_A:
70585d53200SImre Deak 	case AUX_CH_B:
70685d53200SImre Deak 	case AUX_CH_USBC1:
70785d53200SImre Deak 	case AUX_CH_USBC2:
70885d53200SImre Deak 	case AUX_CH_USBC3:
70985d53200SImre Deak 	case AUX_CH_USBC4:
71085d53200SImre Deak 		return XELPDP_DP_AUX_CH_DATA(aux_ch, index);
71185d53200SImre Deak 	default:
71285d53200SImre Deak 		MISSING_CASE(aux_ch);
71385d53200SImre Deak 		return XELPDP_DP_AUX_CH_DATA(AUX_CH_A, index);
71485d53200SImre Deak 	}
71585d53200SImre Deak }
71685d53200SImre Deak 
intel_dp_aux_fini(struct intel_dp * intel_dp)717aa850fb1SJani Nikula void intel_dp_aux_fini(struct intel_dp *intel_dp)
718aa850fb1SJani Nikula {
719aa850fb1SJani Nikula 	if (cpu_latency_qos_request_active(&intel_dp->pm_qos))
720aa850fb1SJani Nikula 		cpu_latency_qos_remove_request(&intel_dp->pm_qos);
721aa850fb1SJani Nikula 
722aa850fb1SJani Nikula 	kfree(intel_dp->aux.name);
723aa850fb1SJani Nikula }
724aa850fb1SJani Nikula 
intel_dp_aux_init(struct intel_dp * intel_dp)725aa850fb1SJani Nikula void intel_dp_aux_init(struct intel_dp *intel_dp)
726aa850fb1SJani Nikula {
727aa850fb1SJani Nikula 	struct drm_i915_private *dev_priv = dp_to_i915(intel_dp);
728aa850fb1SJani Nikula 	struct intel_digital_port *dig_port = dp_to_dig_port(intel_dp);
729aa850fb1SJani Nikula 	struct intel_encoder *encoder = &dig_port->base;
730aa850fb1SJani Nikula 	enum aux_ch aux_ch = dig_port->aux_ch;
731aa850fb1SJani Nikula 
73285d53200SImre Deak 	if (DISPLAY_VER(dev_priv) >= 14) {
73385d53200SImre Deak 		intel_dp->aux_ch_ctl_reg = xelpdp_aux_ctl_reg;
73485d53200SImre Deak 		intel_dp->aux_ch_data_reg = xelpdp_aux_data_reg;
73585d53200SImre Deak 	} else if (DISPLAY_VER(dev_priv) >= 12) {
736aa850fb1SJani Nikula 		intel_dp->aux_ch_ctl_reg = tgl_aux_ctl_reg;
737aa850fb1SJani Nikula 		intel_dp->aux_ch_data_reg = tgl_aux_data_reg;
738005e9537SMatt Roper 	} else if (DISPLAY_VER(dev_priv) >= 9) {
739aa850fb1SJani Nikula 		intel_dp->aux_ch_ctl_reg = skl_aux_ctl_reg;
740aa850fb1SJani Nikula 		intel_dp->aux_ch_data_reg = skl_aux_data_reg;
741aa850fb1SJani Nikula 	} else if (HAS_PCH_SPLIT(dev_priv)) {
742aa850fb1SJani Nikula 		intel_dp->aux_ch_ctl_reg = ilk_aux_ctl_reg;
743aa850fb1SJani Nikula 		intel_dp->aux_ch_data_reg = ilk_aux_data_reg;
744aa850fb1SJani Nikula 	} else {
745aa850fb1SJani Nikula 		intel_dp->aux_ch_ctl_reg = g4x_aux_ctl_reg;
746aa850fb1SJani Nikula 		intel_dp->aux_ch_data_reg = g4x_aux_data_reg;
747aa850fb1SJani Nikula 	}
748aa850fb1SJani Nikula 
749005e9537SMatt Roper 	if (DISPLAY_VER(dev_priv) >= 9)
750aa850fb1SJani Nikula 		intel_dp->get_aux_clock_divider = skl_get_aux_clock_divider;
751aa850fb1SJani Nikula 	else if (IS_BROADWELL(dev_priv) || IS_HASWELL(dev_priv))
752aa850fb1SJani Nikula 		intel_dp->get_aux_clock_divider = hsw_get_aux_clock_divider;
753aa850fb1SJani Nikula 	else if (HAS_PCH_SPLIT(dev_priv))
754aa850fb1SJani Nikula 		intel_dp->get_aux_clock_divider = ilk_get_aux_clock_divider;
755aa850fb1SJani Nikula 	else
756aa850fb1SJani Nikula 		intel_dp->get_aux_clock_divider = g4x_get_aux_clock_divider;
757aa850fb1SJani Nikula 
758005e9537SMatt Roper 	if (DISPLAY_VER(dev_priv) >= 9)
759aa850fb1SJani Nikula 		intel_dp->get_aux_send_ctl = skl_get_aux_send_ctl;
760aa850fb1SJani Nikula 	else
761aa850fb1SJani Nikula 		intel_dp->get_aux_send_ctl = g4x_get_aux_send_ctl;
762aa850fb1SJani Nikula 
7636cba3fe4SLyude Paul 	intel_dp->aux.drm_dev = &dev_priv->drm;
764aa850fb1SJani Nikula 	drm_dp_aux_init(&intel_dp->aux);
765aa850fb1SJani Nikula 
766aa850fb1SJani Nikula 	/* Failure to allocate our preferred name is not critical */
767ed2615a8SMatt Roper 	if (DISPLAY_VER(dev_priv) >= 13 && aux_ch >= AUX_CH_D_XELPD)
768ed2615a8SMatt Roper 		intel_dp->aux.name = kasprintf(GFP_KERNEL, "AUX %c/%s",
769ed2615a8SMatt Roper 					       aux_ch_name(aux_ch - AUX_CH_D_XELPD + AUX_CH_D),
770ed2615a8SMatt Roper 					       encoder->base.name);
771ed2615a8SMatt Roper 	else if (DISPLAY_VER(dev_priv) >= 12 && aux_ch >= AUX_CH_USBC1)
772aa850fb1SJani Nikula 		intel_dp->aux.name = kasprintf(GFP_KERNEL, "AUX USBC%c/%s",
773aa850fb1SJani Nikula 					       aux_ch - AUX_CH_USBC1 + '1',
774aa850fb1SJani Nikula 					       encoder->base.name);
775aa850fb1SJani Nikula 	else
776aa850fb1SJani Nikula 		intel_dp->aux.name = kasprintf(GFP_KERNEL, "AUX %c/%s",
777aa850fb1SJani Nikula 					       aux_ch_name(aux_ch),
778aa850fb1SJani Nikula 					       encoder->base.name);
779aa850fb1SJani Nikula 
780aa850fb1SJani Nikula 	intel_dp->aux.transfer = intel_dp_aux_transfer;
781aa850fb1SJani Nikula 	cpu_latency_qos_add_request(&intel_dp->pm_qos, PM_QOS_DEFAULT_VALUE);
782aa850fb1SJani Nikula }
783bb45217fSVille Syrjälä 
default_aux_ch(struct intel_encoder * encoder)78401a789faSVille Syrjälä static enum aux_ch default_aux_ch(struct intel_encoder *encoder)
78501a789faSVille Syrjälä {
78601a789faSVille Syrjälä 	struct drm_i915_private *i915 = to_i915(encoder->base.dev);
78701a789faSVille Syrjälä 
78801a789faSVille Syrjälä 	/* SKL has DDI E but no AUX E */
78901a789faSVille Syrjälä 	if (DISPLAY_VER(i915) == 9 && encoder->port == PORT_E)
79001a789faSVille Syrjälä 		return AUX_CH_A;
79101a789faSVille Syrjälä 
79201a789faSVille Syrjälä 	return (enum aux_ch)encoder->port;
79301a789faSVille Syrjälä }
79401a789faSVille Syrjälä 
795*b8a13e87SVille Syrjälä static struct intel_encoder *
get_encoder_by_aux_ch(struct intel_encoder * encoder,enum aux_ch aux_ch)796*b8a13e87SVille Syrjälä get_encoder_by_aux_ch(struct intel_encoder *encoder,
797*b8a13e87SVille Syrjälä 		      enum aux_ch aux_ch)
798*b8a13e87SVille Syrjälä {
799*b8a13e87SVille Syrjälä 	struct drm_i915_private *i915 = to_i915(encoder->base.dev);
800*b8a13e87SVille Syrjälä 	struct intel_encoder *other;
801*b8a13e87SVille Syrjälä 
802*b8a13e87SVille Syrjälä 	for_each_intel_encoder(&i915->drm, other) {
803*b8a13e87SVille Syrjälä 		if (other == encoder)
804*b8a13e87SVille Syrjälä 			continue;
805*b8a13e87SVille Syrjälä 
806*b8a13e87SVille Syrjälä 		if (!intel_encoder_is_dig_port(other))
807*b8a13e87SVille Syrjälä 			continue;
808*b8a13e87SVille Syrjälä 
809*b8a13e87SVille Syrjälä 		if (enc_to_dig_port(other)->aux_ch == aux_ch)
810*b8a13e87SVille Syrjälä 			return other;
811*b8a13e87SVille Syrjälä 	}
812*b8a13e87SVille Syrjälä 
813*b8a13e87SVille Syrjälä 	return NULL;
814*b8a13e87SVille Syrjälä }
815*b8a13e87SVille Syrjälä 
intel_dp_aux_ch(struct intel_encoder * encoder)816bb45217fSVille Syrjälä enum aux_ch intel_dp_aux_ch(struct intel_encoder *encoder)
817bb45217fSVille Syrjälä {
818bb45217fSVille Syrjälä 	struct drm_i915_private *i915 = to_i915(encoder->base.dev);
819*b8a13e87SVille Syrjälä 	struct intel_encoder *other;
820*b8a13e87SVille Syrjälä 	const char *source;
821bb45217fSVille Syrjälä 	enum aux_ch aux_ch;
822bb45217fSVille Syrjälä 
823bb45217fSVille Syrjälä 	aux_ch = intel_bios_dp_aux_ch(encoder->devdata);
824*b8a13e87SVille Syrjälä 	source = "VBT";
825*b8a13e87SVille Syrjälä 
826*b8a13e87SVille Syrjälä 	if (aux_ch == AUX_CH_NONE) {
827*b8a13e87SVille Syrjälä 		aux_ch = default_aux_ch(encoder);
828*b8a13e87SVille Syrjälä 		source = "platform default";
829bb45217fSVille Syrjälä 	}
830bb45217fSVille Syrjälä 
831*b8a13e87SVille Syrjälä 	if (aux_ch == AUX_CH_NONE)
832*b8a13e87SVille Syrjälä 		return AUX_CH_NONE;
833*b8a13e87SVille Syrjälä 
834*b8a13e87SVille Syrjälä 	/* FIXME validate aux_ch against platform caps */
835*b8a13e87SVille Syrjälä 
836*b8a13e87SVille Syrjälä 	other = get_encoder_by_aux_ch(encoder, aux_ch);
837*b8a13e87SVille Syrjälä 	if (other) {
838*b8a13e87SVille Syrjälä 		drm_dbg_kms(&i915->drm,
839*b8a13e87SVille Syrjälä 			    "[ENCODER:%d:%s] AUX CH %c already claimed by [ENCODER:%d:%s]\n",
840*b8a13e87SVille Syrjälä 			    encoder->base.base.id, encoder->base.name, aux_ch_name(aux_ch),
841*b8a13e87SVille Syrjälä 			    other->base.base.id, other->base.name);
842*b8a13e87SVille Syrjälä 		return AUX_CH_NONE;
843*b8a13e87SVille Syrjälä 	}
844bb45217fSVille Syrjälä 
845bb45217fSVille Syrjälä 	drm_dbg_kms(&i915->drm,
846*b8a13e87SVille Syrjälä 		    "[ENCODER:%d:%s] Using AUX CH %c (%s)\n",
847fce187caSVille Syrjälä 		    encoder->base.base.id, encoder->base.name,
848*b8a13e87SVille Syrjälä 		    aux_ch_name(aux_ch), source);
849bb45217fSVille Syrjälä 
850bb45217fSVille Syrjälä 	return aux_ch;
851bb45217fSVille Syrjälä }
852685282a3SJani Nikula 
intel_dp_aux_irq_handler(struct drm_i915_private * i915)853685282a3SJani Nikula void intel_dp_aux_irq_handler(struct drm_i915_private *i915)
854685282a3SJani Nikula {
855685282a3SJani Nikula 	wake_up_all(&i915->display.gmbus.wait_queue);
856685282a3SJani Nikula }
857