LCOV - code coverage report
Current view: top level - dev/pci/drm/radeon - radeon_dp_auxch.c (source / functions) Hit Total Coverage
Test: 6.4 Lines: 0 70 0.0 %
Date: 2018-10-19 03:25:38 Functions: 0 1 0.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*
       2             :  * Copyright 2015 Red Hat Inc.
       3             :  *
       4             :  * Permission is hereby granted, free of charge, to any person obtaining a
       5             :  * copy of this software and associated documentation files (the "Software"),
       6             :  * to deal in the Software without restriction, including without limitation
       7             :  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
       8             :  * and/or sell copies of the Software, and to permit persons to whom the
       9             :  * Software is furnished to do so, subject to the following conditions:
      10             :  *
      11             :  * The above copyright notice and this permission notice shall be included in
      12             :  * all copies or substantial portions of the Software.
      13             :  *
      14             :  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
      15             :  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
      16             :  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
      17             :  * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
      18             :  * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
      19             :  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
      20             :  * OTHER DEALINGS IN THE SOFTWARE.
      21             :  *
      22             :  * Authors: Dave Airlie
      23             :  */
      24             : #include <dev/pci/drm/drmP.h>
      25             : #include <dev/pci/drm/radeon_drm.h>
      26             : #include "radeon.h"
      27             : #include "nid.h"
      28             : 
      29             : #define AUX_RX_ERROR_FLAGS (AUX_SW_RX_OVERFLOW |             \
      30             :                             AUX_SW_RX_HPD_DISCON |           \
      31             :                             AUX_SW_RX_PARTIAL_BYTE |         \
      32             :                             AUX_SW_NON_AUX_MODE |            \
      33             :                             AUX_SW_RX_SYNC_INVALID_L |       \
      34             :                             AUX_SW_RX_SYNC_INVALID_H |       \
      35             :                             AUX_SW_RX_INVALID_START |        \
      36             :                             AUX_SW_RX_RECV_NO_DET |          \
      37             :                             AUX_SW_RX_RECV_INVALID_H |       \
      38             :                             AUX_SW_RX_RECV_INVALID_V)
      39             : 
      40             : #define AUX_SW_REPLY_GET_BYTE_COUNT(x) (((x) >> 24) & 0x1f)
      41             : 
      42             : #define BARE_ADDRESS_SIZE 3
      43             : 
      44             : static const u32 aux_offset[] =
      45             : {
      46             :         0x6200 - 0x6200,
      47             :         0x6250 - 0x6200,
      48             :         0x62a0 - 0x6200,
      49             :         0x6300 - 0x6200,
      50             :         0x6350 - 0x6200,
      51             :         0x63a0 - 0x6200,
      52             : };
      53             : 
      54             : ssize_t
      55           0 : radeon_dp_aux_transfer_native(struct drm_dp_aux *aux, struct drm_dp_aux_msg *msg)
      56             : {
      57             :         struct radeon_i2c_chan *chan =
      58           0 :                 container_of(aux, struct radeon_i2c_chan, aux);
      59           0 :         struct drm_device *dev = chan->dev;
      60           0 :         struct radeon_device *rdev = dev->dev_private;
      61             :         int ret = 0, i;
      62             :         uint32_t tmp, ack = 0;
      63           0 :         int instance = chan->rec.i2c_id & 0xf;
      64             :         u8 byte;
      65           0 :         u8 *buf = msg->buffer;
      66             :         int retry_count = 0;
      67             :         int bytes;
      68             :         int msize;
      69             :         bool is_write = false;
      70             : 
      71           0 :         if (WARN_ON(msg->size > 16))
      72           0 :                 return -E2BIG;
      73             : 
      74           0 :         switch (msg->request & ~DP_AUX_I2C_MOT) {
      75             :         case DP_AUX_NATIVE_WRITE:
      76             :         case DP_AUX_I2C_WRITE:
      77             :                 is_write = true;
      78           0 :                 break;
      79             :         case DP_AUX_NATIVE_READ:
      80             :         case DP_AUX_I2C_READ:
      81             :                 break;
      82             :         default:
      83           0 :                 return -EINVAL;
      84             :         }
      85             : 
      86             :         /* work out two sizes required */
      87             :         msize = 0;
      88             :         bytes = BARE_ADDRESS_SIZE;
      89           0 :         if (msg->size) {
      90           0 :                 msize = msg->size - 1;
      91             :                 bytes++;
      92           0 :                 if (is_write)
      93           0 :                         bytes += msg->size;
      94             :         }
      95             : 
      96           0 :         mutex_lock(&chan->mutex);
      97             : 
      98             :         /* switch the pad to aux mode */
      99           0 :         tmp = RREG32(chan->rec.mask_clk_reg);
     100           0 :         tmp |= (1 << 16);
     101           0 :         WREG32(chan->rec.mask_clk_reg, tmp);
     102             : 
     103             :         /* setup AUX control register with correct HPD pin */
     104           0 :         tmp = RREG32(AUX_CONTROL + aux_offset[instance]);
     105             : 
     106           0 :         tmp &= AUX_HPD_SEL(0x7);
     107           0 :         tmp |= AUX_HPD_SEL(chan->rec.hpd);
     108           0 :         tmp |= AUX_EN | AUX_LS_READ_EN;
     109             : 
     110           0 :         WREG32(AUX_CONTROL + aux_offset[instance], tmp);
     111             : 
     112             :         /* atombios appears to write this twice lets copy it */
     113           0 :         WREG32(AUX_SW_CONTROL + aux_offset[instance],
     114             :                AUX_SW_WR_BYTES(bytes));
     115           0 :         WREG32(AUX_SW_CONTROL + aux_offset[instance],
     116             :                AUX_SW_WR_BYTES(bytes));
     117             : 
     118             :         /* write the data header into the registers */
     119             :         /* request, address, msg size */
     120           0 :         byte = (msg->request << 4) | ((msg->address >> 16) & 0xf);
     121           0 :         WREG32(AUX_SW_DATA + aux_offset[instance],
     122             :                AUX_SW_DATA_MASK(byte) | AUX_SW_AUTOINCREMENT_DISABLE);
     123             : 
     124           0 :         byte = (msg->address >> 8) & 0xff;
     125           0 :         WREG32(AUX_SW_DATA + aux_offset[instance],
     126             :                AUX_SW_DATA_MASK(byte));
     127             : 
     128           0 :         byte = msg->address & 0xff;
     129           0 :         WREG32(AUX_SW_DATA + aux_offset[instance],
     130             :                AUX_SW_DATA_MASK(byte));
     131             : 
     132           0 :         byte = msize;
     133           0 :         WREG32(AUX_SW_DATA + aux_offset[instance],
     134             :                AUX_SW_DATA_MASK(byte));
     135             : 
     136             :         /* if we are writing - write the msg buffer */
     137           0 :         if (is_write) {
     138           0 :                 for (i = 0; i < msg->size; i++) {
     139           0 :                         WREG32(AUX_SW_DATA + aux_offset[instance],
     140             :                                AUX_SW_DATA_MASK(buf[i]));
     141             :                 }
     142             :         }
     143             : 
     144             :         /* clear the ACK */
     145           0 :         WREG32(AUX_SW_INTERRUPT_CONTROL + aux_offset[instance], AUX_SW_DONE_ACK);
     146             : 
     147             :         /* write the size and GO bits */
     148           0 :         WREG32(AUX_SW_CONTROL + aux_offset[instance],
     149             :                AUX_SW_WR_BYTES(bytes) | AUX_SW_GO);
     150             : 
     151             :         /* poll the status registers - TODO irq support */
     152           0 :         do {
     153           0 :                 tmp = RREG32(AUX_SW_STATUS + aux_offset[instance]);
     154           0 :                 if (tmp & AUX_SW_DONE) {
     155             :                         break;
     156             :                 }
     157           0 :                 usleep_range(100, 200);
     158           0 :         } while (retry_count++ < 1000);
     159             : 
     160           0 :         if (retry_count >= 1000) {
     161           0 :                 DRM_ERROR("auxch hw never signalled completion, error %08x\n", tmp);
     162             :                 ret = -EIO;
     163           0 :                 goto done;
     164             :         }
     165             : 
     166           0 :         if (tmp & AUX_SW_RX_TIMEOUT) {
     167             :                 DRM_DEBUG_KMS("dp_aux_ch timed out\n");
     168             :                 ret = -ETIMEDOUT;
     169           0 :                 goto done;
     170             :         }
     171           0 :         if (tmp & AUX_RX_ERROR_FLAGS) {
     172             :                 DRM_DEBUG_KMS("dp_aux_ch flags not zero: %08x\n", tmp);
     173             :                 ret = -EIO;
     174           0 :                 goto done;
     175             :         }
     176             : 
     177           0 :         bytes = AUX_SW_REPLY_GET_BYTE_COUNT(tmp);
     178           0 :         if (bytes) {
     179           0 :                 WREG32(AUX_SW_DATA + aux_offset[instance],
     180             :                        AUX_SW_DATA_RW | AUX_SW_AUTOINCREMENT_DISABLE);
     181             : 
     182           0 :                 tmp = RREG32(AUX_SW_DATA + aux_offset[instance]);
     183           0 :                 ack = (tmp >> 8) & 0xff;
     184             : 
     185           0 :                 for (i = 0; i < bytes - 1; i++) {
     186           0 :                         tmp = RREG32(AUX_SW_DATA + aux_offset[instance]);
     187           0 :                         if (buf)
     188           0 :                                 buf[i] = (tmp >> 8) & 0xff;
     189             :                 }
     190           0 :                 if (buf)
     191           0 :                         ret = bytes - 1;
     192             :         }
     193             : 
     194           0 :         WREG32(AUX_SW_INTERRUPT_CONTROL + aux_offset[instance], AUX_SW_DONE_ACK);
     195             : 
     196           0 :         if (is_write)
     197           0 :                 ret = msg->size;
     198             : done:
     199           0 :         mutex_unlock(&chan->mutex);
     200             : 
     201           0 :         if (ret >= 0)
     202           0 :                 msg->reply = ack >> 4;
     203           0 :         return ret;
     204           0 : }

Generated by: LCOV version 1.13