2 * Copyright (c) 2014-2015, The Linux Foundation. All rights reserved.
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 and
6 * only version 2 as published by the Free Software Foundation.
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
17 #define AUX_CMD_FIFO_LEN 144
18 #define AUX_CMD_NATIVE_MAX 16
19 #define AUX_CMD_I2C_MAX 128
21 #define EDP_INTR_AUX_I2C_ERR \
22 (EDP_INTERRUPT_REG_1_WRONG_ADDR | EDP_INTERRUPT_REG_1_TIMEOUT | \
23 EDP_INTERRUPT_REG_1_NACK_DEFER | EDP_INTERRUPT_REG_1_WRONG_DATA_CNT | \
24 EDP_INTERRUPT_REG_1_I2C_NACK | EDP_INTERRUPT_REG_1_I2C_DEFER)
25 #define EDP_INTR_TRANS_STATUS \
26 (EDP_INTERRUPT_REG_1_AUX_I2C_DONE | EDP_INTR_AUX_I2C_ERR)
32 struct completion msg_comp
;
34 /* To prevent the message transaction routine from reentry. */
35 struct mutex msg_mutex
;
37 struct drm_dp_aux drm_aux
;
39 #define to_edp_aux(x) container_of(x, struct edp_aux, drm_aux)
41 static int edp_msg_fifo_tx(struct edp_aux
*aux
, struct drm_dp_aux_msg
*msg
)
45 bool native
= msg
->request
& (DP_AUX_NATIVE_WRITE
& DP_AUX_NATIVE_READ
);
46 bool read
= msg
->request
& (DP_AUX_I2C_READ
& DP_AUX_NATIVE_READ
);
47 u8
*msgdata
= msg
->buffer
;
56 * cmd fifo only has depth of 144 bytes
58 if (len
> AUX_CMD_FIFO_LEN
)
61 /* Pack cmd and write to HW */
62 data
[0] = (msg
->address
>> 16) & 0xf; /* addr[19:16] */
64 data
[0] |= BIT(4); /* R/W */
66 data
[1] = (msg
->address
>> 8) & 0xff; /* addr[15:8] */
67 data
[2] = msg
->address
& 0xff; /* addr[7:0] */
68 data
[3] = (msg
->size
- 1) & 0xff; /* len[7:0] */
70 for (i
= 0; i
< len
; i
++) {
71 reg
= (i
< 4) ? data
[i
] : msgdata
[i
- 4];
72 reg
= EDP_AUX_DATA_DATA(reg
); /* index = 0, write */
74 reg
|= EDP_AUX_DATA_INDEX_WRITE
;
75 edp_write(aux
->base
+ REG_EDP_AUX_DATA
, reg
);
78 reg
= 0; /* Transaction number is always 1 */
79 if (!native
) /* i2c */
80 reg
|= EDP_AUX_TRANS_CTRL_I2C
;
82 reg
|= EDP_AUX_TRANS_CTRL_GO
;
83 edp_write(aux
->base
+ REG_EDP_AUX_TRANS_CTRL
, reg
);
88 static int edp_msg_fifo_rx(struct edp_aux
*aux
, struct drm_dp_aux_msg
*msg
)
95 edp_write(aux
->base
+ REG_EDP_AUX_DATA
,
96 EDP_AUX_DATA_INDEX_WRITE
| EDP_AUX_DATA_READ
); /* index = 0 */
100 /* discard first byte */
101 data
= edp_read(aux
->base
+ REG_EDP_AUX_DATA
);
102 for (i
= 0; i
< len
; i
++) {
103 data
= edp_read(aux
->base
+ REG_EDP_AUX_DATA
);
104 dp
[i
] = (u8
)((data
>> 8) & 0xff);
111 * This function does the real job to process an AUX transaction.
112 * It will call msm_edp_aux_ctrl() function to reset the AUX channel,
113 * if the waiting is timeout.
114 * The caller who triggers the transaction should avoid the
115 * msm_edp_aux_ctrl() running concurrently in other threads, i.e.
116 * start transaction only when AUX channel is fully enabled.
118 static ssize_t
edp_aux_transfer(struct drm_dp_aux
*drm_aux
,
119 struct drm_dp_aux_msg
*msg
)
121 struct edp_aux
*aux
= to_edp_aux(drm_aux
);
123 unsigned long time_left
;
124 bool native
= msg
->request
& (DP_AUX_NATIVE_WRITE
& DP_AUX_NATIVE_READ
);
125 bool read
= msg
->request
& (DP_AUX_I2C_READ
& DP_AUX_NATIVE_READ
);
127 /* Ignore address only message */
128 if ((msg
->size
== 0) || (msg
->buffer
== NULL
)) {
129 msg
->reply
= native
?
130 DP_AUX_NATIVE_REPLY_ACK
: DP_AUX_I2C_REPLY_ACK
;
134 /* msg sanity check */
135 if ((native
&& (msg
->size
> AUX_CMD_NATIVE_MAX
)) ||
136 (msg
->size
> AUX_CMD_I2C_MAX
)) {
137 pr_err("%s: invalid msg: size(%zu), request(%x)\n",
138 __func__
, msg
->size
, msg
->request
);
142 mutex_lock(&aux
->msg_mutex
);
144 aux
->msg_err
= false;
145 reinit_completion(&aux
->msg_comp
);
147 ret
= edp_msg_fifo_tx(aux
, msg
);
151 DBG("wait_for_completion");
152 time_left
= wait_for_completion_timeout(&aux
->msg_comp
,
153 msecs_to_jiffies(300));
156 * Clear GO and reset AUX channel
157 * to cancel the current transaction.
159 edp_write(aux
->base
+ REG_EDP_AUX_TRANS_CTRL
, 0);
160 msm_edp_aux_ctrl(aux
, 1);
161 pr_err("%s: aux timeout,\n", __func__
);
169 ret
= edp_msg_fifo_rx(aux
, msg
);
174 msg
->reply
= native
?
175 DP_AUX_NATIVE_REPLY_ACK
: DP_AUX_I2C_REPLY_ACK
;
177 /* Reply defer to retry */
178 msg
->reply
= native
?
179 DP_AUX_NATIVE_REPLY_DEFER
: DP_AUX_I2C_REPLY_DEFER
;
181 * The sleep time in caller is not long enough to make sure
182 * our H/W completes transactions. Add more defer time here.
187 /* Return requested size for success or retry */
191 mutex_unlock(&aux
->msg_mutex
);
195 void *msm_edp_aux_init(struct device
*dev
, void __iomem
*regbase
,
196 struct drm_dp_aux
**drm_aux
)
198 struct edp_aux
*aux
= NULL
;
202 aux
= devm_kzalloc(dev
, sizeof(*aux
), GFP_KERNEL
);
207 mutex_init(&aux
->msg_mutex
);
208 init_completion(&aux
->msg_comp
);
210 aux
->drm_aux
.name
= "msm_edp_aux";
211 aux
->drm_aux
.dev
= dev
;
212 aux
->drm_aux
.transfer
= edp_aux_transfer
;
213 ret
= drm_dp_aux_register(&aux
->drm_aux
);
215 pr_err("%s: failed to register drm aux: %d\n", __func__
, ret
);
216 mutex_destroy(&aux
->msg_mutex
);
220 *drm_aux
= &aux
->drm_aux
;
225 void msm_edp_aux_destroy(struct device
*dev
, struct edp_aux
*aux
)
228 drm_dp_aux_unregister(&aux
->drm_aux
);
229 mutex_destroy(&aux
->msg_mutex
);
233 irqreturn_t
msm_edp_aux_irq(struct edp_aux
*aux
, u32 isr
)
235 if (isr
& EDP_INTR_TRANS_STATUS
) {
237 edp_write(aux
->base
+ REG_EDP_AUX_TRANS_CTRL
, 0);
239 if (isr
& EDP_INTR_AUX_I2C_ERR
)
242 aux
->msg_err
= false;
244 complete(&aux
->msg_comp
);
250 void msm_edp_aux_ctrl(struct edp_aux
*aux
, int enable
)
254 DBG("enable=%d", enable
);
255 data
= edp_read(aux
->base
+ REG_EDP_AUX_CTRL
);
258 data
|= EDP_AUX_CTRL_RESET
;
259 edp_write(aux
->base
+ REG_EDP_AUX_CTRL
, data
);
260 /* Make sure full reset */
262 usleep_range(500, 1000);
264 data
&= ~EDP_AUX_CTRL_RESET
;
265 data
|= EDP_AUX_CTRL_ENABLE
;
266 edp_write(aux
->base
+ REG_EDP_AUX_CTRL
, data
);
268 data
&= ~EDP_AUX_CTRL_ENABLE
;
269 edp_write(aux
->base
+ REG_EDP_AUX_CTRL
, data
);