xref: /minix/minix/drivers/video/tda19988/tda19988.c (revision 83133719)
1 #include <minix/blockdriver.h>
2 #include <minix/drivers.h>
3 #include <minix/ds.h>
4 #include <minix/i2c.h>
5 #include <minix/i2cdriver.h>
6 #include <minix/log.h>
7 
8 #include <ctype.h>
9 #include <stdio.h>
10 #include <stdlib.h>
11 
12 /* constants */
13 #define NR_DEVS 1		/* number of devices this driver handles */
14 #define TDA19988_DEV 0		/* index of TDA19988 device */
15 #define EDID_LEN 128		/* length of standard EDID block */
16 
17 /* When passing data over a grant one needs to pass
18  * a buffer to sys_safecopy copybuff is used for that*/
19 #define COPYBUF_SIZE 0x1000	/* 4k buf */
20 static unsigned char copybuf[COPYBUF_SIZE];
21 
22 /* The device has two I2C interfaces CEC (0x34) and HDMI (0x70). This driver
23  * needs access to both.
24  */
25 
26 /*
27  * CEC - Register and Bit Definitions
28  */
29 
30 #define CEC_STATUS_REG 0xfe
31 #define CEC_STATUS_CONNECTED_MASK 0x02
32 
33 #define CEC_ENABLE_REG 0xff
34 #define CEC_ENABLE_ALL_MASK 0x87
35 
36 /*
37  * HDMI - Pages
38  *
39  * The HDMI part is much bigger than the CEC part. Memory is accessed according
40  * to page and address. Once the page is set, only the address needs to be
41  * sent if accessing memory locations within the same page (you don't need to
42  * send the page number every time).
43  */
44 
45 #define HDMI_CTRL_PAGE 0x00
46 #define HDMI_PPL_PAGE 0x02
47 #define HDMI_EDID_PAGE 0x09
48 #define HDMI_INFO_PAGE 0x10
49 #define HDMI_AUDIO_PAGE 0x11
50 #define HDMI_HDCP_OTP_PAGE 0x12
51 #define HDMI_GAMUT_PAGE 0x13
52 
53 /*
54  * The page select register isn't part of a page. A dummy value of 0xff is
55  * used to signfiy this in the code.
56  */
57 #define HDMI_PAGELESS 0xff
58 
59 /*
60  * Control Page Registers and Bit Definitions
61  */
62 
63 #define HDMI_CTRL_REV_LO_REG 0x00
64 #define HDMI_CTRL_REV_HI_REG 0x02
65 
66 #define HDMI_CTRL_RESET_REG 0x0a
67 #define HDMI_CTRL_RESET_DDC_MASK 0x02
68 
69 #define HDMI_CTRL_DDC_CTRL_REG 0x0b
70 #define HDMI_CTRL_DDC_EN_MASK 0x00
71 
72 #define HDMI_CTRL_DDC_CLK_REG 0x0c
73 #define HDMI_CTRL_DDC_CLK_EN_MASK 0x01
74 
75 #define HDMI_CTRL_INTR_CTRL_REG 0x0f
76 #define HDMI_CTRL_INTR_EN_GLO_MASK 0x04
77 
78 #define HDMI_CTRL_INT_REG 0x11
79 #define HDMI_CTRL_INT_EDID_MASK 0x02
80 
81 /*
82  * EDID Page Registers and Bit Definitions
83  */
84 
85 #define HDMI_EDID_DATA_REG 0x00
86 
87 #define HDMI_EDID_DEV_ADDR_REG 0xfb
88 #define HDMI_EDID_DEV_ADDR 0xa0
89 
90 #define HDMI_EDID_OFFSET_REG 0xfc
91 #define HDMI_EDID_OFFSET 0x00
92 
93 #define HDMI_EDID_SEG_PTR_ADDR_REG 0xfc
94 #define HDMI_EDID_SEG_PTR_ADDR 0x00
95 
96 #define HDMI_EDID_SEG_ADDR_REG 0xfe
97 #define HDMI_EDID_SEG_ADDR 0x00
98 
99 #define HDMI_EDID_REQ_REG 0xfa
100 #define HDMI_EDID_REQ_READ_MASK 0x01
101 
102 /*
103  * HDCP and OTP
104  */
105 #define HDMI_HDCP_OTP_DDC_CLK_REG 0x9a
106 #define HDMI_HDCP_OTP_DDC_CLK_MASK 0x27
107 
108 /* this register/mask isn't documented but it has to be cleared/set */
109 #define HDMI_HDCP_OTP_SOME_REG 0x9b
110 #define HDMI_HDCP_OTP_SOME_MASK 0x02
111 
112 /*
113  * Pageless Registers
114  */
115 
116 #define HDMI_PAGE_SELECT_REG 0xff
117 
118 /*
119  * Constants
120  */
121 
122 /* Revision of the TDA19988. */
123 #define HDMI_REV_TDA19988 0x0331
124 
125 /* the bus that this device is on (counting starting at 1) */
126 static uint32_t cec_bus;
127 static uint32_t hdmi_bus;
128 
129 /* slave address of the device */
130 static i2c_addr_t cec_address;
131 static i2c_addr_t hdmi_address;
132 
133 /* endpoint for the driver for the bus itself. */
134 static endpoint_t cec_bus_endpoint;
135 static endpoint_t hdmi_bus_endpoint;
136 
137 /* logging - use with log_warn(), log_info(), log_debug(), log_trace(), etc */
138 static struct log log = {
139 	.name = "tda19988",
140 	.log_level = LEVEL_INFO,
141 	.log_func = default_log
142 };
143 
144 static void sef_local_startup(void);
145 static int sef_cb_lu_state_save(int);
146 static int lu_state_restore(void);
147 static int sef_cb_init(int type, sef_init_info_t * info);
148 
149 /* CEC Module */
150 static int is_display_connected(void);
151 static int enable_hdmi_module(void);
152 
153 /* HDMI Module */
154 static int set_page(uint8_t page);
155 static int hdmi_read(uint8_t page, uint8_t reg, uint8_t * val);
156 static int hdmi_write(uint8_t page, uint8_t reg, uint8_t val);
157 static int hdmi_set(uint8_t page, uint8_t reg, uint8_t mask);
158 static int hdmi_clear(uint8_t page, uint8_t reg, uint8_t mask);
159 
160 static int hdmi_ddc_enable(void);
161 static int hdmi_init(void);
162 static int check_revision(void);
163 static int read_edid(uint8_t * data, size_t count);
164 
165 /* libblockdriver callbacks */
166 static int tda19988_blk_open(devminor_t minor, int access);
167 static int tda19988_blk_close(devminor_t minor);
168 static ssize_t tda19988_blk_transfer(devminor_t minor, int do_write, u64_t pos,
169     endpoint_t endpt, iovec_t * iov, unsigned int count, int flags);
170 static int tda19988_blk_ioctl(devminor_t minor, unsigned long request,
171     endpoint_t endpt, cp_grant_id_t grant, endpoint_t user_endpt);
172 static struct device *tda19988_blk_part(devminor_t minor);
173 static void tda19988_blk_other(message * m, int ipc_status);
174 
175 /* Entry points into the device dependent code of block drivers. */
176 struct blockdriver tda19988_tab = {
177 	.bdr_type = BLOCKDRIVER_TYPE_OTHER,
178 	.bdr_open = tda19988_blk_open,
179 	.bdr_close = tda19988_blk_close,
180 	.bdr_transfer = tda19988_blk_transfer,
181 	.bdr_ioctl = tda19988_blk_ioctl,	/* always returns ENOTTY */
182 	.bdr_part = tda19988_blk_part,
183 	.bdr_other = tda19988_blk_other		/* for notify events from DS */
184 };
185 
186 /* counts the number of times a device file is open */
187 static int openct[NR_DEVS];
188 
189 /* base and size of each device */
190 static struct device geom[NR_DEVS];
191 
192 static int
193 tda19988_blk_open(devminor_t minor, int access)
194 {
195 	log_trace(&log, "tda19988_blk_open(%d,%d)\n", minor, access);
196 	if (tda19988_blk_part(minor) == NULL) {
197 		return ENXIO;
198 	}
199 
200 	openct[minor]++;
201 
202 	return OK;
203 }
204 
205 static int
206 tda19988_blk_close(devminor_t minor)
207 {
208 	log_trace(&log, "tda19988_blk_close(%d)\n", minor);
209 	if (tda19988_blk_part(minor) == NULL) {
210 		return ENXIO;
211 	}
212 
213 	if (openct[minor] < 1) {
214 		log_warn(&log, "closing unopened device %d\n", minor);
215 		return EINVAL;
216 	}
217 	openct[minor]--;
218 
219 	return OK;
220 }
221 
222 static ssize_t
223 tda19988_blk_transfer(devminor_t minor, int do_write, u64_t pos64,
224     endpoint_t endpt, iovec_t * iov, unsigned int nr_req, int flags)
225 {
226 	unsigned count;
227 	struct device *dv;
228 	u64_t dv_size;
229 	int r;
230 	cp_grant_id_t grant;
231 
232 	log_trace(&log, "tda19988_blk_transfer()\n");
233 
234 	/* Get minor device information. */
235 	dv = tda19988_blk_part(minor);
236 	if (dv == NULL) {
237 		return ENXIO;
238 	}
239 
240 	if (nr_req > NR_IOREQS) {
241 		return EINVAL;
242 	}
243 
244 	dv_size = dv->dv_size;
245 	if (pos64 >= dv_size) {
246 		return OK;	/* Beyond EOF */
247 	}
248 
249 	if (nr_req > 0) {
250 
251 		/* How much to transfer and where to / from. */
252 		count = iov->iov_size;
253 		grant = (cp_grant_id_t) iov->iov_addr;
254 
255 		/* check for EOF */
256 		if (pos64 >= dv_size) {
257 			return 0;
258 		}
259 
260 		/* don't go past the end of the device */
261 		if (pos64 + count > dv_size) {
262 			count = dv_size - pos64;
263 		}
264 
265 		/* don't overflow copybuf */
266 		if (count > COPYBUF_SIZE) {
267 			count = COPYBUF_SIZE;
268 		}
269 
270 		log_debug(&log, "transfering 0x%x bytes\n", count);
271 
272 		if (do_write) {
273 
274 			log_warn(&log, "Error: writing to read-only device\n");
275 			return EACCES;
276 
277 		} else {
278 
279 			if (is_display_connected() == 1) {
280 
281 				r = hdmi_init();
282 				if (r != OK) {
283 					log_warn(&log,
284 					    "Failed to enable HDMI module\n");
285 					return EIO;
286 				}
287 
288 				memset(copybuf, '\0', COPYBUF_SIZE);
289 				r = read_edid(copybuf, count);
290 				if (r != OK) {
291 					log_warn(&log,
292 					    "read_edid() failed (r=%d)\n", r);
293 					return r;
294 				}
295 
296 				r = sys_safecopyto(endpt, grant, (vir_bytes)
297 				    0, (vir_bytes) copybuf, count);
298 				if (r != OK) {
299 					log_warn(&log, "safecopyto failed\n");
300 					return EINVAL;
301 				}
302 
303 				return iov->iov_size;
304 			} else {
305 				log_warn(&log, "Display not connected.\n");
306 				return ENODEV;
307 			}
308 		}
309 	} else {
310 
311 		/* empty request */
312 		return 0;
313 	}
314 }
315 
316 static int
317 tda19988_blk_ioctl(devminor_t minor, unsigned long request, endpoint_t endpt,
318     cp_grant_id_t grant, endpoint_t UNUSED(user_endpt))
319 {
320 	log_trace(&log, "tda19988_blk_ioctl(%d)\n", minor);
321 	/* no supported ioctls for this device */
322 	return ENOTTY;
323 }
324 
325 static struct device *
326 tda19988_blk_part(devminor_t minor)
327 {
328 	log_trace(&log, "tda19988_blk_part(%d)\n", minor);
329 
330 	if (minor < 0 || minor >= NR_DEVS) {
331 		return NULL;
332 	}
333 
334 	return &geom[minor];
335 }
336 
337 static void
338 tda19988_blk_other(message * m, int ipc_status)
339 {
340 	log_trace(&log, "tda19988_blk_other(0x%x)\n", m->m_type);
341 
342 	if (is_ipc_notify(ipc_status)) {
343 		if (m->m_source == DS_PROC_NR) {
344 			log_debug(&log,
345 			    "bus driver changed state, update endpoint\n");
346 			i2cdriver_handle_bus_update(&cec_bus_endpoint, cec_bus,
347 			    cec_address);
348 			i2cdriver_handle_bus_update(&hdmi_bus_endpoint,
349 			    hdmi_bus, hdmi_address);
350 		}
351 	} else {
352 		log_warn(&log, "Invalid message type (0x%x)\n", m->m_type);
353 	}
354 }
355 
356 /*
357  * Check to see if a display is connected.
358  * Returns 1 for yes, 0 for no, -1 for error.
359  */
360 static int
361 is_display_connected(void)
362 {
363 	int r;
364 	uint8_t val;
365 
366 	r = i2creg_read8(cec_bus_endpoint, cec_address, CEC_STATUS_REG, &val);
367 	if (r != OK) {
368 		log_warn(&log, "Reading connection status failed (r=%d)\n", r);
369 		return -1;
370 	}
371 
372 	if ((CEC_STATUS_CONNECTED_MASK & val) == 0) {
373 		log_debug(&log, "No Display Detected\n");
374 		return 0;
375 	} else {
376 		log_debug(&log, "Display Detected\n");
377 		return 1;
378 	}
379 }
380 
381 /*
382  * Enable all the modules and clocks.
383  */
384 static int
385 enable_hdmi_module(void)
386 {
387 	int r;
388 
389 	r = i2creg_write8(cec_bus_endpoint, cec_address, CEC_ENABLE_REG,
390 	    CEC_ENABLE_ALL_MASK);
391 	if (r != OK) {
392 		log_warn(&log, "Writing enable bits failed (r=%d)\n", r);
393 		return -1;
394 	}
395 
396 	log_debug(&log, "HDMI module enabled\n");
397 
398 	return OK;
399 }
400 
401 static int
402 set_page(uint8_t page)
403 {
404 	int r;
405 	static int current_page = HDMI_PAGELESS;
406 
407 	if (page != current_page) {
408 
409 		r = i2creg_write8(hdmi_bus_endpoint, hdmi_address,
410 		    HDMI_PAGE_SELECT_REG, page);
411 		if (r != OK) {
412 			return r;
413 		}
414 
415 		current_page = page;
416 	}
417 
418 	return OK;
419 }
420 
421 static int
422 hdmi_read_block(uint8_t page, uint8_t reg, uint8_t * buf, size_t buflen)
423 {
424 
425 	int r;
426 	minix_i2c_ioctl_exec_t ioctl_exec;
427 
428 	if (buf == NULL || buflen > I2C_EXEC_MAX_BUFLEN) {
429 		log_warn(&log,
430 		    "Read block called with NULL pointer or invalid buflen.\n");
431 		return EINVAL;
432 	}
433 
434 	if (page != HDMI_PAGELESS) {
435 		r = set_page(page);
436 		if (r != OK) {
437 			log_warn(&log, "Unable to set page to 0x%x\n", page);
438 			return r;
439 		}
440 	}
441 
442 	memset(&ioctl_exec, '\0', sizeof(minix_i2c_ioctl_exec_t));
443 
444 	/* Read from HDMI */
445 	ioctl_exec.iie_op = I2C_OP_READ_WITH_STOP;
446 	ioctl_exec.iie_addr = hdmi_address;
447 
448 	/* write the register address */
449 	ioctl_exec.iie_cmd[0] = reg;
450 	ioctl_exec.iie_cmdlen = 1;
451 
452 	/* read bytes */
453 	ioctl_exec.iie_buflen = buflen;
454 
455 	r = i2cdriver_exec(hdmi_bus_endpoint, &ioctl_exec);
456 	if (r != OK) {
457 		log_warn(&log, "hdmi_read() failed (r=%d)\n", r);
458 		return -1;
459 	}
460 
461 	memcpy(buf, ioctl_exec.iie_buf, buflen);
462 
463 	log_trace(&log, "Read %d bytes from reg 0x%x in page 0x%x\n", buflen,
464 	    reg, page);
465 
466 	return OK;
467 }
468 
469 static int
470 hdmi_read(uint8_t page, uint8_t reg, uint8_t * val)
471 {
472 
473 	int r;
474 
475 	if (val == NULL) {
476 		log_warn(&log, "Read called with NULL pointer\n");
477 		return EINVAL;
478 	}
479 
480 	if (page != HDMI_PAGELESS) {
481 		r = set_page(page);
482 		if (r != OK) {
483 			log_warn(&log, "Unable to set page to 0x%x\n", page);
484 			return r;
485 		}
486 	}
487 
488 	r = i2creg_read8(hdmi_bus_endpoint, hdmi_address, reg, val);
489 	if (r != OK) {
490 		log_warn(&log, "hdmi_read() failed (r=%d)\n", r);
491 		return -1;
492 	}
493 
494 	log_trace(&log, "Read 0x%x from reg 0x%x in page 0x%x\n", *val, reg,
495 	    page);
496 
497 	return OK;
498 }
499 
500 static int
501 hdmi_write(uint8_t page, uint8_t reg, uint8_t val)
502 {
503 	int r;
504 
505 	if (page != HDMI_PAGELESS) {
506 		r = set_page(page);
507 		if (r != OK) {
508 			log_warn(&log, "Unable to set page to 0x%x\n", page);
509 			return r;
510 		}
511 	}
512 
513 	r = i2creg_write8(hdmi_bus_endpoint, hdmi_address, reg, val);
514 	if (r != OK) {
515 		log_warn(&log, "hdmi_write() failed (r=%d)\n", r);
516 		return -1;
517 	}
518 
519 	log_trace(&log, "Successfully wrote 0x%x to reg 0x%x in page 0x%x\n",
520 	    val, reg, page);
521 
522 	return OK;
523 }
524 
525 static int
526 hdmi_set(uint8_t page, uint8_t reg, uint8_t mask)
527 {
528 
529 	int r;
530 	uint8_t val;
531 
532 	val = 0x00;
533 
534 	r = hdmi_read(page, reg, &val);
535 	if (r != OK) {
536 		return r;
537 	}
538 
539 	val |= mask;
540 
541 	r = hdmi_write(page, reg, val);
542 	if (r != OK) {
543 		return r;
544 	}
545 
546 	return OK;
547 }
548 
549 static int
550 hdmi_clear(uint8_t page, uint8_t reg, uint8_t mask)
551 {
552 
553 	int r;
554 	uint8_t val;
555 
556 	val = 0x00;
557 
558 	r = hdmi_read(page, reg, &val);
559 	if (r != OK) {
560 		return r;
561 	}
562 
563 	val &= ~mask;
564 
565 	r = hdmi_write(page, reg, val);
566 	if (r != OK) {
567 		return r;
568 	}
569 
570 	return OK;
571 }
572 
573 static int
574 check_revision(void)
575 {
576 	int r;
577 	uint8_t rev_lo;
578 	uint8_t rev_hi;
579 	uint16_t revision;
580 
581 	r = hdmi_read(HDMI_CTRL_PAGE, HDMI_CTRL_REV_LO_REG, &rev_lo);
582 	if (r != OK) {
583 		log_warn(&log, "Failed to read rev_lo (r=%d)\n", r);
584 		return -1;
585 	}
586 
587 	r = hdmi_read(HDMI_CTRL_PAGE, HDMI_CTRL_REV_HI_REG, &rev_hi);
588 	if (r != OK) {
589 		log_warn(&log, "Failed to read rev_hi (r=%d)\n", r);
590 		return -1;
591 	}
592 
593 	revision = ((rev_hi << 8) | rev_lo);
594 	if (revision != HDMI_REV_TDA19988) {
595 
596 		log_warn(&log, "Unrecognized value in revision registers.\n");
597 		log_warn(&log, "Read: 0x%x | Expected: 0x%x\n", revision,
598 		    HDMI_REV_TDA19988);
599 		return -1;
600 	}
601 
602 	log_debug(&log, "Device Revision: 0x%x\n", revision);
603 
604 	return OK;
605 }
606 
607 static int
608 hdmi_ddc_enable(void)
609 {
610 	int r;
611 
612 	/* Soft Reset DDC Bus */
613 	r = hdmi_set(HDMI_CTRL_PAGE, HDMI_CTRL_RESET_REG,
614 	    HDMI_CTRL_RESET_DDC_MASK);
615 	if (r != OK) {
616 		return r;
617 	}
618 	micro_delay(100000);
619 	r = hdmi_clear(HDMI_CTRL_PAGE, HDMI_CTRL_RESET_REG,
620 	    HDMI_CTRL_RESET_DDC_MASK);
621 	if (r != OK) {
622 		return r;
623 	}
624 	micro_delay(100000);
625 
626 	/* Enable DDC */
627 	r = hdmi_write(HDMI_CTRL_PAGE, HDMI_CTRL_DDC_CTRL_REG,
628 	    HDMI_CTRL_DDC_EN_MASK);
629 	if (r != OK) {
630 		return r;
631 	}
632 
633 	/* Setup the clock (I think) */
634 	r = hdmi_write(HDMI_CTRL_PAGE, HDMI_CTRL_DDC_CLK_REG,
635 	    HDMI_CTRL_DDC_CLK_EN_MASK);
636 	if (r != OK) {
637 		return r;
638 	}
639 
640 	r = hdmi_write(HDMI_HDCP_OTP_PAGE, HDMI_HDCP_OTP_DDC_CLK_REG,
641 	    HDMI_HDCP_OTP_DDC_CLK_MASK);
642 	if (r != OK) {
643 		return r;
644 	}
645 	log_debug(&log, "DDC Enabled\n");
646 
647 	return OK;
648 }
649 
650 static int
651 hdmi_init(void)
652 {
653 	int r;
654 
655 	/* Turn on HDMI module (slave 0x70) */
656 	r = enable_hdmi_module();
657 	if (r != OK) {
658 		log_warn(&log, "HDMI Module Init Failed\n");
659 		return -1;
660 	}
661 
662 	/* Read chip version to ensure compatibility */
663 	r = check_revision();
664 	if (r != OK) {
665 		log_warn(&log, "Couldn't find expected TDA19988 revision\n");
666 		return -1;
667 	}
668 
669 	/* Turn on DDC interface between TDA19988 and display */
670 	r = hdmi_ddc_enable();
671 	if (r != OK) {
672 		log_warn(&log, "Failed to enable DDC\n");
673 		return -1;
674 	}
675 
676 	return OK;
677 }
678 
679 static int
680 read_edid(uint8_t * buf, size_t count)
681 {
682 	int r;
683 	int i, j;
684 	int tries;
685 	int edid_ready;
686 	uint8_t val;
687 
688 	log_debug(&log, "Reading edid...\n");
689 
690 	if (buf == NULL || count < EDID_LEN) {
691 		log_warn(&log, "Expected 128 byte data buffer\n");
692 		return -1;
693 	}
694 
695 	r = hdmi_clear(HDMI_HDCP_OTP_PAGE, HDMI_HDCP_OTP_SOME_REG,
696 	    HDMI_HDCP_OTP_SOME_MASK);
697 	if (r != OK) {
698 		log_warn(&log, "Failed to clear bit in HDCP OTP reg\n");
699 		return -1;
700 	}
701 
702 	/* Enable EDID Block Read Interrupt */
703 	r = hdmi_set(HDMI_CTRL_PAGE, HDMI_CTRL_INT_REG,
704 	    HDMI_CTRL_INT_EDID_MASK);
705 	if (r != OK) {
706 		log_warn(&log, "Failed to enable EDID Block Read interrupt\n");
707 		return -1;
708 	}
709 
710 	/* enable global interrupts */
711 	r = hdmi_write(HDMI_CTRL_PAGE, HDMI_CTRL_INTR_CTRL_REG,
712 	    HDMI_CTRL_INTR_EN_GLO_MASK);
713 	if (r != OK) {
714 		log_warn(&log, "Failed to enable interrupts\n");
715 		return -1;
716 	}
717 
718 	/* Set Device Address */
719 	r = hdmi_write(HDMI_EDID_PAGE, HDMI_EDID_DEV_ADDR_REG,
720 	    HDMI_EDID_DEV_ADDR);
721 	if (r != OK) {
722 		log_warn(&log, "Couldn't set device address\n");
723 		return -1;
724 	}
725 
726 	/* Set Offset */
727 	r = hdmi_write(HDMI_EDID_PAGE, HDMI_EDID_OFFSET_REG, HDMI_EDID_OFFSET);
728 	if (r != OK) {
729 		log_warn(&log, "Couldn't set offset\n");
730 		return -1;
731 	}
732 
733 	/* Set Segment Pointer Address */
734 	r = hdmi_write(HDMI_EDID_PAGE, HDMI_EDID_SEG_PTR_ADDR_REG,
735 	    HDMI_EDID_SEG_PTR_ADDR);
736 	if (r != OK) {
737 		log_warn(&log, "Couldn't set segment pointer address\n");
738 		return -1;
739 	}
740 
741 	/* Set Segment Address */
742 	r = hdmi_write(HDMI_EDID_PAGE, HDMI_EDID_SEG_ADDR_REG,
743 	    HDMI_EDID_SEG_ADDR);
744 	if (r != OK) {
745 		log_warn(&log, "Couldn't set segment address\n");
746 		return -1;
747 	}
748 
749 	/*
750 	 * Toggle EDID Read Request Bit to request a read.
751 	 */
752 
753 	r = hdmi_write(HDMI_EDID_PAGE, HDMI_EDID_REQ_REG,
754 	    HDMI_EDID_REQ_READ_MASK);
755 	if (r != OK) {
756 		log_warn(&log, "Couldn't set Read Request bit\n");
757 		return -1;
758 	}
759 
760 	r = hdmi_write(HDMI_EDID_PAGE, HDMI_EDID_REQ_REG, 0x00);
761 	if (r != OK) {
762 		log_warn(&log, "Couldn't clear Read Request bit\n");
763 		return -1;
764 	}
765 
766 	log_debug(&log, "Starting polling\n");
767 
768 	/* poll interrupt status flag */
769 	edid_ready = 0;
770 	for (tries = 0; tries < 100; tries++) {
771 
772 		r = hdmi_read(HDMI_CTRL_PAGE, HDMI_CTRL_INT_REG, &val);
773 		if (r != OK) {
774 			log_warn(&log, "Read failed while polling int flag\n");
775 			return -1;
776 		}
777 
778 		if (val & HDMI_CTRL_INT_EDID_MASK) {
779 			log_debug(&log, "Mask Set\n");
780 			edid_ready = 1;
781 			break;
782 		}
783 
784 		micro_delay(1000);
785 	}
786 
787 	if (!edid_ready) {
788 		log_warn(&log, "Data Ready interrupt never fired.\n");
789 		return EBUSY;
790 	}
791 
792 	log_debug(&log, "Ready to read\n");
793 
794 	/* Finally, perform the read. */
795 	memset(buf, '\0', count);
796 	r = hdmi_read_block(HDMI_EDID_PAGE, HDMI_EDID_DATA_REG, buf, EDID_LEN);
797 	if (r != OK) {
798 		log_warn(&log, "Failed to read EDID data\n");
799 		return -1;
800 	}
801 
802 	/* Disable EDID Block Read Interrupt */
803 	r = hdmi_clear(HDMI_CTRL_PAGE, HDMI_CTRL_INT_REG,
804 	    HDMI_CTRL_INT_EDID_MASK);
805 	if (r != OK) {
806 		log_warn(&log,
807 		    "Failed to disable EDID Block Read interrupt\n");
808 		return -1;
809 	}
810 
811 	r = hdmi_set(HDMI_HDCP_OTP_PAGE, HDMI_HDCP_OTP_SOME_REG,
812 	    HDMI_HDCP_OTP_SOME_MASK);
813 	if (r != OK) {
814 		log_warn(&log, "Failed to set bit in HDCP/OTP reg\n");
815 		return -1;
816 	}
817 
818 	log_debug(&log, "Done EDID Reading\n");
819 
820 	return OK;
821 }
822 
823 static int
824 sef_cb_lu_state_save(int UNUSED(state))
825 {
826 	ds_publish_u32("cec_bus", cec_bus, DSF_OVERWRITE);
827 	ds_publish_u32("hdmi_bus", hdmi_bus, DSF_OVERWRITE);
828 	ds_publish_u32("cec_address", cec_address, DSF_OVERWRITE);
829 	ds_publish_u32("hdmi_address", hdmi_address, DSF_OVERWRITE);
830 	return OK;
831 }
832 
833 static int
834 lu_state_restore(void)
835 {
836 	/* Restore the state. */
837 	u32_t value;
838 
839 	ds_retrieve_u32("cec_bus", &value);
840 	ds_delete_u32("cec_bus");
841 	cec_bus = (int) value;
842 
843 	ds_retrieve_u32("hdmi_bus", &value);
844 	ds_delete_u32("hdmi_bus");
845 	hdmi_bus = (int) value;
846 
847 	ds_retrieve_u32("cec_address", &value);
848 	ds_delete_u32("cec_address");
849 	cec_address = (int) value;
850 
851 	ds_retrieve_u32("hdmi_address", &value);
852 	ds_delete_u32("hdmi_address");
853 	hdmi_address = (int) value;
854 
855 	return OK;
856 }
857 
858 static int
859 sef_cb_init(int type, sef_init_info_t * UNUSED(info))
860 {
861 	int r;
862 
863 	if (type == SEF_INIT_LU) {
864 		/* Restore the state. */
865 		lu_state_restore();
866 	}
867 
868 	geom[TDA19988_DEV].dv_base = ((u64_t) (0));
869 	geom[TDA19988_DEV].dv_size = ((u64_t) (128));
870 
871 	/*
872 	 * CEC Module
873 	 */
874 
875 	/* look-up the endpoint for the bus driver */
876 	cec_bus_endpoint = i2cdriver_bus_endpoint(cec_bus);
877 	if (cec_bus_endpoint == 0) {
878 		log_warn(&log, "Couldn't find bus driver.\n");
879 		return EXIT_FAILURE;
880 	}
881 
882 	/* claim the device */
883 	r = i2cdriver_reserve_device(cec_bus_endpoint, cec_address);
884 	if (r != OK) {
885 		log_warn(&log, "Couldn't reserve device 0x%x (r=%d)\n",
886 		    cec_address, r);
887 		return EXIT_FAILURE;
888 	}
889 
890 	/*
891 	 * HDMI Module
892 	 */
893 
894 	/* look-up the endpoint for the bus driver */
895 	hdmi_bus_endpoint = i2cdriver_bus_endpoint(hdmi_bus);
896 	if (hdmi_bus_endpoint == 0) {
897 		log_warn(&log, "Couldn't find bus driver.\n");
898 		return EXIT_FAILURE;
899 	}
900 
901 	/* claim the device */
902 	r = i2cdriver_reserve_device(hdmi_bus_endpoint, hdmi_address);
903 	if (r != OK) {
904 		log_warn(&log, "Couldn't reserve device 0x%x (r=%d)\n",
905 		    hdmi_address, r);
906 		return EXIT_FAILURE;
907 	}
908 
909 	if (type != SEF_INIT_LU) {
910 
911 		/* sign up for updates about the i2c bus going down/up */
912 		r = i2cdriver_subscribe_bus_updates(cec_bus);
913 		if (r != OK) {
914 			log_warn(&log, "Couldn't subscribe to bus updates\n");
915 			return EXIT_FAILURE;
916 		}
917 
918 		/* sign up for updates about the i2c bus going down/up */
919 		r = i2cdriver_subscribe_bus_updates(hdmi_bus);
920 		if (r != OK) {
921 			log_warn(&log, "Couldn't subscribe to bus updates\n");
922 			return EXIT_FAILURE;
923 		}
924 
925 		i2cdriver_announce(cec_bus);
926 		if (cec_bus != hdmi_bus) {
927 			i2cdriver_announce(hdmi_bus);
928 		}
929 
930 		blockdriver_announce(type);
931 		log_trace(&log, "announced\n");
932 	}
933 
934 	return OK;
935 }
936 
937 static void
938 sef_local_startup(void)
939 {
940 	/*
941 	 * Register init callbacks. Use the same function for all event types
942 	 */
943 	sef_setcb_init_fresh(sef_cb_init);
944 	sef_setcb_init_lu(sef_cb_init);
945 	sef_setcb_init_restart(sef_cb_init);
946 
947 	/*
948 	 * Register live update callbacks.
949 	 */
950 	/* Agree to update immediately when LU is requested in a valid state. */
951 	sef_setcb_lu_prepare(sef_cb_lu_prepare_always_ready);
952 	/* Support live update starting from any standard state. */
953 	sef_setcb_lu_state_isvalid(sef_cb_lu_state_isvalid_standard);
954 	/* Register a custom routine to save the state. */
955 	sef_setcb_lu_state_save(sef_cb_lu_state_save);
956 
957 	/* Let SEF perform startup. */
958 	sef_startup();
959 }
960 
961 static int
962 tda19988_env_parse()
963 {
964 	int r;
965 	long int cec_busl;
966 	long int cec_addressl;
967 	long int hdmi_busl;
968 	long int hdmi_addressl;
969 
970 	r = env_parse("cec_bus", "d", 0, &cec_busl, 1, 3);
971 	if (r != EP_SET) {
972 		return -1;
973 	}
974 	cec_bus = (uint32_t) cec_busl;
975 
976 	r = env_parse("cec_address", "x", 0, &cec_addressl, 0x34, 0x37);
977 	if (r != EP_SET) {
978 		return -1;
979 	}
980 	cec_address = (i2c_addr_t) cec_addressl;
981 
982 	r = env_parse("hdmi_bus", "d", 0, &hdmi_busl, 1, 3);
983 	if (r != EP_SET) {
984 		return -1;
985 	}
986 	hdmi_bus = (uint32_t) hdmi_busl;
987 
988 	r = env_parse("hdmi_address", "x", 0, &hdmi_addressl, 0x70, 0x73);
989 	if (r != EP_SET) {
990 		return -1;
991 	}
992 	hdmi_address = (i2c_addr_t) hdmi_addressl;
993 
994 	return OK;
995 }
996 
997 int
998 main(int argc, char *argv[])
999 {
1000 	int r;
1001 
1002 	env_setargs(argc, argv);
1003 
1004 	r = tda19988_env_parse();
1005 	if (r < 0) {
1006 		log_warn(&log,
1007 		    "Expecting -args 'cec_bus=X cec_address=0xAA hdmi_bus=Y hdmi_address=0xBB'\n");
1008 		log_warn(&log,
1009 		    "Example -args 'cec_bus=1 cec_address=0x34 hdmi_bus=1 hdmi_address=0x70'\n");
1010 		return EXIT_FAILURE;
1011 	}
1012 
1013 	sef_local_startup();
1014 
1015 	log_debug(&log, "Startup Complete\n");
1016 	blockdriver_task(&tda19988_tab);
1017 	log_debug(&log, "Shutting down\n");
1018 
1019 	return OK;
1020 }
1021