]> git.proxmox.com Git - mirror_ubuntu-artful-kernel.git/blob - drivers/staging/msm/mddihosti.c
Merge git://git.kernel.org/pub/scm/linux/kernel/git/pkl/squashfs-linus
[mirror_ubuntu-artful-kernel.git] / drivers / staging / msm / mddihosti.c
1 /* Copyright (c) 2008-2009, Code Aurora Forum. All rights reserved.
2 *
3 * This program is free software; you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License version 2 and
5 * only version 2 as published by the Free Software Foundation.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
11 *
12 * You should have received a copy of the GNU General Public License
13 * along with this program; if not, write to the Free Software
14 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
15 * 02110-1301, USA.
16 */
17
18 #include <linux/module.h>
19 #include <linux/kernel.h>
20 #include <linux/slab.h>
21 #include <linux/delay.h>
22 #include <linux/mm.h>
23 #include <linux/fb.h>
24 #include <linux/init.h>
25 #include <linux/ioport.h>
26 #include <linux/device.h>
27 #include <linux/dma-mapping.h>
28
29 #include "msm_fb_panel.h"
30 #include "mddihost.h"
31 #include "mddihosti.h"
32
33 #define FEATURE_MDDI_UNDERRUN_RECOVERY
34 #ifndef FEATURE_MDDI_DISABLE_REVERSE
35 static void mddi_read_rev_packet(byte *data_ptr);
36 #endif
37
38 struct timer_list mddi_host_timer;
39
40 #define MDDI_DEFAULT_TIMER_LENGTH 5000 /* 5 seconds */
41 uint32 mddi_rtd_frequency = 60000; /* send RTD every 60 seconds */
42 uint32 mddi_client_status_frequency = 60000; /* get status pkt every 60 secs */
43
44 boolean mddi_vsync_detect_enabled = FALSE;
45 mddi_gpio_info_type mddi_gpio;
46
47 uint32 mddi_host_core_version;
48 boolean mddi_debug_log_statistics = FALSE;
49 /* #define FEATURE_MDDI_HOST_ENABLE_EARLY_HIBERNATION */
50 /* default to TRUE in case MDP does not vote */
51 static boolean mddi_host_mdp_active_flag = TRUE;
52 static uint32 mddi_log_stats_counter;
53 uint32 mddi_log_stats_frequency = 4000;
54
55 #define MDDI_DEFAULT_REV_PKT_SIZE 0x20
56
57 #ifndef FEATURE_MDDI_DISABLE_REVERSE
58 static boolean mddi_rev_ptr_workaround = TRUE;
59 static uint32 mddi_reg_read_retry;
60 static uint32 mddi_reg_read_retry_max = 20;
61 static boolean mddi_enable_reg_read_retry = TRUE;
62 static boolean mddi_enable_reg_read_retry_once = FALSE;
63
64 #define MDDI_MAX_REV_PKT_SIZE 0x60
65
66 #define MDDI_CLIENT_CAPABILITY_REV_PKT_SIZE 0x60
67
68 #define MDDI_VIDEO_REV_PKT_SIZE 0x40
69 #define MDDI_REV_BUFFER_SIZE MDDI_MAX_REV_PKT_SIZE
70 static byte rev_packet_data[MDDI_MAX_REV_PKT_SIZE];
71 #endif /* FEATURE_MDDI_DISABLE_REVERSE */
72 /* leave these variables so graphics will compile */
73
74 #define MDDI_MAX_REV_DATA_SIZE 128
75 /*lint -d__align(x) */
76 boolean mddi_debug_clear_rev_data = TRUE;
77
78 uint32 *mddi_reg_read_value_ptr;
79
80 mddi_client_capability_type mddi_client_capability_pkt;
81 static boolean mddi_client_capability_request = FALSE;
82
83 #ifndef FEATURE_MDDI_DISABLE_REVERSE
84
85 #define MAX_MDDI_REV_HANDLERS 2
86 #define INVALID_PKT_TYPE 0xFFFF
87
88 typedef struct {
89 mddi_rev_handler_type handler; /* ISR to be executed */
90 uint16 pkt_type;
91 } mddi_rev_pkt_handler_type;
92 static mddi_rev_pkt_handler_type mddi_rev_pkt_handler[MAX_MDDI_REV_HANDLERS] =
93 { {NULL, INVALID_PKT_TYPE}, {NULL, INVALID_PKT_TYPE} };
94
95 static boolean mddi_rev_encap_user_request = FALSE;
96 static mddi_linked_list_notify_type mddi_rev_user;
97
98 spinlock_t mddi_host_spin_lock;
99 extern uint32 mdp_in_processing;
100 #endif
101
102 typedef enum {
103 MDDI_REV_IDLE
104 #ifndef FEATURE_MDDI_DISABLE_REVERSE
105 , MDDI_REV_REG_READ_ISSUED,
106 MDDI_REV_REG_READ_SENT,
107 MDDI_REV_ENCAP_ISSUED,
108 MDDI_REV_STATUS_REQ_ISSUED,
109 MDDI_REV_CLIENT_CAP_ISSUED
110 #endif
111 } mddi_rev_link_state_type;
112
113 typedef enum {
114 MDDI_LINK_DISABLED,
115 MDDI_LINK_HIBERNATING,
116 MDDI_LINK_ACTIVATING,
117 MDDI_LINK_ACTIVE
118 } mddi_host_link_state_type;
119
120 typedef struct {
121 uint32 count;
122 uint32 in_count;
123 uint32 disp_req_count;
124 uint32 state_change_count;
125 uint32 ll_done_count;
126 uint32 rev_avail_count;
127 uint32 error_count;
128 uint32 rev_encap_count;
129 uint32 llist_ptr_write_1;
130 uint32 llist_ptr_write_2;
131 } mddi_host_int_type;
132
133 typedef struct {
134 uint32 fwd_crc_count;
135 uint32 rev_crc_count;
136 uint32 pri_underflow;
137 uint32 sec_underflow;
138 uint32 rev_overflow;
139 uint32 pri_overwrite;
140 uint32 sec_overwrite;
141 uint32 rev_overwrite;
142 uint32 dma_failure;
143 uint32 rtd_failure;
144 uint32 reg_read_failure;
145 #ifdef FEATURE_MDDI_UNDERRUN_RECOVERY
146 uint32 pri_underrun_detected;
147 #endif
148 } mddi_host_stat_type;
149
150 typedef struct {
151 uint32 rtd_cnt;
152 uint32 rev_enc_cnt;
153 uint32 vid_cnt;
154 uint32 reg_acc_cnt;
155 uint32 cli_stat_cnt;
156 uint32 cli_cap_cnt;
157 uint32 reg_read_cnt;
158 uint32 link_active_cnt;
159 uint32 link_hibernate_cnt;
160 uint32 vsync_response_cnt;
161 uint32 fwd_crc_cnt;
162 uint32 rev_crc_cnt;
163 } mddi_log_params_struct_type;
164
165 typedef struct {
166 uint32 rtd_value;
167 uint32 rtd_counter;
168 uint32 client_status_cnt;
169 boolean rev_ptr_written;
170 uint8 *rev_ptr_start;
171 uint8 *rev_ptr_curr;
172 uint32 mddi_rev_ptr_write_val;
173 dma_addr_t rev_data_dma_addr;
174 uint16 rev_pkt_size;
175 mddi_rev_link_state_type rev_state;
176 mddi_host_link_state_type link_state;
177 mddi_host_driver_state_type driver_state;
178 boolean disable_hibernation;
179 uint32 saved_int_reg;
180 uint32 saved_int_en;
181 mddi_linked_list_type *llist_ptr;
182 dma_addr_t llist_dma_addr;
183 mddi_linked_list_type *llist_dma_ptr;
184 uint32 *rev_data_buf;
185 struct completion mddi_llist_avail_comp;
186 boolean mddi_waiting_for_llist_avail;
187 mddi_host_int_type int_type;
188 mddi_host_stat_type stats;
189 mddi_log_params_struct_type log_parms;
190 mddi_llist_info_type llist_info;
191 mddi_linked_list_notify_type llist_notify[MDDI_MAX_NUM_LLIST_ITEMS];
192 } mddi_host_cntl_type;
193
194 static mddi_host_type mddi_curr_host = MDDI_HOST_PRIM;
195 static mddi_host_cntl_type mhctl[MDDI_NUM_HOST_CORES];
196 mddi_linked_list_type *llist_extern[MDDI_NUM_HOST_CORES];
197 mddi_linked_list_type *llist_dma_extern[MDDI_NUM_HOST_CORES];
198 mddi_linked_list_notify_type *llist_extern_notify[MDDI_NUM_HOST_CORES];
199 static mddi_log_params_struct_type prev_parms[MDDI_NUM_HOST_CORES];
200
201 extern uint32 mdp_total_vdopkts;
202
203 static boolean mddi_host_io_clock_on = FALSE;
204 static boolean mddi_host_hclk_on = FALSE;
205
206 int int_mddi_pri_flag = FALSE;
207 int int_mddi_ext_flag = FALSE;
208
209 static void mddi_report_errors(uint32 int_reg)
210 {
211 mddi_host_type host_idx = mddi_curr_host;
212 mddi_host_cntl_type *pmhctl = &(mhctl[host_idx]);
213
214 if (int_reg & MDDI_INT_PRI_UNDERFLOW) {
215 pmhctl->stats.pri_underflow++;
216 MDDI_MSG_ERR("!!! MDDI Primary Underflow !!!\n");
217 }
218 if (int_reg & MDDI_INT_SEC_UNDERFLOW) {
219 pmhctl->stats.sec_underflow++;
220 MDDI_MSG_ERR("!!! MDDI Secondary Underflow !!!\n");
221 }
222 #ifndef FEATURE_MDDI_DISABLE_REVERSE
223 if (int_reg & MDDI_INT_REV_OVERFLOW) {
224 pmhctl->stats.rev_overflow++;
225 MDDI_MSG_ERR("!!! MDDI Reverse Overflow !!!\n");
226 pmhctl->rev_ptr_curr = pmhctl->rev_ptr_start;
227 mddi_host_reg_out(REV_PTR, pmhctl->mddi_rev_ptr_write_val);
228
229 }
230 if (int_reg & MDDI_INT_CRC_ERROR)
231 MDDI_MSG_ERR("!!! MDDI Reverse CRC Error !!!\n");
232 #endif
233 if (int_reg & MDDI_INT_PRI_OVERWRITE) {
234 pmhctl->stats.pri_overwrite++;
235 MDDI_MSG_ERR("!!! MDDI Primary Overwrite !!!\n");
236 }
237 if (int_reg & MDDI_INT_SEC_OVERWRITE) {
238 pmhctl->stats.sec_overwrite++;
239 MDDI_MSG_ERR("!!! MDDI Secondary Overwrite !!!\n");
240 }
241 #ifndef FEATURE_MDDI_DISABLE_REVERSE
242 if (int_reg & MDDI_INT_REV_OVERWRITE) {
243 pmhctl->stats.rev_overwrite++;
244 /* This will show up normally and is not a problem */
245 MDDI_MSG_DEBUG("MDDI Reverse Overwrite!\n");
246 }
247 if (int_reg & MDDI_INT_RTD_FAILURE) {
248 mddi_host_reg_outm(INTEN, MDDI_INT_RTD_FAILURE, 0);
249 pmhctl->stats.rtd_failure++;
250 MDDI_MSG_ERR("!!! MDDI RTD Failure !!!\n");
251 }
252 #endif
253 if (int_reg & MDDI_INT_DMA_FAILURE) {
254 pmhctl->stats.dma_failure++;
255 MDDI_MSG_ERR("!!! MDDI DMA Abort !!!\n");
256 }
257 }
258
259 static void mddi_host_enable_io_clock(void)
260 {
261 if (!MDDI_HOST_IS_IO_CLOCK_ON)
262 MDDI_HOST_ENABLE_IO_CLOCK;
263 }
264
265 static void mddi_host_enable_hclk(void)
266 {
267
268 if (!MDDI_HOST_IS_HCLK_ON)
269 MDDI_HOST_ENABLE_HCLK;
270 }
271
272 static void mddi_host_disable_io_clock(void)
273 {
274 #ifndef FEATURE_MDDI_HOST_IO_CLOCK_CONTROL_DISABLE
275 if (MDDI_HOST_IS_IO_CLOCK_ON)
276 MDDI_HOST_DISABLE_IO_CLOCK;
277 #endif
278 }
279
280 static void mddi_host_disable_hclk(void)
281 {
282 #ifndef FEATURE_MDDI_HOST_HCLK_CONTROL_DISABLE
283 if (MDDI_HOST_IS_HCLK_ON)
284 MDDI_HOST_DISABLE_HCLK;
285 #endif
286 }
287
288 static void mddi_vote_to_sleep(mddi_host_type host_idx, boolean sleep)
289 {
290 uint16 vote_mask;
291
292 if (host_idx == MDDI_HOST_PRIM)
293 vote_mask = 0x01;
294 else
295 vote_mask = 0x02;
296 }
297
298 static void mddi_report_state_change(uint32 int_reg)
299 {
300 mddi_host_type host_idx = mddi_curr_host;
301 mddi_host_cntl_type *pmhctl = &(mhctl[host_idx]);
302
303 if ((pmhctl->saved_int_reg & MDDI_INT_IN_HIBERNATION) &&
304 (pmhctl->saved_int_reg & MDDI_INT_LINK_ACTIVE)) {
305 /* recover from condition where the io_clock was turned off by the
306 clock driver during a transition to hibernation. The io_clock
307 disable is to prevent MDP/MDDI underruns when changing ARM
308 clock speeds. In the process of halting the ARM, the hclk
309 divider needs to be set to 1. When it is set to 1, there is
310 a small time (usecs) when hclk is off or slow, and this can
311 cause an underrun. To prevent the underrun, clock driver turns
312 off the MDDI io_clock before making the change. */
313 mddi_host_reg_out(CMD, MDDI_CMD_POWERUP);
314 }
315
316 if (int_reg & MDDI_INT_LINK_ACTIVE) {
317 pmhctl->link_state = MDDI_LINK_ACTIVE;
318 pmhctl->log_parms.link_active_cnt++;
319 pmhctl->rtd_value = mddi_host_reg_in(RTD_VAL);
320 MDDI_MSG_DEBUG("!!! MDDI Active RTD:0x%x!!!\n",
321 pmhctl->rtd_value);
322 /* now interrupt on hibernation */
323 mddi_host_reg_outm(INTEN,
324 (MDDI_INT_IN_HIBERNATION |
325 MDDI_INT_LINK_ACTIVE),
326 MDDI_INT_IN_HIBERNATION);
327
328 #ifdef DEBUG_MDDIHOSTI
329 /* if gpio interrupt is enabled, start polling at fastest
330 * registered rate
331 */
332 if (mddi_gpio.polling_enabled) {
333 timer_reg(&mddi_gpio_poll_timer,
334 mddi_gpio_poll_timer_cb, 0, mddi_gpio.polling_interval, 0);
335 }
336 #endif
337 #ifndef FEATURE_MDDI_DISABLE_REVERSE
338 if (mddi_rev_ptr_workaround) {
339 /* HW CR: need to reset reverse register stuff */
340 pmhctl->rev_ptr_written = FALSE;
341 pmhctl->rev_ptr_curr = pmhctl->rev_ptr_start;
342 }
343 #endif
344 /* vote on sleep */
345 mddi_vote_to_sleep(host_idx, FALSE);
346
347 if (host_idx == MDDI_HOST_PRIM) {
348 if (mddi_vsync_detect_enabled) {
349 /*
350 * Indicate to client specific code that vsync
351 * was enabled, but we did not detect a client
352 * intiated wakeup. The client specific
353 * handler can either reassert vsync detection,
354 * or treat this as a valid vsync.
355 */
356 mddi_client_lcd_vsync_detected(FALSE);
357 pmhctl->log_parms.vsync_response_cnt++;
358 }
359 }
360 }
361 if (int_reg & MDDI_INT_IN_HIBERNATION) {
362 pmhctl->link_state = MDDI_LINK_HIBERNATING;
363 pmhctl->log_parms.link_hibernate_cnt++;
364 MDDI_MSG_DEBUG("!!! MDDI Hibernating !!!\n");
365 /* now interrupt on link_active */
366 #ifdef FEATURE_MDDI_DISABLE_REVERSE
367 mddi_host_reg_outm(INTEN,
368 (MDDI_INT_MDDI_IN |
369 MDDI_INT_IN_HIBERNATION |
370 MDDI_INT_LINK_ACTIVE),
371 MDDI_INT_LINK_ACTIVE);
372 #else
373 mddi_host_reg_outm(INTEN,
374 (MDDI_INT_MDDI_IN |
375 MDDI_INT_IN_HIBERNATION |
376 MDDI_INT_LINK_ACTIVE),
377 (MDDI_INT_MDDI_IN | MDDI_INT_LINK_ACTIVE));
378
379 pmhctl->rtd_counter = mddi_rtd_frequency;
380
381 if (pmhctl->rev_state != MDDI_REV_IDLE) {
382 /* a rev_encap will not wake up the link, so we do that here */
383 pmhctl->link_state = MDDI_LINK_ACTIVATING;
384 mddi_host_reg_out(CMD, MDDI_CMD_LINK_ACTIVE);
385 }
386 #endif
387
388 if (pmhctl->disable_hibernation) {
389 mddi_host_reg_out(CMD, MDDI_CMD_HIBERNATE);
390 mddi_host_reg_out(CMD, MDDI_CMD_LINK_ACTIVE);
391 pmhctl->link_state = MDDI_LINK_ACTIVATING;
392 }
393 #ifdef FEATURE_MDDI_UNDERRUN_RECOVERY
394 if ((pmhctl->llist_info.transmitting_start_idx !=
395 UNASSIGNED_INDEX)
396 &&
397 ((pmhctl->
398 saved_int_reg & (MDDI_INT_PRI_LINK_LIST_DONE |
399 MDDI_INT_PRI_PTR_READ)) ==
400 MDDI_INT_PRI_PTR_READ)) {
401 mddi_linked_list_type *llist_dma;
402 llist_dma = pmhctl->llist_dma_ptr;
403 /*
404 * All indications are that we have not received a
405 * linked list done interrupt, due to an underrun
406 * condition. Recovery attempt is to send again.
407 */
408 dma_coherent_pre_ops();
409 /* Write to primary pointer register again */
410 mddi_host_reg_out(PRI_PTR,
411 &llist_dma[pmhctl->llist_info.
412 transmitting_start_idx]);
413 pmhctl->stats.pri_underrun_detected++;
414 }
415 #endif
416
417 /* vote on sleep */
418 if (pmhctl->link_state == MDDI_LINK_HIBERNATING) {
419 mddi_vote_to_sleep(host_idx, TRUE);
420 }
421
422 #ifdef DEBUG_MDDIHOSTI
423 /* need to stop polling timer */
424 if (mddi_gpio.polling_enabled) {
425 (void) timer_clr(&mddi_gpio_poll_timer, T_NONE);
426 }
427 #endif
428 }
429 }
430
431 void mddi_host_timer_service(unsigned long data)
432 {
433 #ifndef FEATURE_MDDI_DISABLE_REVERSE
434 unsigned long flags;
435 #endif
436 mddi_host_type host_idx;
437 mddi_host_cntl_type *pmhctl;
438
439 unsigned long time_ms = MDDI_DEFAULT_TIMER_LENGTH;
440 init_timer(&mddi_host_timer);
441 mddi_host_timer.function = mddi_host_timer_service;
442 mddi_host_timer.data = 0;
443
444 mddi_host_timer.expires = jiffies + ((time_ms * HZ) / 1000);
445 add_timer(&mddi_host_timer);
446
447 for (host_idx = MDDI_HOST_PRIM; host_idx < MDDI_NUM_HOST_CORES;
448 host_idx++) {
449 pmhctl = &(mhctl[host_idx]);
450 mddi_log_stats_counter += (uint32) time_ms;
451 #ifndef FEATURE_MDDI_DISABLE_REVERSE
452 pmhctl->rtd_counter += (uint32) time_ms;
453 pmhctl->client_status_cnt += (uint32) time_ms;
454
455 if (host_idx == MDDI_HOST_PRIM) {
456 if (pmhctl->client_status_cnt >=
457 mddi_client_status_frequency) {
458 if ((pmhctl->link_state ==
459 MDDI_LINK_HIBERNATING)
460 && (pmhctl->client_status_cnt >
461 mddi_client_status_frequency)) {
462 /*
463 * special case where we are hibernating
464 * and mddi_host_isr is not firing, so
465 * kick the link so that the status can
466 * be retrieved
467 */
468
469 /* need to wake up link before issuing
470 * rev encap command
471 */
472 MDDI_MSG_INFO("wake up link!\n");
473 spin_lock_irqsave(&mddi_host_spin_lock,
474 flags);
475 mddi_host_enable_hclk();
476 mddi_host_enable_io_clock();
477 pmhctl->link_state =
478 MDDI_LINK_ACTIVATING;
479 mddi_host_reg_out(CMD,
480 MDDI_CMD_LINK_ACTIVE);
481 spin_unlock_irqrestore
482 (&mddi_host_spin_lock, flags);
483 } else
484 if ((pmhctl->link_state == MDDI_LINK_ACTIVE)
485 && pmhctl->disable_hibernation) {
486 /*
487 * special case where we have disabled
488 * hibernation and mddi_host_isr
489 * is not firing, so enable interrupt
490 * for no pkts pending, which will
491 * generate an interrupt
492 */
493 MDDI_MSG_INFO("kick isr!\n");
494 spin_lock_irqsave(&mddi_host_spin_lock,
495 flags);
496 mddi_host_enable_hclk();
497 mddi_host_reg_outm(INTEN,
498 MDDI_INT_NO_CMD_PKTS_PEND,
499 MDDI_INT_NO_CMD_PKTS_PEND);
500 spin_unlock_irqrestore
501 (&mddi_host_spin_lock, flags);
502 }
503 }
504 }
505 #endif /* #ifndef FEATURE_MDDI_DISABLE_REVERSE */
506 }
507
508 /* Check if logging is turned on */
509 for (host_idx = MDDI_HOST_PRIM; host_idx < MDDI_NUM_HOST_CORES;
510 host_idx++) {
511 mddi_log_params_struct_type *prev_ptr = &(prev_parms[host_idx]);
512 pmhctl = &(mhctl[host_idx]);
513
514 if (mddi_debug_log_statistics) {
515
516 /* get video pkt count from MDP, since MDDI sw cannot know this */
517 pmhctl->log_parms.vid_cnt = mdp_total_vdopkts;
518
519 if (mddi_log_stats_counter >= mddi_log_stats_frequency) {
520 /* mddi_log_stats_counter = 0; */
521 if (mddi_debug_log_statistics) {
522 MDDI_MSG_NOTICE
523 ("MDDI Statistics since last report:\n");
524 MDDI_MSG_NOTICE(" Packets sent:\n");
525 MDDI_MSG_NOTICE
526 (" %d RTD packet(s)\n",
527 pmhctl->log_parms.rtd_cnt -
528 prev_ptr->rtd_cnt);
529 if (prev_ptr->rtd_cnt !=
530 pmhctl->log_parms.rtd_cnt) {
531 unsigned long flags;
532 spin_lock_irqsave
533 (&mddi_host_spin_lock,
534 flags);
535 mddi_host_enable_hclk();
536 pmhctl->rtd_value =
537 mddi_host_reg_in(RTD_VAL);
538 spin_unlock_irqrestore
539 (&mddi_host_spin_lock,
540 flags);
541 MDDI_MSG_NOTICE
542 (" RTD value=%d\n",
543 pmhctl->rtd_value);
544 }
545 MDDI_MSG_NOTICE
546 (" %d VIDEO packets\n",
547 pmhctl->log_parms.vid_cnt -
548 prev_ptr->vid_cnt);
549 MDDI_MSG_NOTICE
550 (" %d Register Access packets\n",
551 pmhctl->log_parms.reg_acc_cnt -
552 prev_ptr->reg_acc_cnt);
553 MDDI_MSG_NOTICE
554 (" %d Reverse Encapsulation packet(s)\n",
555 pmhctl->log_parms.rev_enc_cnt -
556 prev_ptr->rev_enc_cnt);
557 if (prev_ptr->rev_enc_cnt !=
558 pmhctl->log_parms.rev_enc_cnt) {
559 /* report # of reverse CRC errors */
560 MDDI_MSG_NOTICE
561 (" %d reverse CRC errors detected\n",
562 pmhctl->log_parms.
563 rev_crc_cnt -
564 prev_ptr->rev_crc_cnt);
565 }
566 MDDI_MSG_NOTICE
567 (" Packets received:\n");
568 MDDI_MSG_NOTICE
569 (" %d Client Status packets",
570 pmhctl->log_parms.cli_stat_cnt -
571 prev_ptr->cli_stat_cnt);
572 if (prev_ptr->cli_stat_cnt !=
573 pmhctl->log_parms.cli_stat_cnt) {
574 MDDI_MSG_NOTICE
575 (" %d forward CRC errors reported\n",
576 pmhctl->log_parms.
577 fwd_crc_cnt -
578 prev_ptr->fwd_crc_cnt);
579 }
580 MDDI_MSG_NOTICE
581 (" %d Register Access Read packets\n",
582 pmhctl->log_parms.reg_read_cnt -
583 prev_ptr->reg_read_cnt);
584
585 if (pmhctl->link_state ==
586 MDDI_LINK_ACTIVE) {
587 MDDI_MSG_NOTICE
588 (" Current Link Status: Active\n");
589 } else
590 if ((pmhctl->link_state ==
591 MDDI_LINK_HIBERNATING)
592 || (pmhctl->link_state ==
593 MDDI_LINK_ACTIVATING)) {
594 MDDI_MSG_NOTICE
595 (" Current Link Status: Hibernation\n");
596 } else {
597 MDDI_MSG_NOTICE
598 (" Current Link Status: Inactive\n");
599 }
600 MDDI_MSG_NOTICE
601 (" Active state entered %d times\n",
602 pmhctl->log_parms.link_active_cnt -
603 prev_ptr->link_active_cnt);
604 MDDI_MSG_NOTICE
605 (" Hibernation state entered %d times\n",
606 pmhctl->log_parms.
607 link_hibernate_cnt -
608 prev_ptr->link_hibernate_cnt);
609 }
610 }
611 prev_parms[host_idx] = pmhctl->log_parms;
612 }
613 }
614 if (mddi_log_stats_counter >= mddi_log_stats_frequency)
615 mddi_log_stats_counter = 0;
616
617 return;
618 } /* mddi_host_timer_cb */
619
620 static void mddi_process_link_list_done(void)
621 {
622 mddi_host_type host_idx = mddi_curr_host;
623 mddi_host_cntl_type *pmhctl = &(mhctl[host_idx]);
624
625 /* normal forward linked list packet(s) were sent */
626 if (pmhctl->llist_info.transmitting_start_idx == UNASSIGNED_INDEX) {
627 MDDI_MSG_ERR("**** getting LL done, but no list ****\n");
628 } else {
629 uint16 idx;
630
631 #ifndef FEATURE_MDDI_DISABLE_REVERSE
632 if (pmhctl->rev_state == MDDI_REV_REG_READ_ISSUED) {
633 /* special case where a register read packet was sent */
634 pmhctl->rev_state = MDDI_REV_REG_READ_SENT;
635 if (pmhctl->llist_info.reg_read_idx == UNASSIGNED_INDEX) {
636 MDDI_MSG_ERR
637 ("**** getting LL done, but no list ****\n");
638 }
639 }
640 #endif
641 for (idx = pmhctl->llist_info.transmitting_start_idx;;) {
642 uint16 next_idx = pmhctl->llist_notify[idx].next_idx;
643 /* with reg read we don't release the waiting tcb until after
644 * the reverse encapsulation has completed.
645 */
646 if (idx != pmhctl->llist_info.reg_read_idx) {
647 /* notify task that may be waiting on this completion */
648 if (pmhctl->llist_notify[idx].waiting) {
649 complete(&
650 (pmhctl->llist_notify[idx].
651 done_comp));
652 }
653 if (pmhctl->llist_notify[idx].done_cb != NULL) {
654 (*(pmhctl->llist_notify[idx].done_cb))
655 ();
656 }
657
658 pmhctl->llist_notify[idx].in_use = FALSE;
659 pmhctl->llist_notify[idx].waiting = FALSE;
660 pmhctl->llist_notify[idx].done_cb = NULL;
661 if (idx < MDDI_NUM_DYNAMIC_LLIST_ITEMS) {
662 /* static LLIST items are configured only once */
663 pmhctl->llist_notify[idx].next_idx =
664 UNASSIGNED_INDEX;
665 }
666 /*
667 * currently, all linked list packets are
668 * register access, so we can increment the
669 * counter for that packet type here.
670 */
671 pmhctl->log_parms.reg_acc_cnt++;
672 }
673 if (idx == pmhctl->llist_info.transmitting_end_idx)
674 break;
675 idx = next_idx;
676 if (idx == UNASSIGNED_INDEX)
677 MDDI_MSG_CRIT("MDDI linked list corruption!\n");
678 }
679
680 pmhctl->llist_info.transmitting_start_idx = UNASSIGNED_INDEX;
681 pmhctl->llist_info.transmitting_end_idx = UNASSIGNED_INDEX;
682
683 if (pmhctl->mddi_waiting_for_llist_avail) {
684 if (!
685 (pmhctl->
686 llist_notify[pmhctl->llist_info.next_free_idx].
687 in_use)) {
688 pmhctl->mddi_waiting_for_llist_avail = FALSE;
689 complete(&(pmhctl->mddi_llist_avail_comp));
690 }
691 }
692 }
693
694 /* Turn off MDDI_INT_PRI_LINK_LIST_DONE interrupt */
695 mddi_host_reg_outm(INTEN, MDDI_INT_PRI_LINK_LIST_DONE, 0);
696
697 }
698
699 static void mddi_queue_forward_linked_list(void)
700 {
701 uint16 first_pkt_index;
702 mddi_linked_list_type *llist_dma;
703 mddi_host_type host_idx = mddi_curr_host;
704 mddi_host_cntl_type *pmhctl = &(mhctl[host_idx]);
705 llist_dma = pmhctl->llist_dma_ptr;
706
707 first_pkt_index = UNASSIGNED_INDEX;
708
709 if (pmhctl->llist_info.transmitting_start_idx == UNASSIGNED_INDEX) {
710 #ifndef FEATURE_MDDI_DISABLE_REVERSE
711 if (pmhctl->llist_info.reg_read_waiting) {
712 if (pmhctl->rev_state == MDDI_REV_IDLE) {
713 /*
714 * we have a register read to send and
715 * can send it now
716 */
717 pmhctl->rev_state = MDDI_REV_REG_READ_ISSUED;
718 mddi_reg_read_retry = 0;
719 first_pkt_index =
720 pmhctl->llist_info.waiting_start_idx;
721 pmhctl->llist_info.reg_read_waiting = FALSE;
722 }
723 } else
724 #endif
725 {
726 /*
727 * not register read to worry about, go ahead and write
728 * anything that may be on the waiting list.
729 */
730 first_pkt_index = pmhctl->llist_info.waiting_start_idx;
731 }
732 }
733
734 if (first_pkt_index != UNASSIGNED_INDEX) {
735 pmhctl->llist_info.transmitting_start_idx =
736 pmhctl->llist_info.waiting_start_idx;
737 pmhctl->llist_info.transmitting_end_idx =
738 pmhctl->llist_info.waiting_end_idx;
739 pmhctl->llist_info.waiting_start_idx = UNASSIGNED_INDEX;
740 pmhctl->llist_info.waiting_end_idx = UNASSIGNED_INDEX;
741
742 /* write to the primary pointer register */
743 MDDI_MSG_DEBUG("MDDI writing primary ptr with idx=%d\n",
744 first_pkt_index);
745
746 pmhctl->int_type.llist_ptr_write_2++;
747
748 dma_coherent_pre_ops();
749 mddi_host_reg_out(PRI_PTR, &llist_dma[first_pkt_index]);
750
751 /* enable interrupt when complete */
752 mddi_host_reg_outm(INTEN, MDDI_INT_PRI_LINK_LIST_DONE,
753 MDDI_INT_PRI_LINK_LIST_DONE);
754
755 }
756
757 }
758
759 #ifndef FEATURE_MDDI_DISABLE_REVERSE
760 static void mddi_read_rev_packet(byte *data_ptr)
761 {
762 uint16 i, length;
763 mddi_host_type host_idx = mddi_curr_host;
764 mddi_host_cntl_type *pmhctl = &(mhctl[host_idx]);
765
766 uint8 *rev_ptr_overflow =
767 (pmhctl->rev_ptr_start + MDDI_REV_BUFFER_SIZE);
768
769 /* first determine the length and handle invalid lengths */
770 length = *pmhctl->rev_ptr_curr++;
771 if (pmhctl->rev_ptr_curr >= rev_ptr_overflow)
772 pmhctl->rev_ptr_curr = pmhctl->rev_ptr_start;
773 length |= ((*pmhctl->rev_ptr_curr++) << 8);
774 if (pmhctl->rev_ptr_curr >= rev_ptr_overflow)
775 pmhctl->rev_ptr_curr = pmhctl->rev_ptr_start;
776 if (length > (pmhctl->rev_pkt_size - 2)) {
777 MDDI_MSG_ERR("Invalid rev pkt length %d\n", length);
778 /* rev_pkt_size should always be <= rev_ptr_size so limit to packet size */
779 length = pmhctl->rev_pkt_size - 2;
780 }
781
782 /* If the data pointer is NULL, just increment the pmhctl->rev_ptr_curr.
783 * Loop around if necessary. Don't bother reading the data.
784 */
785 if (data_ptr == NULL) {
786 pmhctl->rev_ptr_curr += length;
787 if (pmhctl->rev_ptr_curr >= rev_ptr_overflow)
788 pmhctl->rev_ptr_curr -= MDDI_REV_BUFFER_SIZE;
789 return;
790 }
791
792 data_ptr[0] = length & 0x0ff;
793 data_ptr[1] = length >> 8;
794 data_ptr += 2;
795 /* copy the data to data_ptr byte-at-a-time */
796 for (i = 0; (i < length) && (pmhctl->rev_ptr_curr < rev_ptr_overflow);
797 i++)
798 *data_ptr++ = *pmhctl->rev_ptr_curr++;
799 if (pmhctl->rev_ptr_curr >= rev_ptr_overflow)
800 pmhctl->rev_ptr_curr = pmhctl->rev_ptr_start;
801 for (; (i < length) && (pmhctl->rev_ptr_curr < rev_ptr_overflow); i++)
802 *data_ptr++ = *pmhctl->rev_ptr_curr++;
803 }
804
805 static void mddi_process_rev_packets(void)
806 {
807 uint32 rev_packet_count;
808 word i;
809 uint32 crc_errors;
810 boolean mddi_reg_read_successful = FALSE;
811 mddi_host_type host_idx = mddi_curr_host;
812 mddi_host_cntl_type *pmhctl = &(mhctl[host_idx]);
813
814 pmhctl->log_parms.rev_enc_cnt++;
815 if ((pmhctl->rev_state != MDDI_REV_ENCAP_ISSUED) &&
816 (pmhctl->rev_state != MDDI_REV_STATUS_REQ_ISSUED) &&
817 (pmhctl->rev_state != MDDI_REV_CLIENT_CAP_ISSUED)) {
818 MDDI_MSG_ERR("Wrong state %d for reverse int\n",
819 pmhctl->rev_state);
820 }
821 /* Turn off MDDI_INT_REV_AVAIL interrupt */
822 mddi_host_reg_outm(INTEN, MDDI_INT_REV_DATA_AVAIL, 0);
823
824 /* Clear rev data avail int */
825 mddi_host_reg_out(INT, MDDI_INT_REV_DATA_AVAIL);
826
827 /* Get Number of packets */
828 rev_packet_count = mddi_host_reg_in(REV_PKT_CNT);
829
830 #ifndef T_MSM7500
831 /* Clear out rev packet counter */
832 mddi_host_reg_out(REV_PKT_CNT, 0x0000);
833 #endif
834
835 #if defined(CONFIG_FB_MSM_MDP31) || defined(CONFIG_FB_MSM_MDP40)
836 if ((pmhctl->rev_state == MDDI_REV_CLIENT_CAP_ISSUED) &&
837 (rev_packet_count > 0) &&
838 (mddi_host_core_version == 0x28 ||
839 mddi_host_core_version == 0x30)) {
840
841 uint32 int_reg;
842 uint32 max_count = 0;
843
844 mddi_host_reg_out(REV_PTR, pmhctl->mddi_rev_ptr_write_val);
845 int_reg = mddi_host_reg_in(INT);
846 while ((int_reg & 0x100000) == 0) {
847 udelay(3);
848 int_reg = mddi_host_reg_in(INT);
849 if (++max_count > 100)
850 break;
851 }
852 }
853 #endif
854
855 /* Get CRC error count */
856 crc_errors = mddi_host_reg_in(REV_CRC_ERR);
857 if (crc_errors != 0) {
858 pmhctl->log_parms.rev_crc_cnt += crc_errors;
859 pmhctl->stats.rev_crc_count += crc_errors;
860 MDDI_MSG_ERR("!!! MDDI %d Reverse CRC Error(s) !!!\n",
861 crc_errors);
862 #ifndef T_MSM7500
863 /* Clear CRC error count */
864 mddi_host_reg_out(REV_CRC_ERR, 0x0000);
865 #endif
866 /* also issue an RTD to attempt recovery */
867 pmhctl->rtd_counter = mddi_rtd_frequency;
868 }
869
870 pmhctl->rtd_value = mddi_host_reg_in(RTD_VAL);
871
872 MDDI_MSG_DEBUG("MDDI rev pkt cnt=%d, ptr=0x%x, RTD:0x%x\n",
873 rev_packet_count,
874 pmhctl->rev_ptr_curr - pmhctl->rev_ptr_start,
875 pmhctl->rtd_value);
876
877 if (rev_packet_count >= 1) {
878 mddi_invalidate_cache_lines((uint32 *) pmhctl->rev_ptr_start,
879 MDDI_REV_BUFFER_SIZE);
880 }
881 /* order the reads */
882 dma_coherent_post_ops();
883 for (i = 0; i < rev_packet_count; i++) {
884 mddi_rev_packet_type *rev_pkt_ptr;
885
886 mddi_read_rev_packet(rev_packet_data);
887
888 rev_pkt_ptr = (mddi_rev_packet_type *) rev_packet_data;
889
890 if (rev_pkt_ptr->packet_length > pmhctl->rev_pkt_size) {
891 MDDI_MSG_ERR("!!!invalid packet size: %d\n",
892 rev_pkt_ptr->packet_length);
893 }
894
895 MDDI_MSG_DEBUG("MDDI rev pkt 0x%x size 0x%x\n",
896 rev_pkt_ptr->packet_type,
897 rev_pkt_ptr->packet_length);
898
899 /* Do whatever you want to do with the data based on the packet type */
900 switch (rev_pkt_ptr->packet_type) {
901 case 66: /* Client Capability */
902 {
903 mddi_client_capability_type
904 *client_capability_pkt_ptr;
905
906 client_capability_pkt_ptr =
907 (mddi_client_capability_type *)
908 rev_packet_data;
909 MDDI_MSG_NOTICE
910 ("Client Capability: Week=%d, Year=%d\n",
911 client_capability_pkt_ptr->
912 Week_of_Manufacture,
913 client_capability_pkt_ptr->
914 Year_of_Manufacture);
915 memcpy((void *)&mddi_client_capability_pkt,
916 (void *)rev_packet_data,
917 sizeof(mddi_client_capability_type));
918 pmhctl->log_parms.cli_cap_cnt++;
919 }
920 break;
921
922 case 70: /* Display Status */
923 {
924 mddi_client_status_type *client_status_pkt_ptr;
925
926 client_status_pkt_ptr =
927 (mddi_client_status_type *) rev_packet_data;
928 if ((client_status_pkt_ptr->crc_error_count !=
929 0)
930 || (client_status_pkt_ptr->
931 reverse_link_request != 0)) {
932 MDDI_MSG_ERR
933 ("Client Status: RevReq=%d, CrcErr=%d\n",
934 client_status_pkt_ptr->
935 reverse_link_request,
936 client_status_pkt_ptr->
937 crc_error_count);
938 } else {
939 MDDI_MSG_DEBUG
940 ("Client Status: RevReq=%d, CrcErr=%d\n",
941 client_status_pkt_ptr->
942 reverse_link_request,
943 client_status_pkt_ptr->
944 crc_error_count);
945 }
946 pmhctl->log_parms.fwd_crc_cnt +=
947 client_status_pkt_ptr->crc_error_count;
948 pmhctl->stats.fwd_crc_count +=
949 client_status_pkt_ptr->crc_error_count;
950 pmhctl->log_parms.cli_stat_cnt++;
951 }
952 break;
953
954 case 146: /* register access packet */
955 {
956 mddi_register_access_packet_type
957 * regacc_pkt_ptr;
958
959 regacc_pkt_ptr =
960 (mddi_register_access_packet_type *)
961 rev_packet_data;
962
963 MDDI_MSG_DEBUG
964 ("Reg Acc parse reg=0x%x, value=0x%x\n",
965 regacc_pkt_ptr->register_address,
966 regacc_pkt_ptr->register_data_list);
967
968 /* Copy register value to location passed in */
969 if (mddi_reg_read_value_ptr) {
970 #if defined(T_MSM6280) && !defined(T_MSM7200)
971 /* only least significant 16 bits are valid with 6280 */
972 *mddi_reg_read_value_ptr =
973 regacc_pkt_ptr->
974 register_data_list & 0x0000ffff;
975 #else
976 *mddi_reg_read_value_ptr =
977 regacc_pkt_ptr->register_data_list;
978 #endif
979 mddi_reg_read_successful = TRUE;
980 mddi_reg_read_value_ptr = NULL;
981 }
982
983 #ifdef DEBUG_MDDIHOSTI
984 if ((mddi_gpio.polling_enabled) &&
985 (regacc_pkt_ptr->register_address ==
986 mddi_gpio.polling_reg)) {
987 /*
988 * ToDo: need to call Linux GPIO call
989 * here...
990 */
991 mddi_client_lcd_gpio_poll(
992 regacc_pkt_ptr->register_data_list);
993 }
994 #endif
995 pmhctl->log_parms.reg_read_cnt++;
996 }
997 break;
998
999 default: /* any other packet */
1000 {
1001 uint16 hdlr;
1002
1003 for (hdlr = 0; hdlr < MAX_MDDI_REV_HANDLERS;
1004 hdlr++) {
1005 if (mddi_rev_pkt_handler[hdlr].
1006 pkt_type ==
1007 rev_pkt_ptr->packet_type) {
1008 (*
1009 (mddi_rev_pkt_handler[hdlr].
1010 handler)) (rev_pkt_ptr);
1011 /* pmhctl->rev_state = MDDI_REV_IDLE; */
1012 break;
1013 }
1014 }
1015 if (hdlr >= MAX_MDDI_REV_HANDLERS)
1016 MDDI_MSG_ERR("MDDI unknown rev pkt\n");
1017 }
1018 break;
1019 }
1020 }
1021 if ((pmhctl->rev_ptr_curr + pmhctl->rev_pkt_size) >=
1022 (pmhctl->rev_ptr_start + MDDI_REV_BUFFER_SIZE)) {
1023 pmhctl->rev_ptr_written = FALSE;
1024 }
1025
1026 if (pmhctl->rev_state == MDDI_REV_ENCAP_ISSUED) {
1027 pmhctl->rev_state = MDDI_REV_IDLE;
1028 if (mddi_rev_user.waiting) {
1029 mddi_rev_user.waiting = FALSE;
1030 complete(&(mddi_rev_user.done_comp));
1031 } else if (pmhctl->llist_info.reg_read_idx == UNASSIGNED_INDEX) {
1032 MDDI_MSG_ERR
1033 ("Reverse Encap state, but no reg read in progress\n");
1034 } else {
1035 if ((!mddi_reg_read_successful) &&
1036 (mddi_reg_read_retry < mddi_reg_read_retry_max) &&
1037 (mddi_enable_reg_read_retry)) {
1038 /*
1039 * There is a race condition that can happen
1040 * where the reverse encapsulation message is
1041 * sent out by the MDDI host before the register
1042 * read packet is sent. As a work-around for
1043 * that problem we issue the reverse
1044 * encapsulation one more time before giving up.
1045 */
1046 if (mddi_enable_reg_read_retry_once)
1047 mddi_reg_read_retry =
1048 mddi_reg_read_retry_max;
1049 pmhctl->rev_state = MDDI_REV_REG_READ_SENT;
1050 pmhctl->stats.reg_read_failure++;
1051 } else {
1052 uint16 reg_read_idx =
1053 pmhctl->llist_info.reg_read_idx;
1054
1055 mddi_reg_read_retry = 0;
1056 if (pmhctl->llist_notify[reg_read_idx].waiting) {
1057 complete(&
1058 (pmhctl->
1059 llist_notify[reg_read_idx].
1060 done_comp));
1061 }
1062 pmhctl->llist_info.reg_read_idx =
1063 UNASSIGNED_INDEX;
1064 if (pmhctl->llist_notify[reg_read_idx].
1065 done_cb != NULL) {
1066 (*
1067 (pmhctl->llist_notify[reg_read_idx].
1068 done_cb)) ();
1069 }
1070 pmhctl->llist_notify[reg_read_idx].next_idx =
1071 UNASSIGNED_INDEX;
1072 pmhctl->llist_notify[reg_read_idx].in_use =
1073 FALSE;
1074 pmhctl->llist_notify[reg_read_idx].waiting =
1075 FALSE;
1076 pmhctl->llist_notify[reg_read_idx].done_cb =
1077 NULL;
1078 if (!mddi_reg_read_successful)
1079 pmhctl->stats.reg_read_failure++;
1080 }
1081 }
1082 } else if (pmhctl->rev_state == MDDI_REV_CLIENT_CAP_ISSUED) {
1083 #if defined(CONFIG_FB_MSM_MDP31) || defined(CONFIG_FB_MSM_MDP40)
1084 if (mddi_host_core_version == 0x28 ||
1085 mddi_host_core_version == 0x30) {
1086 mddi_host_reg_out(FIFO_ALLOC, 0x00);
1087 pmhctl->rev_ptr_written = TRUE;
1088 mddi_host_reg_out(REV_PTR,
1089 pmhctl->mddi_rev_ptr_write_val);
1090 pmhctl->rev_ptr_curr = pmhctl->rev_ptr_start;
1091 mddi_host_reg_out(CMD, 0xC00);
1092 }
1093 #endif
1094
1095 if (mddi_rev_user.waiting) {
1096 mddi_rev_user.waiting = FALSE;
1097 complete(&(mddi_rev_user.done_comp));
1098 }
1099 pmhctl->rev_state = MDDI_REV_IDLE;
1100 } else {
1101 pmhctl->rev_state = MDDI_REV_IDLE;
1102 }
1103
1104 /* pmhctl->rev_state = MDDI_REV_IDLE; */
1105
1106 /* Re-enable interrupt */
1107 mddi_host_reg_outm(INTEN, MDDI_INT_REV_DATA_AVAIL,
1108 MDDI_INT_REV_DATA_AVAIL);
1109
1110 }
1111
1112 static void mddi_issue_reverse_encapsulation(void)
1113 {
1114 mddi_host_type host_idx = mddi_curr_host;
1115 mddi_host_cntl_type *pmhctl = &(mhctl[host_idx]);
1116 /* Only issue a reverse encapsulation packet if:
1117 * 1) another reverse is not in progress (MDDI_REV_IDLE).
1118 * 2) a register read has been sent (MDDI_REV_REG_READ_SENT).
1119 * 3) forward is not in progress, because of a hw bug in client that
1120 * causes forward crc errors on packet immediately after rev encap.
1121 */
1122 if (((pmhctl->rev_state == MDDI_REV_IDLE) ||
1123 (pmhctl->rev_state == MDDI_REV_REG_READ_SENT)) &&
1124 (pmhctl->llist_info.transmitting_start_idx == UNASSIGNED_INDEX) &&
1125 (!mdp_in_processing)) {
1126 uint32 mddi_command = MDDI_CMD_SEND_REV_ENCAP;
1127
1128 if ((pmhctl->rev_state == MDDI_REV_REG_READ_SENT) ||
1129 (mddi_rev_encap_user_request == TRUE)) {
1130 mddi_host_enable_io_clock();
1131 if (pmhctl->link_state == MDDI_LINK_HIBERNATING) {
1132 /* need to wake up link before issuing rev encap command */
1133 MDDI_MSG_DEBUG("wake up link!\n");
1134 pmhctl->link_state = MDDI_LINK_ACTIVATING;
1135 mddi_host_reg_out(CMD, MDDI_CMD_LINK_ACTIVE);
1136 } else {
1137 if (pmhctl->rtd_counter >= mddi_rtd_frequency) {
1138 MDDI_MSG_DEBUG
1139 ("mddi sending RTD command!\n");
1140 mddi_host_reg_out(CMD,
1141 MDDI_CMD_SEND_RTD);
1142 pmhctl->rtd_counter = 0;
1143 pmhctl->log_parms.rtd_cnt++;
1144 }
1145 if (pmhctl->rev_state != MDDI_REV_REG_READ_SENT) {
1146 /* this is generic reverse request by user, so
1147 * reset the waiting flag. */
1148 mddi_rev_encap_user_request = FALSE;
1149 }
1150 /* link is active so send reverse encap to get register read results */
1151 pmhctl->rev_state = MDDI_REV_ENCAP_ISSUED;
1152 mddi_command = MDDI_CMD_SEND_REV_ENCAP;
1153 MDDI_MSG_DEBUG("sending rev encap!\n");
1154 }
1155 } else
1156 if ((pmhctl->client_status_cnt >=
1157 mddi_client_status_frequency)
1158 || mddi_client_capability_request) {
1159 mddi_host_enable_io_clock();
1160 if (pmhctl->link_state == MDDI_LINK_HIBERNATING) {
1161 /* only wake up the link if it client status is overdue */
1162 if ((pmhctl->client_status_cnt >=
1163 (mddi_client_status_frequency * 2))
1164 || mddi_client_capability_request) {
1165 /* need to wake up link before issuing rev encap command */
1166 MDDI_MSG_DEBUG("wake up link!\n");
1167 pmhctl->link_state =
1168 MDDI_LINK_ACTIVATING;
1169 mddi_host_reg_out(CMD,
1170 MDDI_CMD_LINK_ACTIVE);
1171 }
1172 } else {
1173 if (pmhctl->rtd_counter >= mddi_rtd_frequency) {
1174 MDDI_MSG_DEBUG
1175 ("mddi sending RTD command!\n");
1176 mddi_host_reg_out(CMD,
1177 MDDI_CMD_SEND_RTD);
1178 pmhctl->rtd_counter = 0;
1179 pmhctl->log_parms.rtd_cnt++;
1180 }
1181 /* periodically get client status */
1182 MDDI_MSG_DEBUG
1183 ("mddi sending rev enc! (get status)\n");
1184 if (mddi_client_capability_request) {
1185 pmhctl->rev_state =
1186 MDDI_REV_CLIENT_CAP_ISSUED;
1187 mddi_command = MDDI_CMD_GET_CLIENT_CAP;
1188 mddi_client_capability_request = FALSE;
1189 } else {
1190 pmhctl->rev_state =
1191 MDDI_REV_STATUS_REQ_ISSUED;
1192 pmhctl->client_status_cnt = 0;
1193 mddi_command =
1194 MDDI_CMD_GET_CLIENT_STATUS;
1195 }
1196 }
1197 }
1198 if ((pmhctl->rev_state == MDDI_REV_ENCAP_ISSUED) ||
1199 (pmhctl->rev_state == MDDI_REV_STATUS_REQ_ISSUED) ||
1200 (pmhctl->rev_state == MDDI_REV_CLIENT_CAP_ISSUED)) {
1201 pmhctl->int_type.rev_encap_count++;
1202 #if defined(T_MSM6280) && !defined(T_MSM7200)
1203 mddi_rev_pointer_written = TRUE;
1204 mddi_host_reg_out(REV_PTR, mddi_rev_ptr_write_val);
1205 mddi_rev_ptr_curr = mddi_rev_ptr_start;
1206 /* force new rev ptr command */
1207 mddi_host_reg_out(CMD, 0xC00);
1208 #else
1209 if (!pmhctl->rev_ptr_written) {
1210 MDDI_MSG_DEBUG("writing reverse pointer!\n");
1211 pmhctl->rev_ptr_written = TRUE;
1212 #if defined(CONFIG_FB_MSM_MDP31) || defined(CONFIG_FB_MSM_MDP40)
1213 if ((pmhctl->rev_state ==
1214 MDDI_REV_CLIENT_CAP_ISSUED) &&
1215 (mddi_host_core_version == 0x28 ||
1216 mddi_host_core_version == 0x30)) {
1217 pmhctl->rev_ptr_written = FALSE;
1218 mddi_host_reg_out(FIFO_ALLOC, 0x02);
1219 } else
1220 mddi_host_reg_out(REV_PTR,
1221 pmhctl->
1222 mddi_rev_ptr_write_val);
1223 #else
1224 mddi_host_reg_out(REV_PTR,
1225 pmhctl->
1226 mddi_rev_ptr_write_val);
1227 #endif
1228 }
1229 #endif
1230 if (mddi_debug_clear_rev_data) {
1231 uint16 i;
1232 for (i = 0; i < MDDI_MAX_REV_DATA_SIZE / 4; i++)
1233 pmhctl->rev_data_buf[i] = 0xdddddddd;
1234 /* clean cache */
1235 mddi_flush_cache_lines(pmhctl->rev_data_buf,
1236 MDDI_MAX_REV_DATA_SIZE);
1237 }
1238
1239 /* send reverse encapsulation to get needed data */
1240 mddi_host_reg_out(CMD, mddi_command);
1241 }
1242 }
1243
1244 }
1245
1246 static void mddi_process_client_initiated_wakeup(void)
1247 {
1248 mddi_host_type host_idx = mddi_curr_host;
1249 mddi_host_cntl_type *pmhctl = &(mhctl[host_idx]);
1250
1251 /* Disable MDDI_INT Interrupt, we detect client initiated wakeup one
1252 * time for each entry into hibernation */
1253 mddi_host_reg_outm(INTEN, MDDI_INT_MDDI_IN, 0);
1254
1255 if (host_idx == MDDI_HOST_PRIM) {
1256 if (mddi_vsync_detect_enabled) {
1257 mddi_host_enable_io_clock();
1258 #ifndef MDDI_HOST_DISP_LISTEN
1259 /* issue command to bring up link */
1260 /* need to do this to clear the vsync condition */
1261 if (pmhctl->link_state == MDDI_LINK_HIBERNATING) {
1262 pmhctl->link_state = MDDI_LINK_ACTIVATING;
1263 mddi_host_reg_out(CMD, MDDI_CMD_LINK_ACTIVE);
1264 }
1265 #endif
1266 /*
1267 * Indicate to client specific code that vsync was
1268 * enabled, and we did not detect a client initiated
1269 * wakeup. The client specific handler can clear the
1270 * condition if necessary to prevent subsequent
1271 * client initiated wakeups.
1272 */
1273 mddi_client_lcd_vsync_detected(TRUE);
1274 pmhctl->log_parms.vsync_response_cnt++;
1275 MDDI_MSG_NOTICE("MDDI_INT_IN condition\n");
1276
1277 }
1278 }
1279
1280 if (mddi_gpio.polling_enabled) {
1281 mddi_host_enable_io_clock();
1282 /* check interrupt status now */
1283 (void)mddi_queue_register_read_int(mddi_gpio.polling_reg,
1284 &mddi_gpio.polling_val);
1285 }
1286 }
1287 #endif /* FEATURE_MDDI_DISABLE_REVERSE */
1288
1289 static void mddi_host_isr(void)
1290 {
1291 uint32 int_reg, int_en;
1292 #ifndef FEATURE_MDDI_DISABLE_REVERSE
1293 uint32 status_reg;
1294 #endif
1295 mddi_host_type host_idx = mddi_curr_host;
1296 mddi_host_cntl_type *pmhctl = &(mhctl[host_idx]);
1297
1298 if (!MDDI_HOST_IS_HCLK_ON) {
1299 MDDI_HOST_ENABLE_HCLK;
1300 MDDI_MSG_DEBUG("HCLK disabled, but isr is firing\n");
1301 }
1302 int_reg = mddi_host_reg_in(INT);
1303 int_en = mddi_host_reg_in(INTEN);
1304 pmhctl->saved_int_reg = int_reg;
1305 pmhctl->saved_int_en = int_en;
1306 int_reg = int_reg & int_en;
1307 pmhctl->int_type.count++;
1308
1309
1310 #ifndef FEATURE_MDDI_DISABLE_REVERSE
1311 status_reg = mddi_host_reg_in(STAT);
1312
1313 if ((int_reg & MDDI_INT_MDDI_IN) ||
1314 ((int_en & MDDI_INT_MDDI_IN) &&
1315 ((int_reg == 0) || (status_reg & MDDI_STAT_CLIENT_WAKEUP_REQ)))) {
1316 /*
1317 * The MDDI_IN condition will clear itself, and so it is
1318 * possible that MDDI_IN was the reason for the isr firing,
1319 * even though the interrupt register does not have the
1320 * MDDI_IN bit set. To check if this was the case we need to
1321 * look at the status register bit that signifies a client
1322 * initiated wakeup. If the status register bit is set, as well
1323 * as the MDDI_IN interrupt enabled, then we treat this as a
1324 * client initiated wakeup.
1325 */
1326 if (int_reg & MDDI_INT_MDDI_IN)
1327 pmhctl->int_type.in_count++;
1328 mddi_process_client_initiated_wakeup();
1329 }
1330 #endif
1331
1332 if (int_reg & MDDI_INT_LINK_STATE_CHANGES) {
1333 pmhctl->int_type.state_change_count++;
1334 mddi_report_state_change(int_reg);
1335 }
1336
1337 if (int_reg & MDDI_INT_PRI_LINK_LIST_DONE) {
1338 pmhctl->int_type.ll_done_count++;
1339 mddi_process_link_list_done();
1340 }
1341 #ifndef FEATURE_MDDI_DISABLE_REVERSE
1342 if (int_reg & MDDI_INT_REV_DATA_AVAIL) {
1343 pmhctl->int_type.rev_avail_count++;
1344 mddi_process_rev_packets();
1345 }
1346 #endif
1347
1348 if (int_reg & MDDI_INT_ERROR_CONDITIONS) {
1349 pmhctl->int_type.error_count++;
1350 mddi_report_errors(int_reg);
1351
1352 mddi_host_reg_out(INT, int_reg & MDDI_INT_ERROR_CONDITIONS);
1353 }
1354 #ifndef FEATURE_MDDI_DISABLE_REVERSE
1355 mddi_issue_reverse_encapsulation();
1356
1357 if ((pmhctl->rev_state != MDDI_REV_ENCAP_ISSUED) &&
1358 (pmhctl->rev_state != MDDI_REV_STATUS_REQ_ISSUED))
1359 #endif
1360 /* don't want simultaneous reverse and forward with Eagle */
1361 mddi_queue_forward_linked_list();
1362
1363 if (int_reg & MDDI_INT_NO_CMD_PKTS_PEND) {
1364 /* this interrupt is used to kick the isr when hibernation is disabled */
1365 mddi_host_reg_outm(INTEN, MDDI_INT_NO_CMD_PKTS_PEND, 0);
1366 }
1367
1368 if ((!mddi_host_mdp_active_flag) &&
1369 (!mddi_vsync_detect_enabled) &&
1370 (pmhctl->llist_info.transmitting_start_idx == UNASSIGNED_INDEX) &&
1371 (pmhctl->llist_info.waiting_start_idx == UNASSIGNED_INDEX) &&
1372 (pmhctl->rev_state == MDDI_REV_IDLE)) {
1373 if (pmhctl->link_state == MDDI_LINK_HIBERNATING) {
1374 mddi_host_disable_io_clock();
1375 mddi_host_disable_hclk();
1376 }
1377 #ifdef FEATURE_MDDI_HOST_ENABLE_EARLY_HIBERNATION
1378 else if ((pmhctl->link_state == MDDI_LINK_ACTIVE) &&
1379 (!pmhctl->disable_hibernation)) {
1380 mddi_host_reg_out(CMD, MDDI_CMD_POWERDOWN);
1381 }
1382 #endif
1383 }
1384 }
1385
1386 static void mddi_host_isr_primary(void)
1387 {
1388 mddi_curr_host = MDDI_HOST_PRIM;
1389 mddi_host_isr();
1390 }
1391
1392 irqreturn_t mddi_pmdh_isr_proxy(int irq, void *ptr)
1393 {
1394 mddi_host_isr_primary();
1395 return IRQ_HANDLED;
1396 }
1397
1398 static void mddi_host_isr_external(void)
1399 {
1400 mddi_curr_host = MDDI_HOST_EXT;
1401 mddi_host_isr();
1402 mddi_curr_host = MDDI_HOST_PRIM;
1403 }
1404
1405 irqreturn_t mddi_emdh_isr_proxy(int irq, void *ptr)
1406 {
1407 mddi_host_isr_external();
1408 return IRQ_HANDLED;
1409 }
1410
1411 static void mddi_host_initialize_registers(mddi_host_type host_idx)
1412 {
1413 uint32 pad_reg_val;
1414 mddi_host_cntl_type *pmhctl = &(mhctl[host_idx]);
1415
1416 if (pmhctl->driver_state == MDDI_DRIVER_ENABLED)
1417 return;
1418
1419 /* turn on HCLK to MDDI host core */
1420 mddi_host_enable_hclk();
1421
1422 /* MDDI Reset command */
1423 mddi_host_reg_out(CMD, MDDI_CMD_RESET);
1424
1425 /* Version register (= 0x01) */
1426 mddi_host_reg_out(VERSION, 0x0001);
1427
1428 /* Bytes per subframe register */
1429 mddi_host_reg_out(BPS, MDDI_HOST_BYTES_PER_SUBFRAME);
1430
1431 /* Subframes per media frames register (= 0x03) */
1432 mddi_host_reg_out(SPM, 0x0003);
1433
1434 /* Turn Around 1 register (= 0x05) */
1435 mddi_host_reg_out(TA1_LEN, 0x0005);
1436
1437 /* Turn Around 2 register (= 0x0C) */
1438 mddi_host_reg_out(TA2_LEN, MDDI_HOST_TA2_LEN);
1439
1440 /* Drive hi register (= 0x96) */
1441 mddi_host_reg_out(DRIVE_HI, 0x0096);
1442
1443 /* Drive lo register (= 0x32) */
1444 mddi_host_reg_out(DRIVE_LO, 0x0032);
1445
1446 /* Display wakeup count register (= 0x3c) */
1447 mddi_host_reg_out(DISP_WAKE, 0x003c);
1448
1449 /* Reverse Rate Divisor register (= 0x2) */
1450 mddi_host_reg_out(REV_RATE_DIV, MDDI_HOST_REV_RATE_DIV);
1451
1452 #ifndef FEATURE_MDDI_DISABLE_REVERSE
1453 /* Reverse Pointer Size */
1454 mddi_host_reg_out(REV_SIZE, MDDI_REV_BUFFER_SIZE);
1455
1456 /* Rev Encap Size */
1457 mddi_host_reg_out(REV_ENCAP_SZ, pmhctl->rev_pkt_size);
1458 #endif
1459
1460 /* Periodic Rev Encap */
1461 /* don't send periodically */
1462 mddi_host_reg_out(CMD, MDDI_CMD_PERIODIC_REV_ENCAP);
1463
1464 pad_reg_val = mddi_host_reg_in(PAD_CTL);
1465 if (pad_reg_val == 0) {
1466 /* If we are turning on band gap, need to wait 5us before turning
1467 * on the rest of the PAD */
1468 mddi_host_reg_out(PAD_CTL, 0x08000);
1469 udelay(5);
1470 }
1471 #ifdef T_MSM7200
1472 /* Recommendation from PAD hw team */
1473 mddi_host_reg_out(PAD_CTL, 0xa850a);
1474 #else
1475 /* Recommendation from PAD hw team */
1476 mddi_host_reg_out(PAD_CTL, 0xa850f);
1477 #endif
1478
1479 #if defined(CONFIG_FB_MSM_MDP31) || defined(CONFIG_FB_MSM_MDP40)
1480 mddi_host_reg_out(PAD_IO_CTL, 0x00320000);
1481 mddi_host_reg_out(PAD_CAL, 0x00220020);
1482 #endif
1483
1484 mddi_host_core_version = mddi_host_reg_inm(CORE_VER, 0xffff);
1485
1486 #ifndef FEATURE_MDDI_DISABLE_REVERSE
1487 if (mddi_host_core_version >= 8)
1488 mddi_rev_ptr_workaround = FALSE;
1489 pmhctl->rev_ptr_curr = pmhctl->rev_ptr_start;
1490 #endif
1491
1492 if ((mddi_host_core_version > 8) && (mddi_host_core_version < 0x19))
1493 mddi_host_reg_out(TEST, 0x2);
1494
1495 /* Need an even number for counts */
1496 mddi_host_reg_out(DRIVER_START_CNT, 0x60006);
1497
1498 #ifndef T_MSM7500
1499 /* Setup defaults for MDP related register */
1500 mddi_host_reg_out(MDP_VID_FMT_DES, 0x5666);
1501 mddi_host_reg_out(MDP_VID_PIX_ATTR, 0x00C3);
1502 mddi_host_reg_out(MDP_VID_CLIENTID, 0);
1503 #endif
1504
1505 /* automatically hibernate after 1 empty subframe */
1506 if (pmhctl->disable_hibernation)
1507 mddi_host_reg_out(CMD, MDDI_CMD_HIBERNATE);
1508 else
1509 mddi_host_reg_out(CMD, MDDI_CMD_HIBERNATE | 1);
1510
1511 /* Bring up link if display (client) requests it */
1512 #ifdef MDDI_HOST_DISP_LISTEN
1513 mddi_host_reg_out(CMD, MDDI_CMD_DISP_LISTEN);
1514 #else
1515 mddi_host_reg_out(CMD, MDDI_CMD_DISP_IGNORE);
1516 #endif
1517
1518 }
1519
1520 void mddi_host_configure_interrupts(mddi_host_type host_idx, boolean enable)
1521 {
1522 unsigned long flags;
1523 mddi_host_cntl_type *pmhctl = &(mhctl[host_idx]);
1524
1525 spin_lock_irqsave(&mddi_host_spin_lock, flags);
1526
1527 /* turn on HCLK to MDDI host core if it has been disabled */
1528 mddi_host_enable_hclk();
1529 /* Clear MDDI Interrupt enable reg */
1530 mddi_host_reg_out(INTEN, 0);
1531
1532 spin_unlock_irqrestore(&mddi_host_spin_lock, flags);
1533
1534 if (enable) {
1535 pmhctl->driver_state = MDDI_DRIVER_ENABLED;
1536
1537 if (host_idx == MDDI_HOST_PRIM) {
1538 if (request_irq
1539 (INT_MDDI_PRI, mddi_pmdh_isr_proxy, IRQF_DISABLED,
1540 "PMDH", 0) != 0)
1541 printk(KERN_ERR
1542 "a mddi: unable to request_irq\n");
1543 else
1544 int_mddi_pri_flag = TRUE;
1545 } else {
1546 if (request_irq
1547 (INT_MDDI_EXT, mddi_emdh_isr_proxy, IRQF_DISABLED,
1548 "EMDH", 0) != 0)
1549 printk(KERN_ERR
1550 "b mddi: unable to request_irq\n");
1551 else
1552 int_mddi_ext_flag = TRUE;
1553 }
1554
1555 /* Set MDDI Interrupt enable reg -- Enable Reverse data avail */
1556 #ifdef FEATURE_MDDI_DISABLE_REVERSE
1557 mddi_host_reg_out(INTEN,
1558 MDDI_INT_ERROR_CONDITIONS |
1559 MDDI_INT_LINK_STATE_CHANGES);
1560 #else
1561 /* Reverse Pointer register */
1562 pmhctl->rev_ptr_written = FALSE;
1563
1564 mddi_host_reg_out(INTEN,
1565 MDDI_INT_REV_DATA_AVAIL |
1566 MDDI_INT_ERROR_CONDITIONS |
1567 MDDI_INT_LINK_STATE_CHANGES);
1568 pmhctl->rtd_counter = mddi_rtd_frequency;
1569 pmhctl->client_status_cnt = 0;
1570 #endif
1571 } else {
1572 if (pmhctl->driver_state == MDDI_DRIVER_ENABLED)
1573 pmhctl->driver_state = MDDI_DRIVER_DISABLED;
1574 }
1575
1576 }
1577
1578 static void mddi_host_powerup(mddi_host_type host_idx)
1579 {
1580 mddi_host_cntl_type *pmhctl = &(mhctl[host_idx]);
1581
1582 if (pmhctl->link_state != MDDI_LINK_DISABLED)
1583 return;
1584
1585 /* enable IO_CLK and hclk to MDDI host core */
1586 mddi_host_enable_io_clock();
1587
1588 mddi_host_initialize_registers(host_idx);
1589 mddi_host_configure_interrupts(host_idx, TRUE);
1590
1591 pmhctl->link_state = MDDI_LINK_ACTIVATING;
1592
1593 /* Link activate command */
1594 mddi_host_reg_out(CMD, MDDI_CMD_LINK_ACTIVE);
1595
1596 #ifdef CLKRGM_MDDI_IO_CLOCK_IN_MHZ
1597 MDDI_MSG_NOTICE("MDDI Host: Activating Link %d Mbps\n",
1598 CLKRGM_MDDI_IO_CLOCK_IN_MHZ * 2);
1599 #else
1600 MDDI_MSG_NOTICE("MDDI Host: Activating Link\n");
1601 #endif
1602
1603 /* Initialize the timer */
1604 if (host_idx == MDDI_HOST_PRIM)
1605 mddi_host_timer_service(0);
1606 }
1607
1608 void mddi_host_init(mddi_host_type host_idx)
1609 /* Write out the MDDI configuration registers */
1610 {
1611 static boolean initialized = FALSE;
1612 mddi_host_cntl_type *pmhctl;
1613
1614 if (host_idx >= MDDI_NUM_HOST_CORES) {
1615 MDDI_MSG_ERR("Invalid host core index\n");
1616 return;
1617 }
1618
1619 if (!initialized) {
1620 uint16 idx;
1621 mddi_host_type host;
1622 for (host = MDDI_HOST_PRIM; host < MDDI_NUM_HOST_CORES; host++) {
1623 pmhctl = &(mhctl[host]);
1624 initialized = TRUE;
1625
1626 pmhctl->llist_ptr =
1627 dma_alloc_coherent(NULL, MDDI_LLIST_POOL_SIZE,
1628 &(pmhctl->llist_dma_addr),
1629 GFP_KERNEL);
1630 pmhctl->llist_dma_ptr =
1631 (mddi_linked_list_type *) (void *)pmhctl->
1632 llist_dma_addr;
1633 #ifdef FEATURE_MDDI_DISABLE_REVERSE
1634 pmhctl->rev_data_buf = NULL;
1635 if (pmhctl->llist_ptr == NULL)
1636 #else
1637 mddi_rev_user.waiting = FALSE;
1638 init_completion(&(mddi_rev_user.done_comp));
1639 pmhctl->rev_data_buf =
1640 dma_alloc_coherent(NULL, MDDI_MAX_REV_DATA_SIZE,
1641 &(pmhctl->rev_data_dma_addr),
1642 GFP_KERNEL);
1643 if ((pmhctl->llist_ptr == NULL)
1644 || (pmhctl->rev_data_buf == NULL))
1645 #endif
1646 {
1647 MDDI_MSG_CRIT
1648 ("unable to alloc non-cached memory\n");
1649 }
1650 llist_extern[host] = pmhctl->llist_ptr;
1651 llist_dma_extern[host] = pmhctl->llist_dma_ptr;
1652 llist_extern_notify[host] = pmhctl->llist_notify;
1653
1654 for (idx = 0; idx < UNASSIGNED_INDEX; idx++) {
1655 init_completion(&
1656 (pmhctl->llist_notify[idx].
1657 done_comp));
1658 }
1659 init_completion(&(pmhctl->mddi_llist_avail_comp));
1660 spin_lock_init(&mddi_host_spin_lock);
1661 pmhctl->mddi_waiting_for_llist_avail = FALSE;
1662 pmhctl->mddi_rev_ptr_write_val =
1663 (uint32) (void *)(pmhctl->rev_data_dma_addr);
1664 pmhctl->rev_ptr_start = (void *)pmhctl->rev_data_buf;
1665
1666 pmhctl->rev_pkt_size = MDDI_DEFAULT_REV_PKT_SIZE;
1667 pmhctl->rev_state = MDDI_REV_IDLE;
1668 #ifdef IMAGE_MODEM_PROC
1669 /* assume hibernation state is last state from APPS proc, so that
1670 * we don't reinitialize the host core */
1671 pmhctl->link_state = MDDI_LINK_HIBERNATING;
1672 #else
1673 pmhctl->link_state = MDDI_LINK_DISABLED;
1674 #endif
1675 pmhctl->driver_state = MDDI_DRIVER_DISABLED;
1676 pmhctl->disable_hibernation = FALSE;
1677
1678 /* initialize llist variables */
1679 pmhctl->llist_info.transmitting_start_idx =
1680 UNASSIGNED_INDEX;
1681 pmhctl->llist_info.transmitting_end_idx =
1682 UNASSIGNED_INDEX;
1683 pmhctl->llist_info.waiting_start_idx = UNASSIGNED_INDEX;
1684 pmhctl->llist_info.waiting_end_idx = UNASSIGNED_INDEX;
1685 pmhctl->llist_info.reg_read_idx = UNASSIGNED_INDEX;
1686 pmhctl->llist_info.next_free_idx =
1687 MDDI_FIRST_DYNAMIC_LLIST_IDX;
1688 pmhctl->llist_info.reg_read_waiting = FALSE;
1689
1690 mddi_vsync_detect_enabled = FALSE;
1691 mddi_gpio.polling_enabled = FALSE;
1692
1693 pmhctl->int_type.count = 0;
1694 pmhctl->int_type.in_count = 0;
1695 pmhctl->int_type.disp_req_count = 0;
1696 pmhctl->int_type.state_change_count = 0;
1697 pmhctl->int_type.ll_done_count = 0;
1698 pmhctl->int_type.rev_avail_count = 0;
1699 pmhctl->int_type.error_count = 0;
1700 pmhctl->int_type.rev_encap_count = 0;
1701 pmhctl->int_type.llist_ptr_write_1 = 0;
1702 pmhctl->int_type.llist_ptr_write_2 = 0;
1703
1704 pmhctl->stats.fwd_crc_count = 0;
1705 pmhctl->stats.rev_crc_count = 0;
1706 pmhctl->stats.pri_underflow = 0;
1707 pmhctl->stats.sec_underflow = 0;
1708 pmhctl->stats.rev_overflow = 0;
1709 pmhctl->stats.pri_overwrite = 0;
1710 pmhctl->stats.sec_overwrite = 0;
1711 pmhctl->stats.rev_overwrite = 0;
1712 pmhctl->stats.dma_failure = 0;
1713 pmhctl->stats.rtd_failure = 0;
1714 pmhctl->stats.reg_read_failure = 0;
1715 #ifdef FEATURE_MDDI_UNDERRUN_RECOVERY
1716 pmhctl->stats.pri_underrun_detected = 0;
1717 #endif
1718
1719 pmhctl->log_parms.rtd_cnt = 0;
1720 pmhctl->log_parms.rev_enc_cnt = 0;
1721 pmhctl->log_parms.vid_cnt = 0;
1722 pmhctl->log_parms.reg_acc_cnt = 0;
1723 pmhctl->log_parms.cli_stat_cnt = 0;
1724 pmhctl->log_parms.cli_cap_cnt = 0;
1725 pmhctl->log_parms.reg_read_cnt = 0;
1726 pmhctl->log_parms.link_active_cnt = 0;
1727 pmhctl->log_parms.link_hibernate_cnt = 0;
1728 pmhctl->log_parms.fwd_crc_cnt = 0;
1729 pmhctl->log_parms.rev_crc_cnt = 0;
1730 pmhctl->log_parms.vsync_response_cnt = 0;
1731
1732 prev_parms[host_idx] = pmhctl->log_parms;
1733 mddi_client_capability_pkt.packet_length = 0;
1734 }
1735
1736 #ifndef T_MSM7500
1737 /* tell clock driver we are user of this PLL */
1738 MDDI_HOST_ENABLE_IO_CLOCK;
1739 #endif
1740 }
1741
1742 mddi_host_powerup(host_idx);
1743 pmhctl = &(mhctl[host_idx]);
1744 }
1745
1746 #ifdef CONFIG_FB_MSM_MDDI_AUTO_DETECT
1747 static uint32 mddi_client_id;
1748
1749 uint32 mddi_get_client_id(void)
1750 {
1751
1752 #ifndef FEATURE_MDDI_DISABLE_REVERSE
1753 mddi_host_type host_idx = MDDI_HOST_PRIM;
1754 static boolean client_detection_try = FALSE;
1755 mddi_host_cntl_type *pmhctl;
1756 unsigned long flags;
1757 uint16 saved_rev_pkt_size;
1758
1759 if (!client_detection_try) {
1760 /* Toshiba display requires larger drive_lo value */
1761 mddi_host_reg_out(DRIVE_LO, 0x0050);
1762
1763 pmhctl = &(mhctl[MDDI_HOST_PRIM]);
1764
1765 saved_rev_pkt_size = pmhctl->rev_pkt_size;
1766
1767 /* Increase Rev Encap Size */
1768 pmhctl->rev_pkt_size = MDDI_CLIENT_CAPABILITY_REV_PKT_SIZE;
1769 mddi_host_reg_out(REV_ENCAP_SZ, pmhctl->rev_pkt_size);
1770
1771 /* disable hibernation temporarily */
1772 if (!pmhctl->disable_hibernation)
1773 mddi_host_reg_out(CMD, MDDI_CMD_HIBERNATE);
1774
1775 mddi_rev_user.waiting = TRUE;
1776 INIT_COMPLETION(mddi_rev_user.done_comp);
1777
1778 spin_lock_irqsave(&mddi_host_spin_lock, flags);
1779
1780 /* turn on clock(s), if they have been disabled */
1781 mddi_host_enable_hclk();
1782 mddi_host_enable_io_clock();
1783
1784 mddi_client_capability_request = TRUE;
1785
1786 if (pmhctl->rev_state == MDDI_REV_IDLE) {
1787 /* attempt to send the reverse encapsulation now */
1788 mddi_issue_reverse_encapsulation();
1789 }
1790 spin_unlock_irqrestore(&mddi_host_spin_lock, flags);
1791
1792 wait_for_completion_killable(&(mddi_rev_user.done_comp));
1793
1794 /* Set Rev Encap Size back to its original value */
1795 pmhctl->rev_pkt_size = saved_rev_pkt_size;
1796 mddi_host_reg_out(REV_ENCAP_SZ, pmhctl->rev_pkt_size);
1797
1798 /* reenable auto-hibernate */
1799 if (!pmhctl->disable_hibernation)
1800 mddi_host_reg_out(CMD, MDDI_CMD_HIBERNATE | 1);
1801
1802 mddi_host_reg_out(DRIVE_LO, 0x0032);
1803 client_detection_try = TRUE;
1804
1805 mddi_client_id = (mddi_client_capability_pkt.Mfr_Name<<16) |
1806 mddi_client_capability_pkt.Product_Code;
1807
1808 if (!mddi_client_id)
1809 mddi_disable(1);
1810 }
1811
1812 #if 0
1813 switch (mddi_client_capability_pkt.Mfr_Name) {
1814 case 0x4474:
1815 if ((mddi_client_capability_pkt.Product_Code != 0x8960) &&
1816 (target == DISPLAY_1)) {
1817 ret = PRISM_WVGA;
1818 }
1819 break;
1820
1821 case 0xD263:
1822 if (target == DISPLAY_1)
1823 ret = TOSHIBA_VGA_PRIM;
1824 else if (target == DISPLAY_2)
1825 ret = TOSHIBA_QCIF_SECD;
1826 break;
1827
1828 case 0:
1829 if (mddi_client_capability_pkt.Product_Code == 0x8835) {
1830 if (target == DISPLAY_1)
1831 ret = SHARP_QVGA_PRIM;
1832 else if (target == DISPLAY_2)
1833 ret = SHARP_128x128_SECD;
1834 }
1835 break;
1836
1837 default:
1838 break;
1839 }
1840
1841 if ((!client_detection_try) && (ret != TOSHIBA_VGA_PRIM)
1842 && (ret != TOSHIBA_QCIF_SECD)) {
1843 /* Not a Toshiba display, so change drive_lo back to default value */
1844 mddi_host_reg_out(DRIVE_LO, 0x0032);
1845 }
1846 #endif
1847
1848 #endif
1849
1850 return mddi_client_id;
1851 }
1852 #endif
1853
1854 void mddi_host_powerdown(mddi_host_type host_idx)
1855 {
1856 mddi_host_cntl_type *pmhctl = &(mhctl[host_idx]);
1857
1858 if (host_idx >= MDDI_NUM_HOST_CORES) {
1859 MDDI_MSG_ERR("Invalid host core index\n");
1860 return;
1861 }
1862
1863 if (pmhctl->driver_state == MDDI_DRIVER_RESET) {
1864 return;
1865 }
1866
1867 if (host_idx == MDDI_HOST_PRIM) {
1868 /* disable timer */
1869 del_timer(&mddi_host_timer);
1870 }
1871
1872 mddi_host_configure_interrupts(host_idx, FALSE);
1873
1874 /* turn on HCLK to MDDI host core if it has been disabled */
1875 mddi_host_enable_hclk();
1876
1877 /* MDDI Reset command */
1878 mddi_host_reg_out(CMD, MDDI_CMD_RESET);
1879
1880 /* Pad Control Register */
1881 mddi_host_reg_out(PAD_CTL, 0x0);
1882
1883 /* disable IO_CLK and hclk to MDDI host core */
1884 mddi_host_disable_io_clock();
1885 mddi_host_disable_hclk();
1886
1887 pmhctl->link_state = MDDI_LINK_DISABLED;
1888 pmhctl->driver_state = MDDI_DRIVER_RESET;
1889
1890 MDDI_MSG_NOTICE("MDDI Host: Disabling Link\n");
1891
1892 }
1893
1894 uint16 mddi_get_next_free_llist_item(mddi_host_type host_idx, boolean wait)
1895 {
1896 unsigned long flags;
1897 uint16 ret_idx;
1898 boolean forced_wait = FALSE;
1899 mddi_host_cntl_type *pmhctl = &(mhctl[host_idx]);
1900
1901 ret_idx = pmhctl->llist_info.next_free_idx;
1902
1903 pmhctl->llist_info.next_free_idx++;
1904 if (pmhctl->llist_info.next_free_idx >= MDDI_NUM_DYNAMIC_LLIST_ITEMS)
1905 pmhctl->llist_info.next_free_idx = MDDI_FIRST_DYNAMIC_LLIST_IDX;
1906 spin_lock_irqsave(&mddi_host_spin_lock, flags);
1907 if (pmhctl->llist_notify[ret_idx].in_use) {
1908 if (!wait) {
1909 pmhctl->llist_info.next_free_idx = ret_idx;
1910 ret_idx = UNASSIGNED_INDEX;
1911 } else {
1912 forced_wait = TRUE;
1913 INIT_COMPLETION(pmhctl->mddi_llist_avail_comp);
1914 }
1915 }
1916 spin_unlock_irqrestore(&mddi_host_spin_lock, flags);
1917
1918 if (forced_wait) {
1919 wait_for_completion_killable(&
1920 (pmhctl->
1921 mddi_llist_avail_comp));
1922 MDDI_MSG_ERR("task waiting on mddi llist item\n");
1923 }
1924
1925 if (ret_idx != UNASSIGNED_INDEX) {
1926 pmhctl->llist_notify[ret_idx].waiting = FALSE;
1927 pmhctl->llist_notify[ret_idx].done_cb = NULL;
1928 pmhctl->llist_notify[ret_idx].in_use = TRUE;
1929 pmhctl->llist_notify[ret_idx].next_idx = UNASSIGNED_INDEX;
1930 }
1931
1932 return ret_idx;
1933 }
1934
1935 uint16 mddi_get_reg_read_llist_item(mddi_host_type host_idx, boolean wait)
1936 {
1937 #ifdef FEATURE_MDDI_DISABLE_REVERSE
1938 MDDI_MSG_CRIT("No reverse link available\n");
1939 (void)wait;
1940 return FALSE;
1941 #else
1942 unsigned long flags;
1943 uint16 ret_idx;
1944 boolean error = FALSE;
1945 mddi_host_cntl_type *pmhctl = &(mhctl[host_idx]);
1946
1947 spin_lock_irqsave(&mddi_host_spin_lock, flags);
1948 if (pmhctl->llist_info.reg_read_idx != UNASSIGNED_INDEX) {
1949 /* need to block here or is this an error condition? */
1950 error = TRUE;
1951 ret_idx = UNASSIGNED_INDEX;
1952 }
1953 spin_unlock_irqrestore(&mddi_host_spin_lock, flags);
1954
1955 if (!error) {
1956 ret_idx = pmhctl->llist_info.reg_read_idx =
1957 mddi_get_next_free_llist_item(host_idx, wait);
1958 /* clear the reg_read_waiting flag */
1959 pmhctl->llist_info.reg_read_waiting = FALSE;
1960 }
1961
1962 if (error)
1963 MDDI_MSG_ERR("***** Reg read still in progress! ****\n");
1964 return ret_idx;
1965 #endif
1966
1967 }
1968
1969 void mddi_queue_forward_packets(uint16 first_llist_idx,
1970 uint16 last_llist_idx,
1971 boolean wait,
1972 mddi_llist_done_cb_type llist_done_cb,
1973 mddi_host_type host_idx)
1974 {
1975 unsigned long flags;
1976 mddi_linked_list_type *llist;
1977 mddi_linked_list_type *llist_dma;
1978 mddi_host_cntl_type *pmhctl = &(mhctl[host_idx]);
1979
1980 if ((first_llist_idx >= UNASSIGNED_INDEX) ||
1981 (last_llist_idx >= UNASSIGNED_INDEX)) {
1982 MDDI_MSG_ERR("MDDI queueing invalid linked list\n");
1983 return;
1984 }
1985
1986 if (pmhctl->link_state == MDDI_LINK_DISABLED)
1987 MDDI_MSG_CRIT("MDDI host powered down!\n");
1988
1989 llist = pmhctl->llist_ptr;
1990 llist_dma = pmhctl->llist_dma_ptr;
1991
1992 /* clean cache so MDDI host can read data */
1993 memory_barrier();
1994
1995 pmhctl->llist_notify[last_llist_idx].waiting = wait;
1996 if (wait)
1997 INIT_COMPLETION(pmhctl->llist_notify[last_llist_idx].done_comp);
1998 pmhctl->llist_notify[last_llist_idx].done_cb = llist_done_cb;
1999
2000 spin_lock_irqsave(&mddi_host_spin_lock, flags);
2001
2002 if ((pmhctl->llist_info.transmitting_start_idx == UNASSIGNED_INDEX) &&
2003 (pmhctl->llist_info.waiting_start_idx == UNASSIGNED_INDEX) &&
2004 (pmhctl->rev_state == MDDI_REV_IDLE)) {
2005 /* no packets are currently transmitting */
2006 #ifndef FEATURE_MDDI_DISABLE_REVERSE
2007 if (first_llist_idx == pmhctl->llist_info.reg_read_idx) {
2008 /* This is the special case where the packet is a register read. */
2009 pmhctl->rev_state = MDDI_REV_REG_READ_ISSUED;
2010 mddi_reg_read_retry = 0;
2011 /* mddi_rev_reg_read_attempt = 1; */
2012 }
2013 #endif
2014 /* assign transmitting index values */
2015 pmhctl->llist_info.transmitting_start_idx = first_llist_idx;
2016 pmhctl->llist_info.transmitting_end_idx = last_llist_idx;
2017
2018 /* turn on clock(s), if they have been disabled */
2019 mddi_host_enable_hclk();
2020 mddi_host_enable_io_clock();
2021 pmhctl->int_type.llist_ptr_write_1++;
2022 /* Write to primary pointer register */
2023 dma_coherent_pre_ops();
2024 mddi_host_reg_out(PRI_PTR, &llist_dma[first_llist_idx]);
2025
2026 /* enable interrupt when complete */
2027 mddi_host_reg_outm(INTEN, MDDI_INT_PRI_LINK_LIST_DONE,
2028 MDDI_INT_PRI_LINK_LIST_DONE);
2029
2030 } else if (pmhctl->llist_info.waiting_start_idx == UNASSIGNED_INDEX) {
2031 #ifndef FEATURE_MDDI_DISABLE_REVERSE
2032 if (first_llist_idx == pmhctl->llist_info.reg_read_idx) {
2033 /*
2034 * we have a register read to send but need to wait
2035 * for current reverse activity to end or there are
2036 * packets currently transmitting
2037 */
2038 /* mddi_rev_reg_read_attempt = 0; */
2039 pmhctl->llist_info.reg_read_waiting = TRUE;
2040 }
2041 #endif
2042
2043 /* assign waiting index values */
2044 pmhctl->llist_info.waiting_start_idx = first_llist_idx;
2045 pmhctl->llist_info.waiting_end_idx = last_llist_idx;
2046 } else {
2047 uint16 prev_end_idx = pmhctl->llist_info.waiting_end_idx;
2048 #ifndef FEATURE_MDDI_DISABLE_REVERSE
2049 if (first_llist_idx == pmhctl->llist_info.reg_read_idx) {
2050 /*
2051 * we have a register read to send but need to wait
2052 * for current reverse activity to end or there are
2053 * packets currently transmitting
2054 */
2055 /* mddi_rev_reg_read_attempt = 0; */
2056 pmhctl->llist_info.reg_read_waiting = TRUE;
2057 }
2058 #endif
2059
2060 llist = pmhctl->llist_ptr;
2061
2062 /* clear end flag in previous last packet */
2063 llist[prev_end_idx].link_controller_flags = 0;
2064 pmhctl->llist_notify[prev_end_idx].next_idx = first_llist_idx;
2065
2066 /* set the next_packet_pointer of the previous last packet */
2067 llist[prev_end_idx].next_packet_pointer =
2068 (void *)(&llist_dma[first_llist_idx]);
2069
2070 /* clean cache so MDDI host can read data */
2071 memory_barrier();
2072
2073 /* assign new waiting last index value */
2074 pmhctl->llist_info.waiting_end_idx = last_llist_idx;
2075 }
2076
2077 spin_unlock_irqrestore(&mddi_host_spin_lock, flags);
2078
2079 }
2080
2081 void mddi_host_write_pix_attr_reg(uint32 value)
2082 {
2083 (void)value;
2084 }
2085
2086 void mddi_queue_reverse_encapsulation(boolean wait)
2087 {
2088 #ifdef FEATURE_MDDI_DISABLE_REVERSE
2089 MDDI_MSG_CRIT("No reverse link available\n");
2090 (void)wait;
2091 #else
2092 unsigned long flags;
2093 boolean error = FALSE;
2094 mddi_host_type host_idx = MDDI_HOST_PRIM;
2095 mddi_host_cntl_type *pmhctl = &(mhctl[MDDI_HOST_PRIM]);
2096
2097 spin_lock_irqsave(&mddi_host_spin_lock, flags);
2098
2099 /* turn on clock(s), if they have been disabled */
2100 mddi_host_enable_hclk();
2101 mddi_host_enable_io_clock();
2102
2103 if (wait) {
2104 if (!mddi_rev_user.waiting) {
2105 mddi_rev_user.waiting = TRUE;
2106 INIT_COMPLETION(mddi_rev_user.done_comp);
2107 } else
2108 error = TRUE;
2109 }
2110 mddi_rev_encap_user_request = TRUE;
2111
2112 if (pmhctl->rev_state == MDDI_REV_IDLE) {
2113 /* attempt to send the reverse encapsulation now */
2114 mddi_host_type orig_host_idx = mddi_curr_host;
2115 mddi_curr_host = host_idx;
2116 mddi_issue_reverse_encapsulation();
2117 mddi_curr_host = orig_host_idx;
2118 }
2119 spin_unlock_irqrestore(&mddi_host_spin_lock, flags);
2120
2121 if (error) {
2122 MDDI_MSG_ERR("Reverse Encap request already in progress\n");
2123 } else if (wait)
2124 wait_for_completion_killable(&(mddi_rev_user.done_comp));
2125 #endif
2126 }
2127
2128 /* ISR to be executed */
2129 boolean mddi_set_rev_handler(mddi_rev_handler_type handler, uint16 pkt_type)
2130 {
2131 #ifdef FEATURE_MDDI_DISABLE_REVERSE
2132 MDDI_MSG_CRIT("No reverse link available\n");
2133 (void)handler;
2134 (void)pkt_type;
2135 return (FALSE);
2136 #else
2137 unsigned long flags;
2138 uint16 hdlr;
2139 boolean handler_set = FALSE;
2140 boolean overwrite = FALSE;
2141 mddi_host_type host_idx = MDDI_HOST_PRIM;
2142 mddi_host_cntl_type *pmhctl = &(mhctl[MDDI_HOST_PRIM]);
2143
2144 /* Disable interrupts */
2145 spin_lock_irqsave(&mddi_host_spin_lock, flags);
2146
2147 for (hdlr = 0; hdlr < MAX_MDDI_REV_HANDLERS; hdlr++) {
2148 if (mddi_rev_pkt_handler[hdlr].pkt_type == pkt_type) {
2149 mddi_rev_pkt_handler[hdlr].handler = handler;
2150 if (handler == NULL) {
2151 /* clearing handler from table */
2152 mddi_rev_pkt_handler[hdlr].pkt_type =
2153 INVALID_PKT_TYPE;
2154 handler_set = TRUE;
2155 if (pkt_type == 0x10) { /* video stream packet */
2156 /* ensure HCLK on to MDDI host core before register write */
2157 mddi_host_enable_hclk();
2158 /* No longer getting video, so reset rev encap size to default */
2159 pmhctl->rev_pkt_size =
2160 MDDI_DEFAULT_REV_PKT_SIZE;
2161 mddi_host_reg_out(REV_ENCAP_SZ,
2162 pmhctl->rev_pkt_size);
2163 }
2164 } else {
2165 /* already a handler for this packet */
2166 overwrite = TRUE;
2167 }
2168 break;
2169 }
2170 }
2171 if ((hdlr >= MAX_MDDI_REV_HANDLERS) && (handler != NULL)) {
2172 /* assigning new handler */
2173 for (hdlr = 0; hdlr < MAX_MDDI_REV_HANDLERS; hdlr++) {
2174 if (mddi_rev_pkt_handler[hdlr].pkt_type ==
2175 INVALID_PKT_TYPE) {
2176 if ((pkt_type == 0x10) && /* video stream packet */
2177 (pmhctl->rev_pkt_size <
2178 MDDI_VIDEO_REV_PKT_SIZE)) {
2179 /* ensure HCLK on to MDDI host core before register write */
2180 mddi_host_enable_hclk();
2181 /* Increase Rev Encap Size */
2182 pmhctl->rev_pkt_size =
2183 MDDI_VIDEO_REV_PKT_SIZE;
2184 mddi_host_reg_out(REV_ENCAP_SZ,
2185 pmhctl->rev_pkt_size);
2186 }
2187 mddi_rev_pkt_handler[hdlr].handler = handler;
2188 mddi_rev_pkt_handler[hdlr].pkt_type = pkt_type;
2189 handler_set = TRUE;
2190 break;
2191 }
2192 }
2193 }
2194
2195 /* Restore interrupts */
2196 spin_unlock_irqrestore(&mddi_host_spin_lock, flags);
2197
2198 if (overwrite)
2199 MDDI_MSG_ERR("Overwriting previous rev packet handler\n");
2200
2201 return handler_set;
2202
2203 #endif
2204 } /* mddi_set_rev_handler */
2205
2206 void mddi_host_disable_hibernation(boolean disable)
2207 {
2208 mddi_host_type host_idx = MDDI_HOST_PRIM;
2209 mddi_host_cntl_type *pmhctl = &(mhctl[MDDI_HOST_PRIM]);
2210
2211 if (disable) {
2212 pmhctl->disable_hibernation = TRUE;
2213 /* hibernation will be turned off by isr next time it is entered */
2214 } else {
2215 if (pmhctl->disable_hibernation) {
2216 unsigned long flags;
2217 spin_lock_irqsave(&mddi_host_spin_lock, flags);
2218 if (!MDDI_HOST_IS_HCLK_ON)
2219 MDDI_HOST_ENABLE_HCLK;
2220 mddi_host_reg_out(CMD, MDDI_CMD_HIBERNATE | 1);
2221 spin_unlock_irqrestore(&mddi_host_spin_lock, flags);
2222 pmhctl->disable_hibernation = FALSE;
2223 }
2224 }
2225 }
2226
2227 void mddi_mhctl_remove(mddi_host_type host_idx)
2228 {
2229 mddi_host_cntl_type *pmhctl;
2230
2231 pmhctl = &(mhctl[host_idx]);
2232
2233 dma_free_coherent(NULL, MDDI_LLIST_POOL_SIZE, (void *)pmhctl->llist_ptr,
2234 pmhctl->llist_dma_addr);
2235
2236 dma_free_coherent(NULL, MDDI_MAX_REV_DATA_SIZE,
2237 (void *)pmhctl->rev_data_buf,
2238 pmhctl->rev_data_dma_addr);
2239 }