]> git.karo-electronics.de Git - karo-tx-linux.git/blobdiff - drivers/gpu/drm/tegra/dpaux.c
Merge branch 'x86-vdso-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git...
[karo-tx-linux.git] / drivers / gpu / drm / tegra / dpaux.c
index d536ed381fbd9e305951d06529d61fbad83f2685..005c19bd92dfa0e5350303d84290b27b9aae144d 100644 (file)
@@ -99,55 +99,73 @@ static void tegra_dpaux_read_fifo(struct tegra_dpaux *dpaux, u8 *buffer,
 static ssize_t tegra_dpaux_transfer(struct drm_dp_aux *aux,
                                    struct drm_dp_aux_msg *msg)
 {
-       unsigned long value = DPAUX_DP_AUXCTL_TRANSACTREQ;
        unsigned long timeout = msecs_to_jiffies(250);
        struct tegra_dpaux *dpaux = to_dpaux(aux);
        unsigned long status;
        ssize_t ret = 0;
+       u32 value;
 
-       if (msg->size < 1 || msg->size > 16)
+       /* Tegra has 4x4 byte DP AUX transmit and receive FIFOs. */
+       if (msg->size > 16)
                return -EINVAL;
 
-       tegra_dpaux_writel(dpaux, msg->address, DPAUX_DP_AUXADDR);
+       /*
+        * Allow zero-sized messages only for I2C, in which case they specify
+        * address-only transactions.
+        */
+       if (msg->size < 1) {
+               switch (msg->request & ~DP_AUX_I2C_MOT) {
+               case DP_AUX_I2C_WRITE:
+               case DP_AUX_I2C_READ:
+                       value = DPAUX_DP_AUXCTL_CMD_ADDRESS_ONLY;
+                       break;
+
+               default:
+                       return -EINVAL;
+               }
+       } else {
+               /* For non-zero-sized messages, set the CMDLEN field. */
+               value = DPAUX_DP_AUXCTL_CMDLEN(msg->size - 1);
+       }
 
        switch (msg->request & ~DP_AUX_I2C_MOT) {
        case DP_AUX_I2C_WRITE:
                if (msg->request & DP_AUX_I2C_MOT)
-                       value = DPAUX_DP_AUXCTL_CMD_MOT_WR;
+                       value |= DPAUX_DP_AUXCTL_CMD_MOT_WR;
                else
-                       value = DPAUX_DP_AUXCTL_CMD_I2C_WR;
+                       value |= DPAUX_DP_AUXCTL_CMD_I2C_WR;
 
                break;
 
        case DP_AUX_I2C_READ:
                if (msg->request & DP_AUX_I2C_MOT)
-                       value = DPAUX_DP_AUXCTL_CMD_MOT_RD;
+                       value |= DPAUX_DP_AUXCTL_CMD_MOT_RD;
                else
-                       value = DPAUX_DP_AUXCTL_CMD_I2C_RD;
+                       value |= DPAUX_DP_AUXCTL_CMD_I2C_RD;
 
                break;
 
        case DP_AUX_I2C_STATUS:
                if (msg->request & DP_AUX_I2C_MOT)
-                       value = DPAUX_DP_AUXCTL_CMD_MOT_RQ;
+                       value |= DPAUX_DP_AUXCTL_CMD_MOT_RQ;
                else
-                       value = DPAUX_DP_AUXCTL_CMD_I2C_RQ;
+                       value |= DPAUX_DP_AUXCTL_CMD_I2C_RQ;
 
                break;
 
        case DP_AUX_NATIVE_WRITE:
-               value = DPAUX_DP_AUXCTL_CMD_AUX_WR;
+               value |= DPAUX_DP_AUXCTL_CMD_AUX_WR;
                break;
 
        case DP_AUX_NATIVE_READ:
-               value = DPAUX_DP_AUXCTL_CMD_AUX_RD;
+               value |= DPAUX_DP_AUXCTL_CMD_AUX_RD;
                break;
 
        default:
                return -EINVAL;
        }
 
-       value |= DPAUX_DP_AUXCTL_CMDLEN(msg->size - 1);
+       tegra_dpaux_writel(dpaux, msg->address, DPAUX_DP_AUXADDR);
        tegra_dpaux_writel(dpaux, value, DPAUX_DP_AUXCTL);
 
        if ((msg->request & DP_AUX_I2C_READ) == 0) {
@@ -198,7 +216,7 @@ static ssize_t tegra_dpaux_transfer(struct drm_dp_aux *aux,
                break;
        }
 
-       if (msg->reply == DP_AUX_NATIVE_REPLY_ACK) {
+       if ((msg->size > 0) && (msg->reply == DP_AUX_NATIVE_REPLY_ACK)) {
                if (msg->request & DP_AUX_I2C_READ) {
                        size_t count = value & DPAUX_DP_AUXSTAT_REPLY_MASK;