diff options
Diffstat (limited to 'drivers/gpu/drm/tegra/dpaux.c')
-rw-r--r-- | drivers/gpu/drm/tegra/dpaux.c | 44 |
1 files changed, 31 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 | ||