aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/gpu/drm/tegra/dpaux.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/gpu/drm/tegra/dpaux.c')
-rw-r--r--drivers/gpu/drm/tegra/dpaux.c44
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,
99static ssize_t tegra_dpaux_transfer(struct drm_dp_aux *aux, 99static 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