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