diff options
Diffstat (limited to 'drivers/gpu/drm/gma500/mdfld_dsi_pkg_sender.c')
-rw-r--r-- | drivers/gpu/drm/gma500/mdfld_dsi_pkg_sender.c | 694 |
1 files changed, 694 insertions, 0 deletions
diff --git a/drivers/gpu/drm/gma500/mdfld_dsi_pkg_sender.c b/drivers/gpu/drm/gma500/mdfld_dsi_pkg_sender.c new file mode 100644 index 00000000000..f193acec657 --- /dev/null +++ b/drivers/gpu/drm/gma500/mdfld_dsi_pkg_sender.c | |||
@@ -0,0 +1,694 @@ | |||
1 | /* | ||
2 | * Copyright © 2010 Intel Corporation | ||
3 | * | ||
4 | * Permission is hereby granted, free of charge, to any person obtaining a | ||
5 | * copy of this software and associated documentation files (the "Software"), | ||
6 | * to deal in the Software without restriction, including without limitation | ||
7 | * the rights to use, copy, modify, merge, publish, distribute, sublicense, | ||
8 | * and/or sell copies of the Software, and to permit persons to whom the | ||
9 | * Software is furnished to do so, subject to the following conditions: | ||
10 | * | ||
11 | * The above copyright notice and this permission notice (including the next | ||
12 | * paragraph) shall be included in all copies or substantial portions of the | ||
13 | * Software. | ||
14 | * | ||
15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
16 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
17 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | ||
18 | * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
19 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING | ||
20 | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER | ||
21 | * DEALINGS IN THE SOFTWARE. | ||
22 | * | ||
23 | * Authors: | ||
24 | * Jackie Li<yaodong.li@intel.com> | ||
25 | */ | ||
26 | |||
27 | #include <linux/freezer.h> | ||
28 | |||
29 | #include "mdfld_dsi_output.h" | ||
30 | #include "mdfld_dsi_pkg_sender.h" | ||
31 | #include "mdfld_dsi_dpi.h" | ||
32 | |||
33 | #define MDFLD_DSI_READ_MAX_COUNT 5000 | ||
34 | |||
35 | enum data_type { | ||
36 | DSI_DT_GENERIC_SHORT_WRITE_0 = 0x03, | ||
37 | DSI_DT_GENERIC_SHORT_WRITE_1 = 0x13, | ||
38 | DSI_DT_GENERIC_SHORT_WRITE_2 = 0x23, | ||
39 | DSI_DT_GENERIC_READ_0 = 0x04, | ||
40 | DSI_DT_GENERIC_READ_1 = 0x14, | ||
41 | DSI_DT_GENERIC_READ_2 = 0x24, | ||
42 | DSI_DT_GENERIC_LONG_WRITE = 0x29, | ||
43 | DSI_DT_DCS_SHORT_WRITE_0 = 0x05, | ||
44 | DSI_DT_DCS_SHORT_WRITE_1 = 0x15, | ||
45 | DSI_DT_DCS_READ = 0x06, | ||
46 | DSI_DT_DCS_LONG_WRITE = 0x39, | ||
47 | }; | ||
48 | |||
49 | enum { | ||
50 | MDFLD_DSI_PANEL_MODE_SLEEP = 0x1, | ||
51 | }; | ||
52 | |||
53 | enum { | ||
54 | MDFLD_DSI_PKG_SENDER_FREE = 0x0, | ||
55 | MDFLD_DSI_PKG_SENDER_BUSY = 0x1, | ||
56 | }; | ||
57 | |||
58 | static const char *const dsi_errors[] = { | ||
59 | "RX SOT Error", | ||
60 | "RX SOT Sync Error", | ||
61 | "RX EOT Sync Error", | ||
62 | "RX Escape Mode Entry Error", | ||
63 | "RX LP TX Sync Error", | ||
64 | "RX HS Receive Timeout Error", | ||
65 | "RX False Control Error", | ||
66 | "RX ECC Single Bit Error", | ||
67 | "RX ECC Multibit Error", | ||
68 | "RX Checksum Error", | ||
69 | "RX DSI Data Type Not Recognised", | ||
70 | "RX DSI VC ID Invalid", | ||
71 | "TX False Control Error", | ||
72 | "TX ECC Single Bit Error", | ||
73 | "TX ECC Multibit Error", | ||
74 | "TX Checksum Error", | ||
75 | "TX DSI Data Type Not Recognised", | ||
76 | "TX DSI VC ID invalid", | ||
77 | "High Contention", | ||
78 | "Low contention", | ||
79 | "DPI FIFO Under run", | ||
80 | "HS TX Timeout", | ||
81 | "LP RX Timeout", | ||
82 | "Turn Around ACK Timeout", | ||
83 | "ACK With No Error", | ||
84 | "RX Invalid TX Length", | ||
85 | "RX Prot Violation", | ||
86 | "HS Generic Write FIFO Full", | ||
87 | "LP Generic Write FIFO Full", | ||
88 | "Generic Read Data Avail" | ||
89 | "Special Packet Sent", | ||
90 | "Tearing Effect", | ||
91 | }; | ||
92 | |||
93 | static inline int wait_for_gen_fifo_empty(struct mdfld_dsi_pkg_sender *sender, | ||
94 | u32 mask) | ||
95 | { | ||
96 | struct drm_device *dev = sender->dev; | ||
97 | u32 gen_fifo_stat_reg = sender->mipi_gen_fifo_stat_reg; | ||
98 | int retry = 0xffff; | ||
99 | |||
100 | while (retry--) { | ||
101 | if ((mask & REG_READ(gen_fifo_stat_reg)) == mask) | ||
102 | return 0; | ||
103 | udelay(100); | ||
104 | } | ||
105 | DRM_ERROR("fifo is NOT empty 0x%08x\n", REG_READ(gen_fifo_stat_reg)); | ||
106 | return -EIO; | ||
107 | } | ||
108 | |||
109 | static int wait_for_all_fifos_empty(struct mdfld_dsi_pkg_sender *sender) | ||
110 | { | ||
111 | return wait_for_gen_fifo_empty(sender, (BIT(2) | BIT(10) | BIT(18) | | ||
112 | BIT(26) | BIT(27) | BIT(28))); | ||
113 | } | ||
114 | |||
115 | static int wait_for_lp_fifos_empty(struct mdfld_dsi_pkg_sender *sender) | ||
116 | { | ||
117 | return wait_for_gen_fifo_empty(sender, (BIT(10) | BIT(26))); | ||
118 | } | ||
119 | |||
120 | static int wait_for_hs_fifos_empty(struct mdfld_dsi_pkg_sender *sender) | ||
121 | { | ||
122 | return wait_for_gen_fifo_empty(sender, (BIT(2) | BIT(18))); | ||
123 | } | ||
124 | |||
125 | static int handle_dsi_error(struct mdfld_dsi_pkg_sender *sender, u32 mask) | ||
126 | { | ||
127 | u32 intr_stat_reg = sender->mipi_intr_stat_reg; | ||
128 | struct drm_device *dev = sender->dev; | ||
129 | |||
130 | dev_dbg(sender->dev->dev, "Handling error 0x%08x\n", mask); | ||
131 | |||
132 | switch (mask) { | ||
133 | case BIT(0): | ||
134 | case BIT(1): | ||
135 | case BIT(2): | ||
136 | case BIT(3): | ||
137 | case BIT(4): | ||
138 | case BIT(5): | ||
139 | case BIT(6): | ||
140 | case BIT(7): | ||
141 | case BIT(8): | ||
142 | case BIT(9): | ||
143 | case BIT(10): | ||
144 | case BIT(11): | ||
145 | case BIT(12): | ||
146 | case BIT(13): | ||
147 | dev_dbg(sender->dev->dev, "No Action required\n"); | ||
148 | break; | ||
149 | case BIT(14): | ||
150 | /*wait for all fifo empty*/ | ||
151 | /*wait_for_all_fifos_empty(sender)*/; | ||
152 | break; | ||
153 | case BIT(15): | ||
154 | dev_dbg(sender->dev->dev, "No Action required\n"); | ||
155 | break; | ||
156 | case BIT(16): | ||
157 | break; | ||
158 | case BIT(17): | ||
159 | break; | ||
160 | case BIT(18): | ||
161 | case BIT(19): | ||
162 | dev_dbg(sender->dev->dev, "High/Low contention detected\n"); | ||
163 | /*wait for contention recovery time*/ | ||
164 | /*mdelay(10);*/ | ||
165 | /*wait for all fifo empty*/ | ||
166 | if (0) | ||
167 | wait_for_all_fifos_empty(sender); | ||
168 | break; | ||
169 | case BIT(20): | ||
170 | dev_dbg(sender->dev->dev, "No Action required\n"); | ||
171 | break; | ||
172 | case BIT(21): | ||
173 | /*wait for all fifo empty*/ | ||
174 | /*wait_for_all_fifos_empty(sender);*/ | ||
175 | break; | ||
176 | case BIT(22): | ||
177 | break; | ||
178 | case BIT(23): | ||
179 | case BIT(24): | ||
180 | case BIT(25): | ||
181 | case BIT(26): | ||
182 | case BIT(27): | ||
183 | dev_dbg(sender->dev->dev, "HS Gen fifo full\n"); | ||
184 | REG_WRITE(intr_stat_reg, mask); | ||
185 | wait_for_hs_fifos_empty(sender); | ||
186 | break; | ||
187 | case BIT(28): | ||
188 | dev_dbg(sender->dev->dev, "LP Gen fifo full\n"); | ||
189 | REG_WRITE(intr_stat_reg, mask); | ||
190 | wait_for_lp_fifos_empty(sender); | ||
191 | break; | ||
192 | case BIT(29): | ||
193 | case BIT(30): | ||
194 | case BIT(31): | ||
195 | dev_dbg(sender->dev->dev, "No Action required\n"); | ||
196 | break; | ||
197 | } | ||
198 | |||
199 | if (mask & REG_READ(intr_stat_reg)) | ||
200 | dev_dbg(sender->dev->dev, | ||
201 | "Cannot clean interrupt 0x%08x\n", mask); | ||
202 | return 0; | ||
203 | } | ||
204 | |||
205 | static int dsi_error_handler(struct mdfld_dsi_pkg_sender *sender) | ||
206 | { | ||
207 | struct drm_device *dev = sender->dev; | ||
208 | u32 intr_stat_reg = sender->mipi_intr_stat_reg; | ||
209 | u32 mask; | ||
210 | u32 intr_stat; | ||
211 | int i; | ||
212 | int err = 0; | ||
213 | |||
214 | intr_stat = REG_READ(intr_stat_reg); | ||
215 | |||
216 | for (i = 0; i < 32; i++) { | ||
217 | mask = (0x00000001UL) << i; | ||
218 | if (intr_stat & mask) { | ||
219 | dev_dbg(sender->dev->dev, "[DSI]: %s\n", dsi_errors[i]); | ||
220 | err = handle_dsi_error(sender, mask); | ||
221 | if (err) | ||
222 | DRM_ERROR("Cannot handle error\n"); | ||
223 | } | ||
224 | } | ||
225 | return err; | ||
226 | } | ||
227 | |||
228 | static int send_short_pkg(struct mdfld_dsi_pkg_sender *sender, u8 data_type, | ||
229 | u8 cmd, u8 param, bool hs) | ||
230 | { | ||
231 | struct drm_device *dev = sender->dev; | ||
232 | u32 ctrl_reg; | ||
233 | u32 val; | ||
234 | u8 virtual_channel = 0; | ||
235 | |||
236 | if (hs) { | ||
237 | ctrl_reg = sender->mipi_hs_gen_ctrl_reg; | ||
238 | |||
239 | /* FIXME: wait_for_hs_fifos_empty(sender); */ | ||
240 | } else { | ||
241 | ctrl_reg = sender->mipi_lp_gen_ctrl_reg; | ||
242 | |||
243 | /* FIXME: wait_for_lp_fifos_empty(sender); */ | ||
244 | } | ||
245 | |||
246 | val = FLD_VAL(param, 23, 16) | FLD_VAL(cmd, 15, 8) | | ||
247 | FLD_VAL(virtual_channel, 7, 6) | FLD_VAL(data_type, 5, 0); | ||
248 | |||
249 | REG_WRITE(ctrl_reg, val); | ||
250 | |||
251 | return 0; | ||
252 | } | ||
253 | |||
254 | static int send_long_pkg(struct mdfld_dsi_pkg_sender *sender, u8 data_type, | ||
255 | u8 *data, int len, bool hs) | ||
256 | { | ||
257 | struct drm_device *dev = sender->dev; | ||
258 | u32 ctrl_reg; | ||
259 | u32 data_reg; | ||
260 | u32 val; | ||
261 | u8 *p; | ||
262 | u8 b1, b2, b3, b4; | ||
263 | u8 virtual_channel = 0; | ||
264 | int i; | ||
265 | |||
266 | if (hs) { | ||
267 | ctrl_reg = sender->mipi_hs_gen_ctrl_reg; | ||
268 | data_reg = sender->mipi_hs_gen_data_reg; | ||
269 | |||
270 | /* FIXME: wait_for_hs_fifos_empty(sender); */ | ||
271 | } else { | ||
272 | ctrl_reg = sender->mipi_lp_gen_ctrl_reg; | ||
273 | data_reg = sender->mipi_lp_gen_data_reg; | ||
274 | |||
275 | /* FIXME: wait_for_lp_fifos_empty(sender); */ | ||
276 | } | ||
277 | |||
278 | p = data; | ||
279 | for (i = 0; i < len / 4; i++) { | ||
280 | b1 = *p++; | ||
281 | b2 = *p++; | ||
282 | b3 = *p++; | ||
283 | b4 = *p++; | ||
284 | |||
285 | REG_WRITE(data_reg, b4 << 24 | b3 << 16 | b2 << 8 | b1); | ||
286 | } | ||
287 | |||
288 | i = len % 4; | ||
289 | if (i) { | ||
290 | b1 = 0; b2 = 0; b3 = 0; | ||
291 | |||
292 | switch (i) { | ||
293 | case 3: | ||
294 | b1 = *p++; | ||
295 | b2 = *p++; | ||
296 | b3 = *p++; | ||
297 | break; | ||
298 | case 2: | ||
299 | b1 = *p++; | ||
300 | b2 = *p++; | ||
301 | break; | ||
302 | case 1: | ||
303 | b1 = *p++; | ||
304 | break; | ||
305 | } | ||
306 | |||
307 | REG_WRITE(data_reg, b3 << 16 | b2 << 8 | b1); | ||
308 | } | ||
309 | |||
310 | val = FLD_VAL(len, 23, 8) | FLD_VAL(virtual_channel, 7, 6) | | ||
311 | FLD_VAL(data_type, 5, 0); | ||
312 | |||
313 | REG_WRITE(ctrl_reg, val); | ||
314 | |||
315 | return 0; | ||
316 | } | ||
317 | |||
318 | static int send_pkg_prepare(struct mdfld_dsi_pkg_sender *sender, u8 data_type, | ||
319 | u8 *data, u16 len) | ||
320 | { | ||
321 | u8 cmd; | ||
322 | |||
323 | switch (data_type) { | ||
324 | case DSI_DT_DCS_SHORT_WRITE_0: | ||
325 | case DSI_DT_DCS_SHORT_WRITE_1: | ||
326 | case DSI_DT_DCS_LONG_WRITE: | ||
327 | cmd = *data; | ||
328 | break; | ||
329 | default: | ||
330 | return 0; | ||
331 | } | ||
332 | |||
333 | /*this prevents other package sending while doing msleep*/ | ||
334 | sender->status = MDFLD_DSI_PKG_SENDER_BUSY; | ||
335 | |||
336 | /*wait for 120 milliseconds in case exit_sleep_mode just be sent*/ | ||
337 | if (unlikely(cmd == DCS_ENTER_SLEEP_MODE)) { | ||
338 | /*TODO: replace it with msleep later*/ | ||
339 | mdelay(120); | ||
340 | } | ||
341 | |||
342 | if (unlikely(cmd == DCS_EXIT_SLEEP_MODE)) { | ||
343 | /*TODO: replace it with msleep later*/ | ||
344 | mdelay(120); | ||
345 | } | ||
346 | return 0; | ||
347 | } | ||
348 | |||
349 | static int send_pkg_done(struct mdfld_dsi_pkg_sender *sender, u8 data_type, | ||
350 | u8 *data, u16 len) | ||
351 | { | ||
352 | u8 cmd; | ||
353 | |||
354 | switch (data_type) { | ||
355 | case DSI_DT_DCS_SHORT_WRITE_0: | ||
356 | case DSI_DT_DCS_SHORT_WRITE_1: | ||
357 | case DSI_DT_DCS_LONG_WRITE: | ||
358 | cmd = *data; | ||
359 | break; | ||
360 | default: | ||
361 | return 0; | ||
362 | } | ||
363 | |||
364 | /*update panel status*/ | ||
365 | if (unlikely(cmd == DCS_ENTER_SLEEP_MODE)) { | ||
366 | sender->panel_mode |= MDFLD_DSI_PANEL_MODE_SLEEP; | ||
367 | /*TODO: replace it with msleep later*/ | ||
368 | mdelay(120); | ||
369 | } else if (unlikely(cmd == DCS_EXIT_SLEEP_MODE)) { | ||
370 | sender->panel_mode &= ~MDFLD_DSI_PANEL_MODE_SLEEP; | ||
371 | /*TODO: replace it with msleep later*/ | ||
372 | mdelay(120); | ||
373 | } else if (unlikely(cmd == DCS_SOFT_RESET)) { | ||
374 | /*TODO: replace it with msleep later*/ | ||
375 | mdelay(5); | ||
376 | } | ||
377 | |||
378 | sender->status = MDFLD_DSI_PKG_SENDER_FREE; | ||
379 | |||
380 | return 0; | ||
381 | } | ||
382 | |||
383 | static int send_pkg(struct mdfld_dsi_pkg_sender *sender, u8 data_type, | ||
384 | u8 *data, u16 len, bool hs) | ||
385 | { | ||
386 | int ret; | ||
387 | |||
388 | /*handle DSI error*/ | ||
389 | ret = dsi_error_handler(sender); | ||
390 | if (ret) { | ||
391 | DRM_ERROR("Error handling failed\n"); | ||
392 | return -EAGAIN; | ||
393 | } | ||
394 | |||
395 | /* send pkg */ | ||
396 | if (sender->status == MDFLD_DSI_PKG_SENDER_BUSY) { | ||
397 | DRM_ERROR("sender is busy\n"); | ||
398 | return -EAGAIN; | ||
399 | } | ||
400 | |||
401 | ret = send_pkg_prepare(sender, data_type, data, len); | ||
402 | if (ret) { | ||
403 | DRM_ERROR("send_pkg_prepare error\n"); | ||
404 | return ret; | ||
405 | } | ||
406 | |||
407 | switch (data_type) { | ||
408 | case DSI_DT_GENERIC_SHORT_WRITE_0: | ||
409 | case DSI_DT_GENERIC_SHORT_WRITE_1: | ||
410 | case DSI_DT_GENERIC_SHORT_WRITE_2: | ||
411 | case DSI_DT_GENERIC_READ_0: | ||
412 | case DSI_DT_GENERIC_READ_1: | ||
413 | case DSI_DT_GENERIC_READ_2: | ||
414 | case DSI_DT_DCS_SHORT_WRITE_0: | ||
415 | case DSI_DT_DCS_SHORT_WRITE_1: | ||
416 | case DSI_DT_DCS_READ: | ||
417 | ret = send_short_pkg(sender, data_type, data[0], data[1], hs); | ||
418 | break; | ||
419 | case DSI_DT_GENERIC_LONG_WRITE: | ||
420 | case DSI_DT_DCS_LONG_WRITE: | ||
421 | ret = send_long_pkg(sender, data_type, data, len, hs); | ||
422 | break; | ||
423 | } | ||
424 | |||
425 | send_pkg_done(sender, data_type, data, len); | ||
426 | |||
427 | /*FIXME: should I query complete and fifo empty here?*/ | ||
428 | |||
429 | return ret; | ||
430 | } | ||
431 | |||
432 | int mdfld_dsi_send_mcs_long(struct mdfld_dsi_pkg_sender *sender, u8 *data, | ||
433 | u32 len, bool hs) | ||
434 | { | ||
435 | unsigned long flags; | ||
436 | |||
437 | if (!sender || !data || !len) { | ||
438 | DRM_ERROR("Invalid parameters\n"); | ||
439 | return -EINVAL; | ||
440 | } | ||
441 | |||
442 | spin_lock_irqsave(&sender->lock, flags); | ||
443 | send_pkg(sender, DSI_DT_DCS_LONG_WRITE, data, len, hs); | ||
444 | spin_unlock_irqrestore(&sender->lock, flags); | ||
445 | |||
446 | return 0; | ||
447 | } | ||
448 | |||
449 | int mdfld_dsi_send_mcs_short(struct mdfld_dsi_pkg_sender *sender, u8 cmd, | ||
450 | u8 param, u8 param_num, bool hs) | ||
451 | { | ||
452 | u8 data[2]; | ||
453 | unsigned long flags; | ||
454 | u8 data_type; | ||
455 | |||
456 | if (!sender) { | ||
457 | DRM_ERROR("Invalid parameter\n"); | ||
458 | return -EINVAL; | ||
459 | } | ||
460 | |||
461 | data[0] = cmd; | ||
462 | |||
463 | if (param_num) { | ||
464 | data_type = DSI_DT_DCS_SHORT_WRITE_1; | ||
465 | data[1] = param; | ||
466 | } else { | ||
467 | data_type = DSI_DT_DCS_SHORT_WRITE_0; | ||
468 | data[1] = 0; | ||
469 | } | ||
470 | |||
471 | spin_lock_irqsave(&sender->lock, flags); | ||
472 | send_pkg(sender, data_type, data, sizeof(data), hs); | ||
473 | spin_unlock_irqrestore(&sender->lock, flags); | ||
474 | |||
475 | return 0; | ||
476 | } | ||
477 | |||
478 | int mdfld_dsi_send_gen_short(struct mdfld_dsi_pkg_sender *sender, u8 param0, | ||
479 | u8 param1, u8 param_num, bool hs) | ||
480 | { | ||
481 | u8 data[2]; | ||
482 | unsigned long flags; | ||
483 | u8 data_type; | ||
484 | |||
485 | if (!sender || param_num < 0 || param_num > 2) { | ||
486 | DRM_ERROR("Invalid parameter\n"); | ||
487 | return -EINVAL; | ||
488 | } | ||
489 | |||
490 | switch (param_num) { | ||
491 | case 0: | ||
492 | data_type = DSI_DT_GENERIC_SHORT_WRITE_0; | ||
493 | data[0] = 0; | ||
494 | data[1] = 0; | ||
495 | break; | ||
496 | case 1: | ||
497 | data_type = DSI_DT_GENERIC_SHORT_WRITE_1; | ||
498 | data[0] = param0; | ||
499 | data[1] = 0; | ||
500 | break; | ||
501 | case 2: | ||
502 | data_type = DSI_DT_GENERIC_SHORT_WRITE_2; | ||
503 | data[0] = param0; | ||
504 | data[1] = param1; | ||
505 | break; | ||
506 | } | ||
507 | |||
508 | spin_lock_irqsave(&sender->lock, flags); | ||
509 | send_pkg(sender, data_type, data, sizeof(data), hs); | ||
510 | spin_unlock_irqrestore(&sender->lock, flags); | ||
511 | |||
512 | return 0; | ||
513 | } | ||
514 | |||
515 | int mdfld_dsi_send_gen_long(struct mdfld_dsi_pkg_sender *sender, u8 *data, | ||
516 | u32 len, bool hs) | ||
517 | { | ||
518 | unsigned long flags; | ||
519 | |||
520 | if (!sender || !data || !len) { | ||
521 | DRM_ERROR("Invalid parameters\n"); | ||
522 | return -EINVAL; | ||
523 | } | ||
524 | |||
525 | spin_lock_irqsave(&sender->lock, flags); | ||
526 | send_pkg(sender, DSI_DT_GENERIC_LONG_WRITE, data, len, hs); | ||
527 | spin_unlock_irqrestore(&sender->lock, flags); | ||
528 | |||
529 | return 0; | ||
530 | } | ||
531 | |||
532 | static int __read_panel_data(struct mdfld_dsi_pkg_sender *sender, u8 data_type, | ||
533 | u8 *data, u16 len, u32 *data_out, u16 len_out, bool hs) | ||
534 | { | ||
535 | unsigned long flags; | ||
536 | struct drm_device *dev = sender->dev; | ||
537 | int i; | ||
538 | u32 gen_data_reg; | ||
539 | int retry = MDFLD_DSI_READ_MAX_COUNT; | ||
540 | |||
541 | if (!sender || !data_out || !len_out) { | ||
542 | DRM_ERROR("Invalid parameters\n"); | ||
543 | return -EINVAL; | ||
544 | } | ||
545 | |||
546 | /** | ||
547 | * do reading. | ||
548 | * 0) send out generic read request | ||
549 | * 1) polling read data avail interrupt | ||
550 | * 2) read data | ||
551 | */ | ||
552 | spin_lock_irqsave(&sender->lock, flags); | ||
553 | |||
554 | REG_WRITE(sender->mipi_intr_stat_reg, BIT(29)); | ||
555 | |||
556 | if ((REG_READ(sender->mipi_intr_stat_reg) & BIT(29))) | ||
557 | DRM_ERROR("Can NOT clean read data valid interrupt\n"); | ||
558 | |||
559 | /*send out read request*/ | ||
560 | send_pkg(sender, data_type, data, len, hs); | ||
561 | |||
562 | /*polling read data avail interrupt*/ | ||
563 | while (retry && !(REG_READ(sender->mipi_intr_stat_reg) & BIT(29))) { | ||
564 | udelay(100); | ||
565 | retry--; | ||
566 | } | ||
567 | |||
568 | if (!retry) { | ||
569 | spin_unlock_irqrestore(&sender->lock, flags); | ||
570 | return -ETIMEDOUT; | ||
571 | } | ||
572 | |||
573 | REG_WRITE(sender->mipi_intr_stat_reg, BIT(29)); | ||
574 | |||
575 | /*read data*/ | ||
576 | if (hs) | ||
577 | gen_data_reg = sender->mipi_hs_gen_data_reg; | ||
578 | else | ||
579 | gen_data_reg = sender->mipi_lp_gen_data_reg; | ||
580 | |||
581 | for (i = 0; i < len_out; i++) | ||
582 | *(data_out + i) = REG_READ(gen_data_reg); | ||
583 | |||
584 | spin_unlock_irqrestore(&sender->lock, flags); | ||
585 | |||
586 | return 0; | ||
587 | } | ||
588 | |||
589 | int mdfld_dsi_read_mcs(struct mdfld_dsi_pkg_sender *sender, u8 cmd, | ||
590 | u32 *data, u16 len, bool hs) | ||
591 | { | ||
592 | if (!sender || !data || !len) { | ||
593 | DRM_ERROR("Invalid parameters\n"); | ||
594 | return -EINVAL; | ||
595 | } | ||
596 | |||
597 | return __read_panel_data(sender, DSI_DT_DCS_READ, &cmd, 1, | ||
598 | data, len, hs); | ||
599 | } | ||
600 | |||
601 | int mdfld_dsi_pkg_sender_init(struct mdfld_dsi_connector *dsi_connector, | ||
602 | int pipe) | ||
603 | { | ||
604 | struct mdfld_dsi_pkg_sender *pkg_sender; | ||
605 | struct mdfld_dsi_config *dsi_config = | ||
606 | mdfld_dsi_get_config(dsi_connector); | ||
607 | struct drm_device *dev = dsi_config->dev; | ||
608 | u32 mipi_val = 0; | ||
609 | |||
610 | if (!dsi_connector) { | ||
611 | DRM_ERROR("Invalid parameter\n"); | ||
612 | return -EINVAL; | ||
613 | } | ||
614 | |||
615 | pkg_sender = dsi_connector->pkg_sender; | ||
616 | |||
617 | if (!pkg_sender || IS_ERR(pkg_sender)) { | ||
618 | pkg_sender = kzalloc(sizeof(struct mdfld_dsi_pkg_sender), | ||
619 | GFP_KERNEL); | ||
620 | if (!pkg_sender) { | ||
621 | DRM_ERROR("Create DSI pkg sender failed\n"); | ||
622 | return -ENOMEM; | ||
623 | } | ||
624 | dsi_connector->pkg_sender = (void *)pkg_sender; | ||
625 | } | ||
626 | |||
627 | pkg_sender->dev = dev; | ||
628 | pkg_sender->dsi_connector = dsi_connector; | ||
629 | pkg_sender->pipe = pipe; | ||
630 | pkg_sender->pkg_num = 0; | ||
631 | pkg_sender->panel_mode = 0; | ||
632 | pkg_sender->status = MDFLD_DSI_PKG_SENDER_FREE; | ||
633 | |||
634 | /*init regs*/ | ||
635 | if (pipe == 0) { | ||
636 | pkg_sender->dpll_reg = MRST_DPLL_A; | ||
637 | pkg_sender->dspcntr_reg = DSPACNTR; | ||
638 | pkg_sender->pipeconf_reg = PIPEACONF; | ||
639 | pkg_sender->dsplinoff_reg = DSPALINOFF; | ||
640 | pkg_sender->dspsurf_reg = DSPASURF; | ||
641 | pkg_sender->pipestat_reg = PIPEASTAT; | ||
642 | } else if (pipe == 2) { | ||
643 | pkg_sender->dpll_reg = MRST_DPLL_A; | ||
644 | pkg_sender->dspcntr_reg = DSPCCNTR; | ||
645 | pkg_sender->pipeconf_reg = PIPECCONF; | ||
646 | pkg_sender->dsplinoff_reg = DSPCLINOFF; | ||
647 | pkg_sender->dspsurf_reg = DSPCSURF; | ||
648 | pkg_sender->pipestat_reg = PIPECSTAT; | ||
649 | } | ||
650 | |||
651 | pkg_sender->mipi_intr_stat_reg = MIPI_INTR_STAT_REG(pipe); | ||
652 | pkg_sender->mipi_lp_gen_data_reg = MIPI_LP_GEN_DATA_REG(pipe); | ||
653 | pkg_sender->mipi_hs_gen_data_reg = MIPI_HS_GEN_DATA_REG(pipe); | ||
654 | pkg_sender->mipi_lp_gen_ctrl_reg = MIPI_LP_GEN_CTRL_REG(pipe); | ||
655 | pkg_sender->mipi_hs_gen_ctrl_reg = MIPI_HS_GEN_CTRL_REG(pipe); | ||
656 | pkg_sender->mipi_gen_fifo_stat_reg = MIPI_GEN_FIFO_STAT_REG(pipe); | ||
657 | pkg_sender->mipi_data_addr_reg = MIPI_DATA_ADD_REG(pipe); | ||
658 | pkg_sender->mipi_data_len_reg = MIPI_DATA_LEN_REG(pipe); | ||
659 | pkg_sender->mipi_cmd_addr_reg = MIPI_CMD_ADD_REG(pipe); | ||
660 | pkg_sender->mipi_cmd_len_reg = MIPI_CMD_LEN_REG(pipe); | ||
661 | |||
662 | /*init lock*/ | ||
663 | spin_lock_init(&pkg_sender->lock); | ||
664 | |||
665 | if (mdfld_get_panel_type(dev, pipe) != TC35876X) { | ||
666 | /** | ||
667 | * For video mode, don't enable DPI timing output here, | ||
668 | * will init the DPI timing output during mode setting. | ||
669 | */ | ||
670 | mipi_val = PASS_FROM_SPHY_TO_AFE | SEL_FLOPPED_HSTX; | ||
671 | |||
672 | if (pipe == 0) | ||
673 | mipi_val |= 0x2; | ||
674 | |||
675 | REG_WRITE(MIPI_PORT_CONTROL(pipe), mipi_val); | ||
676 | REG_READ(MIPI_PORT_CONTROL(pipe)); | ||
677 | |||
678 | /* do dsi controller init */ | ||
679 | mdfld_dsi_controller_init(dsi_config, pipe); | ||
680 | } | ||
681 | |||
682 | return 0; | ||
683 | } | ||
684 | |||
685 | void mdfld_dsi_pkg_sender_destroy(struct mdfld_dsi_pkg_sender *sender) | ||
686 | { | ||
687 | if (!sender || IS_ERR(sender)) | ||
688 | return; | ||
689 | |||
690 | /*free*/ | ||
691 | kfree(sender); | ||
692 | } | ||
693 | |||
694 | |||