diff options
| author | Thierry Reding <treding@nvidia.com> | 2014-04-07 04:37:44 -0400 |
|---|---|---|
| committer | Christian König <christian.koenig@amd.com> | 2014-04-08 10:12:36 -0400 |
| commit | 1ca2030563534bc0b057df9fddd30fb6257826cb (patch) | |
| tree | 733c5e1f8aecb6bb231c7c07bc3428c21288a2f3 | |
| parent | c39b06951f1dc2e384650288676c5b7dcc0ec92c (diff) | |
drm/tegra: dp: Support address-only I2C-over-AUX transactions
Certain types of I2C-over-AUX transactions require that only the address
is transferred. Detect this by looking at the AUX message's size and set
the address-only bit appropriately.
Signed-off-by: Thierry Reding <treding@nvidia.com>
| -rw-r--r-- | drivers/gpu/drm/tegra/dpaux.c | 44 | ||||
| -rw-r--r-- | drivers/gpu/drm/tegra/dpaux.h | 1 |
2 files changed, 32 insertions, 13 deletions
diff --git a/drivers/gpu/drm/tegra/dpaux.c b/drivers/gpu/drm/tegra/dpaux.c index d536ed381fbd..005c19bd92df 100644 --- a/drivers/gpu/drm/tegra/dpaux.c +++ b/drivers/gpu/drm/tegra/dpaux.c | |||
| @@ -99,55 +99,73 @@ static void tegra_dpaux_read_fifo(struct tegra_dpaux *dpaux, u8 *buffer, | |||
| 99 | static ssize_t tegra_dpaux_transfer(struct drm_dp_aux *aux, | 99 | static ssize_t tegra_dpaux_transfer(struct drm_dp_aux *aux, |
| 100 | struct drm_dp_aux_msg *msg) | 100 | struct drm_dp_aux_msg *msg) |
| 101 | { | 101 | { |
| 102 | unsigned long value = DPAUX_DP_AUXCTL_TRANSACTREQ; | ||
| 103 | unsigned long timeout = msecs_to_jiffies(250); | 102 | unsigned long timeout = msecs_to_jiffies(250); |
| 104 | struct tegra_dpaux *dpaux = to_dpaux(aux); | 103 | struct tegra_dpaux *dpaux = to_dpaux(aux); |
| 105 | unsigned long status; | 104 | unsigned long status; |
| 106 | ssize_t ret = 0; | 105 | ssize_t ret = 0; |
| 106 | u32 value; | ||
| 107 | 107 | ||
| 108 | if (msg->size < 1 || msg->size > 16) | 108 | /* Tegra has 4x4 byte DP AUX transmit and receive FIFOs. */ |
| 109 | if (msg->size > 16) | ||
| 109 | return -EINVAL; | 110 | return -EINVAL; |
| 110 | 111 | ||
| 111 | tegra_dpaux_writel(dpaux, msg->address, DPAUX_DP_AUXADDR); | 112 | /* |
| 113 | * Allow zero-sized messages only for I2C, in which case they specify | ||
| 114 | * address-only transactions. | ||
| 115 | */ | ||
| 116 | if (msg->size < 1) { | ||
| 117 | switch (msg->request & ~DP_AUX_I2C_MOT) { | ||
| 118 | case DP_AUX_I2C_WRITE: | ||
| 119 | case DP_AUX_I2C_READ: | ||
| 120 | value = DPAUX_DP_AUXCTL_CMD_ADDRESS_ONLY; | ||
| 121 | break; | ||
| 122 | |||
| 123 | default: | ||
| 124 | return -EINVAL; | ||
| 125 | } | ||
| 126 | } else { | ||
| 127 | /* For non-zero-sized messages, set the CMDLEN field. */ | ||
| 128 | value = DPAUX_DP_AUXCTL_CMDLEN(msg->size - 1); | ||
| 129 | } | ||
| 112 | 130 | ||
| 113 | switch (msg->request & ~DP_AUX_I2C_MOT) { | 131 | switch (msg->request & ~DP_AUX_I2C_MOT) { |
| 114 | case DP_AUX_I2C_WRITE: | 132 | case DP_AUX_I2C_WRITE: |
| 115 | if (msg->request & DP_AUX_I2C_MOT) | 133 | if (msg->request & DP_AUX_I2C_MOT) |
| 116 | value = DPAUX_DP_AUXCTL_CMD_MOT_WR; | 134 | value |= DPAUX_DP_AUXCTL_CMD_MOT_WR; |
| 117 | else | 135 | else |
| 118 | value = DPAUX_DP_AUXCTL_CMD_I2C_WR; | 136 | value |= DPAUX_DP_AUXCTL_CMD_I2C_WR; |
| 119 | 137 | ||
| 120 | break; | 138 | break; |
| 121 | 139 | ||
| 122 | case DP_AUX_I2C_READ: | 140 | case DP_AUX_I2C_READ: |
| 123 | if (msg->request & DP_AUX_I2C_MOT) | 141 | if (msg->request & DP_AUX_I2C_MOT) |
| 124 | value = DPAUX_DP_AUXCTL_CMD_MOT_RD; | 142 | value |= DPAUX_DP_AUXCTL_CMD_MOT_RD; |
| 125 | else | 143 | else |
| 126 | value = DPAUX_DP_AUXCTL_CMD_I2C_RD; | 144 | value |= DPAUX_DP_AUXCTL_CMD_I2C_RD; |
| 127 | 145 | ||
| 128 | break; | 146 | break; |
| 129 | 147 | ||
| 130 | case DP_AUX_I2C_STATUS: | 148 | case DP_AUX_I2C_STATUS: |
| 131 | if (msg->request & DP_AUX_I2C_MOT) | 149 | if (msg->request & DP_AUX_I2C_MOT) |
| 132 | value = DPAUX_DP_AUXCTL_CMD_MOT_RQ; | 150 | value |= DPAUX_DP_AUXCTL_CMD_MOT_RQ; |
| 133 | else | 151 | else |
| 134 | value = DPAUX_DP_AUXCTL_CMD_I2C_RQ; | 152 | value |= DPAUX_DP_AUXCTL_CMD_I2C_RQ; |
| 135 | 153 | ||
| 136 | break; | 154 | break; |
| 137 | 155 | ||
| 138 | case DP_AUX_NATIVE_WRITE: | 156 | case DP_AUX_NATIVE_WRITE: |
| 139 | value = DPAUX_DP_AUXCTL_CMD_AUX_WR; | 157 | value |= DPAUX_DP_AUXCTL_CMD_AUX_WR; |
| 140 | break; | 158 | break; |
| 141 | 159 | ||
| 142 | case DP_AUX_NATIVE_READ: | 160 | case DP_AUX_NATIVE_READ: |
| 143 | value = DPAUX_DP_AUXCTL_CMD_AUX_RD; | 161 | value |= DPAUX_DP_AUXCTL_CMD_AUX_RD; |
| 144 | break; | 162 | break; |
| 145 | 163 | ||
| 146 | default: | 164 | default: |
| 147 | return -EINVAL; | 165 | return -EINVAL; |
| 148 | } | 166 | } |
| 149 | 167 | ||
| 150 | value |= DPAUX_DP_AUXCTL_CMDLEN(msg->size - 1); | 168 | tegra_dpaux_writel(dpaux, msg->address, DPAUX_DP_AUXADDR); |
| 151 | tegra_dpaux_writel(dpaux, value, DPAUX_DP_AUXCTL); | 169 | tegra_dpaux_writel(dpaux, value, DPAUX_DP_AUXCTL); |
| 152 | 170 | ||
| 153 | if ((msg->request & DP_AUX_I2C_READ) == 0) { | 171 | if ((msg->request & DP_AUX_I2C_READ) == 0) { |
| @@ -198,7 +216,7 @@ static ssize_t tegra_dpaux_transfer(struct drm_dp_aux *aux, | |||
| 198 | break; | 216 | break; |
| 199 | } | 217 | } |
| 200 | 218 | ||
| 201 | if (msg->reply == DP_AUX_NATIVE_REPLY_ACK) { | 219 | if ((msg->size > 0) && (msg->reply == DP_AUX_NATIVE_REPLY_ACK)) { |
| 202 | if (msg->request & DP_AUX_I2C_READ) { | 220 | if (msg->request & DP_AUX_I2C_READ) { |
| 203 | size_t count = value & DPAUX_DP_AUXSTAT_REPLY_MASK; | 221 | size_t count = value & DPAUX_DP_AUXSTAT_REPLY_MASK; |
| 204 | 222 | ||
diff --git a/drivers/gpu/drm/tegra/dpaux.h b/drivers/gpu/drm/tegra/dpaux.h index 4f5bf10fdff9..806e245ca787 100644 --- a/drivers/gpu/drm/tegra/dpaux.h +++ b/drivers/gpu/drm/tegra/dpaux.h | |||
| @@ -32,6 +32,7 @@ | |||
| 32 | #define DPAUX_DP_AUXCTL_CMD_I2C_RQ (2 << 12) | 32 | #define DPAUX_DP_AUXCTL_CMD_I2C_RQ (2 << 12) |
| 33 | #define DPAUX_DP_AUXCTL_CMD_I2C_RD (1 << 12) | 33 | #define DPAUX_DP_AUXCTL_CMD_I2C_RD (1 << 12) |
| 34 | #define DPAUX_DP_AUXCTL_CMD_I2C_WR (0 << 12) | 34 | #define DPAUX_DP_AUXCTL_CMD_I2C_WR (0 << 12) |
| 35 | #define DPAUX_DP_AUXCTL_CMD_ADDRESS_ONLY (1 << 8) | ||
| 35 | #define DPAUX_DP_AUXCTL_CMDLEN(x) ((x) & 0xff) | 36 | #define DPAUX_DP_AUXCTL_CMDLEN(x) ((x) & 0xff) |
| 36 | 37 | ||
| 37 | #define DPAUX_DP_AUXSTAT 0x31 | 38 | #define DPAUX_DP_AUXSTAT 0x31 |
