From: "Gupta, Anshuman" <anshuman.gupta@intel.com>
To: "Nikula, Jani" <jani.nikula@intel.com>,
"intel-gfx@lists.freedesktop.org"
<intel-gfx@lists.freedesktop.org>
Cc: "Nikula, Jani" <jani.nikula@intel.com>
Subject: Re: [Intel-gfx] [PATCH v2 17/17] drm/i915/dp: split out aux functionality to intel_dp_aux.c
Date: Wed, 20 Jan 2021 04:44:47 +0000 [thread overview]
Message-ID: <6b8a6fc970a842e2b1b68cac23b5f1f7@intel.com> (raw)
In-Reply-To: <bbd62ab6dade23932b8bfa0a382923628f18e3d1.1610127741.git.jani.nikula@intel.com>
> -----Original Message-----
> From: Jani Nikula <jani.nikula@intel.com>
> Sent: Friday, January 8, 2021 11:14 PM
> To: intel-gfx@lists.freedesktop.org
> Cc: Nikula, Jani <jani.nikula@intel.com>; Gupta, Anshuman
> <anshuman.gupta@intel.com>; ville.syrjala@linux.intel.com
> Subject: [PATCH v2 17/17] drm/i915/dp: split out aux functionality to
> intel_dp_aux.c
>
> Split out the DP aux functionality to a new intel_dp_aux.[ch]. This is a
> surprisingly clean cut.
>
> 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_aux.c | 687
> ++++++++++++++++++++ drivers/gpu/drm/i915/display/intel_dp_aux.h |
> 18 +
> 4 files changed, 707 insertions(+), 679 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 8a04403a11bb..71df8cbd63bc
> 100644
> --- a/drivers/gpu/drm/i915/Makefile
> +++ b/drivers/gpu/drm/i915/Makefile
> @@ -238,6 +238,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 e6859b9925b9..1705d58bf64c 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"
> @@ -856,684 +856,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_aux.c
> b/drivers/gpu/drm/i915/display/intel_dp_aux.c
> new file mode 100644
> index 000000000000..3d96ab5851df
> --- /dev/null
> +++ b/drivers/gpu/drm/i915/display/intel_dp_aux.c
> @@ -0,0 +1,687 @@
> +// SPDX-License-Identifier: MIT
> +/*
> + * Copyright © 2020 Intel Corporation
> + */
> +
> +#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);
This declaration has not removed from intel_dp.h in this patch.
Thanks,
Anshuman Gupta.
> +
> +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__ */
> --
> 2.20.1
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx
next prev parent reply other threads:[~2021-01-20 4:44 UTC|newest]
Thread overview: 37+ messages / expand[flat|nested] mbox.gz Atom feed top
2021-01-08 17:44 [Intel-gfx] [PATCH v2 00/17] drm/i915/dp: split out pps and aux Jani Nikula
2021-01-08 17:44 ` [Intel-gfx] [PATCH v2 01/17] drm/i915/pps: abstract panel power sequencer from intel_dp.c Jani Nikula
2021-01-13 15:34 ` Jani Nikula
2021-01-13 16:47 ` Anshuman Gupta
2021-01-08 17:44 ` [Intel-gfx] [PATCH v2 02/17] drm/i915/pps: rename pps_{, un}lock -> intel_pps_{, un}lock Jani Nikula
2021-01-08 17:44 ` [Intel-gfx] [PATCH v2 03/17] drm/i915/pps: rename intel_edp_backlight_* to intel_pps_backlight_* Jani Nikula
2021-01-08 17:44 ` [Intel-gfx] [PATCH v2 04/17] drm/i915/pps: rename intel_edp_panel_* to intel_pps_* Jani Nikula
2021-01-13 10:39 ` Anshuman Gupta
2021-01-08 17:44 ` [Intel-gfx] [PATCH v2 05/17] drm/i915/pps: rename edp_panel_* to intel_pps_*_unlocked Jani Nikula
2021-01-13 10:41 ` Anshuman Gupta
2021-01-08 17:44 ` [Intel-gfx] [PATCH v2 06/17] drm/i915/pps: abstract intel_pps_vdd_off_sync Jani Nikula
2021-01-13 10:42 ` Anshuman Gupta
2021-01-08 17:44 ` [Intel-gfx] [PATCH v2 07/17] drm/i915/pps: add higher level intel_pps_init() call Jani Nikula
2021-01-08 17:44 ` [Intel-gfx] [PATCH v2 08/17] drm/i915/pps: abstract intel_pps_encoder_reset() Jani Nikula
2021-01-08 17:44 ` [Intel-gfx] [PATCH v2 09/17] drm/i915/pps: rename intel_dp_check_edp to intel_pps_check_power_unlocked Jani Nikula
2021-01-08 17:44 ` [Intel-gfx] [PATCH v2 10/17] drm/i915/pps: rename intel_power_sequencer_reset to intel_pps_reset_all Jani Nikula
2021-01-08 17:44 ` [Intel-gfx] [PATCH v2 11/17] drm/i915/pps: add locked intel_pps_wait_power_cycle Jani Nikula
2021-01-08 17:44 ` [Intel-gfx] [PATCH v2 12/17] drm/i915/pps: rename vlv_init_panel_power_sequencer to vlv_pps_init Jani Nikula
2021-01-08 17:44 ` [Intel-gfx] [PATCH v2 13/17] drm/i915/pps: rename intel_dp_init_panel_power_sequencer* functions Jani Nikula
2021-01-13 11:02 ` Anshuman Gupta
2021-01-14 8:31 ` Jani Nikula
2021-01-08 17:44 ` [Intel-gfx] [PATCH v2 14/17] drm/i915/pps: refactor init abstractions Jani Nikula
2021-01-13 11:44 ` Anshuman Gupta
2021-01-14 8:46 ` Jani Nikula
2021-01-20 4:20 ` Gupta, Anshuman
2021-01-08 17:44 ` [Intel-gfx] [PATCH v2 15/17] drm/i915/pps: move pps code over from intel_display.c and refactor Jani Nikula
2021-01-13 11:55 ` Anshuman Gupta
2021-01-14 8:56 ` Jani Nikula
2021-01-20 4:22 ` Gupta, Anshuman
2021-01-08 17:44 ` [Intel-gfx] [PATCH v2 16/17] drm/i915/dp: abstract struct intel_dp pps members to a sub-struct Jani Nikula
2021-01-13 11:58 ` Anshuman Gupta
2021-01-08 17:44 ` [Intel-gfx] [PATCH v2 17/17] drm/i915/dp: split out aux functionality to intel_dp_aux.c Jani Nikula
2021-01-20 4:44 ` Gupta, Anshuman [this message]
2021-01-08 19:23 ` [Intel-gfx] ✗ Fi.CI.CHECKPATCH: warning for drm/i915/dp: split out pps and aux (rev2) Patchwork
2021-01-08 19:24 ` [Intel-gfx] ✗ Fi.CI.SPARSE: " Patchwork
2021-01-08 19:52 ` [Intel-gfx] ✓ Fi.CI.BAT: success " Patchwork
2021-01-09 1:05 ` [Intel-gfx] ✗ Fi.CI.IGT: failure " 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=6b8a6fc970a842e2b1b68cac23b5f1f7@intel.com \
--to=anshuman.gupta@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.