Back to home page

OSCL-LXR

 
 

    


0001 /*
0002  * Copyright 2015 Red Hat Inc.
0003  *
0004  * Permission is hereby granted, free of charge, to any person obtaining a
0005  * copy of this software and associated documentation files (the "Software"),
0006  * to deal in the Software without restriction, including without limitation
0007  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
0008  * and/or sell copies of the Software, and to permit persons to whom the
0009  * Software is furnished to do so, subject to the following conditions:
0010  *
0011  * The above copyright notice and this permission notice shall be included in
0012  * all copies or substantial portions of the Software.
0013  *
0014  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
0015  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
0016  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
0017  * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
0018  * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
0019  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
0020  * OTHER DEALINGS IN THE SOFTWARE.
0021  *
0022  * Authors: Dave Airlie
0023  */
0024 
0025 #include <drm/radeon_drm.h>
0026 #include "radeon.h"
0027 #include "nid.h"
0028 
0029 #define AUX_RX_ERROR_FLAGS (AUX_SW_RX_OVERFLOW |         \
0030                 AUX_SW_RX_HPD_DISCON |       \
0031                 AUX_SW_RX_PARTIAL_BYTE |         \
0032                 AUX_SW_NON_AUX_MODE |        \
0033                 AUX_SW_RX_SYNC_INVALID_L |       \
0034                 AUX_SW_RX_SYNC_INVALID_H |       \
0035                 AUX_SW_RX_INVALID_START |        \
0036                 AUX_SW_RX_RECV_NO_DET |      \
0037                 AUX_SW_RX_RECV_INVALID_H |       \
0038                 AUX_SW_RX_RECV_INVALID_V)
0039 
0040 #define AUX_SW_REPLY_GET_BYTE_COUNT(x) (((x) >> 24) & 0x1f)
0041 
0042 #define BARE_ADDRESS_SIZE 3
0043 
0044 static const u32 aux_offset[] =
0045 {
0046     0x6200 - 0x6200,
0047     0x6250 - 0x6200,
0048     0x62a0 - 0x6200,
0049     0x6300 - 0x6200,
0050     0x6350 - 0x6200,
0051     0x63a0 - 0x6200,
0052 };
0053 
0054 ssize_t
0055 radeon_dp_aux_transfer_native(struct drm_dp_aux *aux, struct drm_dp_aux_msg *msg)
0056 {
0057     struct radeon_i2c_chan *chan =
0058         container_of(aux, struct radeon_i2c_chan, aux);
0059     struct drm_device *dev = chan->dev;
0060     struct radeon_device *rdev = dev->dev_private;
0061     int ret = 0, i;
0062     uint32_t tmp, ack = 0;
0063     int instance = chan->rec.i2c_id & 0xf;
0064     u8 byte;
0065     u8 *buf = msg->buffer;
0066     int retry_count = 0;
0067     int bytes;
0068     int msize;
0069     bool is_write = false;
0070 
0071     if (WARN_ON(msg->size > 16))
0072         return -E2BIG;
0073 
0074     switch (msg->request & ~DP_AUX_I2C_MOT) {
0075     case DP_AUX_NATIVE_WRITE:
0076     case DP_AUX_I2C_WRITE:
0077         is_write = true;
0078         break;
0079     case DP_AUX_NATIVE_READ:
0080     case DP_AUX_I2C_READ:
0081         break;
0082     default:
0083         return -EINVAL;
0084     }
0085 
0086     /* work out two sizes required */
0087     msize = 0;
0088     bytes = BARE_ADDRESS_SIZE;
0089     if (msg->size) {
0090         msize = msg->size - 1;
0091         bytes++;
0092         if (is_write)
0093             bytes += msg->size;
0094     }
0095 
0096     mutex_lock(&chan->mutex);
0097 
0098     /* switch the pad to aux mode */
0099     tmp = RREG32(chan->rec.mask_clk_reg);
0100     tmp |= (1 << 16);
0101     WREG32(chan->rec.mask_clk_reg, tmp);
0102 
0103     /* setup AUX control register with correct HPD pin */
0104     tmp = RREG32(AUX_CONTROL + aux_offset[instance]);
0105 
0106     tmp &= AUX_HPD_SEL(0x7);
0107     tmp |= AUX_HPD_SEL(chan->rec.hpd);
0108     tmp |= AUX_EN | AUX_LS_READ_EN;
0109 
0110     WREG32(AUX_CONTROL + aux_offset[instance], tmp);
0111 
0112     /* atombios appears to write this twice lets copy it */
0113     WREG32(AUX_SW_CONTROL + aux_offset[instance],
0114            AUX_SW_WR_BYTES(bytes));
0115     WREG32(AUX_SW_CONTROL + aux_offset[instance],
0116            AUX_SW_WR_BYTES(bytes));
0117 
0118     /* write the data header into the registers */
0119     /* request, address, msg size */
0120     byte = (msg->request << 4) | ((msg->address >> 16) & 0xf);
0121     WREG32(AUX_SW_DATA + aux_offset[instance],
0122            AUX_SW_DATA_MASK(byte) | AUX_SW_AUTOINCREMENT_DISABLE);
0123 
0124     byte = (msg->address >> 8) & 0xff;
0125     WREG32(AUX_SW_DATA + aux_offset[instance],
0126            AUX_SW_DATA_MASK(byte));
0127 
0128     byte = msg->address & 0xff;
0129     WREG32(AUX_SW_DATA + aux_offset[instance],
0130            AUX_SW_DATA_MASK(byte));
0131 
0132     byte = msize;
0133     WREG32(AUX_SW_DATA + aux_offset[instance],
0134            AUX_SW_DATA_MASK(byte));
0135 
0136     /* if we are writing - write the msg buffer */
0137     if (is_write) {
0138         for (i = 0; i < msg->size; i++) {
0139             WREG32(AUX_SW_DATA + aux_offset[instance],
0140                    AUX_SW_DATA_MASK(buf[i]));
0141         }
0142     }
0143 
0144     /* clear the ACK */
0145     WREG32(AUX_SW_INTERRUPT_CONTROL + aux_offset[instance], AUX_SW_DONE_ACK);
0146 
0147     /* write the size and GO bits */
0148     WREG32(AUX_SW_CONTROL + aux_offset[instance],
0149            AUX_SW_WR_BYTES(bytes) | AUX_SW_GO);
0150 
0151     /* poll the status registers - TODO irq support */
0152     do {
0153         tmp = RREG32(AUX_SW_STATUS + aux_offset[instance]);
0154         if (tmp & AUX_SW_DONE) {
0155             break;
0156         }
0157         usleep_range(100, 200);
0158     } while (retry_count++ < 1000);
0159 
0160     if (retry_count >= 1000) {
0161         DRM_ERROR("auxch hw never signalled completion, error %08x\n", tmp);
0162         ret = -EIO;
0163         goto done;
0164     }
0165 
0166     if (tmp & AUX_SW_RX_TIMEOUT) {
0167         ret = -ETIMEDOUT;
0168         goto done;
0169     }
0170     if (tmp & AUX_RX_ERROR_FLAGS) {
0171         DRM_DEBUG_KMS_RATELIMITED("dp_aux_ch flags not zero: %08x\n",
0172                       tmp);
0173         ret = -EIO;
0174         goto done;
0175     }
0176 
0177     bytes = AUX_SW_REPLY_GET_BYTE_COUNT(tmp);
0178     if (bytes) {
0179         WREG32(AUX_SW_DATA + aux_offset[instance],
0180                AUX_SW_DATA_RW | AUX_SW_AUTOINCREMENT_DISABLE);
0181 
0182         tmp = RREG32(AUX_SW_DATA + aux_offset[instance]);
0183         ack = (tmp >> 8) & 0xff;
0184 
0185         for (i = 0; i < bytes - 1; i++) {
0186             tmp = RREG32(AUX_SW_DATA + aux_offset[instance]);
0187             if (buf)
0188                 buf[i] = (tmp >> 8) & 0xff;
0189         }
0190         if (buf)
0191             ret = bytes - 1;
0192     }
0193 
0194     WREG32(AUX_SW_INTERRUPT_CONTROL + aux_offset[instance], AUX_SW_DONE_ACK);
0195 
0196     if (is_write)
0197         ret = msg->size;
0198 done:
0199     mutex_unlock(&chan->mutex);
0200 
0201     if (ret >= 0)
0202         msg->reply = ack >> 4;
0203     return ret;
0204 }