staging:iio: Trivial kconfig reorganization and uniformity improvements.
[linux-2.6/linux-acpi-2.6/ibm-acpi-2.6.git] / drivers / staging / msm / mddihosti.c
blobf9d6e91e8d5d92a0a6bfa975d561bccf7f9e6e13
1 /* Copyright (c) 2008-2009, Code Aurora Forum. All rights reserved.
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.
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.
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.
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>
29 #include "msm_fb_panel.h"
30 #include "mddihost.h"
31 #include "mddihosti.h"
33 #define FEATURE_MDDI_UNDERRUN_RECOVERY
34 #ifndef FEATURE_MDDI_DISABLE_REVERSE
35 static void mddi_read_rev_packet(byte *data_ptr);
36 #endif
38 struct timer_list mddi_host_timer;
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 */
44 boolean mddi_vsync_detect_enabled = FALSE;
45 mddi_gpio_info_type mddi_gpio;
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;
55 #define MDDI_DEFAULT_REV_PKT_SIZE 0x20
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;
64 #define MDDI_MAX_REV_PKT_SIZE 0x60
66 #define MDDI_CLIENT_CAPABILITY_REV_PKT_SIZE 0x60
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 */
74 #define MDDI_MAX_REV_DATA_SIZE 128
75 /*lint -d__align(x) */
76 boolean mddi_debug_clear_rev_data = TRUE;
78 uint32 *mddi_reg_read_value_ptr;
80 mddi_client_capability_type mddi_client_capability_pkt;
81 static boolean mddi_client_capability_request = FALSE;
83 #ifndef FEATURE_MDDI_DISABLE_REVERSE
85 #define MAX_MDDI_REV_HANDLERS 2
86 #define INVALID_PKT_TYPE 0xFFFF
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} };
95 static boolean mddi_rev_encap_user_request = FALSE;
96 static mddi_linked_list_notify_type mddi_rev_user;
98 spinlock_t mddi_host_spin_lock;
99 extern uint32 mdp_in_processing;
100 #endif
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;
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;
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;
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;
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;
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;
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];
201 extern uint32 mdp_total_vdopkts;
203 static boolean mddi_host_io_clock_on = FALSE;
204 static boolean mddi_host_hclk_on = FALSE;
206 int int_mddi_pri_flag = FALSE;
207 int int_mddi_ext_flag = FALSE;
209 static void mddi_report_errors(uint32 int_reg)
211 mddi_host_type host_idx = mddi_curr_host;
212 mddi_host_cntl_type *pmhctl = &(mhctl[host_idx]);
214 if (int_reg & MDDI_INT_PRI_UNDERFLOW) {
215 pmhctl->stats.pri_underflow++;
216 MDDI_MSG_ERR("!!! MDDI Primary Underflow !!!\n");
218 if (int_reg & MDDI_INT_SEC_UNDERFLOW) {
219 pmhctl->stats.sec_underflow++;
220 MDDI_MSG_ERR("!!! MDDI Secondary Underflow !!!\n");
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);
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");
237 if (int_reg & MDDI_INT_SEC_OVERWRITE) {
238 pmhctl->stats.sec_overwrite++;
239 MDDI_MSG_ERR("!!! MDDI Secondary Overwrite !!!\n");
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");
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");
252 #endif
253 if (int_reg & MDDI_INT_DMA_FAILURE) {
254 pmhctl->stats.dma_failure++;
255 MDDI_MSG_ERR("!!! MDDI DMA Abort !!!\n");
259 static void mddi_host_enable_io_clock(void)
261 if (!MDDI_HOST_IS_IO_CLOCK_ON)
262 MDDI_HOST_ENABLE_IO_CLOCK;
265 static void mddi_host_enable_hclk(void)
268 if (!MDDI_HOST_IS_HCLK_ON)
269 MDDI_HOST_ENABLE_HCLK;
272 static void mddi_host_disable_io_clock(void)
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
280 static void mddi_host_disable_hclk(void)
282 #ifndef FEATURE_MDDI_HOST_HCLK_CONTROL_DISABLE
283 if (MDDI_HOST_IS_HCLK_ON)
284 MDDI_HOST_DISABLE_HCLK;
285 #endif
288 static void mddi_vote_to_sleep(mddi_host_type host_idx, boolean sleep)
290 uint16 vote_mask;
292 if (host_idx == MDDI_HOST_PRIM)
293 vote_mask = 0x01;
294 else
295 vote_mask = 0x02;
298 static void mddi_report_state_change(uint32 int_reg)
300 mddi_host_type host_idx = mddi_curr_host;
301 mddi_host_cntl_type *pmhctl = &(mhctl[host_idx]);
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);
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);
328 #ifdef DEBUG_MDDIHOSTI
329 /* if gpio interrupt is enabled, start polling at fastest
330 * registered rate
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);
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;
343 #endif
344 /* vote on sleep */
345 mddi_vote_to_sleep(host_idx, FALSE);
347 if (host_idx == MDDI_HOST_PRIM) {
348 if (mddi_vsync_detect_enabled) {
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.
356 mddi_client_lcd_vsync_detected(FALSE);
357 pmhctl->log_parms.vsync_response_cnt++;
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));
379 pmhctl->rtd_counter = mddi_rtd_frequency;
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);
386 #endif
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;
393 #ifdef FEATURE_MDDI_UNDERRUN_RECOVERY
394 if ((pmhctl->llist_info.transmitting_start_idx !=
395 UNASSIGNED_INDEX)
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;
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.
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++;
415 #endif
417 /* vote on sleep */
418 if (pmhctl->link_state == MDDI_LINK_HIBERNATING) {
419 mddi_vote_to_sleep(host_idx, TRUE);
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);
427 #endif
431 void mddi_host_timer_service(unsigned long data)
433 #ifndef FEATURE_MDDI_DISABLE_REVERSE
434 unsigned long flags;
435 #endif
436 mddi_host_type host_idx;
437 mddi_host_cntl_type *pmhctl;
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;
444 mddi_host_timer.expires = jiffies + ((time_ms * HZ) / 1000);
445 add_timer(&mddi_host_timer);
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;
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)) {
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
469 /* need to wake up link before issuing
470 * rev encap command
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) {
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
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);
505 #endif /* #ifndef FEATURE_MDDI_DISABLE_REVERSE */
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]);
514 if (mddi_debug_log_statistics) {
516 /* get video pkt count from MDP, since MDDI sw cannot know this */
517 pmhctl->log_parms.vid_cnt = mdp_total_vdopkts;
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);
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);
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);
580 MDDI_MSG_NOTICE
581 (" %d Register Access Read packets\n",
582 pmhctl->log_parms.reg_read_cnt -
583 prev_ptr->reg_read_cnt);
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");
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);
611 prev_parms[host_idx] = pmhctl->log_parms;
614 if (mddi_log_stats_counter >= mddi_log_stats_frequency)
615 mddi_log_stats_counter = 0;
617 return;
618 } /* mddi_host_timer_cb */
620 static void mddi_process_link_list_done(void)
622 mddi_host_type host_idx = mddi_curr_host;
623 mddi_host_cntl_type *pmhctl = &(mhctl[host_idx]);
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;
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");
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.
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));
653 if (pmhctl->llist_notify[idx].done_cb != NULL) {
654 (*(pmhctl->llist_notify[idx].done_cb))
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;
667 * currently, all linked list packets are
668 * register access, so we can increment the
669 * counter for that packet type here.
671 pmhctl->log_parms.reg_acc_cnt++;
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");
680 pmhctl->llist_info.transmitting_start_idx = UNASSIGNED_INDEX;
681 pmhctl->llist_info.transmitting_end_idx = UNASSIGNED_INDEX;
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));
694 /* Turn off MDDI_INT_PRI_LINK_LIST_DONE interrupt */
695 mddi_host_reg_outm(INTEN, MDDI_INT_PRI_LINK_LIST_DONE, 0);
699 static void mddi_queue_forward_linked_list(void)
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;
707 first_pkt_index = UNASSIGNED_INDEX;
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) {
714 * we have a register read to send and
715 * can send it now
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;
723 } else
724 #endif
727 * not register read to worry about, go ahead and write
728 * anything that may be on the waiting list.
730 first_pkt_index = pmhctl->llist_info.waiting_start_idx;
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;
742 /* write to the primary pointer register */
743 MDDI_MSG_DEBUG("MDDI writing primary ptr with idx=%d\n",
744 first_pkt_index);
746 pmhctl->int_type.llist_ptr_write_2++;
748 dma_coherent_pre_ops();
749 mddi_host_reg_out(PRI_PTR, &llist_dma[first_pkt_index]);
751 /* enable interrupt when complete */
752 mddi_host_reg_outm(INTEN, MDDI_INT_PRI_LINK_LIST_DONE,
753 MDDI_INT_PRI_LINK_LIST_DONE);
759 #ifndef FEATURE_MDDI_DISABLE_REVERSE
760 static void mddi_read_rev_packet(byte *data_ptr)
762 uint16 i, length;
763 mddi_host_type host_idx = mddi_curr_host;
764 mddi_host_cntl_type *pmhctl = &(mhctl[host_idx]);
766 uint8 *rev_ptr_overflow =
767 (pmhctl->rev_ptr_start + MDDI_REV_BUFFER_SIZE);
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;
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.
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;
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++;
805 static void mddi_process_rev_packets(void)
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]);
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);
821 /* Turn off MDDI_INT_REV_AVAIL interrupt */
822 mddi_host_reg_outm(INTEN, MDDI_INT_REV_DATA_AVAIL, 0);
824 /* Clear rev data avail int */
825 mddi_host_reg_out(INT, MDDI_INT_REV_DATA_AVAIL);
827 /* Get Number of packets */
828 rev_packet_count = mddi_host_reg_in(REV_PKT_CNT);
830 #ifndef T_MSM7500
831 /* Clear out rev packet counter */
832 mddi_host_reg_out(REV_PKT_CNT, 0x0000);
833 #endif
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)) {
841 uint32 int_reg;
842 uint32 max_count = 0;
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;
853 #endif
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;
870 pmhctl->rtd_value = mddi_host_reg_in(RTD_VAL);
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);
877 if (rev_packet_count >= 1) {
878 mddi_invalidate_cache_lines((uint32 *) pmhctl->rev_ptr_start,
879 MDDI_REV_BUFFER_SIZE);
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;
886 mddi_read_rev_packet(rev_packet_data);
888 rev_pkt_ptr = (mddi_rev_packet_type *) rev_packet_data;
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);
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);
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 */
903 mddi_client_capability_type
904 *client_capability_pkt_ptr;
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++;
920 break;
922 case 70: /* Display Status */
924 mddi_client_status_type *client_status_pkt_ptr;
926 client_status_pkt_ptr =
927 (mddi_client_status_type *) rev_packet_data;
928 if ((client_status_pkt_ptr->crc_error_count !=
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);
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++;
952 break;
954 case 146: /* register access packet */
956 mddi_register_access_packet_type
957 * regacc_pkt_ptr;
959 regacc_pkt_ptr =
960 (mddi_register_access_packet_type *)
961 rev_packet_data;
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);
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;
983 #ifdef DEBUG_MDDIHOSTI
984 if ((mddi_gpio.polling_enabled) &&
985 (regacc_pkt_ptr->register_address ==
986 mddi_gpio.polling_reg)) {
988 * ToDo: need to call Linux GPIO call
989 * here...
991 mddi_client_lcd_gpio_poll(
992 regacc_pkt_ptr->register_data_list);
994 #endif
995 pmhctl->log_parms.reg_read_cnt++;
997 break;
999 default: /* any other packet */
1001 uint16 hdlr;
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) {
1009 (mddi_rev_pkt_handler[hdlr].
1010 handler)) (rev_pkt_ptr);
1011 /* pmhctl->rev_state = MDDI_REV_IDLE; */
1012 break;
1015 if (hdlr >= MAX_MDDI_REV_HANDLERS)
1016 MDDI_MSG_ERR("MDDI unknown rev pkt\n");
1018 break;
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;
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)) {
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.
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;
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));
1062 pmhctl->llist_info.reg_read_idx =
1063 UNASSIGNED_INDEX;
1064 if (pmhctl->llist_notify[reg_read_idx].
1065 done_cb != NULL) {
1067 (pmhctl->llist_notify[reg_read_idx].
1068 done_cb)) ();
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++;
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);
1093 #endif
1095 if (mddi_rev_user.waiting) {
1096 mddi_rev_user.waiting = FALSE;
1097 complete(&(mddi_rev_user.done_comp));
1099 pmhctl->rev_state = MDDI_REV_IDLE;
1100 } else {
1101 pmhctl->rev_state = MDDI_REV_IDLE;
1104 /* pmhctl->rev_state = MDDI_REV_IDLE; */
1106 /* Re-enable interrupt */
1107 mddi_host_reg_outm(INTEN, MDDI_INT_REV_DATA_AVAIL,
1108 MDDI_INT_REV_DATA_AVAIL);
1112 static void mddi_issue_reverse_encapsulation(void)
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.
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;
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++;
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;
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");
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);
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++;
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;
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
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);
1239 /* send reverse encapsulation to get needed data */
1240 mddi_host_reg_out(CMD, mddi_command);
1246 static void mddi_process_client_initiated_wakeup(void)
1248 mddi_host_type host_idx = mddi_curr_host;
1249 mddi_host_cntl_type *pmhctl = &(mhctl[host_idx]);
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);
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);
1265 #endif
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.
1273 mddi_client_lcd_vsync_detected(TRUE);
1274 pmhctl->log_parms.vsync_response_cnt++;
1275 MDDI_MSG_NOTICE("MDDI_INT_IN condition\n");
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);
1287 #endif /* FEATURE_MDDI_DISABLE_REVERSE */
1289 static void mddi_host_isr(void)
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]);
1298 if (!MDDI_HOST_IS_HCLK_ON) {
1299 MDDI_HOST_ENABLE_HCLK;
1300 MDDI_MSG_DEBUG("HCLK disabled, but isr is firing\n");
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++;
1310 #ifndef FEATURE_MDDI_DISABLE_REVERSE
1311 status_reg = mddi_host_reg_in(STAT);
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)))) {
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.
1326 if (int_reg & MDDI_INT_MDDI_IN)
1327 pmhctl->int_type.in_count++;
1328 mddi_process_client_initiated_wakeup();
1330 #endif
1332 if (int_reg & MDDI_INT_LINK_STATE_CHANGES) {
1333 pmhctl->int_type.state_change_count++;
1334 mddi_report_state_change(int_reg);
1337 if (int_reg & MDDI_INT_PRI_LINK_LIST_DONE) {
1338 pmhctl->int_type.ll_done_count++;
1339 mddi_process_link_list_done();
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();
1346 #endif
1348 if (int_reg & MDDI_INT_ERROR_CONDITIONS) {
1349 pmhctl->int_type.error_count++;
1350 mddi_report_errors(int_reg);
1352 mddi_host_reg_out(INT, int_reg & MDDI_INT_ERROR_CONDITIONS);
1354 #ifndef FEATURE_MDDI_DISABLE_REVERSE
1355 mddi_issue_reverse_encapsulation();
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();
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);
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();
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);
1382 #endif
1386 static void mddi_host_isr_primary(void)
1388 mddi_curr_host = MDDI_HOST_PRIM;
1389 mddi_host_isr();
1392 irqreturn_t mddi_pmdh_isr_proxy(int irq, void *ptr)
1394 mddi_host_isr_primary();
1395 return IRQ_HANDLED;
1398 static void mddi_host_isr_external(void)
1400 mddi_curr_host = MDDI_HOST_EXT;
1401 mddi_host_isr();
1402 mddi_curr_host = MDDI_HOST_PRIM;
1405 irqreturn_t mddi_emdh_isr_proxy(int irq, void *ptr)
1407 mddi_host_isr_external();
1408 return IRQ_HANDLED;
1411 static void mddi_host_initialize_registers(mddi_host_type host_idx)
1413 uint32 pad_reg_val;
1414 mddi_host_cntl_type *pmhctl = &(mhctl[host_idx]);
1416 if (pmhctl->driver_state == MDDI_DRIVER_ENABLED)
1417 return;
1419 /* turn on HCLK to MDDI host core */
1420 mddi_host_enable_hclk();
1422 /* MDDI Reset command */
1423 mddi_host_reg_out(CMD, MDDI_CMD_RESET);
1425 /* Version register (= 0x01) */
1426 mddi_host_reg_out(VERSION, 0x0001);
1428 /* Bytes per subframe register */
1429 mddi_host_reg_out(BPS, MDDI_HOST_BYTES_PER_SUBFRAME);
1431 /* Subframes per media frames register (= 0x03) */
1432 mddi_host_reg_out(SPM, 0x0003);
1434 /* Turn Around 1 register (= 0x05) */
1435 mddi_host_reg_out(TA1_LEN, 0x0005);
1437 /* Turn Around 2 register (= 0x0C) */
1438 mddi_host_reg_out(TA2_LEN, MDDI_HOST_TA2_LEN);
1440 /* Drive hi register (= 0x96) */
1441 mddi_host_reg_out(DRIVE_HI, 0x0096);
1443 /* Drive lo register (= 0x32) */
1444 mddi_host_reg_out(DRIVE_LO, 0x0032);
1446 /* Display wakeup count register (= 0x3c) */
1447 mddi_host_reg_out(DISP_WAKE, 0x003c);
1449 /* Reverse Rate Divisor register (= 0x2) */
1450 mddi_host_reg_out(REV_RATE_DIV, MDDI_HOST_REV_RATE_DIV);
1452 #ifndef FEATURE_MDDI_DISABLE_REVERSE
1453 /* Reverse Pointer Size */
1454 mddi_host_reg_out(REV_SIZE, MDDI_REV_BUFFER_SIZE);
1456 /* Rev Encap Size */
1457 mddi_host_reg_out(REV_ENCAP_SZ, pmhctl->rev_pkt_size);
1458 #endif
1460 /* Periodic Rev Encap */
1461 /* don't send periodically */
1462 mddi_host_reg_out(CMD, MDDI_CMD_PERIODIC_REV_ENCAP);
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);
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
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
1484 mddi_host_core_version = mddi_host_reg_inm(CORE_VER, 0xffff);
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
1492 if ((mddi_host_core_version > 8) && (mddi_host_core_version < 0x19))
1493 mddi_host_reg_out(TEST, 0x2);
1495 /* Need an even number for counts */
1496 mddi_host_reg_out(DRIVER_START_CNT, 0x60006);
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
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);
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
1520 void mddi_host_configure_interrupts(mddi_host_type host_idx, boolean enable)
1522 unsigned long flags;
1523 mddi_host_cntl_type *pmhctl = &(mhctl[host_idx]);
1525 spin_lock_irqsave(&mddi_host_spin_lock, flags);
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);
1532 spin_unlock_irqrestore(&mddi_host_spin_lock, flags);
1534 if (enable) {
1535 pmhctl->driver_state = MDDI_DRIVER_ENABLED;
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;
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;
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;
1578 static void mddi_host_powerup(mddi_host_type host_idx)
1580 mddi_host_cntl_type *pmhctl = &(mhctl[host_idx]);
1582 if (pmhctl->link_state != MDDI_LINK_DISABLED)
1583 return;
1585 /* enable IO_CLK and hclk to MDDI host core */
1586 mddi_host_enable_io_clock();
1588 mddi_host_initialize_registers(host_idx);
1589 mddi_host_configure_interrupts(host_idx, TRUE);
1591 pmhctl->link_state = MDDI_LINK_ACTIVATING;
1593 /* Link activate command */
1594 mddi_host_reg_out(CMD, MDDI_CMD_LINK_ACTIVE);
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
1603 /* Initialize the timer */
1604 if (host_idx == MDDI_HOST_PRIM)
1605 mddi_host_timer_service(0);
1608 void mddi_host_init(mddi_host_type host_idx)
1609 /* Write out the MDDI configuration registers */
1611 static boolean initialized = FALSE;
1612 mddi_host_cntl_type *pmhctl;
1614 if (host_idx >= MDDI_NUM_HOST_CORES) {
1615 MDDI_MSG_ERR("Invalid host core index\n");
1616 return;
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;
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
1647 MDDI_MSG_CRIT
1648 ("unable to alloc non-cached memory\n");
1650 llist_extern[host] = pmhctl->llist_ptr;
1651 llist_dma_extern[host] = pmhctl->llist_dma_ptr;
1652 llist_extern_notify[host] = pmhctl->llist_notify;
1654 for (idx = 0; idx < UNASSIGNED_INDEX; idx++) {
1655 init_completion(&
1656 (pmhctl->llist_notify[idx].
1657 done_comp));
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;
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;
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;
1690 mddi_vsync_detect_enabled = FALSE;
1691 mddi_gpio.polling_enabled = FALSE;
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;
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
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;
1732 prev_parms[host_idx] = pmhctl->log_parms;
1733 mddi_client_capability_pkt.packet_length = 0;
1736 #ifndef T_MSM7500
1737 /* tell clock driver we are user of this PLL */
1738 MDDI_HOST_ENABLE_IO_CLOCK;
1739 #endif
1742 mddi_host_powerup(host_idx);
1743 pmhctl = &(mhctl[host_idx]);
1746 #ifdef CONFIG_FB_MSM_MDDI_AUTO_DETECT
1747 static uint32 mddi_client_id;
1749 uint32 mddi_get_client_id(void)
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;
1759 if (!client_detection_try) {
1760 /* Toshiba display requires larger drive_lo value */
1761 mddi_host_reg_out(DRIVE_LO, 0x0050);
1763 pmhctl = &(mhctl[MDDI_HOST_PRIM]);
1765 saved_rev_pkt_size = pmhctl->rev_pkt_size;
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);
1771 /* disable hibernation temporarily */
1772 if (!pmhctl->disable_hibernation)
1773 mddi_host_reg_out(CMD, MDDI_CMD_HIBERNATE);
1775 mddi_rev_user.waiting = TRUE;
1776 INIT_COMPLETION(mddi_rev_user.done_comp);
1778 spin_lock_irqsave(&mddi_host_spin_lock, flags);
1780 /* turn on clock(s), if they have been disabled */
1781 mddi_host_enable_hclk();
1782 mddi_host_enable_io_clock();
1784 mddi_client_capability_request = TRUE;
1786 if (pmhctl->rev_state == MDDI_REV_IDLE) {
1787 /* attempt to send the reverse encapsulation now */
1788 mddi_issue_reverse_encapsulation();
1790 spin_unlock_irqrestore(&mddi_host_spin_lock, flags);
1792 wait_for_completion_killable(&(mddi_rev_user.done_comp));
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);
1798 /* reenable auto-hibernate */
1799 if (!pmhctl->disable_hibernation)
1800 mddi_host_reg_out(CMD, MDDI_CMD_HIBERNATE | 1);
1802 mddi_host_reg_out(DRIVE_LO, 0x0032);
1803 client_detection_try = TRUE;
1805 mddi_client_id = (mddi_client_capability_pkt.Mfr_Name<<16) |
1806 mddi_client_capability_pkt.Product_Code;
1808 if (!mddi_client_id)
1809 mddi_disable(1);
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;
1819 break;
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;
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;
1835 break;
1837 default:
1838 break;
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);
1846 #endif
1848 #endif
1850 return mddi_client_id;
1852 #endif
1854 void mddi_host_powerdown(mddi_host_type host_idx)
1856 mddi_host_cntl_type *pmhctl = &(mhctl[host_idx]);
1858 if (host_idx >= MDDI_NUM_HOST_CORES) {
1859 MDDI_MSG_ERR("Invalid host core index\n");
1860 return;
1863 if (pmhctl->driver_state == MDDI_DRIVER_RESET) {
1864 return;
1867 if (host_idx == MDDI_HOST_PRIM) {
1868 /* disable timer */
1869 del_timer(&mddi_host_timer);
1872 mddi_host_configure_interrupts(host_idx, FALSE);
1874 /* turn on HCLK to MDDI host core if it has been disabled */
1875 mddi_host_enable_hclk();
1877 /* MDDI Reset command */
1878 mddi_host_reg_out(CMD, MDDI_CMD_RESET);
1880 /* Pad Control Register */
1881 mddi_host_reg_out(PAD_CTL, 0x0);
1883 /* disable IO_CLK and hclk to MDDI host core */
1884 mddi_host_disable_io_clock();
1885 mddi_host_disable_hclk();
1887 pmhctl->link_state = MDDI_LINK_DISABLED;
1888 pmhctl->driver_state = MDDI_DRIVER_RESET;
1890 MDDI_MSG_NOTICE("MDDI Host: Disabling Link\n");
1894 uint16 mddi_get_next_free_llist_item(mddi_host_type host_idx, boolean wait)
1896 unsigned long flags;
1897 uint16 ret_idx;
1898 boolean forced_wait = FALSE;
1899 mddi_host_cntl_type *pmhctl = &(mhctl[host_idx]);
1901 ret_idx = pmhctl->llist_info.next_free_idx;
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);
1916 spin_unlock_irqrestore(&mddi_host_spin_lock, flags);
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");
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;
1932 return ret_idx;
1935 uint16 mddi_get_reg_read_llist_item(mddi_host_type host_idx, boolean wait)
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]);
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;
1953 spin_unlock_irqrestore(&mddi_host_spin_lock, flags);
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;
1962 if (error)
1963 MDDI_MSG_ERR("***** Reg read still in progress! ****\n");
1964 return ret_idx;
1965 #endif
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)
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]);
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;
1986 if (pmhctl->link_state == MDDI_LINK_DISABLED)
1987 MDDI_MSG_CRIT("MDDI host powered down!\n");
1989 llist = pmhctl->llist_ptr;
1990 llist_dma = pmhctl->llist_dma_ptr;
1992 /* clean cache so MDDI host can read data */
1993 memory_barrier();
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;
2000 spin_lock_irqsave(&mddi_host_spin_lock, flags);
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; */
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;
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]);
2026 /* enable interrupt when complete */
2027 mddi_host_reg_outm(INTEN, MDDI_INT_PRI_LINK_LIST_DONE,
2028 MDDI_INT_PRI_LINK_LIST_DONE);
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) {
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
2038 /* mddi_rev_reg_read_attempt = 0; */
2039 pmhctl->llist_info.reg_read_waiting = TRUE;
2041 #endif
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) {
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
2055 /* mddi_rev_reg_read_attempt = 0; */
2056 pmhctl->llist_info.reg_read_waiting = TRUE;
2058 #endif
2060 llist = pmhctl->llist_ptr;
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;
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]);
2070 /* clean cache so MDDI host can read data */
2071 memory_barrier();
2073 /* assign new waiting last index value */
2074 pmhctl->llist_info.waiting_end_idx = last_llist_idx;
2077 spin_unlock_irqrestore(&mddi_host_spin_lock, flags);
2081 void mddi_host_write_pix_attr_reg(uint32 value)
2083 (void)value;
2086 void mddi_queue_reverse_encapsulation(boolean wait)
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]);
2097 spin_lock_irqsave(&mddi_host_spin_lock, flags);
2099 /* turn on clock(s), if they have been disabled */
2100 mddi_host_enable_hclk();
2101 mddi_host_enable_io_clock();
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;
2110 mddi_rev_encap_user_request = TRUE;
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;
2119 spin_unlock_irqrestore(&mddi_host_spin_lock, flags);
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
2128 /* ISR to be executed */
2129 boolean mddi_set_rev_handler(mddi_rev_handler_type handler, uint16 pkt_type)
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]);
2144 /* Disable interrupts */
2145 spin_lock_irqsave(&mddi_host_spin_lock, flags);
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);
2164 } else {
2165 /* already a handler for this packet */
2166 overwrite = TRUE;
2168 break;
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);
2187 mddi_rev_pkt_handler[hdlr].handler = handler;
2188 mddi_rev_pkt_handler[hdlr].pkt_type = pkt_type;
2189 handler_set = TRUE;
2190 break;
2195 /* Restore interrupts */
2196 spin_unlock_irqrestore(&mddi_host_spin_lock, flags);
2198 if (overwrite)
2199 MDDI_MSG_ERR("Overwriting previous rev packet handler\n");
2201 return handler_set;
2203 #endif
2204 } /* mddi_set_rev_handler */
2206 void mddi_host_disable_hibernation(boolean disable)
2208 mddi_host_type host_idx = MDDI_HOST_PRIM;
2209 mddi_host_cntl_type *pmhctl = &(mhctl[MDDI_HOST_PRIM]);
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;
2227 void mddi_mhctl_remove(mddi_host_type host_idx)
2229 mddi_host_cntl_type *pmhctl;
2231 pmhctl = &(mhctl[host_idx]);
2233 dma_free_coherent(NULL, MDDI_LLIST_POOL_SIZE, (void *)pmhctl->llist_ptr,
2234 pmhctl->llist_dma_addr);
2236 dma_free_coherent(NULL, MDDI_MAX_REV_DATA_SIZE,
2237 (void *)pmhctl->rev_data_buf,
2238 pmhctl->rev_data_dma_addr);