LCOV - code coverage report
Current view: top level - drivers/gpu/drm/amd/amdgpu - atombios_dp.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 0 315 0.0 %
Date: 2022-12-09 01:23:36 Functions: 0 22 0.0 %

          Line data    Source code
       1             : /*
       2             :  * Copyright 2007-8 Advanced Micro Devices, Inc.
       3             :  * Copyright 2008 Red Hat Inc.
       4             :  *
       5             :  * Permission is hereby granted, free of charge, to any person obtaining a
       6             :  * copy of this software and associated documentation files (the "Software"),
       7             :  * to deal in the Software without restriction, including without limitation
       8             :  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
       9             :  * and/or sell copies of the Software, and to permit persons to whom the
      10             :  * Software is furnished to do so, subject to the following conditions:
      11             :  *
      12             :  * The above copyright notice and this permission notice shall be included in
      13             :  * all copies or substantial portions of the Software.
      14             :  *
      15             :  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
      16             :  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
      17             :  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
      18             :  * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
      19             :  * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
      20             :  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
      21             :  * OTHER DEALINGS IN THE SOFTWARE.
      22             :  *
      23             :  * Authors: Dave Airlie
      24             :  *          Alex Deucher
      25             :  *          Jerome Glisse
      26             :  */
      27             : 
      28             : #include <drm/amdgpu_drm.h>
      29             : #include <drm/display/drm_dp_helper.h>
      30             : 
      31             : #include "amdgpu.h"
      32             : 
      33             : #include "atom.h"
      34             : #include "atom-bits.h"
      35             : #include "atombios_encoders.h"
      36             : #include "atombios_dp.h"
      37             : #include "amdgpu_connectors.h"
      38             : #include "amdgpu_atombios.h"
      39             : 
      40             : /* move these to drm_dp_helper.c/h */
      41             : #define DP_LINK_CONFIGURATION_SIZE 9
      42             : #define DP_DPCD_SIZE DP_RECEIVER_CAP_SIZE
      43             : 
      44             : static char *voltage_names[] = {
      45             :         "0.4V", "0.6V", "0.8V", "1.2V"
      46             : };
      47             : static char *pre_emph_names[] = {
      48             :         "0dB", "3.5dB", "6dB", "9.5dB"
      49             : };
      50             : 
      51             : /***** amdgpu AUX functions *****/
      52             : 
      53             : union aux_channel_transaction {
      54             :         PROCESS_AUX_CHANNEL_TRANSACTION_PS_ALLOCATION v1;
      55             :         PROCESS_AUX_CHANNEL_TRANSACTION_PARAMETERS_V2 v2;
      56             : };
      57             : 
      58           0 : static int amdgpu_atombios_dp_process_aux_ch(struct amdgpu_i2c_chan *chan,
      59             :                                       u8 *send, int send_bytes,
      60             :                                       u8 *recv, int recv_size,
      61             :                                       u8 delay, u8 *ack)
      62             : {
      63           0 :         struct drm_device *dev = chan->dev;
      64           0 :         struct amdgpu_device *adev = drm_to_adev(dev);
      65             :         union aux_channel_transaction args;
      66           0 :         int index = GetIndexIntoMasterTable(COMMAND, ProcessAuxChannelTransaction);
      67             :         unsigned char *base;
      68             :         int recv_bytes;
      69           0 :         int r = 0;
      70             : 
      71           0 :         memset(&args, 0, sizeof(args));
      72             : 
      73           0 :         mutex_lock(&chan->mutex);
      74             : 
      75           0 :         base = (unsigned char *)(adev->mode_info.atom_context->scratch + 1);
      76             : 
      77           0 :         amdgpu_atombios_copy_swap(base, send, send_bytes, true);
      78             : 
      79           0 :         args.v2.lpAuxRequest = cpu_to_le16((u16)(0 + 4));
      80           0 :         args.v2.lpDataOut = cpu_to_le16((u16)(16 + 4));
      81           0 :         args.v2.ucDataOutLen = 0;
      82           0 :         args.v2.ucChannelID = chan->rec.i2c_id;
      83           0 :         args.v2.ucDelay = delay / 10;
      84           0 :         args.v2.ucHPD_ID = chan->rec.hpd;
      85             : 
      86           0 :         amdgpu_atom_execute_table(adev->mode_info.atom_context, index, (uint32_t *)&args);
      87             : 
      88           0 :         *ack = args.v2.ucReplyStatus;
      89             : 
      90             :         /* timeout */
      91           0 :         if (args.v2.ucReplyStatus == 1) {
      92             :                 r = -ETIMEDOUT;
      93             :                 goto done;
      94             :         }
      95             : 
      96             :         /* flags not zero */
      97           0 :         if (args.v2.ucReplyStatus == 2) {
      98           0 :                 DRM_DEBUG_KMS("dp_aux_ch flags not zero\n");
      99           0 :                 r = -EIO;
     100           0 :                 goto done;
     101             :         }
     102             : 
     103             :         /* error */
     104           0 :         if (args.v2.ucReplyStatus == 3) {
     105           0 :                 DRM_DEBUG_KMS("dp_aux_ch error\n");
     106           0 :                 r = -EIO;
     107           0 :                 goto done;
     108             :         }
     109             : 
     110           0 :         recv_bytes = args.v1.ucDataOutLen;
     111           0 :         if (recv_bytes > recv_size)
     112           0 :                 recv_bytes = recv_size;
     113             : 
     114           0 :         if (recv && recv_size)
     115           0 :                 amdgpu_atombios_copy_swap(recv, base + 16, recv_bytes, false);
     116             : 
     117             :         r = recv_bytes;
     118             : done:
     119           0 :         mutex_unlock(&chan->mutex);
     120             : 
     121           0 :         return r;
     122             : }
     123             : 
     124             : #define BARE_ADDRESS_SIZE 3
     125             : #define HEADER_SIZE (BARE_ADDRESS_SIZE + 1)
     126             : 
     127             : static ssize_t
     128           0 : amdgpu_atombios_dp_aux_transfer(struct drm_dp_aux *aux, struct drm_dp_aux_msg *msg)
     129             : {
     130           0 :         struct amdgpu_i2c_chan *chan =
     131           0 :                 container_of(aux, struct amdgpu_i2c_chan, aux);
     132             :         int ret;
     133             :         u8 tx_buf[20];
     134             :         size_t tx_size;
     135           0 :         u8 ack, delay = 0;
     136             : 
     137           0 :         if (WARN_ON(msg->size > 16))
     138             :                 return -E2BIG;
     139             : 
     140           0 :         tx_buf[0] = msg->address & 0xff;
     141           0 :         tx_buf[1] = msg->address >> 8;
     142           0 :         tx_buf[2] = (msg->request << 4) |
     143           0 :                 ((msg->address >> 16) & 0xf);
     144           0 :         tx_buf[3] = msg->size ? (msg->size - 1) : 0;
     145             : 
     146           0 :         switch (msg->request & ~DP_AUX_I2C_MOT) {
     147             :         case DP_AUX_NATIVE_WRITE:
     148             :         case DP_AUX_I2C_WRITE:
     149             :                 /* tx_size needs to be 4 even for bare address packets since the atom
     150             :                  * table needs the info in tx_buf[3].
     151             :                  */
     152           0 :                 tx_size = HEADER_SIZE + msg->size;
     153           0 :                 if (msg->size == 0)
     154           0 :                         tx_buf[3] |= BARE_ADDRESS_SIZE << 4;
     155             :                 else
     156           0 :                         tx_buf[3] |= tx_size << 4;
     157           0 :                 memcpy(tx_buf + HEADER_SIZE, msg->buffer, msg->size);
     158           0 :                 ret = amdgpu_atombios_dp_process_aux_ch(chan,
     159             :                                                  tx_buf, tx_size, NULL, 0, delay, &ack);
     160           0 :                 if (ret >= 0)
     161             :                         /* Return payload size. */
     162           0 :                         ret = msg->size;
     163             :                 break;
     164             :         case DP_AUX_NATIVE_READ:
     165             :         case DP_AUX_I2C_READ:
     166             :                 /* tx_size needs to be 4 even for bare address packets since the atom
     167             :                  * table needs the info in tx_buf[3].
     168             :                  */
     169           0 :                 tx_size = HEADER_SIZE;
     170           0 :                 if (msg->size == 0)
     171           0 :                         tx_buf[3] |= BARE_ADDRESS_SIZE << 4;
     172             :                 else
     173           0 :                         tx_buf[3] |= tx_size << 4;
     174           0 :                 ret = amdgpu_atombios_dp_process_aux_ch(chan,
     175           0 :                                                  tx_buf, tx_size, msg->buffer, msg->size, delay, &ack);
     176           0 :                 break;
     177             :         default:
     178             :                 ret = -EINVAL;
     179             :                 break;
     180             :         }
     181             : 
     182           0 :         if (ret >= 0)
     183           0 :                 msg->reply = ack >> 4;
     184             : 
     185           0 :         return ret;
     186             : }
     187             : 
     188           0 : void amdgpu_atombios_dp_aux_init(struct amdgpu_connector *amdgpu_connector)
     189             : {
     190           0 :         amdgpu_connector->ddc_bus->rec.hpd = amdgpu_connector->hpd.hpd;
     191           0 :         amdgpu_connector->ddc_bus->aux.transfer = amdgpu_atombios_dp_aux_transfer;
     192           0 :         amdgpu_connector->ddc_bus->aux.drm_dev = amdgpu_connector->base.dev;
     193             : 
     194           0 :         drm_dp_aux_init(&amdgpu_connector->ddc_bus->aux);
     195           0 :         amdgpu_connector->ddc_bus->has_aux = true;
     196           0 : }
     197             : 
     198             : /***** general DP utility functions *****/
     199             : 
     200             : #define DP_VOLTAGE_MAX         DP_TRAIN_VOLTAGE_SWING_LEVEL_3
     201             : #define DP_PRE_EMPHASIS_MAX    DP_TRAIN_PRE_EMPH_LEVEL_3
     202             : 
     203           0 : static void amdgpu_atombios_dp_get_adjust_train(const u8 link_status[DP_LINK_STATUS_SIZE],
     204             :                                                 int lane_count,
     205             :                                                 u8 train_set[4])
     206             : {
     207           0 :         u8 v = 0;
     208           0 :         u8 p = 0;
     209             :         int lane;
     210             : 
     211           0 :         for (lane = 0; lane < lane_count; lane++) {
     212           0 :                 u8 this_v = drm_dp_get_adjust_request_voltage(link_status, lane);
     213           0 :                 u8 this_p = drm_dp_get_adjust_request_pre_emphasis(link_status, lane);
     214             : 
     215           0 :                 DRM_DEBUG_KMS("requested signal parameters: lane %d voltage %s pre_emph %s\n",
     216             :                           lane,
     217             :                           voltage_names[this_v >> DP_TRAIN_VOLTAGE_SWING_SHIFT],
     218             :                           pre_emph_names[this_p >> DP_TRAIN_PRE_EMPHASIS_SHIFT]);
     219             : 
     220           0 :                 if (this_v > v)
     221           0 :                         v = this_v;
     222           0 :                 if (this_p > p)
     223           0 :                         p = this_p;
     224             :         }
     225             : 
     226           0 :         if (v >= DP_VOLTAGE_MAX)
     227           0 :                 v |= DP_TRAIN_MAX_SWING_REACHED;
     228             : 
     229           0 :         if (p >= DP_PRE_EMPHASIS_MAX)
     230           0 :                 p |= DP_TRAIN_MAX_PRE_EMPHASIS_REACHED;
     231             : 
     232           0 :         DRM_DEBUG_KMS("using signal parameters: voltage %s pre_emph %s\n",
     233             :                   voltage_names[(v & DP_TRAIN_VOLTAGE_SWING_MASK) >> DP_TRAIN_VOLTAGE_SWING_SHIFT],
     234             :                   pre_emph_names[(p & DP_TRAIN_PRE_EMPHASIS_MASK) >> DP_TRAIN_PRE_EMPHASIS_SHIFT]);
     235             : 
     236           0 :         for (lane = 0; lane < 4; lane++)
     237           0 :                 train_set[lane] = v | p;
     238           0 : }
     239             : 
     240             : /* convert bits per color to bits per pixel */
     241             : /* get bpc from the EDID */
     242             : static unsigned amdgpu_atombios_dp_convert_bpc_to_bpp(int bpc)
     243             : {
     244           0 :         if (bpc == 0)
     245             :                 return 24;
     246             :         else
     247           0 :                 return bpc * 3;
     248             : }
     249             : 
     250             : /***** amdgpu specific DP functions *****/
     251             : 
     252           0 : static int amdgpu_atombios_dp_get_dp_link_config(struct drm_connector *connector,
     253             :                                                  const u8 dpcd[DP_DPCD_SIZE],
     254             :                                                  unsigned pix_clock,
     255             :                                                  unsigned *dp_lanes, unsigned *dp_rate)
     256             : {
     257           0 :         unsigned bpp =
     258           0 :                 amdgpu_atombios_dp_convert_bpc_to_bpp(amdgpu_connector_get_monitor_bpc(connector));
     259             :         static const unsigned link_rates[3] = { 162000, 270000, 540000 };
     260           0 :         unsigned max_link_rate = drm_dp_max_link_rate(dpcd);
     261           0 :         unsigned max_lane_num = drm_dp_max_lane_count(dpcd);
     262             :         unsigned lane_num, i, max_pix_clock;
     263             : 
     264           0 :         if (amdgpu_connector_encoder_get_dp_bridge_encoder_id(connector) ==
     265             :             ENCODER_OBJECT_ID_NUTMEG) {
     266           0 :                 for (lane_num = 1; lane_num <= max_lane_num; lane_num <<= 1) {
     267           0 :                         max_pix_clock = (lane_num * 270000 * 8) / bpp;
     268           0 :                         if (max_pix_clock >= pix_clock) {
     269           0 :                                 *dp_lanes = lane_num;
     270           0 :                                 *dp_rate = 270000;
     271           0 :                                 return 0;
     272             :                         }
     273             :                 }
     274             :         } else {
     275           0 :                 for (i = 0; i < ARRAY_SIZE(link_rates) && link_rates[i] <= max_link_rate; i++) {
     276           0 :                         for (lane_num = 1; lane_num <= max_lane_num; lane_num <<= 1) {
     277           0 :                                 max_pix_clock = (lane_num * link_rates[i] * 8) / bpp;
     278           0 :                                 if (max_pix_clock >= pix_clock) {
     279           0 :                                         *dp_lanes = lane_num;
     280           0 :                                         *dp_rate = link_rates[i];
     281           0 :                                         return 0;
     282             :                                 }
     283             :                         }
     284             :                 }
     285             :         }
     286             : 
     287             :         return -EINVAL;
     288             : }
     289             : 
     290           0 : static u8 amdgpu_atombios_dp_encoder_service(struct amdgpu_device *adev,
     291             :                                       int action, int dp_clock,
     292             :                                       u8 ucconfig, u8 lane_num)
     293             : {
     294             :         DP_ENCODER_SERVICE_PARAMETERS args;
     295           0 :         int index = GetIndexIntoMasterTable(COMMAND, DPEncoderService);
     296             : 
     297           0 :         memset(&args, 0, sizeof(args));
     298           0 :         args.ucLinkClock = dp_clock / 10;
     299           0 :         args.ucConfig = ucconfig;
     300           0 :         args.ucAction = action;
     301           0 :         args.ucLaneNum = lane_num;
     302           0 :         args.ucStatus = 0;
     303             : 
     304           0 :         amdgpu_atom_execute_table(adev->mode_info.atom_context, index, (uint32_t *)&args);
     305           0 :         return args.ucStatus;
     306             : }
     307             : 
     308           0 : u8 amdgpu_atombios_dp_get_sinktype(struct amdgpu_connector *amdgpu_connector)
     309             : {
     310           0 :         struct drm_device *dev = amdgpu_connector->base.dev;
     311           0 :         struct amdgpu_device *adev = drm_to_adev(dev);
     312             : 
     313           0 :         return amdgpu_atombios_dp_encoder_service(adev, ATOM_DP_ACTION_GET_SINK_TYPE, 0,
     314           0 :                                            amdgpu_connector->ddc_bus->rec.i2c_id, 0);
     315             : }
     316             : 
     317           0 : static void amdgpu_atombios_dp_probe_oui(struct amdgpu_connector *amdgpu_connector)
     318             : {
     319           0 :         struct amdgpu_connector_atom_dig *dig_connector = amdgpu_connector->con_priv;
     320             :         u8 buf[3];
     321             : 
     322           0 :         if (!(dig_connector->dpcd[DP_DOWN_STREAM_PORT_COUNT] & DP_OUI_SUPPORT))
     323           0 :                 return;
     324             : 
     325           0 :         if (drm_dp_dpcd_read(&amdgpu_connector->ddc_bus->aux, DP_SINK_OUI, buf, 3) == 3)
     326           0 :                 DRM_DEBUG_KMS("Sink OUI: %02hx%02hx%02hx\n",
     327             :                               buf[0], buf[1], buf[2]);
     328             : 
     329           0 :         if (drm_dp_dpcd_read(&amdgpu_connector->ddc_bus->aux, DP_BRANCH_OUI, buf, 3) == 3)
     330           0 :                 DRM_DEBUG_KMS("Branch OUI: %02hx%02hx%02hx\n",
     331             :                               buf[0], buf[1], buf[2]);
     332             : }
     333             : 
     334           0 : static void amdgpu_atombios_dp_ds_ports(struct amdgpu_connector *amdgpu_connector)
     335             : {
     336           0 :         struct amdgpu_connector_atom_dig *dig_connector = amdgpu_connector->con_priv;
     337             :         int ret;
     338             : 
     339           0 :         if (dig_connector->dpcd[DP_DPCD_REV] > 0x10) {
     340           0 :                 ret = drm_dp_dpcd_read(&amdgpu_connector->ddc_bus->aux,
     341             :                                        DP_DOWNSTREAM_PORT_0,
     342           0 :                                        dig_connector->downstream_ports,
     343             :                                        DP_MAX_DOWNSTREAM_PORTS);
     344           0 :                 if (ret)
     345           0 :                         memset(dig_connector->downstream_ports, 0,
     346             :                                DP_MAX_DOWNSTREAM_PORTS);
     347             :         }
     348           0 : }
     349             : 
     350           0 : int amdgpu_atombios_dp_get_dpcd(struct amdgpu_connector *amdgpu_connector)
     351             : {
     352           0 :         struct amdgpu_connector_atom_dig *dig_connector = amdgpu_connector->con_priv;
     353             :         u8 msg[DP_DPCD_SIZE];
     354             :         int ret;
     355             : 
     356           0 :         ret = drm_dp_dpcd_read(&amdgpu_connector->ddc_bus->aux, DP_DPCD_REV,
     357             :                                msg, DP_DPCD_SIZE);
     358           0 :         if (ret == DP_DPCD_SIZE) {
     359           0 :                 memcpy(dig_connector->dpcd, msg, DP_DPCD_SIZE);
     360             : 
     361           0 :                 DRM_DEBUG_KMS("DPCD: %*ph\n", (int)sizeof(dig_connector->dpcd),
     362             :                               dig_connector->dpcd);
     363             : 
     364           0 :                 amdgpu_atombios_dp_probe_oui(amdgpu_connector);
     365           0 :                 amdgpu_atombios_dp_ds_ports(amdgpu_connector);
     366           0 :                 return 0;
     367             :         }
     368             : 
     369           0 :         dig_connector->dpcd[0] = 0;
     370           0 :         return -EINVAL;
     371             : }
     372             : 
     373           0 : int amdgpu_atombios_dp_get_panel_mode(struct drm_encoder *encoder,
     374             :                                struct drm_connector *connector)
     375             : {
     376           0 :         struct amdgpu_connector *amdgpu_connector = to_amdgpu_connector(connector);
     377           0 :         int panel_mode = DP_PANEL_MODE_EXTERNAL_DP_MODE;
     378           0 :         u16 dp_bridge = amdgpu_connector_encoder_get_dp_bridge_encoder_id(connector);
     379             :         u8 tmp;
     380             : 
     381           0 :         if (!amdgpu_connector->con_priv)
     382             :                 return panel_mode;
     383             : 
     384           0 :         if (dp_bridge != ENCODER_OBJECT_ID_NONE) {
     385             :                 /* DP bridge chips */
     386           0 :                 if (drm_dp_dpcd_readb(&amdgpu_connector->ddc_bus->aux,
     387             :                                       DP_EDP_CONFIGURATION_CAP, &tmp) == 1) {
     388           0 :                         if (tmp & 1)
     389             :                                 panel_mode = DP_PANEL_MODE_INTERNAL_DP2_MODE;
     390           0 :                         else if ((dp_bridge == ENCODER_OBJECT_ID_NUTMEG) ||
     391             :                                  (dp_bridge == ENCODER_OBJECT_ID_TRAVIS))
     392             :                                 panel_mode = DP_PANEL_MODE_INTERNAL_DP1_MODE;
     393             :                         else
     394           0 :                                 panel_mode = DP_PANEL_MODE_EXTERNAL_DP_MODE;
     395             :                 }
     396           0 :         } else if (connector->connector_type == DRM_MODE_CONNECTOR_eDP) {
     397             :                 /* eDP */
     398           0 :                 if (drm_dp_dpcd_readb(&amdgpu_connector->ddc_bus->aux,
     399             :                                       DP_EDP_CONFIGURATION_CAP, &tmp) == 1) {
     400           0 :                         if (tmp & 1)
     401           0 :                                 panel_mode = DP_PANEL_MODE_INTERNAL_DP2_MODE;
     402             :                 }
     403             :         }
     404             : 
     405             :         return panel_mode;
     406             : }
     407             : 
     408           0 : void amdgpu_atombios_dp_set_link_config(struct drm_connector *connector,
     409             :                                  const struct drm_display_mode *mode)
     410             : {
     411           0 :         struct amdgpu_connector *amdgpu_connector = to_amdgpu_connector(connector);
     412             :         struct amdgpu_connector_atom_dig *dig_connector;
     413             :         int ret;
     414             : 
     415           0 :         if (!amdgpu_connector->con_priv)
     416             :                 return;
     417           0 :         dig_connector = amdgpu_connector->con_priv;
     418             : 
     419           0 :         if ((dig_connector->dp_sink_type == CONNECTOR_OBJECT_ID_DISPLAYPORT) ||
     420             :             (dig_connector->dp_sink_type == CONNECTOR_OBJECT_ID_eDP)) {
     421           0 :                 ret = amdgpu_atombios_dp_get_dp_link_config(connector, dig_connector->dpcd,
     422           0 :                                                             mode->clock,
     423           0 :                                                             &dig_connector->dp_lane_count,
     424           0 :                                                             &dig_connector->dp_clock);
     425           0 :                 if (ret) {
     426           0 :                         dig_connector->dp_clock = 0;
     427           0 :                         dig_connector->dp_lane_count = 0;
     428             :                 }
     429             :         }
     430             : }
     431             : 
     432           0 : int amdgpu_atombios_dp_mode_valid_helper(struct drm_connector *connector,
     433             :                                   struct drm_display_mode *mode)
     434             : {
     435           0 :         struct amdgpu_connector *amdgpu_connector = to_amdgpu_connector(connector);
     436             :         struct amdgpu_connector_atom_dig *dig_connector;
     437             :         unsigned dp_lanes, dp_clock;
     438             :         int ret;
     439             : 
     440           0 :         if (!amdgpu_connector->con_priv)
     441             :                 return MODE_CLOCK_HIGH;
     442           0 :         dig_connector = amdgpu_connector->con_priv;
     443             : 
     444           0 :         ret = amdgpu_atombios_dp_get_dp_link_config(connector, dig_connector->dpcd,
     445           0 :                                                     mode->clock, &dp_lanes, &dp_clock);
     446           0 :         if (ret)
     447             :                 return MODE_CLOCK_HIGH;
     448             : 
     449           0 :         if ((dp_clock == 540000) &&
     450           0 :             (!amdgpu_connector_is_dp12_capable(connector)))
     451             :                 return MODE_CLOCK_HIGH;
     452             : 
     453             :         return MODE_OK;
     454             : }
     455             : 
     456           0 : bool amdgpu_atombios_dp_needs_link_train(struct amdgpu_connector *amdgpu_connector)
     457             : {
     458             :         u8 link_status[DP_LINK_STATUS_SIZE];
     459           0 :         struct amdgpu_connector_atom_dig *dig = amdgpu_connector->con_priv;
     460             : 
     461           0 :         if (drm_dp_dpcd_read_link_status(&amdgpu_connector->ddc_bus->aux, link_status)
     462             :             <= 0)
     463             :                 return false;
     464           0 :         if (drm_dp_channel_eq_ok(link_status, dig->dp_lane_count))
     465             :                 return false;
     466           0 :         return true;
     467             : }
     468             : 
     469           0 : void amdgpu_atombios_dp_set_rx_power_state(struct drm_connector *connector,
     470             :                                     u8 power_state)
     471             : {
     472           0 :         struct amdgpu_connector *amdgpu_connector = to_amdgpu_connector(connector);
     473             :         struct amdgpu_connector_atom_dig *dig_connector;
     474             : 
     475           0 :         if (!amdgpu_connector->con_priv)
     476             :                 return;
     477             : 
     478           0 :         dig_connector = amdgpu_connector->con_priv;
     479             : 
     480             :         /* power up/down the sink */
     481           0 :         if (dig_connector->dpcd[0] >= 0x11) {
     482           0 :                 drm_dp_dpcd_writeb(&amdgpu_connector->ddc_bus->aux,
     483             :                                    DP_SET_POWER, power_state);
     484             :                 usleep_range(1000, 2000);
     485             :         }
     486             : }
     487             : 
     488             : struct amdgpu_atombios_dp_link_train_info {
     489             :         struct amdgpu_device *adev;
     490             :         struct drm_encoder *encoder;
     491             :         struct drm_connector *connector;
     492             :         int dp_clock;
     493             :         int dp_lane_count;
     494             :         bool tp3_supported;
     495             :         u8 dpcd[DP_RECEIVER_CAP_SIZE];
     496             :         u8 train_set[4];
     497             :         u8 link_status[DP_LINK_STATUS_SIZE];
     498             :         u8 tries;
     499             :         struct drm_dp_aux *aux;
     500             : };
     501             : 
     502             : static void
     503           0 : amdgpu_atombios_dp_update_vs_emph(struct amdgpu_atombios_dp_link_train_info *dp_info)
     504             : {
     505             :         /* set the initial vs/emph on the source */
     506           0 :         amdgpu_atombios_encoder_setup_dig_transmitter(dp_info->encoder,
     507             :                                                ATOM_TRANSMITTER_ACTION_SETUP_VSEMPH,
     508           0 :                                                0, dp_info->train_set[0]); /* sets all lanes at once */
     509             : 
     510             :         /* set the vs/emph on the sink */
     511           0 :         drm_dp_dpcd_write(dp_info->aux, DP_TRAINING_LANE0_SET,
     512           0 :                           dp_info->train_set, dp_info->dp_lane_count);
     513           0 : }
     514             : 
     515             : static void
     516           0 : amdgpu_atombios_dp_set_tp(struct amdgpu_atombios_dp_link_train_info *dp_info, int tp)
     517             : {
     518           0 :         int rtp = 0;
     519             : 
     520             :         /* set training pattern on the source */
     521           0 :         switch (tp) {
     522             :         case DP_TRAINING_PATTERN_1:
     523             :                 rtp = ATOM_ENCODER_CMD_DP_LINK_TRAINING_PATTERN1;
     524             :                 break;
     525             :         case DP_TRAINING_PATTERN_2:
     526             :                 rtp = ATOM_ENCODER_CMD_DP_LINK_TRAINING_PATTERN2;
     527             :                 break;
     528             :         case DP_TRAINING_PATTERN_3:
     529             :                 rtp = ATOM_ENCODER_CMD_DP_LINK_TRAINING_PATTERN3;
     530             :                         break;
     531             :         }
     532           0 :         amdgpu_atombios_encoder_setup_dig_encoder(dp_info->encoder, rtp, 0);
     533             : 
     534             :         /* enable training pattern on the sink */
     535           0 :         drm_dp_dpcd_writeb(dp_info->aux, DP_TRAINING_PATTERN_SET, tp);
     536           0 : }
     537             : 
     538             : static int
     539           0 : amdgpu_atombios_dp_link_train_init(struct amdgpu_atombios_dp_link_train_info *dp_info)
     540             : {
     541           0 :         struct amdgpu_encoder *amdgpu_encoder = to_amdgpu_encoder(dp_info->encoder);
     542           0 :         struct amdgpu_encoder_atom_dig *dig = amdgpu_encoder->enc_priv;
     543             :         u8 tmp;
     544             : 
     545             :         /* power up the sink */
     546           0 :         amdgpu_atombios_dp_set_rx_power_state(dp_info->connector, DP_SET_POWER_D0);
     547             : 
     548             :         /* possibly enable downspread on the sink */
     549           0 :         if (dp_info->dpcd[3] & 0x1)
     550           0 :                 drm_dp_dpcd_writeb(dp_info->aux,
     551             :                                    DP_DOWNSPREAD_CTRL, DP_SPREAD_AMP_0_5);
     552             :         else
     553           0 :                 drm_dp_dpcd_writeb(dp_info->aux,
     554             :                                    DP_DOWNSPREAD_CTRL, 0);
     555             : 
     556           0 :         if (dig->panel_mode == DP_PANEL_MODE_INTERNAL_DP2_MODE)
     557           0 :                 drm_dp_dpcd_writeb(dp_info->aux, DP_EDP_CONFIGURATION_SET, 1);
     558             : 
     559             :         /* set the lane count on the sink */
     560           0 :         tmp = dp_info->dp_lane_count;
     561           0 :         if (drm_dp_enhanced_frame_cap(dp_info->dpcd))
     562           0 :                 tmp |= DP_LANE_COUNT_ENHANCED_FRAME_EN;
     563           0 :         drm_dp_dpcd_writeb(dp_info->aux, DP_LANE_COUNT_SET, tmp);
     564             : 
     565             :         /* set the link rate on the sink */
     566           0 :         tmp = drm_dp_link_rate_to_bw_code(dp_info->dp_clock);
     567           0 :         drm_dp_dpcd_writeb(dp_info->aux, DP_LINK_BW_SET, tmp);
     568             : 
     569             :         /* start training on the source */
     570           0 :         amdgpu_atombios_encoder_setup_dig_encoder(dp_info->encoder,
     571             :                                            ATOM_ENCODER_CMD_DP_LINK_TRAINING_START, 0);
     572             : 
     573             :         /* disable the training pattern on the sink */
     574           0 :         drm_dp_dpcd_writeb(dp_info->aux,
     575             :                            DP_TRAINING_PATTERN_SET,
     576             :                            DP_TRAINING_PATTERN_DISABLE);
     577             : 
     578           0 :         return 0;
     579             : }
     580             : 
     581             : static int
     582           0 : amdgpu_atombios_dp_link_train_finish(struct amdgpu_atombios_dp_link_train_info *dp_info)
     583             : {
     584           0 :         udelay(400);
     585             : 
     586             :         /* disable the training pattern on the sink */
     587           0 :         drm_dp_dpcd_writeb(dp_info->aux,
     588             :                            DP_TRAINING_PATTERN_SET,
     589             :                            DP_TRAINING_PATTERN_DISABLE);
     590             : 
     591             :         /* disable the training pattern on the source */
     592           0 :         amdgpu_atombios_encoder_setup_dig_encoder(dp_info->encoder,
     593             :                                            ATOM_ENCODER_CMD_DP_LINK_TRAINING_COMPLETE, 0);
     594             : 
     595           0 :         return 0;
     596             : }
     597             : 
     598             : static int
     599           0 : amdgpu_atombios_dp_link_train_cr(struct amdgpu_atombios_dp_link_train_info *dp_info)
     600             : {
     601             :         bool clock_recovery;
     602             :         u8 voltage;
     603             :         int i;
     604             : 
     605           0 :         amdgpu_atombios_dp_set_tp(dp_info, DP_TRAINING_PATTERN_1);
     606           0 :         memset(dp_info->train_set, 0, 4);
     607           0 :         amdgpu_atombios_dp_update_vs_emph(dp_info);
     608             : 
     609           0 :         udelay(400);
     610             : 
     611             :         /* clock recovery loop */
     612           0 :         clock_recovery = false;
     613           0 :         dp_info->tries = 0;
     614           0 :         voltage = 0xff;
     615             :         while (1) {
     616           0 :                 drm_dp_link_train_clock_recovery_delay(dp_info->aux, dp_info->dpcd);
     617             : 
     618           0 :                 if (drm_dp_dpcd_read_link_status(dp_info->aux,
     619           0 :                                                  dp_info->link_status) <= 0) {
     620           0 :                         DRM_ERROR("displayport link status failed\n");
     621           0 :                         break;
     622             :                 }
     623             : 
     624           0 :                 if (drm_dp_clock_recovery_ok(dp_info->link_status, dp_info->dp_lane_count)) {
     625             :                         clock_recovery = true;
     626             :                         break;
     627             :                 }
     628             : 
     629           0 :                 for (i = 0; i < dp_info->dp_lane_count; i++) {
     630           0 :                         if ((dp_info->train_set[i] & DP_TRAIN_MAX_SWING_REACHED) == 0)
     631             :                                 break;
     632             :                 }
     633           0 :                 if (i == dp_info->dp_lane_count) {
     634           0 :                         DRM_ERROR("clock recovery reached max voltage\n");
     635           0 :                         break;
     636             :                 }
     637             : 
     638           0 :                 if ((dp_info->train_set[0] & DP_TRAIN_VOLTAGE_SWING_MASK) == voltage) {
     639           0 :                         ++dp_info->tries;
     640           0 :                         if (dp_info->tries == 5) {
     641           0 :                                 DRM_ERROR("clock recovery tried 5 times\n");
     642           0 :                                 break;
     643             :                         }
     644             :                 } else
     645           0 :                         dp_info->tries = 0;
     646             : 
     647           0 :                 voltage = dp_info->train_set[0] & DP_TRAIN_VOLTAGE_SWING_MASK;
     648             : 
     649             :                 /* Compute new train_set as requested by sink */
     650           0 :                 amdgpu_atombios_dp_get_adjust_train(dp_info->link_status, dp_info->dp_lane_count,
     651             :                                              dp_info->train_set);
     652             : 
     653           0 :                 amdgpu_atombios_dp_update_vs_emph(dp_info);
     654             :         }
     655           0 :         if (!clock_recovery) {
     656           0 :                 DRM_ERROR("clock recovery failed\n");
     657           0 :                 return -1;
     658             :         } else {
     659           0 :                 DRM_DEBUG_KMS("clock recovery at voltage %d pre-emphasis %d\n",
     660             :                           dp_info->train_set[0] & DP_TRAIN_VOLTAGE_SWING_MASK,
     661             :                           (dp_info->train_set[0] & DP_TRAIN_PRE_EMPHASIS_MASK) >>
     662             :                           DP_TRAIN_PRE_EMPHASIS_SHIFT);
     663           0 :                 return 0;
     664             :         }
     665             : }
     666             : 
     667             : static int
     668           0 : amdgpu_atombios_dp_link_train_ce(struct amdgpu_atombios_dp_link_train_info *dp_info)
     669             : {
     670             :         bool channel_eq;
     671             : 
     672           0 :         if (dp_info->tp3_supported)
     673           0 :                 amdgpu_atombios_dp_set_tp(dp_info, DP_TRAINING_PATTERN_3);
     674             :         else
     675           0 :                 amdgpu_atombios_dp_set_tp(dp_info, DP_TRAINING_PATTERN_2);
     676             : 
     677             :         /* channel equalization loop */
     678           0 :         dp_info->tries = 0;
     679           0 :         channel_eq = false;
     680             :         while (1) {
     681           0 :                 drm_dp_link_train_channel_eq_delay(dp_info->aux, dp_info->dpcd);
     682             : 
     683           0 :                 if (drm_dp_dpcd_read_link_status(dp_info->aux,
     684           0 :                                                  dp_info->link_status) <= 0) {
     685           0 :                         DRM_ERROR("displayport link status failed\n");
     686           0 :                         break;
     687             :                 }
     688             : 
     689           0 :                 if (drm_dp_channel_eq_ok(dp_info->link_status, dp_info->dp_lane_count)) {
     690             :                         channel_eq = true;
     691             :                         break;
     692             :                 }
     693             : 
     694             :                 /* Try 5 times */
     695           0 :                 if (dp_info->tries > 5) {
     696           0 :                         DRM_ERROR("channel eq failed: 5 tries\n");
     697           0 :                         break;
     698             :                 }
     699             : 
     700             :                 /* Compute new train_set as requested by sink */
     701           0 :                 amdgpu_atombios_dp_get_adjust_train(dp_info->link_status, dp_info->dp_lane_count,
     702           0 :                                              dp_info->train_set);
     703             : 
     704           0 :                 amdgpu_atombios_dp_update_vs_emph(dp_info);
     705           0 :                 dp_info->tries++;
     706             :         }
     707             : 
     708           0 :         if (!channel_eq) {
     709           0 :                 DRM_ERROR("channel eq failed\n");
     710           0 :                 return -1;
     711             :         } else {
     712           0 :                 DRM_DEBUG_KMS("channel eq at voltage %d pre-emphasis %d\n",
     713             :                           dp_info->train_set[0] & DP_TRAIN_VOLTAGE_SWING_MASK,
     714             :                           (dp_info->train_set[0] & DP_TRAIN_PRE_EMPHASIS_MASK)
     715             :                           >> DP_TRAIN_PRE_EMPHASIS_SHIFT);
     716           0 :                 return 0;
     717             :         }
     718             : }
     719             : 
     720           0 : void amdgpu_atombios_dp_link_train(struct drm_encoder *encoder,
     721             :                             struct drm_connector *connector)
     722             : {
     723           0 :         struct drm_device *dev = encoder->dev;
     724           0 :         struct amdgpu_device *adev = drm_to_adev(dev);
     725           0 :         struct amdgpu_encoder *amdgpu_encoder = to_amdgpu_encoder(encoder);
     726             :         struct amdgpu_connector *amdgpu_connector;
     727             :         struct amdgpu_connector_atom_dig *dig_connector;
     728             :         struct amdgpu_atombios_dp_link_train_info dp_info;
     729             :         u8 tmp;
     730             : 
     731           0 :         if (!amdgpu_encoder->enc_priv)
     732           0 :                 return;
     733             : 
     734           0 :         amdgpu_connector = to_amdgpu_connector(connector);
     735           0 :         if (!amdgpu_connector->con_priv)
     736             :                 return;
     737           0 :         dig_connector = amdgpu_connector->con_priv;
     738             : 
     739           0 :         if ((dig_connector->dp_sink_type != CONNECTOR_OBJECT_ID_DISPLAYPORT) &&
     740             :             (dig_connector->dp_sink_type != CONNECTOR_OBJECT_ID_eDP))
     741             :                 return;
     742             : 
     743           0 :         if (drm_dp_dpcd_readb(&amdgpu_connector->ddc_bus->aux, DP_MAX_LANE_COUNT, &tmp)
     744             :             == 1) {
     745           0 :                 if (tmp & DP_TPS3_SUPPORTED)
     746           0 :                         dp_info.tp3_supported = true;
     747             :                 else
     748           0 :                         dp_info.tp3_supported = false;
     749             :         } else {
     750           0 :                 dp_info.tp3_supported = false;
     751             :         }
     752             : 
     753           0 :         memcpy(dp_info.dpcd, dig_connector->dpcd, DP_RECEIVER_CAP_SIZE);
     754           0 :         dp_info.adev = adev;
     755           0 :         dp_info.encoder = encoder;
     756           0 :         dp_info.connector = connector;
     757           0 :         dp_info.dp_lane_count = dig_connector->dp_lane_count;
     758           0 :         dp_info.dp_clock = dig_connector->dp_clock;
     759           0 :         dp_info.aux = &amdgpu_connector->ddc_bus->aux;
     760             : 
     761           0 :         if (amdgpu_atombios_dp_link_train_init(&dp_info))
     762             :                 goto done;
     763           0 :         if (amdgpu_atombios_dp_link_train_cr(&dp_info))
     764             :                 goto done;
     765           0 :         if (amdgpu_atombios_dp_link_train_ce(&dp_info))
     766             :                 goto done;
     767             : done:
     768           0 :         if (amdgpu_atombios_dp_link_train_finish(&dp_info))
     769             :                 return;
     770             : }

Generated by: LCOV version 1.14