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 
mddi_report_errors(uint32 int_reg)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 
mddi_host_enable_io_clock(void)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 
mddi_host_enable_hclk(void)265 static void mddi_host_enable_hclk(void)
266 {
267 
268 	if (!MDDI_HOST_IS_HCLK_ON)
269 		MDDI_HOST_ENABLE_HCLK;
270 }
271 
mddi_host_disable_io_clock(void)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 
mddi_host_disable_hclk(void)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 
mddi_vote_to_sleep(mddi_host_type host_idx,boolean sleep)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 
mddi_report_state_change(uint32 int_reg)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 
mddi_host_timer_service(unsigned long data)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 
mddi_process_link_list_done(void)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 
mddi_queue_forward_linked_list(void)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
mddi_read_rev_packet(byte * data_ptr)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 
mddi_process_rev_packets(void)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 
mddi_issue_reverse_encapsulation(void)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 
mddi_process_client_initiated_wakeup(void)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 
mddi_host_isr(void)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 
mddi_host_isr_primary(void)1386 static void mddi_host_isr_primary(void)
1387 {
1388 	mddi_curr_host = MDDI_HOST_PRIM;
1389 	mddi_host_isr();
1390 }
1391 
mddi_pmdh_isr_proxy(int irq,void * ptr)1392 irqreturn_t mddi_pmdh_isr_proxy(int irq, void *ptr)
1393 {
1394 	mddi_host_isr_primary();
1395 	return IRQ_HANDLED;
1396 }
1397 
mddi_host_isr_external(void)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 
mddi_emdh_isr_proxy(int irq,void * ptr)1405 irqreturn_t mddi_emdh_isr_proxy(int irq, void *ptr)
1406 {
1407 	mddi_host_isr_external();
1408 	return IRQ_HANDLED;
1409 }
1410 
mddi_host_initialize_registers(mddi_host_type host_idx)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 
mddi_host_configure_interrupts(mddi_host_type host_idx,boolean enable)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 
mddi_host_powerup(mddi_host_type host_idx)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 
mddi_host_init(mddi_host_type host_idx)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 
mddi_get_client_id(void)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 
mddi_host_powerdown(mddi_host_type host_idx)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 
mddi_get_next_free_llist_item(mddi_host_type host_idx,boolean wait)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 
mddi_get_reg_read_llist_item(mddi_host_type host_idx,boolean wait)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 
mddi_queue_forward_packets(uint16 first_llist_idx,uint16 last_llist_idx,boolean wait,mddi_llist_done_cb_type llist_done_cb,mddi_host_type host_idx)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 
mddi_host_write_pix_attr_reg(uint32 value)2081 void mddi_host_write_pix_attr_reg(uint32 value)
2082 {
2083 	(void)value;
2084 }
2085 
mddi_queue_reverse_encapsulation(boolean wait)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 */
mddi_set_rev_handler(mddi_rev_handler_type handler,uint16 pkt_type)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 
mddi_host_disable_hibernation(boolean disable)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 
mddi_mhctl_remove(mddi_host_type host_idx)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 }
2240