All of lore.kernel.org
 help / color / mirror / Atom feed
From: Rodrigo Vivi <rodrigo.vivi@intel.com>
To: Jani Nikula <jani.nikula@intel.com>
Cc: intel-gfx@lists.freedesktop.org
Subject: Re: [Intel-gfx] [PATCH 4/4] drm/i915/dp: split out aux functionality to intel_dp_aux.c
Date: Wed, 20 Jan 2021 12:31:49 -0500	[thread overview]
Message-ID: <20210120173149.GC3970@intel.com> (raw)
In-Reply-To: <20210120101834.19813-4-jani.nikula@intel.com>

On Wed, Jan 20, 2021 at 12:18:34PM +0200, Jani Nikula wrote:
> Split out the DP aux functionality to a new intel_dp_aux.[ch]. This is a
> surprisingly clean cut.

I had wondered about this split in the past... surprisingly clean cut indeed...

> 
> v2:
> - Remove intel_dp_pack_aux declaration from intel_dp.h (Anshuman)
> - Fixed some whitespace/comment checkpatch warnings
> 
> Cc: Anshuman Gupta <anshuman.gupta@intel.com>
> Signed-off-by: Jani Nikula <jani.nikula@intel.com>
> ---
>  drivers/gpu/drm/i915/Makefile               |   1 +
>  drivers/gpu/drm/i915/display/intel_dp.c     | 680 +------------------
>  drivers/gpu/drm/i915/display/intel_dp.h     |   1 -
>  drivers/gpu/drm/i915/display/intel_dp_aux.c | 692 ++++++++++++++++++++
>  drivers/gpu/drm/i915/display/intel_dp_aux.h |  18 +
>  drivers/gpu/drm/i915/display/intel_psr.c    |   3 +-
>  6 files changed, 714 insertions(+), 681 deletions(-)
>  create mode 100644 drivers/gpu/drm/i915/display/intel_dp_aux.c
>  create mode 100644 drivers/gpu/drm/i915/display/intel_dp_aux.h
> 
> diff --git a/drivers/gpu/drm/i915/Makefile b/drivers/gpu/drm/i915/Makefile
> index 006dec54408d..ea1cc5736049 100644
> --- a/drivers/gpu/drm/i915/Makefile
> +++ b/drivers/gpu/drm/i915/Makefile
> @@ -243,6 +243,7 @@ i915-y += \
>  	display/intel_crt.o \
>  	display/intel_ddi.o \
>  	display/intel_dp.o \
> +	display/intel_dp_aux.o \
>  	display/intel_dp_aux_backlight.o \
>  	display/intel_dp_hdcp.o \
>  	display/intel_dp_link_training.o \
> diff --git a/drivers/gpu/drm/i915/display/intel_dp.c b/drivers/gpu/drm/i915/display/intel_dp.c
> index d815087a26aa..8979996f1747 100644
> --- a/drivers/gpu/drm/i915/display/intel_dp.c
> +++ b/drivers/gpu/drm/i915/display/intel_dp.c
> @@ -41,13 +41,13 @@
>  
>  #include "i915_debugfs.h"
>  #include "i915_drv.h"
> -#include "i915_trace.h"
>  #include "intel_atomic.h"
>  #include "intel_audio.h"
>  #include "intel_connector.h"
>  #include "intel_ddi.h"
>  #include "intel_display_types.h"
>  #include "intel_dp.h"
> +#include "intel_dp_aux.h"
>  #include "intel_dp_link_training.h"
>  #include "intel_dp_mst.h"
>  #include "intel_dpio_phy.h"
> @@ -862,684 +862,6 @@ intel_dp_mode_valid(struct drm_connector *connector,
>  	return intel_mode_valid_max_plane_size(dev_priv, mode, bigjoiner);
>  }
>  
> -u32 intel_dp_pack_aux(const u8 *src, int src_bytes)
> -{
> -	int i;
> -	u32 v = 0;
> -
> -	if (src_bytes > 4)
> -		src_bytes = 4;
> -	for (i = 0; i < src_bytes; i++)
> -		v |= ((u32)src[i]) << ((3 - i) * 8);
> -	return v;
> -}
> -
> -static void intel_dp_unpack_aux(u32 src, u8 *dst, int dst_bytes)
> -{
> -	int i;
> -	if (dst_bytes > 4)
> -		dst_bytes = 4;
> -	for (i = 0; i < dst_bytes; i++)
> -		dst[i] = src >> ((3-i) * 8);
> -}
> -
> -static u32
> -intel_dp_aux_wait_done(struct intel_dp *intel_dp)
> -{
> -	struct drm_i915_private *i915 = dp_to_i915(intel_dp);
> -	i915_reg_t ch_ctl = intel_dp->aux_ch_ctl_reg(intel_dp);
> -	const unsigned int timeout_ms = 10;
> -	u32 status;
> -	bool done;
> -
> -#define C (((status = intel_uncore_read_notrace(&i915->uncore, ch_ctl)) & DP_AUX_CH_CTL_SEND_BUSY) == 0)
> -	done = wait_event_timeout(i915->gmbus_wait_queue, C,
> -				  msecs_to_jiffies_timeout(timeout_ms));
> -
> -	/* just trace the final value */
> -	trace_i915_reg_rw(false, ch_ctl, status, sizeof(status), true);
> -
> -	if (!done)
> -		drm_err(&i915->drm,
> -			"%s: did not complete or timeout within %ums (status 0x%08x)\n",
> -			intel_dp->aux.name, timeout_ms, status);
> -#undef C
> -
> -	return status;
> -}
> -
> -static u32 g4x_get_aux_clock_divider(struct intel_dp *intel_dp, int index)
> -{
> -	struct drm_i915_private *dev_priv = dp_to_i915(intel_dp);
> -
> -	if (index)
> -		return 0;
> -
> -	/*
> -	 * The clock divider is based off the hrawclk, and would like to run at
> -	 * 2MHz.  So, take the hrawclk value and divide by 2000 and use that
> -	 */
> -	return DIV_ROUND_CLOSEST(RUNTIME_INFO(dev_priv)->rawclk_freq, 2000);
> -}
> -
> -static u32 ilk_get_aux_clock_divider(struct intel_dp *intel_dp, int index)
> -{
> -	struct drm_i915_private *dev_priv = dp_to_i915(intel_dp);
> -	struct intel_digital_port *dig_port = dp_to_dig_port(intel_dp);
> -	u32 freq;
> -
> -	if (index)
> -		return 0;
> -
> -	/*
> -	 * The clock divider is based off the cdclk or PCH rawclk, and would
> -	 * like to run at 2MHz.  So, take the cdclk or PCH rawclk value and
> -	 * divide by 2000 and use that
> -	 */
> -	if (dig_port->aux_ch == AUX_CH_A)
> -		freq = dev_priv->cdclk.hw.cdclk;
> -	else
> -		freq = RUNTIME_INFO(dev_priv)->rawclk_freq;
> -	return DIV_ROUND_CLOSEST(freq, 2000);
> -}
> -
> -static u32 hsw_get_aux_clock_divider(struct intel_dp *intel_dp, int index)
> -{
> -	struct drm_i915_private *dev_priv = dp_to_i915(intel_dp);
> -	struct intel_digital_port *dig_port = dp_to_dig_port(intel_dp);
> -
> -	if (dig_port->aux_ch != AUX_CH_A && HAS_PCH_LPT_H(dev_priv)) {
> -		/* Workaround for non-ULT HSW */
> -		switch (index) {
> -		case 0: return 63;
> -		case 1: return 72;
> -		default: return 0;
> -		}
> -	}
> -
> -	return ilk_get_aux_clock_divider(intel_dp, index);
> -}
> -
> -static u32 skl_get_aux_clock_divider(struct intel_dp *intel_dp, int index)
> -{
> -	/*
> -	 * SKL doesn't need us to program the AUX clock divider (Hardware will
> -	 * derive the clock from CDCLK automatically). We still implement the
> -	 * get_aux_clock_divider vfunc to plug-in into the existing code.
> -	 */
> -	return index ? 0 : 1;
> -}
> -
> -static u32 g4x_get_aux_send_ctl(struct intel_dp *intel_dp,
> -				int send_bytes,
> -				u32 aux_clock_divider)
> -{
> -	struct intel_digital_port *dig_port = dp_to_dig_port(intel_dp);
> -	struct drm_i915_private *dev_priv =
> -			to_i915(dig_port->base.base.dev);
> -	u32 precharge, timeout;
> -
> -	if (IS_GEN(dev_priv, 6))
> -		precharge = 3;
> -	else
> -		precharge = 5;
> -
> -	if (IS_BROADWELL(dev_priv))
> -		timeout = DP_AUX_CH_CTL_TIME_OUT_600us;
> -	else
> -		timeout = DP_AUX_CH_CTL_TIME_OUT_400us;
> -
> -	return DP_AUX_CH_CTL_SEND_BUSY |
> -	       DP_AUX_CH_CTL_DONE |
> -	       DP_AUX_CH_CTL_INTERRUPT |
> -	       DP_AUX_CH_CTL_TIME_OUT_ERROR |
> -	       timeout |
> -	       DP_AUX_CH_CTL_RECEIVE_ERROR |
> -	       (send_bytes << DP_AUX_CH_CTL_MESSAGE_SIZE_SHIFT) |
> -	       (precharge << DP_AUX_CH_CTL_PRECHARGE_2US_SHIFT) |
> -	       (aux_clock_divider << DP_AUX_CH_CTL_BIT_CLOCK_2X_SHIFT);
> -}
> -
> -static u32 skl_get_aux_send_ctl(struct intel_dp *intel_dp,
> -				int send_bytes,
> -				u32 unused)
> -{
> -	struct intel_digital_port *dig_port = dp_to_dig_port(intel_dp);
> -	struct drm_i915_private *i915 =
> -			to_i915(dig_port->base.base.dev);
> -	enum phy phy = intel_port_to_phy(i915, dig_port->base.port);
> -	u32 ret;
> -
> -	ret = DP_AUX_CH_CTL_SEND_BUSY |
> -	      DP_AUX_CH_CTL_DONE |
> -	      DP_AUX_CH_CTL_INTERRUPT |
> -	      DP_AUX_CH_CTL_TIME_OUT_ERROR |
> -	      DP_AUX_CH_CTL_TIME_OUT_MAX |
> -	      DP_AUX_CH_CTL_RECEIVE_ERROR |
> -	      (send_bytes << DP_AUX_CH_CTL_MESSAGE_SIZE_SHIFT) |
> -	      DP_AUX_CH_CTL_FW_SYNC_PULSE_SKL(32) |
> -	      DP_AUX_CH_CTL_SYNC_PULSE_SKL(32);
> -
> -	if (intel_phy_is_tc(i915, phy) &&
> -	    dig_port->tc_mode == TC_PORT_TBT_ALT)
> -		ret |= DP_AUX_CH_CTL_TBT_IO;
> -
> -	return ret;
> -}
> -
> -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)
> -{
> -	struct intel_digital_port *dig_port = dp_to_dig_port(intel_dp);
> -	struct drm_i915_private *i915 =
> -			to_i915(dig_port->base.base.dev);
> -	struct intel_uncore *uncore = &i915->uncore;
> -	enum phy phy = intel_port_to_phy(i915, dig_port->base.port);
> -	bool is_tc_port = intel_phy_is_tc(i915, phy);
> -	i915_reg_t ch_ctl, ch_data[5];
> -	u32 aux_clock_divider;
> -	enum intel_display_power_domain aux_domain;
> -	intel_wakeref_t aux_wakeref;
> -	intel_wakeref_t pps_wakeref;
> -	int i, ret, recv_bytes;
> -	int try, clock = 0;
> -	u32 status;
> -	bool vdd;
> -
> -	ch_ctl = intel_dp->aux_ch_ctl_reg(intel_dp);
> -	for (i = 0; i < ARRAY_SIZE(ch_data); i++)
> -		ch_data[i] = intel_dp->aux_ch_data_reg(intel_dp, i);
> -
> -	if (is_tc_port)
> -		intel_tc_port_lock(dig_port);
> -
> -	aux_domain = intel_aux_power_domain(dig_port);
> -
> -	aux_wakeref = intel_display_power_get(i915, aux_domain);
> -	pps_wakeref = intel_pps_lock(intel_dp);
> -
> -	/*
> -	 * We will be called with VDD already enabled for dpcd/edid/oui reads.
> -	 * In such cases we want to leave VDD enabled and it's up to upper layers
> -	 * to turn it off. But for eg. i2c-dev access we need to turn it on/off
> -	 * ourselves.
> -	 */
> -	vdd = intel_pps_vdd_on_unlocked(intel_dp);
> -
> -	/* dp aux is extremely sensitive to irq latency, hence request the
> -	 * lowest possible wakeup latency and so prevent the cpu from going into
> -	 * deep sleep states.
> -	 */
> -	cpu_latency_qos_update_request(&intel_dp->pm_qos, 0);
> -
> -	intel_pps_check_power_unlocked(intel_dp);
> -
> -	/* Try to wait for any previous AUX channel activity */
> -	for (try = 0; try < 3; try++) {
> -		status = intel_uncore_read_notrace(uncore, ch_ctl);
> -		if ((status & DP_AUX_CH_CTL_SEND_BUSY) == 0)
> -			break;
> -		msleep(1);
> -	}
> -	/* just trace the final value */
> -	trace_i915_reg_rw(false, ch_ctl, status, sizeof(status), true);
> -
> -	if (try == 3) {
> -		const u32 status = intel_uncore_read(uncore, ch_ctl);
> -
> -		if (status != intel_dp->aux_busy_last_status) {
> -			drm_WARN(&i915->drm, 1,
> -				 "%s: not started (status 0x%08x)\n",
> -				 intel_dp->aux.name, status);
> -			intel_dp->aux_busy_last_status = status;
> -		}
> -
> -		ret = -EBUSY;
> -		goto out;
> -	}
> -
> -	/* Only 5 data registers! */
> -	if (drm_WARN_ON(&i915->drm, send_bytes > 20 || recv_size > 20)) {
> -		ret = -E2BIG;
> -		goto out;
> -	}
> -
> -	while ((aux_clock_divider = intel_dp->get_aux_clock_divider(intel_dp, clock++))) {
> -		u32 send_ctl = intel_dp->get_aux_send_ctl(intel_dp,
> -							  send_bytes,
> -							  aux_clock_divider);
> -
> -		send_ctl |= aux_send_ctl_flags;
> -
> -		/* Must try at least 3 times according to DP spec */
> -		for (try = 0; try < 5; try++) {
> -			/* Load the send data into the aux channel data registers */
> -			for (i = 0; i < send_bytes; i += 4)
> -				intel_uncore_write(uncore,
> -						   ch_data[i >> 2],
> -						   intel_dp_pack_aux(send + i,
> -								     send_bytes - i));
> -
> -			/* Send the command and wait for it to complete */
> -			intel_uncore_write(uncore, ch_ctl, send_ctl);
> -
> -			status = intel_dp_aux_wait_done(intel_dp);
> -
> -			/* Clear done status and any errors */
> -			intel_uncore_write(uncore,
> -					   ch_ctl,
> -					   status |
> -					   DP_AUX_CH_CTL_DONE |
> -					   DP_AUX_CH_CTL_TIME_OUT_ERROR |
> -					   DP_AUX_CH_CTL_RECEIVE_ERROR);
> -
> -			/* DP CTS 1.2 Core Rev 1.1, 4.2.1.1 & 4.2.1.2
> -			 *   400us delay required for errors and timeouts
> -			 *   Timeout errors from the HW already meet this
> -			 *   requirement so skip to next iteration
> -			 */
> -			if (status & DP_AUX_CH_CTL_TIME_OUT_ERROR)
> -				continue;
> -
> -			if (status & DP_AUX_CH_CTL_RECEIVE_ERROR) {
> -				usleep_range(400, 500);
> -				continue;
> -			}
> -			if (status & DP_AUX_CH_CTL_DONE)
> -				goto done;
> -		}
> -	}
> -
> -	if ((status & DP_AUX_CH_CTL_DONE) == 0) {
> -		drm_err(&i915->drm, "%s: not done (status 0x%08x)\n",
> -			intel_dp->aux.name, status);
> -		ret = -EBUSY;
> -		goto out;
> -	}
> -
> -done:
> -	/* Check for timeout or receive error.
> -	 * Timeouts occur when the sink is not connected
> -	 */
> -	if (status & DP_AUX_CH_CTL_RECEIVE_ERROR) {
> -		drm_err(&i915->drm, "%s: receive error (status 0x%08x)\n",
> -			intel_dp->aux.name, status);
> -		ret = -EIO;
> -		goto out;
> -	}
> -
> -	/* Timeouts occur when the device isn't connected, so they're
> -	 * "normal" -- don't fill the kernel log with these */
> -	if (status & DP_AUX_CH_CTL_TIME_OUT_ERROR) {
> -		drm_dbg_kms(&i915->drm, "%s: timeout (status 0x%08x)\n",
> -			    intel_dp->aux.name, status);
> -		ret = -ETIMEDOUT;
> -		goto out;
> -	}
> -
> -	/* Unload any bytes sent back from the other side */
> -	recv_bytes = ((status & DP_AUX_CH_CTL_MESSAGE_SIZE_MASK) >>
> -		      DP_AUX_CH_CTL_MESSAGE_SIZE_SHIFT);
> -
> -	/*
> -	 * By BSpec: "Message sizes of 0 or >20 are not allowed."
> -	 * We have no idea of what happened so we return -EBUSY so
> -	 * drm layer takes care for the necessary retries.
> -	 */
> -	if (recv_bytes == 0 || recv_bytes > 20) {
> -		drm_dbg_kms(&i915->drm,
> -			    "%s: Forbidden recv_bytes = %d on aux transaction\n",
> -			    intel_dp->aux.name, recv_bytes);
> -		ret = -EBUSY;
> -		goto out;
> -	}
> -
> -	if (recv_bytes > recv_size)
> -		recv_bytes = recv_size;
> -
> -	for (i = 0; i < recv_bytes; i += 4)
> -		intel_dp_unpack_aux(intel_uncore_read(uncore, ch_data[i >> 2]),
> -				    recv + i, recv_bytes - i);
> -
> -	ret = recv_bytes;
> -out:
> -	cpu_latency_qos_update_request(&intel_dp->pm_qos, PM_QOS_DEFAULT_VALUE);
> -
> -	if (vdd)
> -		intel_pps_vdd_off_unlocked(intel_dp, false);
> -
> -	intel_pps_unlock(intel_dp, pps_wakeref);
> -	intel_display_power_put_async(i915, aux_domain, aux_wakeref);
> -
> -	if (is_tc_port)
> -		intel_tc_port_unlock(dig_port);
> -
> -	return ret;
> -}
> -
> -#define BARE_ADDRESS_SIZE	3
> -#define HEADER_SIZE		(BARE_ADDRESS_SIZE + 1)
> -
> -static void
> -intel_dp_aux_header(u8 txbuf[HEADER_SIZE],
> -		    const struct drm_dp_aux_msg *msg)
> -{
> -	txbuf[0] = (msg->request << 4) | ((msg->address >> 16) & 0xf);
> -	txbuf[1] = (msg->address >> 8) & 0xff;
> -	txbuf[2] = msg->address & 0xff;
> -	txbuf[3] = msg->size - 1;
> -}
> -
> -static u32 intel_dp_aux_xfer_flags(const struct drm_dp_aux_msg *msg)
> -{
> -	/*
> -	 * If we're trying to send the HDCP Aksv, we need to set a the Aksv
> -	 * select bit to inform the hardware to send the Aksv after our header
> -	 * since we can't access that data from software.
> -	 */
> -	if ((msg->request & ~DP_AUX_I2C_MOT) == DP_AUX_NATIVE_WRITE &&
> -	    msg->address == DP_AUX_HDCP_AKSV)
> -		return DP_AUX_CH_CTL_AUX_AKSV_SELECT;
> -
> -	return 0;
> -}
> -
> -static ssize_t
> -intel_dp_aux_transfer(struct drm_dp_aux *aux, struct drm_dp_aux_msg *msg)
> -{
> -	struct intel_dp *intel_dp = container_of(aux, struct intel_dp, aux);
> -	struct drm_i915_private *i915 = dp_to_i915(intel_dp);
> -	u8 txbuf[20], rxbuf[20];
> -	size_t txsize, rxsize;
> -	u32 flags = intel_dp_aux_xfer_flags(msg);
> -	int ret;
> -
> -	intel_dp_aux_header(txbuf, msg);
> -
> -	switch (msg->request & ~DP_AUX_I2C_MOT) {
> -	case DP_AUX_NATIVE_WRITE:
> -	case DP_AUX_I2C_WRITE:
> -	case DP_AUX_I2C_WRITE_STATUS_UPDATE:
> -		txsize = msg->size ? HEADER_SIZE + msg->size : BARE_ADDRESS_SIZE;
> -		rxsize = 2; /* 0 or 1 data bytes */
> -
> -		if (drm_WARN_ON(&i915->drm, txsize > 20))
> -			return -E2BIG;
> -
> -		drm_WARN_ON(&i915->drm, !msg->buffer != !msg->size);
> -
> -		if (msg->buffer)
> -			memcpy(txbuf + HEADER_SIZE, msg->buffer, msg->size);
> -
> -		ret = intel_dp_aux_xfer(intel_dp, txbuf, txsize,
> -					rxbuf, rxsize, flags);
> -		if (ret > 0) {
> -			msg->reply = rxbuf[0] >> 4;
> -
> -			if (ret > 1) {
> -				/* Number of bytes written in a short write. */
> -				ret = clamp_t(int, rxbuf[1], 0, msg->size);
> -			} else {
> -				/* Return payload size. */
> -				ret = msg->size;
> -			}
> -		}
> -		break;
> -
> -	case DP_AUX_NATIVE_READ:
> -	case DP_AUX_I2C_READ:
> -		txsize = msg->size ? HEADER_SIZE : BARE_ADDRESS_SIZE;
> -		rxsize = msg->size + 1;
> -
> -		if (drm_WARN_ON(&i915->drm, rxsize > 20))
> -			return -E2BIG;
> -
> -		ret = intel_dp_aux_xfer(intel_dp, txbuf, txsize,
> -					rxbuf, rxsize, flags);
> -		if (ret > 0) {
> -			msg->reply = rxbuf[0] >> 4;
> -			/*
> -			 * Assume happy day, and copy the data. The caller is
> -			 * expected to check msg->reply before touching it.
> -			 *
> -			 * Return payload size.
> -			 */
> -			ret--;
> -			memcpy(msg->buffer, rxbuf + 1, ret);
> -		}
> -		break;
> -
> -	default:
> -		ret = -EINVAL;
> -		break;
> -	}
> -
> -	return ret;
> -}
> -
> -
> -static i915_reg_t g4x_aux_ctl_reg(struct intel_dp *intel_dp)
> -{
> -	struct drm_i915_private *dev_priv = dp_to_i915(intel_dp);
> -	struct intel_digital_port *dig_port = dp_to_dig_port(intel_dp);
> -	enum aux_ch aux_ch = dig_port->aux_ch;
> -
> -	switch (aux_ch) {
> -	case AUX_CH_B:
> -	case AUX_CH_C:
> -	case AUX_CH_D:
> -		return DP_AUX_CH_CTL(aux_ch);
> -	default:
> -		MISSING_CASE(aux_ch);
> -		return DP_AUX_CH_CTL(AUX_CH_B);
> -	}
> -}
> -
> -static i915_reg_t g4x_aux_data_reg(struct intel_dp *intel_dp, int index)
> -{
> -	struct drm_i915_private *dev_priv = dp_to_i915(intel_dp);
> -	struct intel_digital_port *dig_port = dp_to_dig_port(intel_dp);
> -	enum aux_ch aux_ch = dig_port->aux_ch;
> -
> -	switch (aux_ch) {
> -	case AUX_CH_B:
> -	case AUX_CH_C:
> -	case AUX_CH_D:
> -		return DP_AUX_CH_DATA(aux_ch, index);
> -	default:
> -		MISSING_CASE(aux_ch);
> -		return DP_AUX_CH_DATA(AUX_CH_B, index);
> -	}
> -}
> -
> -static i915_reg_t ilk_aux_ctl_reg(struct intel_dp *intel_dp)
> -{
> -	struct drm_i915_private *dev_priv = dp_to_i915(intel_dp);
> -	struct intel_digital_port *dig_port = dp_to_dig_port(intel_dp);
> -	enum aux_ch aux_ch = dig_port->aux_ch;
> -
> -	switch (aux_ch) {
> -	case AUX_CH_A:
> -		return DP_AUX_CH_CTL(aux_ch);
> -	case AUX_CH_B:
> -	case AUX_CH_C:
> -	case AUX_CH_D:
> -		return PCH_DP_AUX_CH_CTL(aux_ch);
> -	default:
> -		MISSING_CASE(aux_ch);
> -		return DP_AUX_CH_CTL(AUX_CH_A);
> -	}
> -}
> -
> -static i915_reg_t ilk_aux_data_reg(struct intel_dp *intel_dp, int index)
> -{
> -	struct drm_i915_private *dev_priv = dp_to_i915(intel_dp);
> -	struct intel_digital_port *dig_port = dp_to_dig_port(intel_dp);
> -	enum aux_ch aux_ch = dig_port->aux_ch;
> -
> -	switch (aux_ch) {
> -	case AUX_CH_A:
> -		return DP_AUX_CH_DATA(aux_ch, index);
> -	case AUX_CH_B:
> -	case AUX_CH_C:
> -	case AUX_CH_D:
> -		return PCH_DP_AUX_CH_DATA(aux_ch, index);
> -	default:
> -		MISSING_CASE(aux_ch);
> -		return DP_AUX_CH_DATA(AUX_CH_A, index);
> -	}
> -}
> -
> -static i915_reg_t skl_aux_ctl_reg(struct intel_dp *intel_dp)
> -{
> -	struct drm_i915_private *dev_priv = dp_to_i915(intel_dp);
> -	struct intel_digital_port *dig_port = dp_to_dig_port(intel_dp);
> -	enum aux_ch aux_ch = dig_port->aux_ch;
> -
> -	switch (aux_ch) {
> -	case AUX_CH_A:
> -	case AUX_CH_B:
> -	case AUX_CH_C:
> -	case AUX_CH_D:
> -	case AUX_CH_E:
> -	case AUX_CH_F:
> -		return DP_AUX_CH_CTL(aux_ch);
> -	default:
> -		MISSING_CASE(aux_ch);
> -		return DP_AUX_CH_CTL(AUX_CH_A);
> -	}
> -}
> -
> -static i915_reg_t skl_aux_data_reg(struct intel_dp *intel_dp, int index)
> -{
> -	struct drm_i915_private *dev_priv = dp_to_i915(intel_dp);
> -	struct intel_digital_port *dig_port = dp_to_dig_port(intel_dp);
> -	enum aux_ch aux_ch = dig_port->aux_ch;
> -
> -	switch (aux_ch) {
> -	case AUX_CH_A:
> -	case AUX_CH_B:
> -	case AUX_CH_C:
> -	case AUX_CH_D:
> -	case AUX_CH_E:
> -	case AUX_CH_F:
> -		return DP_AUX_CH_DATA(aux_ch, index);
> -	default:
> -		MISSING_CASE(aux_ch);
> -		return DP_AUX_CH_DATA(AUX_CH_A, index);
> -	}
> -}
> -
> -static i915_reg_t tgl_aux_ctl_reg(struct intel_dp *intel_dp)
> -{
> -	struct drm_i915_private *dev_priv = dp_to_i915(intel_dp);
> -	struct intel_digital_port *dig_port = dp_to_dig_port(intel_dp);
> -	enum aux_ch aux_ch = dig_port->aux_ch;
> -
> -	switch (aux_ch) {
> -	case AUX_CH_A:
> -	case AUX_CH_B:
> -	case AUX_CH_C:
> -	case AUX_CH_USBC1:
> -	case AUX_CH_USBC2:
> -	case AUX_CH_USBC3:
> -	case AUX_CH_USBC4:
> -	case AUX_CH_USBC5:
> -	case AUX_CH_USBC6:
> -		return DP_AUX_CH_CTL(aux_ch);
> -	default:
> -		MISSING_CASE(aux_ch);
> -		return DP_AUX_CH_CTL(AUX_CH_A);
> -	}
> -}
> -
> -static i915_reg_t tgl_aux_data_reg(struct intel_dp *intel_dp, int index)
> -{
> -	struct drm_i915_private *dev_priv = dp_to_i915(intel_dp);
> -	struct intel_digital_port *dig_port = dp_to_dig_port(intel_dp);
> -	enum aux_ch aux_ch = dig_port->aux_ch;
> -
> -	switch (aux_ch) {
> -	case AUX_CH_A:
> -	case AUX_CH_B:
> -	case AUX_CH_C:
> -	case AUX_CH_USBC1:
> -	case AUX_CH_USBC2:
> -	case AUX_CH_USBC3:
> -	case AUX_CH_USBC4:
> -	case AUX_CH_USBC5:
> -	case AUX_CH_USBC6:
> -		return DP_AUX_CH_DATA(aux_ch, index);
> -	default:
> -		MISSING_CASE(aux_ch);
> -		return DP_AUX_CH_DATA(AUX_CH_A, index);
> -	}
> -}
> -
> -static void
> -intel_dp_aux_fini(struct intel_dp *intel_dp)
> -{
> -	if (cpu_latency_qos_request_active(&intel_dp->pm_qos))
> -		cpu_latency_qos_remove_request(&intel_dp->pm_qos);
> -
> -	kfree(intel_dp->aux.name);
> -}
> -
> -static void
> -intel_dp_aux_init(struct intel_dp *intel_dp)
> -{
> -	struct drm_i915_private *dev_priv = dp_to_i915(intel_dp);
> -	struct intel_digital_port *dig_port = dp_to_dig_port(intel_dp);
> -	struct intel_encoder *encoder = &dig_port->base;
> -	enum aux_ch aux_ch = dig_port->aux_ch;
> -
> -	if (INTEL_GEN(dev_priv) >= 12) {
> -		intel_dp->aux_ch_ctl_reg = tgl_aux_ctl_reg;
> -		intel_dp->aux_ch_data_reg = tgl_aux_data_reg;
> -	} else if (INTEL_GEN(dev_priv) >= 9) {
> -		intel_dp->aux_ch_ctl_reg = skl_aux_ctl_reg;
> -		intel_dp->aux_ch_data_reg = skl_aux_data_reg;
> -	} else if (HAS_PCH_SPLIT(dev_priv)) {
> -		intel_dp->aux_ch_ctl_reg = ilk_aux_ctl_reg;
> -		intel_dp->aux_ch_data_reg = ilk_aux_data_reg;
> -	} else {
> -		intel_dp->aux_ch_ctl_reg = g4x_aux_ctl_reg;
> -		intel_dp->aux_ch_data_reg = g4x_aux_data_reg;
> -	}
> -
> -	if (INTEL_GEN(dev_priv) >= 9)
> -		intel_dp->get_aux_clock_divider = skl_get_aux_clock_divider;
> -	else if (IS_BROADWELL(dev_priv) || IS_HASWELL(dev_priv))
> -		intel_dp->get_aux_clock_divider = hsw_get_aux_clock_divider;
> -	else if (HAS_PCH_SPLIT(dev_priv))
> -		intel_dp->get_aux_clock_divider = ilk_get_aux_clock_divider;
> -	else
> -		intel_dp->get_aux_clock_divider = g4x_get_aux_clock_divider;
> -
> -	if (INTEL_GEN(dev_priv) >= 9)
> -		intel_dp->get_aux_send_ctl = skl_get_aux_send_ctl;
> -	else
> -		intel_dp->get_aux_send_ctl = g4x_get_aux_send_ctl;
> -
> -	drm_dp_aux_init(&intel_dp->aux);
> -
> -	/* Failure to allocate our preferred name is not critical */
> -	if (INTEL_GEN(dev_priv) >= 12 && aux_ch >= AUX_CH_USBC1)
> -		intel_dp->aux.name = kasprintf(GFP_KERNEL, "AUX USBC%c/%s",
> -					       aux_ch - AUX_CH_USBC1 + '1',
> -					       encoder->base.name);
> -	else
> -		intel_dp->aux.name = kasprintf(GFP_KERNEL, "AUX %c/%s",
> -					       aux_ch_name(aux_ch),
> -					       encoder->base.name);
> -
> -	intel_dp->aux.transfer = intel_dp_aux_transfer;
> -	cpu_latency_qos_add_request(&intel_dp->pm_qos, PM_QOS_DEFAULT_VALUE);
> -}
> -
>  bool intel_dp_source_supports_hbr2(struct intel_dp *intel_dp)
>  {
>  	int max_rate = intel_dp->source_rates[intel_dp->num_source_rates - 1];
> diff --git a/drivers/gpu/drm/i915/display/intel_dp.h b/drivers/gpu/drm/i915/display/intel_dp.h
> index 40e70531296c..d80839139bfb 100644
> --- a/drivers/gpu/drm/i915/display/intel_dp.h
> +++ b/drivers/gpu/drm/i915/display/intel_dp.h
> @@ -75,7 +75,6 @@ void intel_dp_mst_resume(struct drm_i915_private *dev_priv);
>  int intel_dp_max_link_rate(struct intel_dp *intel_dp);
>  int intel_dp_max_lane_count(struct intel_dp *intel_dp);
>  int intel_dp_rate_select(struct intel_dp *intel_dp, int rate);
> -u32 intel_dp_pack_aux(const u8 *src, int src_bytes);
>  
>  void intel_edp_drrs_enable(struct intel_dp *intel_dp,
>  			   const struct intel_crtc_state *crtc_state);
> diff --git a/drivers/gpu/drm/i915/display/intel_dp_aux.c b/drivers/gpu/drm/i915/display/intel_dp_aux.c
> new file mode 100644
> index 000000000000..c7c82a6cd63c
> --- /dev/null
> +++ b/drivers/gpu/drm/i915/display/intel_dp_aux.c
> @@ -0,0 +1,692 @@
> +// SPDX-License-Identifier: MIT
> +/*
> + * Copyright © 2020 Intel Corporation

2021?!

Reviewed-by: Rodrigo Vivi <rodrigo.vivi@intel.com>

> + */
> +
> +#include "i915_drv.h"
> +#include "i915_trace.h"
> +#include "intel_display_types.h"
> +#include "intel_dp_aux.h"
> +#include "intel_pps.h"
> +#include "intel_tc.h"
> +
> +u32 intel_dp_pack_aux(const u8 *src, int src_bytes)
> +{
> +	int i;
> +	u32 v = 0;
> +
> +	if (src_bytes > 4)
> +		src_bytes = 4;
> +	for (i = 0; i < src_bytes; i++)
> +		v |= ((u32)src[i]) << ((3 - i) * 8);
> +	return v;
> +}
> +
> +static void intel_dp_unpack_aux(u32 src, u8 *dst, int dst_bytes)
> +{
> +	int i;
> +
> +	if (dst_bytes > 4)
> +		dst_bytes = 4;
> +	for (i = 0; i < dst_bytes; i++)
> +		dst[i] = src >> ((3 - i) * 8);
> +}
> +
> +static u32
> +intel_dp_aux_wait_done(struct intel_dp *intel_dp)
> +{
> +	struct drm_i915_private *i915 = dp_to_i915(intel_dp);
> +	i915_reg_t ch_ctl = intel_dp->aux_ch_ctl_reg(intel_dp);
> +	const unsigned int timeout_ms = 10;
> +	u32 status;
> +	bool done;
> +
> +#define C (((status = intel_uncore_read_notrace(&i915->uncore, ch_ctl)) & DP_AUX_CH_CTL_SEND_BUSY) == 0)
> +	done = wait_event_timeout(i915->gmbus_wait_queue, C,
> +				  msecs_to_jiffies_timeout(timeout_ms));
> +
> +	/* just trace the final value */
> +	trace_i915_reg_rw(false, ch_ctl, status, sizeof(status), true);
> +
> +	if (!done)
> +		drm_err(&i915->drm,
> +			"%s: did not complete or timeout within %ums (status 0x%08x)\n",
> +			intel_dp->aux.name, timeout_ms, status);
> +#undef C
> +
> +	return status;
> +}
> +
> +static u32 g4x_get_aux_clock_divider(struct intel_dp *intel_dp, int index)
> +{
> +	struct drm_i915_private *dev_priv = dp_to_i915(intel_dp);
> +
> +	if (index)
> +		return 0;
> +
> +	/*
> +	 * The clock divider is based off the hrawclk, and would like to run at
> +	 * 2MHz.  So, take the hrawclk value and divide by 2000 and use that
> +	 */
> +	return DIV_ROUND_CLOSEST(RUNTIME_INFO(dev_priv)->rawclk_freq, 2000);
> +}
> +
> +static u32 ilk_get_aux_clock_divider(struct intel_dp *intel_dp, int index)
> +{
> +	struct drm_i915_private *dev_priv = dp_to_i915(intel_dp);
> +	struct intel_digital_port *dig_port = dp_to_dig_port(intel_dp);
> +	u32 freq;
> +
> +	if (index)
> +		return 0;
> +
> +	/*
> +	 * The clock divider is based off the cdclk or PCH rawclk, and would
> +	 * like to run at 2MHz.  So, take the cdclk or PCH rawclk value and
> +	 * divide by 2000 and use that
> +	 */
> +	if (dig_port->aux_ch == AUX_CH_A)
> +		freq = dev_priv->cdclk.hw.cdclk;
> +	else
> +		freq = RUNTIME_INFO(dev_priv)->rawclk_freq;
> +	return DIV_ROUND_CLOSEST(freq, 2000);
> +}
> +
> +static u32 hsw_get_aux_clock_divider(struct intel_dp *intel_dp, int index)
> +{
> +	struct drm_i915_private *dev_priv = dp_to_i915(intel_dp);
> +	struct intel_digital_port *dig_port = dp_to_dig_port(intel_dp);
> +
> +	if (dig_port->aux_ch != AUX_CH_A && HAS_PCH_LPT_H(dev_priv)) {
> +		/* Workaround for non-ULT HSW */
> +		switch (index) {
> +		case 0: return 63;
> +		case 1: return 72;
> +		default: return 0;
> +		}
> +	}
> +
> +	return ilk_get_aux_clock_divider(intel_dp, index);
> +}
> +
> +static u32 skl_get_aux_clock_divider(struct intel_dp *intel_dp, int index)
> +{
> +	/*
> +	 * SKL doesn't need us to program the AUX clock divider (Hardware will
> +	 * derive the clock from CDCLK automatically). We still implement the
> +	 * get_aux_clock_divider vfunc to plug-in into the existing code.
> +	 */
> +	return index ? 0 : 1;
> +}
> +
> +static u32 g4x_get_aux_send_ctl(struct intel_dp *intel_dp,
> +				int send_bytes,
> +				u32 aux_clock_divider)
> +{
> +	struct intel_digital_port *dig_port = dp_to_dig_port(intel_dp);
> +	struct drm_i915_private *dev_priv =
> +			to_i915(dig_port->base.base.dev);
> +	u32 precharge, timeout;
> +
> +	if (IS_GEN(dev_priv, 6))
> +		precharge = 3;
> +	else
> +		precharge = 5;
> +
> +	if (IS_BROADWELL(dev_priv))
> +		timeout = DP_AUX_CH_CTL_TIME_OUT_600us;
> +	else
> +		timeout = DP_AUX_CH_CTL_TIME_OUT_400us;
> +
> +	return DP_AUX_CH_CTL_SEND_BUSY |
> +	       DP_AUX_CH_CTL_DONE |
> +	       DP_AUX_CH_CTL_INTERRUPT |
> +	       DP_AUX_CH_CTL_TIME_OUT_ERROR |
> +	       timeout |
> +	       DP_AUX_CH_CTL_RECEIVE_ERROR |
> +	       (send_bytes << DP_AUX_CH_CTL_MESSAGE_SIZE_SHIFT) |
> +	       (precharge << DP_AUX_CH_CTL_PRECHARGE_2US_SHIFT) |
> +	       (aux_clock_divider << DP_AUX_CH_CTL_BIT_CLOCK_2X_SHIFT);
> +}
> +
> +static u32 skl_get_aux_send_ctl(struct intel_dp *intel_dp,
> +				int send_bytes,
> +				u32 unused)
> +{
> +	struct intel_digital_port *dig_port = dp_to_dig_port(intel_dp);
> +	struct drm_i915_private *i915 =
> +			to_i915(dig_port->base.base.dev);
> +	enum phy phy = intel_port_to_phy(i915, dig_port->base.port);
> +	u32 ret;
> +
> +	ret = DP_AUX_CH_CTL_SEND_BUSY |
> +	      DP_AUX_CH_CTL_DONE |
> +	      DP_AUX_CH_CTL_INTERRUPT |
> +	      DP_AUX_CH_CTL_TIME_OUT_ERROR |
> +	      DP_AUX_CH_CTL_TIME_OUT_MAX |
> +	      DP_AUX_CH_CTL_RECEIVE_ERROR |
> +	      (send_bytes << DP_AUX_CH_CTL_MESSAGE_SIZE_SHIFT) |
> +	      DP_AUX_CH_CTL_FW_SYNC_PULSE_SKL(32) |
> +	      DP_AUX_CH_CTL_SYNC_PULSE_SKL(32);
> +
> +	if (intel_phy_is_tc(i915, phy) &&
> +	    dig_port->tc_mode == TC_PORT_TBT_ALT)
> +		ret |= DP_AUX_CH_CTL_TBT_IO;
> +
> +	return ret;
> +}
> +
> +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)
> +{
> +	struct intel_digital_port *dig_port = dp_to_dig_port(intel_dp);
> +	struct drm_i915_private *i915 =
> +			to_i915(dig_port->base.base.dev);
> +	struct intel_uncore *uncore = &i915->uncore;
> +	enum phy phy = intel_port_to_phy(i915, dig_port->base.port);
> +	bool is_tc_port = intel_phy_is_tc(i915, phy);
> +	i915_reg_t ch_ctl, ch_data[5];
> +	u32 aux_clock_divider;
> +	enum intel_display_power_domain aux_domain;
> +	intel_wakeref_t aux_wakeref;
> +	intel_wakeref_t pps_wakeref;
> +	int i, ret, recv_bytes;
> +	int try, clock = 0;
> +	u32 status;
> +	bool vdd;
> +
> +	ch_ctl = intel_dp->aux_ch_ctl_reg(intel_dp);
> +	for (i = 0; i < ARRAY_SIZE(ch_data); i++)
> +		ch_data[i] = intel_dp->aux_ch_data_reg(intel_dp, i);
> +
> +	if (is_tc_port)
> +		intel_tc_port_lock(dig_port);
> +
> +	aux_domain = intel_aux_power_domain(dig_port);
> +
> +	aux_wakeref = intel_display_power_get(i915, aux_domain);
> +	pps_wakeref = intel_pps_lock(intel_dp);
> +
> +	/*
> +	 * We will be called with VDD already enabled for dpcd/edid/oui reads.
> +	 * In such cases we want to leave VDD enabled and it's up to upper layers
> +	 * to turn it off. But for eg. i2c-dev access we need to turn it on/off
> +	 * ourselves.
> +	 */
> +	vdd = intel_pps_vdd_on_unlocked(intel_dp);
> +
> +	/*
> +	 * dp aux is extremely sensitive to irq latency, hence request the
> +	 * lowest possible wakeup latency and so prevent the cpu from going into
> +	 * deep sleep states.
> +	 */
> +	cpu_latency_qos_update_request(&intel_dp->pm_qos, 0);
> +
> +	intel_pps_check_power_unlocked(intel_dp);
> +
> +	/* Try to wait for any previous AUX channel activity */
> +	for (try = 0; try < 3; try++) {
> +		status = intel_uncore_read_notrace(uncore, ch_ctl);
> +		if ((status & DP_AUX_CH_CTL_SEND_BUSY) == 0)
> +			break;
> +		msleep(1);
> +	}
> +	/* just trace the final value */
> +	trace_i915_reg_rw(false, ch_ctl, status, sizeof(status), true);
> +
> +	if (try == 3) {
> +		const u32 status = intel_uncore_read(uncore, ch_ctl);
> +
> +		if (status != intel_dp->aux_busy_last_status) {
> +			drm_WARN(&i915->drm, 1,
> +				 "%s: not started (status 0x%08x)\n",
> +				 intel_dp->aux.name, status);
> +			intel_dp->aux_busy_last_status = status;
> +		}
> +
> +		ret = -EBUSY;
> +		goto out;
> +	}
> +
> +	/* Only 5 data registers! */
> +	if (drm_WARN_ON(&i915->drm, send_bytes > 20 || recv_size > 20)) {
> +		ret = -E2BIG;
> +		goto out;
> +	}
> +
> +	while ((aux_clock_divider = intel_dp->get_aux_clock_divider(intel_dp, clock++))) {
> +		u32 send_ctl = intel_dp->get_aux_send_ctl(intel_dp,
> +							  send_bytes,
> +							  aux_clock_divider);
> +
> +		send_ctl |= aux_send_ctl_flags;
> +
> +		/* Must try at least 3 times according to DP spec */
> +		for (try = 0; try < 5; try++) {
> +			/* Load the send data into the aux channel data registers */
> +			for (i = 0; i < send_bytes; i += 4)
> +				intel_uncore_write(uncore,
> +						   ch_data[i >> 2],
> +						   intel_dp_pack_aux(send + i,
> +								     send_bytes - i));
> +
> +			/* Send the command and wait for it to complete */
> +			intel_uncore_write(uncore, ch_ctl, send_ctl);
> +
> +			status = intel_dp_aux_wait_done(intel_dp);
> +
> +			/* Clear done status and any errors */
> +			intel_uncore_write(uncore,
> +					   ch_ctl,
> +					   status |
> +					   DP_AUX_CH_CTL_DONE |
> +					   DP_AUX_CH_CTL_TIME_OUT_ERROR |
> +					   DP_AUX_CH_CTL_RECEIVE_ERROR);
> +
> +			/*
> +			 * DP CTS 1.2 Core Rev 1.1, 4.2.1.1 & 4.2.1.2
> +			 *   400us delay required for errors and timeouts
> +			 *   Timeout errors from the HW already meet this
> +			 *   requirement so skip to next iteration
> +			 */
> +			if (status & DP_AUX_CH_CTL_TIME_OUT_ERROR)
> +				continue;
> +
> +			if (status & DP_AUX_CH_CTL_RECEIVE_ERROR) {
> +				usleep_range(400, 500);
> +				continue;
> +			}
> +			if (status & DP_AUX_CH_CTL_DONE)
> +				goto done;
> +		}
> +	}
> +
> +	if ((status & DP_AUX_CH_CTL_DONE) == 0) {
> +		drm_err(&i915->drm, "%s: not done (status 0x%08x)\n",
> +			intel_dp->aux.name, status);
> +		ret = -EBUSY;
> +		goto out;
> +	}
> +
> +done:
> +	/*
> +	 * Check for timeout or receive error. Timeouts occur when the sink is
> +	 * not connected.
> +	 */
> +	if (status & DP_AUX_CH_CTL_RECEIVE_ERROR) {
> +		drm_err(&i915->drm, "%s: receive error (status 0x%08x)\n",
> +			intel_dp->aux.name, status);
> +		ret = -EIO;
> +		goto out;
> +	}
> +
> +	/*
> +	 * Timeouts occur when the device isn't connected, so they're "normal"
> +	 * -- don't fill the kernel log with these
> +	 */
> +	if (status & DP_AUX_CH_CTL_TIME_OUT_ERROR) {
> +		drm_dbg_kms(&i915->drm, "%s: timeout (status 0x%08x)\n",
> +			    intel_dp->aux.name, status);
> +		ret = -ETIMEDOUT;
> +		goto out;
> +	}
> +
> +	/* Unload any bytes sent back from the other side */
> +	recv_bytes = ((status & DP_AUX_CH_CTL_MESSAGE_SIZE_MASK) >>
> +		      DP_AUX_CH_CTL_MESSAGE_SIZE_SHIFT);
> +
> +	/*
> +	 * By BSpec: "Message sizes of 0 or >20 are not allowed."
> +	 * We have no idea of what happened so we return -EBUSY so
> +	 * drm layer takes care for the necessary retries.
> +	 */
> +	if (recv_bytes == 0 || recv_bytes > 20) {
> +		drm_dbg_kms(&i915->drm,
> +			    "%s: Forbidden recv_bytes = %d on aux transaction\n",
> +			    intel_dp->aux.name, recv_bytes);
> +		ret = -EBUSY;
> +		goto out;
> +	}
> +
> +	if (recv_bytes > recv_size)
> +		recv_bytes = recv_size;
> +
> +	for (i = 0; i < recv_bytes; i += 4)
> +		intel_dp_unpack_aux(intel_uncore_read(uncore, ch_data[i >> 2]),
> +				    recv + i, recv_bytes - i);
> +
> +	ret = recv_bytes;
> +out:
> +	cpu_latency_qos_update_request(&intel_dp->pm_qos, PM_QOS_DEFAULT_VALUE);
> +
> +	if (vdd)
> +		intel_pps_vdd_off_unlocked(intel_dp, false);
> +
> +	intel_pps_unlock(intel_dp, pps_wakeref);
> +	intel_display_power_put_async(i915, aux_domain, aux_wakeref);
> +
> +	if (is_tc_port)
> +		intel_tc_port_unlock(dig_port);
> +
> +	return ret;
> +}
> +
> +#define BARE_ADDRESS_SIZE	3
> +#define HEADER_SIZE		(BARE_ADDRESS_SIZE + 1)
> +
> +static void
> +intel_dp_aux_header(u8 txbuf[HEADER_SIZE],
> +		    const struct drm_dp_aux_msg *msg)
> +{
> +	txbuf[0] = (msg->request << 4) | ((msg->address >> 16) & 0xf);
> +	txbuf[1] = (msg->address >> 8) & 0xff;
> +	txbuf[2] = msg->address & 0xff;
> +	txbuf[3] = msg->size - 1;
> +}
> +
> +static u32 intel_dp_aux_xfer_flags(const struct drm_dp_aux_msg *msg)
> +{
> +	/*
> +	 * If we're trying to send the HDCP Aksv, we need to set a the Aksv
> +	 * select bit to inform the hardware to send the Aksv after our header
> +	 * since we can't access that data from software.
> +	 */
> +	if ((msg->request & ~DP_AUX_I2C_MOT) == DP_AUX_NATIVE_WRITE &&
> +	    msg->address == DP_AUX_HDCP_AKSV)
> +		return DP_AUX_CH_CTL_AUX_AKSV_SELECT;
> +
> +	return 0;
> +}
> +
> +static ssize_t
> +intel_dp_aux_transfer(struct drm_dp_aux *aux, struct drm_dp_aux_msg *msg)
> +{
> +	struct intel_dp *intel_dp = container_of(aux, struct intel_dp, aux);
> +	struct drm_i915_private *i915 = dp_to_i915(intel_dp);
> +	u8 txbuf[20], rxbuf[20];
> +	size_t txsize, rxsize;
> +	u32 flags = intel_dp_aux_xfer_flags(msg);
> +	int ret;
> +
> +	intel_dp_aux_header(txbuf, msg);
> +
> +	switch (msg->request & ~DP_AUX_I2C_MOT) {
> +	case DP_AUX_NATIVE_WRITE:
> +	case DP_AUX_I2C_WRITE:
> +	case DP_AUX_I2C_WRITE_STATUS_UPDATE:
> +		txsize = msg->size ? HEADER_SIZE + msg->size : BARE_ADDRESS_SIZE;
> +		rxsize = 2; /* 0 or 1 data bytes */
> +
> +		if (drm_WARN_ON(&i915->drm, txsize > 20))
> +			return -E2BIG;
> +
> +		drm_WARN_ON(&i915->drm, !msg->buffer != !msg->size);
> +
> +		if (msg->buffer)
> +			memcpy(txbuf + HEADER_SIZE, msg->buffer, msg->size);
> +
> +		ret = intel_dp_aux_xfer(intel_dp, txbuf, txsize,
> +					rxbuf, rxsize, flags);
> +		if (ret > 0) {
> +			msg->reply = rxbuf[0] >> 4;
> +
> +			if (ret > 1) {
> +				/* Number of bytes written in a short write. */
> +				ret = clamp_t(int, rxbuf[1], 0, msg->size);
> +			} else {
> +				/* Return payload size. */
> +				ret = msg->size;
> +			}
> +		}
> +		break;
> +
> +	case DP_AUX_NATIVE_READ:
> +	case DP_AUX_I2C_READ:
> +		txsize = msg->size ? HEADER_SIZE : BARE_ADDRESS_SIZE;
> +		rxsize = msg->size + 1;
> +
> +		if (drm_WARN_ON(&i915->drm, rxsize > 20))
> +			return -E2BIG;
> +
> +		ret = intel_dp_aux_xfer(intel_dp, txbuf, txsize,
> +					rxbuf, rxsize, flags);
> +		if (ret > 0) {
> +			msg->reply = rxbuf[0] >> 4;
> +			/*
> +			 * Assume happy day, and copy the data. The caller is
> +			 * expected to check msg->reply before touching it.
> +			 *
> +			 * Return payload size.
> +			 */
> +			ret--;
> +			memcpy(msg->buffer, rxbuf + 1, ret);
> +		}
> +		break;
> +
> +	default:
> +		ret = -EINVAL;
> +		break;
> +	}
> +
> +	return ret;
> +}
> +
> +static i915_reg_t g4x_aux_ctl_reg(struct intel_dp *intel_dp)
> +{
> +	struct drm_i915_private *dev_priv = dp_to_i915(intel_dp);
> +	struct intel_digital_port *dig_port = dp_to_dig_port(intel_dp);
> +	enum aux_ch aux_ch = dig_port->aux_ch;
> +
> +	switch (aux_ch) {
> +	case AUX_CH_B:
> +	case AUX_CH_C:
> +	case AUX_CH_D:
> +		return DP_AUX_CH_CTL(aux_ch);
> +	default:
> +		MISSING_CASE(aux_ch);
> +		return DP_AUX_CH_CTL(AUX_CH_B);
> +	}
> +}
> +
> +static i915_reg_t g4x_aux_data_reg(struct intel_dp *intel_dp, int index)
> +{
> +	struct drm_i915_private *dev_priv = dp_to_i915(intel_dp);
> +	struct intel_digital_port *dig_port = dp_to_dig_port(intel_dp);
> +	enum aux_ch aux_ch = dig_port->aux_ch;
> +
> +	switch (aux_ch) {
> +	case AUX_CH_B:
> +	case AUX_CH_C:
> +	case AUX_CH_D:
> +		return DP_AUX_CH_DATA(aux_ch, index);
> +	default:
> +		MISSING_CASE(aux_ch);
> +		return DP_AUX_CH_DATA(AUX_CH_B, index);
> +	}
> +}
> +
> +static i915_reg_t ilk_aux_ctl_reg(struct intel_dp *intel_dp)
> +{
> +	struct drm_i915_private *dev_priv = dp_to_i915(intel_dp);
> +	struct intel_digital_port *dig_port = dp_to_dig_port(intel_dp);
> +	enum aux_ch aux_ch = dig_port->aux_ch;
> +
> +	switch (aux_ch) {
> +	case AUX_CH_A:
> +		return DP_AUX_CH_CTL(aux_ch);
> +	case AUX_CH_B:
> +	case AUX_CH_C:
> +	case AUX_CH_D:
> +		return PCH_DP_AUX_CH_CTL(aux_ch);
> +	default:
> +		MISSING_CASE(aux_ch);
> +		return DP_AUX_CH_CTL(AUX_CH_A);
> +	}
> +}
> +
> +static i915_reg_t ilk_aux_data_reg(struct intel_dp *intel_dp, int index)
> +{
> +	struct drm_i915_private *dev_priv = dp_to_i915(intel_dp);
> +	struct intel_digital_port *dig_port = dp_to_dig_port(intel_dp);
> +	enum aux_ch aux_ch = dig_port->aux_ch;
> +
> +	switch (aux_ch) {
> +	case AUX_CH_A:
> +		return DP_AUX_CH_DATA(aux_ch, index);
> +	case AUX_CH_B:
> +	case AUX_CH_C:
> +	case AUX_CH_D:
> +		return PCH_DP_AUX_CH_DATA(aux_ch, index);
> +	default:
> +		MISSING_CASE(aux_ch);
> +		return DP_AUX_CH_DATA(AUX_CH_A, index);
> +	}
> +}
> +
> +static i915_reg_t skl_aux_ctl_reg(struct intel_dp *intel_dp)
> +{
> +	struct drm_i915_private *dev_priv = dp_to_i915(intel_dp);
> +	struct intel_digital_port *dig_port = dp_to_dig_port(intel_dp);
> +	enum aux_ch aux_ch = dig_port->aux_ch;
> +
> +	switch (aux_ch) {
> +	case AUX_CH_A:
> +	case AUX_CH_B:
> +	case AUX_CH_C:
> +	case AUX_CH_D:
> +	case AUX_CH_E:
> +	case AUX_CH_F:
> +		return DP_AUX_CH_CTL(aux_ch);
> +	default:
> +		MISSING_CASE(aux_ch);
> +		return DP_AUX_CH_CTL(AUX_CH_A);
> +	}
> +}
> +
> +static i915_reg_t skl_aux_data_reg(struct intel_dp *intel_dp, int index)
> +{
> +	struct drm_i915_private *dev_priv = dp_to_i915(intel_dp);
> +	struct intel_digital_port *dig_port = dp_to_dig_port(intel_dp);
> +	enum aux_ch aux_ch = dig_port->aux_ch;
> +
> +	switch (aux_ch) {
> +	case AUX_CH_A:
> +	case AUX_CH_B:
> +	case AUX_CH_C:
> +	case AUX_CH_D:
> +	case AUX_CH_E:
> +	case AUX_CH_F:
> +		return DP_AUX_CH_DATA(aux_ch, index);
> +	default:
> +		MISSING_CASE(aux_ch);
> +		return DP_AUX_CH_DATA(AUX_CH_A, index);
> +	}
> +}
> +
> +static i915_reg_t tgl_aux_ctl_reg(struct intel_dp *intel_dp)
> +{
> +	struct drm_i915_private *dev_priv = dp_to_i915(intel_dp);
> +	struct intel_digital_port *dig_port = dp_to_dig_port(intel_dp);
> +	enum aux_ch aux_ch = dig_port->aux_ch;
> +
> +	switch (aux_ch) {
> +	case AUX_CH_A:
> +	case AUX_CH_B:
> +	case AUX_CH_C:
> +	case AUX_CH_USBC1:
> +	case AUX_CH_USBC2:
> +	case AUX_CH_USBC3:
> +	case AUX_CH_USBC4:
> +	case AUX_CH_USBC5:
> +	case AUX_CH_USBC6:
> +		return DP_AUX_CH_CTL(aux_ch);
> +	default:
> +		MISSING_CASE(aux_ch);
> +		return DP_AUX_CH_CTL(AUX_CH_A);
> +	}
> +}
> +
> +static i915_reg_t tgl_aux_data_reg(struct intel_dp *intel_dp, int index)
> +{
> +	struct drm_i915_private *dev_priv = dp_to_i915(intel_dp);
> +	struct intel_digital_port *dig_port = dp_to_dig_port(intel_dp);
> +	enum aux_ch aux_ch = dig_port->aux_ch;
> +
> +	switch (aux_ch) {
> +	case AUX_CH_A:
> +	case AUX_CH_B:
> +	case AUX_CH_C:
> +	case AUX_CH_USBC1:
> +	case AUX_CH_USBC2:
> +	case AUX_CH_USBC3:
> +	case AUX_CH_USBC4:
> +	case AUX_CH_USBC5:
> +	case AUX_CH_USBC6:
> +		return DP_AUX_CH_DATA(aux_ch, index);
> +	default:
> +		MISSING_CASE(aux_ch);
> +		return DP_AUX_CH_DATA(AUX_CH_A, index);
> +	}
> +}
> +
> +void intel_dp_aux_fini(struct intel_dp *intel_dp)
> +{
> +	if (cpu_latency_qos_request_active(&intel_dp->pm_qos))
> +		cpu_latency_qos_remove_request(&intel_dp->pm_qos);
> +
> +	kfree(intel_dp->aux.name);
> +}
> +
> +void intel_dp_aux_init(struct intel_dp *intel_dp)
> +{
> +	struct drm_i915_private *dev_priv = dp_to_i915(intel_dp);
> +	struct intel_digital_port *dig_port = dp_to_dig_port(intel_dp);
> +	struct intel_encoder *encoder = &dig_port->base;
> +	enum aux_ch aux_ch = dig_port->aux_ch;
> +
> +	if (INTEL_GEN(dev_priv) >= 12) {
> +		intel_dp->aux_ch_ctl_reg = tgl_aux_ctl_reg;
> +		intel_dp->aux_ch_data_reg = tgl_aux_data_reg;
> +	} else if (INTEL_GEN(dev_priv) >= 9) {
> +		intel_dp->aux_ch_ctl_reg = skl_aux_ctl_reg;
> +		intel_dp->aux_ch_data_reg = skl_aux_data_reg;
> +	} else if (HAS_PCH_SPLIT(dev_priv)) {
> +		intel_dp->aux_ch_ctl_reg = ilk_aux_ctl_reg;
> +		intel_dp->aux_ch_data_reg = ilk_aux_data_reg;
> +	} else {
> +		intel_dp->aux_ch_ctl_reg = g4x_aux_ctl_reg;
> +		intel_dp->aux_ch_data_reg = g4x_aux_data_reg;
> +	}
> +
> +	if (INTEL_GEN(dev_priv) >= 9)
> +		intel_dp->get_aux_clock_divider = skl_get_aux_clock_divider;
> +	else if (IS_BROADWELL(dev_priv) || IS_HASWELL(dev_priv))
> +		intel_dp->get_aux_clock_divider = hsw_get_aux_clock_divider;
> +	else if (HAS_PCH_SPLIT(dev_priv))
> +		intel_dp->get_aux_clock_divider = ilk_get_aux_clock_divider;
> +	else
> +		intel_dp->get_aux_clock_divider = g4x_get_aux_clock_divider;
> +
> +	if (INTEL_GEN(dev_priv) >= 9)
> +		intel_dp->get_aux_send_ctl = skl_get_aux_send_ctl;
> +	else
> +		intel_dp->get_aux_send_ctl = g4x_get_aux_send_ctl;
> +
> +	drm_dp_aux_init(&intel_dp->aux);
> +
> +	/* Failure to allocate our preferred name is not critical */
> +	if (INTEL_GEN(dev_priv) >= 12 && aux_ch >= AUX_CH_USBC1)
> +		intel_dp->aux.name = kasprintf(GFP_KERNEL, "AUX USBC%c/%s",
> +					       aux_ch - AUX_CH_USBC1 + '1',
> +					       encoder->base.name);
> +	else
> +		intel_dp->aux.name = kasprintf(GFP_KERNEL, "AUX %c/%s",
> +					       aux_ch_name(aux_ch),
> +					       encoder->base.name);
> +
> +	intel_dp->aux.transfer = intel_dp_aux_transfer;
> +	cpu_latency_qos_add_request(&intel_dp->pm_qos, PM_QOS_DEFAULT_VALUE);
> +}
> diff --git a/drivers/gpu/drm/i915/display/intel_dp_aux.h b/drivers/gpu/drm/i915/display/intel_dp_aux.h
> new file mode 100644
> index 000000000000..cea58dd86c49
> --- /dev/null
> +++ b/drivers/gpu/drm/i915/display/intel_dp_aux.h
> @@ -0,0 +1,18 @@
> +/* SPDX-License-Identifier: MIT */
> +/*
> + * Copyright © 2020 Intel Corporation
> + */
> +
> +#ifndef __INTEL_DP_AUX_H__
> +#define __INTEL_DP_AUX_H__
> +
> +#include <linux/types.h>
> +
> +struct intel_dp;
> +
> +u32 intel_dp_pack_aux(const u8 *src, int src_bytes);
> +
> +void intel_dp_aux_fini(struct intel_dp *intel_dp);
> +void intel_dp_aux_init(struct intel_dp *intel_dp);
> +
> +#endif /* __INTEL_DP_AUX_H__ */
> diff --git a/drivers/gpu/drm/i915/display/intel_psr.c b/drivers/gpu/drm/i915/display/intel_psr.c
> index 1e6c1fa59d4a..72d4c61e142e 100644
> --- a/drivers/gpu/drm/i915/display/intel_psr.c
> +++ b/drivers/gpu/drm/i915/display/intel_psr.c
> @@ -28,9 +28,10 @@
>  #include "i915_drv.h"
>  #include "intel_atomic.h"
>  #include "intel_display_types.h"
> +#include "intel_dp_aux.h"
> +#include "intel_hdmi.h"
>  #include "intel_psr.h"
>  #include "intel_sprite.h"
> -#include "intel_hdmi.h"
>  
>  /**
>   * DOC: Panel Self Refresh (PSR/SRD)
> -- 
> 2.20.1
> 
> _______________________________________________
> Intel-gfx mailing list
> Intel-gfx@lists.freedesktop.org
> https://lists.freedesktop.org/mailman/listinfo/intel-gfx
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

  reply	other threads:[~2021-01-20 17:32 UTC|newest]

Thread overview: 13+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2021-01-20 10:18 [Intel-gfx] [PATCH 1/4] drm/i915/pps: refactor init abstractions Jani Nikula
2021-01-20 10:18 ` [Intel-gfx] [PATCH 2/4] drm/i915/pps: move pps code over from intel_display.c and refactor Jani Nikula
2021-01-20 10:18 ` [Intel-gfx] [PATCH 3/4] drm/i915/dp: abstract struct intel_dp pps members to a sub-struct Jani Nikula
2021-01-20 17:30   ` Rodrigo Vivi
2021-01-20 19:25     ` Jani Nikula
2021-01-20 20:08       ` Rodrigo Vivi
2021-01-21 11:47         ` Jani Nikula
2021-01-20 10:18 ` [Intel-gfx] [PATCH 4/4] drm/i915/dp: split out aux functionality to intel_dp_aux.c Jani Nikula
2021-01-20 17:31   ` Rodrigo Vivi [this message]
2021-01-20 14:17 ` [Intel-gfx] ✗ Fi.CI.CHECKPATCH: warning for series starting with [1/4] drm/i915/pps: refactor init abstractions Patchwork
2021-01-20 14:19 ` [Intel-gfx] ✗ Fi.CI.SPARSE: " Patchwork
2021-01-20 14:46 ` [Intel-gfx] ✓ Fi.CI.BAT: success " Patchwork
2021-01-20 16:08 ` [Intel-gfx] ✓ Fi.CI.IGT: " Patchwork

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20210120173149.GC3970@intel.com \
    --to=rodrigo.vivi@intel.com \
    --cc=intel-gfx@lists.freedesktop.org \
    --cc=jani.nikula@intel.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.