xref: /openbsd-src/sys/arch/armv7/omap/nxphdmi.c (revision 9fdf0c627b1fec102f212f847a6f7676c1829e65)
1*9fdf0c62Smpi /* $OpenBSD: nxphdmi.c,v 1.8 2021/10/24 17:52:27 mpi Exp $ */
22b401c1dSians /*
351bdad2cSians  * Copyright (c) 2016 Ian Sutton <ians@openbsd.org>
42b401c1dSians  * All rights reserved.
52b401c1dSians  *
62b401c1dSians  * Redistribution and use in source and binary forms, with or without
72b401c1dSians  * modification, are permitted provided that the following conditions
82b401c1dSians  * are met:
92b401c1dSians  * 1. Redistributions of source code must retain the above copyright
102b401c1dSians  *    notice, this list of conditions and the following disclaimer.
112b401c1dSians  * 2. Redistributions in binary form must reproduce the above copyright
122b401c1dSians  *    notice, this list of conditions and the following disclaimer in the
132b401c1dSians  *    documentation and/or other materials provided with the distribution.
142b401c1dSians  *
152b401c1dSians  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
162b401c1dSians  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
172b401c1dSians  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
182b401c1dSians  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
192b401c1dSians  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
202b401c1dSians  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
212b401c1dSians  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
222b401c1dSians  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
232b401c1dSians  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
242b401c1dSians  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
252b401c1dSians  * SUCH DAMAGE.
262b401c1dSians  */
272b401c1dSians 
282b401c1dSians /*
292b401c1dSians  * Copyright (c) 2015 Oleksandr Tymoshenko <gonzo@freebsd.org>
302b401c1dSians  * All rights reserved.
312b401c1dSians  *
322b401c1dSians  * Redistribution and use in source and binary forms, with or without
332b401c1dSians  * modification, are permitted provided that the following conditions
342b401c1dSians  * are met:
352b401c1dSians  * 1. Redistributions of source code must retain the above copyright
362b401c1dSians  *    notice, this list of conditions and the following disclaimer.
372b401c1dSians  * 2. Redistributions in binary form must reproduce the above copyright
382b401c1dSians  *    notice, this list of conditions and the following disclaimer in the
392b401c1dSians  *    documentation and/or other materials provided with the distribution.
402b401c1dSians  *
412b401c1dSians  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
422b401c1dSians  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
432b401c1dSians  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
442b401c1dSians  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
452b401c1dSians  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
462b401c1dSians  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
472b401c1dSians  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
482b401c1dSians  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
492b401c1dSians  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
502b401c1dSians  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
512b401c1dSians  * SUCH DAMAGE.
522b401c1dSians  */
532b401c1dSians 
542b401c1dSians #include <sys/param.h>
552b401c1dSians #include <sys/systm.h>
562b401c1dSians #include <sys/device.h>
572b401c1dSians #include <sys/errno.h>
582b401c1dSians 
592b401c1dSians #include <dev/i2c/i2cvar.h>
602b401c1dSians #include <dev/videomode/videomode.h>
612b401c1dSians 
622b401c1dSians #include <dev/ofw/ofw_pinctrl.h>
632b401c1dSians 
642b401c1dSians #include <arch/armv7/omap/nxphdmivar.h>
652b401c1dSians 
662b401c1dSians /* TDA19988 registers */
672b401c1dSians #define	MKREG(page, addr)	(((page) << 8) | (addr))
682b401c1dSians 
692b401c1dSians #define	REGPAGE(reg)		(((reg) >> 8) & 0xff)
702b401c1dSians #define	REGADDR(reg)		((reg) & 0xff)
712b401c1dSians 
722b401c1dSians #define	TDA_VERSION		MKREG(0x00, 0x00)
732b401c1dSians #define	TDA_MAIN_CNTRL0		MKREG(0x00, 0x01)
742b401c1dSians #define		MAIN_CNTRL0_SR		(1 << 0)
752b401c1dSians #define	TDA_VERSION_MSB		MKREG(0x00, 0x02)
762b401c1dSians #define	TDA_SOFTRESET		MKREG(0x00, 0x0a)
772b401c1dSians #define		SOFTRESET_I2C		(1 << 1)
782b401c1dSians #define		SOFTRESET_AUDIO		(1 << 0)
792b401c1dSians #define	TDA_DDC_CTRL		MKREG(0x00, 0x0b)
802b401c1dSians #define		DDC_ENABLE		0
812b401c1dSians #define	TDA_CCLK		MKREG(0x00, 0x0c)
822b401c1dSians #define		CCLK_ENABLE		1
832b401c1dSians #define	TDA_INT_FLAGS_2		MKREG(0x00, 0x11)
842b401c1dSians #define		INT_FLAGS_2_EDID_BLK_RD	(1 << 1)
852b401c1dSians 
862b401c1dSians #define	TDA_VIP_CNTRL_0		MKREG(0x00, 0x20)
872b401c1dSians #define	TDA_VIP_CNTRL_1		MKREG(0x00, 0x21)
882b401c1dSians #define	TDA_VIP_CNTRL_2		MKREG(0x00, 0x22)
892b401c1dSians #define	TDA_VIP_CNTRL_3		MKREG(0x00, 0x23)
902b401c1dSians #define		VIP_CNTRL_3_SYNC_HS	(2 << 4)
912b401c1dSians #define		VIP_CNTRL_3_V_TGL	(1 << 2)
922b401c1dSians #define		VIP_CNTRL_3_H_TGL	(1 << 1)
932b401c1dSians 
942b401c1dSians #define	TDA_VIP_CNTRL_4		MKREG(0x00, 0x24)
952b401c1dSians #define		VIP_CNTRL_4_BLANKIT_NDE		(0 << 2)
962b401c1dSians #define		VIP_CNTRL_4_BLANKIT_HS_VS	(1 << 2)
972b401c1dSians #define		VIP_CNTRL_4_BLANKIT_NHS_VS	(2 << 2)
982b401c1dSians #define		VIP_CNTRL_4_BLANKIT_HE_VE	(3 << 2)
992b401c1dSians #define		VIP_CNTRL_4_BLC_NONE		(0 << 0)
1002b401c1dSians #define		VIP_CNTRL_4_BLC_RGB444		(1 << 0)
1012b401c1dSians #define		VIP_CNTRL_4_BLC_YUV444		(2 << 0)
1022b401c1dSians #define		VIP_CNTRL_4_BLC_YUV422		(3 << 0)
1032b401c1dSians #define	TDA_VIP_CNTRL_5		MKREG(0x00, 0x25)
1042b401c1dSians #define		VIP_CNTRL_5_SP_CNT(n)	(((n) & 3) << 1)
1052b401c1dSians #define	TDA_MUX_VP_VIP_OUT	MKREG(0x00, 0x27)
1062b401c1dSians #define	TDA_MAT_CONTRL		MKREG(0x00, 0x80)
1072b401c1dSians #define		MAT_CONTRL_MAT_BP	(1 << 2)
1082b401c1dSians #define	TDA_VIDFORMAT		MKREG(0x00, 0xa0)
1092b401c1dSians #define	TDA_REFPIX_MSB		MKREG(0x00, 0xa1)
1102b401c1dSians #define	TDA_REFPIX_LSB		MKREG(0x00, 0xa2)
1112b401c1dSians #define	TDA_REFLINE_MSB		MKREG(0x00, 0xa3)
1122b401c1dSians #define	TDA_REFLINE_LSB		MKREG(0x00, 0xa4)
1132b401c1dSians #define	TDA_NPIX_MSB		MKREG(0x00, 0xa5)
1142b401c1dSians #define	TDA_NPIX_LSB		MKREG(0x00, 0xa6)
1152b401c1dSians #define	TDA_NLINE_MSB		MKREG(0x00, 0xa7)
1162b401c1dSians #define	TDA_NLINE_LSB		MKREG(0x00, 0xa8)
1172b401c1dSians #define	TDA_VS_LINE_STRT_1_MSB	MKREG(0x00, 0xa9)
1182b401c1dSians #define	TDA_VS_LINE_STRT_1_LSB	MKREG(0x00, 0xaa)
1192b401c1dSians #define	TDA_VS_PIX_STRT_1_MSB	MKREG(0x00, 0xab)
1202b401c1dSians #define	TDA_VS_PIX_STRT_1_LSB	MKREG(0x00, 0xac)
1212b401c1dSians #define	TDA_VS_LINE_END_1_MSB	MKREG(0x00, 0xad)
1222b401c1dSians #define	TDA_VS_LINE_END_1_LSB	MKREG(0x00, 0xae)
1232b401c1dSians #define	TDA_VS_PIX_END_1_MSB	MKREG(0x00, 0xaf)
1242b401c1dSians #define	TDA_VS_PIX_END_1_LSB	MKREG(0x00, 0xb0)
1252b401c1dSians #define	TDA_VS_LINE_STRT_2_MSB	MKREG(0x00, 0xb1)
1262b401c1dSians #define	TDA_VS_LINE_STRT_2_LSB	MKREG(0x00, 0xb2)
1272b401c1dSians #define	TDA_VS_PIX_STRT_2_MSB	MKREG(0x00, 0xb3)
1282b401c1dSians #define	TDA_VS_PIX_STRT_2_LSB	MKREG(0x00, 0xb4)
1292b401c1dSians #define	TDA_VS_LINE_END_2_MSB	MKREG(0x00, 0xb5)
1302b401c1dSians #define	TDA_VS_LINE_END_2_LSB	MKREG(0x00, 0xb6)
1312b401c1dSians #define	TDA_VS_PIX_END_2_MSB	MKREG(0x00, 0xb7)
1322b401c1dSians #define	TDA_VS_PIX_END_2_LSB	MKREG(0x00, 0xb8)
1332b401c1dSians #define	TDA_HS_PIX_START_MSB	MKREG(0x00, 0xb9)
1342b401c1dSians #define	TDA_HS_PIX_START_LSB	MKREG(0x00, 0xba)
1352b401c1dSians #define	TDA_HS_PIX_STOP_MSB	MKREG(0x00, 0xbb)
1362b401c1dSians #define	TDA_HS_PIX_STOP_LSB	MKREG(0x00, 0xbc)
1372b401c1dSians #define	TDA_VWIN_START_1_MSB	MKREG(0x00, 0xbd)
1382b401c1dSians #define	TDA_VWIN_START_1_LSB	MKREG(0x00, 0xbe)
1392b401c1dSians #define	TDA_VWIN_END_1_MSB	MKREG(0x00, 0xbf)
1402b401c1dSians #define	TDA_VWIN_END_1_LSB	MKREG(0x00, 0xc0)
1412b401c1dSians #define	TDA_VWIN_START_2_MSB	MKREG(0x00, 0xc1)
1422b401c1dSians #define	TDA_VWIN_START_2_LSB	MKREG(0x00, 0xc2)
1432b401c1dSians #define	TDA_VWIN_END_2_MSB	MKREG(0x00, 0xc3)
1442b401c1dSians #define	TDA_VWIN_END_2_LSB	MKREG(0x00, 0xc4)
1452b401c1dSians #define	TDA_DE_START_MSB	MKREG(0x00, 0xc5)
1462b401c1dSians #define	TDA_DE_START_LSB	MKREG(0x00, 0xc6)
1472b401c1dSians #define	TDA_DE_STOP_MSB		MKREG(0x00, 0xc7)
1482b401c1dSians #define	TDA_DE_STOP_LSB		MKREG(0x00, 0xc8)
1492b401c1dSians 
1502b401c1dSians #define	TDA_TBG_CNTRL_0		MKREG(0x00, 0xca)
1512b401c1dSians #define		TBG_CNTRL_0_SYNC_ONCE	(1 << 7)
1522b401c1dSians #define		TBG_CNTRL_0_SYNC_MTHD	(1 << 6)
1532b401c1dSians 
1542b401c1dSians #define	TDA_TBG_CNTRL_1		MKREG(0x00, 0xcb)
1552b401c1dSians #define		TBG_CNTRL_1_DWIN_DIS	(1 << 6)
1562b401c1dSians #define		TBG_CNTRL_1_TGL_EN	(1 << 2)
1572b401c1dSians #define		TBG_CNTRL_1_V_TGL	(1 << 1)
1582b401c1dSians #define		TBG_CNTRL_1_H_TGL	(1 << 0)
1592b401c1dSians 
1602b401c1dSians #define	TDA_HVF_CNTRL_0		MKREG(0x00, 0xe4)
1612b401c1dSians #define		HVF_CNTRL_0_PREFIL_NONE		(0 << 2)
1622b401c1dSians #define		HVF_CNTRL_0_INTPOL_BYPASS	(0 << 0)
1632b401c1dSians #define	TDA_HVF_CNTRL_1		MKREG(0x00, 0xe5)
1642b401c1dSians #define		HVF_CNTRL_1_VQR(x)	(((x) & 3) << 2)
1652b401c1dSians #define		HVF_CNTRL_1_VQR_FULL	HVF_CNTRL_1_VQR(0)
1662b401c1dSians #define	TDA_ENABLE_SPACE	MKREG(0x00, 0xd6)
1672b401c1dSians #define	TDA_RPT_CNTRL		MKREG(0x00, 0xf0)
1682b401c1dSians 
1692b401c1dSians #define	TDA_PLL_SERIAL_1	MKREG(0x02, 0x00)
1702b401c1dSians #define		PLL_SERIAL_1_SRL_MAN_IP	(1 << 6)
1712b401c1dSians #define	TDA_PLL_SERIAL_2	MKREG(0x02, 0x01)
1722b401c1dSians #define		PLL_SERIAL_2_SRL_PR(x)		(((x) & 0xf) << 4)
1732b401c1dSians #define		PLL_SERIAL_2_SRL_NOSC(x)	(((x) & 0x3) << 0)
1742b401c1dSians #define	TDA_PLL_SERIAL_3	MKREG(0x02, 0x02)
1752b401c1dSians #define		PLL_SERIAL_3_SRL_PXIN_SEL	(1 << 4)
1762b401c1dSians #define		PLL_SERIAL_3_SRL_DE		(1 << 2)
1772b401c1dSians #define		PLL_SERIAL_3_SRL_CCIR		(1 << 0)
1782b401c1dSians #define	TDA_SERIALIZER		MKREG(0x02, 0x03)
1792b401c1dSians #define	TDA_BUFFER_OUT		MKREG(0x02, 0x04)
1802b401c1dSians #define	TDA_PLL_SCG1		MKREG(0x02, 0x05)
1812b401c1dSians #define	TDA_PLL_SCG2		MKREG(0x02, 0x06)
1822b401c1dSians #define	TDA_PLL_SCGN1		MKREG(0x02, 0x07)
1832b401c1dSians #define	TDA_PLL_SCGN2		MKREG(0x02, 0x08)
1842b401c1dSians #define	TDA_PLL_SCGR1		MKREG(0x02, 0x09)
1852b401c1dSians #define	TDA_PLL_SCGR2		MKREG(0x02, 0x0a)
1862b401c1dSians 
1872b401c1dSians #define	TDA_SEL_CLK		MKREG(0x02, 0x11)
1882b401c1dSians #define		SEL_CLK_ENA_SC_CLK	(1 << 3)
1892b401c1dSians #define		SEL_CLK_SEL_VRF_CLK(x)	(((x) & 3) << 1)
1902b401c1dSians #define		SEL_CLK_SEL_CLK1	(1 << 0)
1912b401c1dSians #define	TDA_ANA_GENERAL		MKREG(0x02, 0x12)
1922b401c1dSians 
1932b401c1dSians #define	TDA_EDID_DATA0		MKREG(0x09, 0x00)
1942b401c1dSians #define	TDA_EDID_CTRL		MKREG(0x09, 0xfa)
1952b401c1dSians #define	TDA_DDC_ADDR		MKREG(0x09, 0xfb)
1962b401c1dSians #define	TDA_DDC_OFFS		MKREG(0x09, 0xfc)
1972b401c1dSians #define	TDA_DDC_SEGM_ADDR	MKREG(0x09, 0xfd)
1982b401c1dSians #define	TDA_DDC_SEGM		MKREG(0x09, 0xfe)
1992b401c1dSians 
2002b401c1dSians #define	TDA_IF_VSP		MKREG(0x10, 0x20)
2012b401c1dSians #define	TDA_IF_AVI		MKREG(0x10, 0x40)
2022b401c1dSians #define	TDA_IF_SPD		MKREG(0x10, 0x60)
2032b401c1dSians #define	TDA_IF_AUD		MKREG(0x10, 0x80)
2042b401c1dSians #define	TDA_IF_MPS		MKREG(0x10, 0xa0)
2052b401c1dSians 
2062b401c1dSians #define	TDA_ENC_CNTRL		MKREG(0x11, 0x0d)
2072b401c1dSians #define		ENC_CNTRL_DVI_MODE	(0 << 2)
2082b401c1dSians #define		ENC_CNTRL_HDMI_MODE	(1 << 2)
2092b401c1dSians #define	TDA_DIP_IF_FLAGS	MKREG(0x11, 0x0f)
2102b401c1dSians #define		DIP_IF_FLAGS_IF5	(1 << 5)
2112b401c1dSians #define		DIP_IF_FLAGS_IF4	(1 << 4)
2122b401c1dSians #define		DIP_IF_FLAGS_IF3	(1 << 3)
2132b401c1dSians #define		DIP_IF_FLAGS_IF2	(1 << 2) /*  AVI IF on page 10h */
2142b401c1dSians #define		DIP_IF_FLAGS_IF1	(1 << 1)
2152b401c1dSians 
2162b401c1dSians #define	TDA_TX3			MKREG(0x12, 0x9a)
2172b401c1dSians #define	TDA_TX4			MKREG(0x12, 0x9b)
2182b401c1dSians #define		TX4_PD_RAM		(1 << 1)
2192b401c1dSians #define	TDA_HDCP_TX33		MKREG(0x12, 0xb8)
2202b401c1dSians #define		HDCP_TX33_HDMI		(1 << 1)
2212b401c1dSians 
2222b401c1dSians #define	TDA_CURPAGE_ADDR	0xff
2232b401c1dSians 
2242b401c1dSians #define	TDA_CEC_ENAMODS		0xff
2252b401c1dSians #define		ENAMODS_RXSENS		(1 << 2)
2262b401c1dSians #define		ENAMODS_HDMI		(1 << 1)
2272b401c1dSians #define	TDA_CEC_FRO_IM_CLK_CTRL	0xfb
2282b401c1dSians #define		CEC_FRO_IM_CLK_CTRL_GHOST_DIS	(1 << 7)
2292b401c1dSians #define		CEC_FRO_IM_CLK_CTRL_IMCLK_SEL	(1 << 1)
2302b401c1dSians 
2312b401c1dSians /* EDID reading */
2322b401c1dSians #define	EDID_LENGTH		0x80
2332b401c1dSians #define	MAX_READ_ATTEMPTS	100
2342b401c1dSians 
2352b401c1dSians /* EDID fields */
2362b401c1dSians #define	EDID_MODES0		35
2372b401c1dSians #define	EDID_MODES1		36
2382b401c1dSians #define	EDID_TIMING_START	38
2392b401c1dSians #define	EDID_TIMING_END		54
2402b401c1dSians #define	EDID_TIMING_X(v)	(((v) + 31) * 8)
2412b401c1dSians #define	EDID_FREQ(v)		(((v) & 0x3f) + 60)
2422b401c1dSians #define	EDID_RATIO(v)		(((v) >> 6) & 0x3)
2432b401c1dSians #define	EDID_RATIO_10x16	0
2442b401c1dSians #define	EDID_RATIO_3x4		1
2452b401c1dSians #define	EDID_RATIO_4x5		2
2462b401c1dSians #define	EDID_RATIO_9x16		3
2472b401c1dSians 
2482b401c1dSians /* NXP TDA19988 slave addrs. */
2492b401c1dSians #define	TDA_HDMI		0x70
2502b401c1dSians #define	TDA_CEC			0x34
2512b401c1dSians 
2522b401c1dSians /* debug/etc macros */
2532b401c1dSians #define DEVNAME(s)		((s)->sc_dev.dv_xname)
2542b401c1dSians #ifdef NXPTDA_DEBUG
2552b401c1dSians int nxphdmi_debug = 1;
2562b401c1dSians #define DPRINTF(n,s)	do { if ((n) <= nxphdmi_debug) printf s; } while (0)
2572b401c1dSians #else
2582b401c1dSians #define DPRINTF(n,s)	do {} while (0)
2592b401c1dSians #endif
2602b401c1dSians 
2612b401c1dSians struct nxphdmi_softc {
2622b401c1dSians 	struct device	sc_dev;
2632b401c1dSians 	i2c_tag_t	sc_tag;
2642b401c1dSians 	i2c_addr_t	sc_addr;
2652b401c1dSians 
2662b401c1dSians 	uint8_t		sc_curpage;
2672b401c1dSians 	uint8_t		sc_edid[EDID_LENGTH];
2682b401c1dSians };
2692b401c1dSians 
2702b401c1dSians int	nxphdmi_match(struct device *, void *, void *);
2712b401c1dSians void	nxphdmi_attach(struct device *, struct device *, void *);
2722b401c1dSians 
2732b401c1dSians int	nxphdmi_cec_read(struct nxphdmi_softc *, uint8_t, uint8_t *);
2742b401c1dSians int	nxphdmi_cec_write(struct nxphdmi_softc *, uint8_t, uint8_t);
2752b401c1dSians int	nxphdmi_read(struct nxphdmi_softc *, uint16_t, uint8_t *);
2762b401c1dSians int	nxphdmi_write(struct nxphdmi_softc *, uint16_t, uint8_t);
2772b401c1dSians int	nxphdmi_write2(struct nxphdmi_softc *, uint16_t, uint16_t);
2782b401c1dSians int	nxphdmi_set(struct nxphdmi_softc *, uint16_t, uint8_t);
2792b401c1dSians int	nxphdmi_clear(struct nxphdmi_softc *, uint16_t, uint8_t);
2802b401c1dSians int	nxphdmi_set_page(struct nxphdmi_softc *, uint8_t);
2812b401c1dSians int	nxphdmi_read_edid(struct nxphdmi_softc *);
2822b401c1dSians int	nxphdmi_reset(struct nxphdmi_softc *);
2832b401c1dSians int	nxphdmi_init_encoder(struct nxphdmi_softc *, struct videomode *);
2842b401c1dSians 
2852b401c1dSians int	nxphdmi_get_edid(uint8_t *, int);
2862b401c1dSians int	nxphdmi_set_videomode(struct videomode *);
2872b401c1dSians 
288*9fdf0c62Smpi const struct cfattach nxphdmi_ca = {
2892b401c1dSians 	sizeof(struct nxphdmi_softc), nxphdmi_match, nxphdmi_attach
2902b401c1dSians };
2912b401c1dSians 
2922b401c1dSians struct cfdriver nxphdmi_cd = {
2932b401c1dSians 	NULL, "nxphdmi", DV_DULL
2942b401c1dSians };
2952b401c1dSians 
2962b401c1dSians int
nxphdmi_match(struct device * parent,void * match,void * aux)2972b401c1dSians nxphdmi_match(struct device *parent, void *match, void *aux)
2982b401c1dSians {
2992b401c1dSians 	struct i2c_attach_args *ia = aux;
3002b401c1dSians 
3012b401c1dSians 	if (strcmp(ia->ia_name, "nxp,tda998x") == 0)
3022b401c1dSians 		return 1;
3032b401c1dSians 
3042b401c1dSians 	return 0;
3052b401c1dSians }
3062b401c1dSians 
3072b401c1dSians void
nxphdmi_attach(struct device * parent,struct device * self,void * aux)3082b401c1dSians nxphdmi_attach(struct device *parent, struct device *self, void *aux)
3092b401c1dSians {
3102b401c1dSians 	struct nxphdmi_softc *sc = (struct nxphdmi_softc *)self;
3112b401c1dSians 	struct i2c_attach_args *ia = aux;
3122b401c1dSians 	uint8_t data = 0;
3132b401c1dSians 	uint16_t version = 0;
3142b401c1dSians 	int res = 0, node = *(int *)(ia->ia_cookie);
3152b401c1dSians 
3162b401c1dSians 	sc->sc_tag = ia->ia_tag;
3172b401c1dSians 	sc->sc_addr = ia->ia_addr;
3182b401c1dSians 	sc->sc_curpage = 0xff;
3192b401c1dSians 
3202b401c1dSians 	if (!node) {
3212b401c1dSians 		printf(": not configured\n");
3222b401c1dSians 		return;
3232b401c1dSians 	} else if ((pinctrl_byname(node, "default") == -1)) {
3242b401c1dSians 		printf(": not configured\n");
3252b401c1dSians 		return;
3262b401c1dSians 	}
3272b401c1dSians 
3282b401c1dSians 	iic_acquire_bus(sc->sc_tag, 0);
3292b401c1dSians 
3302b401c1dSians 	DPRINTF(3,("\n"));
3312b401c1dSians 
3322b401c1dSians 	/* enable HDMI core */
3332b401c1dSians 	nxphdmi_cec_write(sc, TDA_CEC_ENAMODS, ENAMODS_RXSENS | ENAMODS_HDMI);
3342b401c1dSians 	delay(1000);
3352b401c1dSians 
3362b401c1dSians 	if (!(nxphdmi_reset(sc)))
3372b401c1dSians 		DPRINTF(3,("%s: software reset OK\n", DEVNAME(sc)));
3382b401c1dSians 	else
3392b401c1dSians 		DPRINTF(3,("%s: software reset failed!\n", DEVNAME(sc)));
3402b401c1dSians 
3412b401c1dSians 	/*  PLL registers common configuration */
3422b401c1dSians 	nxphdmi_write(sc, TDA_PLL_SERIAL_1, 0x00);
3432b401c1dSians 	nxphdmi_write(sc, TDA_PLL_SERIAL_2, PLL_SERIAL_2_SRL_NOSC(1));
3442b401c1dSians 	nxphdmi_write(sc, TDA_PLL_SERIAL_3, 0x00);
3452b401c1dSians 	nxphdmi_write(sc, TDA_SERIALIZER, 0x00);
3462b401c1dSians 	nxphdmi_write(sc, TDA_BUFFER_OUT, 0x00);
3472b401c1dSians 	nxphdmi_write(sc, TDA_PLL_SCG1, 0x00);
3482b401c1dSians 	nxphdmi_write(sc, TDA_SEL_CLK, SEL_CLK_SEL_CLK1 | SEL_CLK_ENA_SC_CLK);
3492b401c1dSians 	nxphdmi_write(sc, TDA_PLL_SCGN1, 0xfa);
3502b401c1dSians 	nxphdmi_write(sc, TDA_PLL_SCGN2, 0x00);
3512b401c1dSians 	nxphdmi_write(sc, TDA_PLL_SCGR1, 0x5b);
3522b401c1dSians 	nxphdmi_write(sc, TDA_PLL_SCGR2, 0x00);
3532b401c1dSians 	nxphdmi_write(sc, TDA_PLL_SCG2, 0x10);
3542b401c1dSians 
3552b401c1dSians 	/*  Write the default value MUX register */
3562b401c1dSians 	nxphdmi_write(sc, TDA_MUX_VP_VIP_OUT, 0x24);
3572b401c1dSians 
3582b401c1dSians 	res |= nxphdmi_read(sc, TDA_VERSION, &data);
3592b401c1dSians 	version |= data;
3602b401c1dSians 	res |= nxphdmi_read(sc, TDA_VERSION_MSB, &data);
3612b401c1dSians 	version |= (data << 8);
3622b401c1dSians 	version &= ~0x30;
3632b401c1dSians 
3642b401c1dSians 	if (!res) {
3652b401c1dSians 		DPRINTF(3,("%s: ", DEVNAME(sc)));
3662b401c1dSians 		printf(": rev 0x%04x\n", version);
3672b401c1dSians 	} else {
3682b401c1dSians 		DPRINTF(3,("%s: ", DEVNAME(sc)));
3692b401c1dSians 		printf(": failed to enable HDMI core, exiting...\n");
3702b401c1dSians 		iic_release_bus(sc->sc_tag, 0);
3712b401c1dSians 		return;
3722b401c1dSians 	}
3732b401c1dSians 
3742b401c1dSians 	nxphdmi_write(sc, TDA_DDC_CTRL, DDC_ENABLE);
3752b401c1dSians 	nxphdmi_write(sc, TDA_TX3, 39);
3762b401c1dSians 
3772b401c1dSians 	nxphdmi_cec_write(sc, TDA_CEC_FRO_IM_CLK_CTRL,
3782b401c1dSians 	    CEC_FRO_IM_CLK_CTRL_GHOST_DIS | CEC_FRO_IM_CLK_CTRL_IMCLK_SEL);
3792b401c1dSians 
3802b401c1dSians 	if (nxphdmi_read_edid(sc)) {
3812b401c1dSians 		DPRINTF(3,("%s: failed to read EDID bits, exiting!\n",
3822b401c1dSians 		    DEVNAME(sc)));
3832b401c1dSians 		return;
3842b401c1dSians 	}
3852b401c1dSians 
3862b401c1dSians 	/*  Default values for RGB 4:4:4 mapping */
3872b401c1dSians 	nxphdmi_write(sc, TDA_VIP_CNTRL_0, 0x23);
3882b401c1dSians 	nxphdmi_write(sc, TDA_VIP_CNTRL_1, 0x01);
3892b401c1dSians 	nxphdmi_write(sc, TDA_VIP_CNTRL_2, 0x45);
3902b401c1dSians 
3912b401c1dSians 	iic_release_bus(sc->sc_tag, 0);
3922b401c1dSians }
3932b401c1dSians 
3942b401c1dSians int
nxphdmi_cec_read(struct nxphdmi_softc * sc,uint8_t addr,uint8_t * buf)3952b401c1dSians nxphdmi_cec_read(struct nxphdmi_softc *sc, uint8_t addr, uint8_t *buf)
3962b401c1dSians {
3972b401c1dSians 	int ret = 0;
3982b401c1dSians 
3992b401c1dSians 	if ((ret |= iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP, TDA_CEC,
4002b401c1dSians 	    &addr, 1, NULL, 0, 0))) {
4012b401c1dSians 		DPRINTF(3,("%s: (CEC) failed to read addr 0x%02x, errno %d\n",
4022b401c1dSians 		    DEVNAME(sc), addr, ret));
4032b401c1dSians 		return ret;
4042b401c1dSians 	}
4052b401c1dSians 
4062b401c1dSians 	DPRINTF(3,("%s: (CEC) read 0x%02x from 0x%02x\n", DEVNAME(sc), *buf,
4072b401c1dSians 	    addr));
4082b401c1dSians 
4092b401c1dSians 	return ret;
4102b401c1dSians }
4112b401c1dSians 
4122b401c1dSians int
nxphdmi_cec_write(struct nxphdmi_softc * sc,uint8_t addr,uint8_t val)4132b401c1dSians nxphdmi_cec_write(struct nxphdmi_softc *sc, uint8_t addr, uint8_t val)
4142b401c1dSians {
4152b401c1dSians 	int ret = 0;
4162b401c1dSians 	uint8_t sendbuf[] = { addr, val };
4172b401c1dSians 
4182b401c1dSians 	if ((ret |= iic_exec(sc->sc_tag, I2C_OP_WRITE_WITH_STOP, TDA_CEC,
4192b401c1dSians 	    &sendbuf, 2, NULL, 0, 0))) {
4202b401c1dSians 		DPRINTF(3,(
4212b401c1dSians 		    "%s: (CEC) failed to write 0x%02x to 0x%02x, errno %d\n",
4222b401c1dSians 		    DEVNAME(sc), val, addr, ret));
4232b401c1dSians 		return ret;
4242b401c1dSians 	}
4252b401c1dSians 
4262b401c1dSians 	DPRINTF(3,("%s: (CEC) wrote 0x%02x to 0x%02x\n", DEVNAME(sc), val,
4272b401c1dSians 	    addr));
4282b401c1dSians 
4292b401c1dSians 	return ret;
4302b401c1dSians }
4312b401c1dSians 
4322b401c1dSians int
nxphdmi_read(struct nxphdmi_softc * sc,uint16_t reg,uint8_t * buf)4332b401c1dSians nxphdmi_read(struct nxphdmi_softc *sc, uint16_t reg, uint8_t *buf)
4342b401c1dSians {
4352b401c1dSians 	int ret = 0;
4362b401c1dSians 
4372b401c1dSians 	nxphdmi_set_page(sc, REGPAGE(reg));
4382b401c1dSians 
4392b401c1dSians 	if ((ret = iic_smbus_read_byte(sc->sc_tag, TDA_HDMI, REGADDR(reg),
4402b401c1dSians 	    buf, 0))) {
4412b401c1dSians 		DPRINTF(3,(
4422b401c1dSians 		    "%s: failed to read addr 0x%02x on page 0x%02x, errno %d\n",
4432b401c1dSians 		    DEVNAME(sc), REGADDR(reg), REGPAGE(reg), ret));
4442b401c1dSians 		return ret;
4452b401c1dSians 	}
4462b401c1dSians 
4472b401c1dSians 	DPRINTF(3,("%s: read  0x%02x from 0x%02x on page 0x%02x\n",
4482b401c1dSians 	    DEVNAME(sc), *buf, REGADDR(reg), REGPAGE(reg)));
4492b401c1dSians 
4502b401c1dSians 	return ret;
4512b401c1dSians }
4522b401c1dSians 
4532b401c1dSians int
nxphdmi_write(struct nxphdmi_softc * sc,uint16_t reg,uint8_t val)4542b401c1dSians nxphdmi_write(struct nxphdmi_softc *sc, uint16_t reg, uint8_t val)
4552b401c1dSians {
4562b401c1dSians 	int ret = 0;
4572b401c1dSians 	uint8_t sendbuf[] = { REGADDR(reg), val };
4582b401c1dSians 
4592b401c1dSians 	nxphdmi_set_page(sc, REGPAGE(reg));
4602b401c1dSians 
4612b401c1dSians 	if ((ret = iic_exec(sc->sc_tag, I2C_OP_WRITE_WITH_STOP, TDA_HDMI,
4622b401c1dSians 	    &sendbuf, 2, NULL, 0, 0))) {
4632b401c1dSians 	    DPRINTF(3,(
4642b401c1dSians 		"%s: failed to write 0x%02x to 0x%02x on page 0x%02x, errno %d\n",
4652b401c1dSians 		DEVNAME(sc), val, REGADDR(reg), REGPAGE(reg), ret));
4662b401c1dSians 		return ret;
4672b401c1dSians 	}
4682b401c1dSians 
4692b401c1dSians 	DPRINTF(3,("%s: wrote 0x%02x  to  0x%02x on page 0x%02x\n",
4702b401c1dSians 	    DEVNAME(sc), val, REGADDR(reg), REGPAGE(reg)));
4712b401c1dSians 
4722b401c1dSians 	return ret;
4732b401c1dSians }
4742b401c1dSians 
4752b401c1dSians int
nxphdmi_write2(struct nxphdmi_softc * sc,uint16_t reg,uint16_t val)4762b401c1dSians nxphdmi_write2(struct nxphdmi_softc *sc, uint16_t reg, uint16_t val)
4772b401c1dSians {
4782b401c1dSians 	int ret = 0;
4792b401c1dSians 	uint8_t sendbuf[] = { REGADDR(reg), val >> 8, val & 0xff };
4802b401c1dSians 
4812b401c1dSians 	nxphdmi_set_page(sc, REGPAGE(reg));
4822b401c1dSians 
4832b401c1dSians 	if ((ret = iic_exec(sc->sc_tag, I2C_OP_WRITE_WITH_STOP, TDA_HDMI,
4842b401c1dSians 	    &sendbuf, 3, NULL, 0, 0))) {
4852b401c1dSians 		DPRINTF(3,(
4862b401c1dSians 		"%s: failed to write 0x%04x to 0x%02x on page 0x%02x, errno %d\n",
4872b401c1dSians 		DEVNAME(sc), val, REGADDR(reg), REGPAGE(reg), ret));
4882b401c1dSians 		return ret;
4892b401c1dSians 	}
4902b401c1dSians 
4912b401c1dSians 	DPRINTF(3,("%s: wrote 0x%04x  to  0x%02x on page 0x%02x\n",
4922b401c1dSians 	    DEVNAME(sc), val, REGADDR(reg), REGPAGE(reg)));
4932b401c1dSians 
4942b401c1dSians 	return ret;
4952b401c1dSians 
4962b401c1dSians }
4972b401c1dSians 
4982b401c1dSians int
nxphdmi_set(struct nxphdmi_softc * sc,uint16_t reg,uint8_t bits)4992b401c1dSians nxphdmi_set(struct nxphdmi_softc *sc, uint16_t reg, uint8_t bits)
5002b401c1dSians {
5012b401c1dSians 	int ret = 0;
5022b401c1dSians 	uint8_t buf;
5032b401c1dSians 
5042b401c1dSians 	ret |= nxphdmi_read(sc, reg, &buf);
5052b401c1dSians 	buf |= bits;
5062b401c1dSians 	ret |= nxphdmi_write(sc, reg, buf);
5072b401c1dSians 
5082b401c1dSians 	return ret;
5092b401c1dSians }
5102b401c1dSians 
5112b401c1dSians int
nxphdmi_clear(struct nxphdmi_softc * sc,uint16_t reg,uint8_t bits)5122b401c1dSians nxphdmi_clear(struct nxphdmi_softc *sc, uint16_t reg, uint8_t bits)
5132b401c1dSians {
5142b401c1dSians 	int ret = 0;
5152b401c1dSians 	uint8_t buf;
5162b401c1dSians 
5172b401c1dSians 	ret |= nxphdmi_read(sc, reg, &buf);
5182b401c1dSians 	buf &= ~bits;
5192b401c1dSians 	ret |= nxphdmi_write(sc, reg, buf);
5202b401c1dSians 
5212b401c1dSians 	return ret;
5222b401c1dSians }
5232b401c1dSians 
5242b401c1dSians int
nxphdmi_set_page(struct nxphdmi_softc * sc,uint8_t page)5252b401c1dSians nxphdmi_set_page(struct nxphdmi_softc *sc, uint8_t page)
5262b401c1dSians {
5272b401c1dSians 	int ret = 0;
5282b401c1dSians 	uint8_t sendbuf[] = { TDA_CURPAGE_ADDR, page };
5292b401c1dSians 
5302b401c1dSians 	if (sc->sc_curpage == page)
5312b401c1dSians 		return ret;
5322b401c1dSians 
5332b401c1dSians 	if ((ret = iic_exec(sc->sc_tag, I2C_OP_WRITE_WITH_STOP, TDA_HDMI,
5342b401c1dSians 	    &sendbuf, sizeof(sendbuf), NULL, 0, 0))) {
5352b401c1dSians 		DPRINTF(3,("%s: failed to set memory page 0x%02x, errno %d\n",
5362b401c1dSians 		    DEVNAME(sc),
5372b401c1dSians 		page, ret));
5382b401c1dSians 		return ret;
5392b401c1dSians 	}
5402b401c1dSians 
5412b401c1dSians 	sc->sc_curpage = page;
5422b401c1dSians 	DPRINTF(3,("%s: set page to 0x%02x\n", DEVNAME(sc), page));
5432b401c1dSians 
5442b401c1dSians 	return ret;
5452b401c1dSians }
5462b401c1dSians 
5472b401c1dSians int
nxphdmi_read_edid(struct nxphdmi_softc * sc)5482b401c1dSians nxphdmi_read_edid(struct nxphdmi_softc *sc)
5492b401c1dSians {
5502b401c1dSians 	int i = 0, ret = 0;
5512b401c1dSians 	uint8_t reg;
5522b401c1dSians 
5532b401c1dSians 	nxphdmi_set(sc, TDA_INT_FLAGS_2, INT_FLAGS_2_EDID_BLK_RD);
5542b401c1dSians 
5552b401c1dSians 	/*  Block 0 */
5562b401c1dSians 	nxphdmi_write(sc, TDA_DDC_ADDR, 0xa0);
5572b401c1dSians 	nxphdmi_write(sc, TDA_DDC_OFFS, 0x00);
5582b401c1dSians 	nxphdmi_write(sc, TDA_DDC_SEGM_ADDR, 0x60);
5592b401c1dSians 	nxphdmi_write(sc, TDA_DDC_SEGM, 0x00);
5602b401c1dSians 
5612b401c1dSians 	nxphdmi_write(sc, TDA_EDID_CTRL, 1);
5622b401c1dSians 	nxphdmi_write(sc, TDA_EDID_CTRL, 0);
5632b401c1dSians 
5642b401c1dSians 	for (; i < MAX_READ_ATTEMPTS; i++) {
5652b401c1dSians 		nxphdmi_read(sc, TDA_INT_FLAGS_2, &reg);
5662b401c1dSians 		if (reg & INT_FLAGS_2_EDID_BLK_RD) {
5672b401c1dSians 			DPRINTF(3,("%s: EDID-ready IRQ fired\n", DEVNAME(sc)));
5682b401c1dSians 			break;
5692b401c1dSians 		}
5702b401c1dSians 	}
5712b401c1dSians 
5722b401c1dSians 	if (i == MAX_READ_ATTEMPTS) {
5732b401c1dSians 		printf("%s: no display detected\n", DEVNAME(sc));
5742b401c1dSians 		ret = ENXIO;
5752b401c1dSians 		return ret;
5762b401c1dSians 	}
5772b401c1dSians 
5782b401c1dSians 	nxphdmi_set_page(sc, 0x09);
5792b401c1dSians 
5802b401c1dSians 	reg = 0x00;
5812b401c1dSians 	DPRINTF(1,("%s: ------------- EDID -------------", DEVNAME(sc)));
5822b401c1dSians 	for (i = 0; i < EDID_LENGTH; i++) {
5832b401c1dSians 		iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP, TDA_HDMI, &reg, 1,
5842b401c1dSians 		    &sc->sc_edid[i], 1, 0);
5852b401c1dSians 		if (!(i % 16))
5862b401c1dSians 			DPRINTF(1,("\n%s: ", DEVNAME(sc)));
5872b401c1dSians 		DPRINTF(1,("%02x", sc->sc_edid[i]));
5882b401c1dSians 		reg++;
5892b401c1dSians 	}
5902b401c1dSians 	DPRINTF(1,("\n%s: --------------------------------\n", DEVNAME(sc)));
5912b401c1dSians 
5922b401c1dSians 	nxphdmi_clear(sc, TDA_INT_FLAGS_2, INT_FLAGS_2_EDID_BLK_RD);
5932b401c1dSians 	nxphdmi_set(sc, TDA_TX4, TX4_PD_RAM);
5942b401c1dSians 
5952b401c1dSians 	return ret;
5962b401c1dSians }
5972b401c1dSians 
5982b401c1dSians int
nxphdmi_reset(struct nxphdmi_softc * sc)5992b401c1dSians nxphdmi_reset(struct nxphdmi_softc *sc)
6002b401c1dSians {
6012b401c1dSians 	int ret = 0;
6022b401c1dSians 
6032b401c1dSians 	/* reset core */
6042b401c1dSians 	ret |= nxphdmi_set(sc, TDA_SOFTRESET, 3);
6052b401c1dSians 	delay(100);
6062b401c1dSians 	ret |= nxphdmi_clear(sc, TDA_SOFTRESET, 3);
6072b401c1dSians 	delay(100);
6082b401c1dSians 
6092b401c1dSians 	/* reset transmitter */
6102b401c1dSians 	ret |= nxphdmi_set(sc, TDA_MAIN_CNTRL0, MAIN_CNTRL0_SR);
6112b401c1dSians 	ret |= nxphdmi_clear(sc, TDA_MAIN_CNTRL0, MAIN_CNTRL0_SR);
6122b401c1dSians 
6132b401c1dSians 	return ret;
6142b401c1dSians }
6152b401c1dSians 
6162b401c1dSians int
nxphdmi_init_encoder(struct nxphdmi_softc * sc,struct videomode * mode)6172b401c1dSians nxphdmi_init_encoder(struct nxphdmi_softc *sc, struct videomode *mode)
6182b401c1dSians {
6192b401c1dSians 	int ret = 0;
6202b401c1dSians 
6212b401c1dSians 	uint16_t ref_pix, ref_line, n_pix, n_line;
6222b401c1dSians 	uint16_t hs_pix_start, hs_pix_stop;
6232b401c1dSians 	uint16_t vs1_pix_start, vs1_pix_stop;
6242b401c1dSians 	uint16_t vs1_line_start, vs1_line_end;
6252b401c1dSians 	uint16_t vs2_pix_start, vs2_pix_stop;
6262b401c1dSians 	uint16_t vs2_line_start, vs2_line_end;
6272b401c1dSians 	uint16_t vwin1_line_start, vwin1_line_end;
6282b401c1dSians 	uint16_t vwin2_line_start, vwin2_line_end;
6292b401c1dSians 	uint16_t de_start, de_stop;
6302b401c1dSians 	uint8_t reg, div;
6312b401c1dSians 
6322b401c1dSians 	n_pix = mode->htotal;
6332b401c1dSians 	n_line = mode->vtotal;
6342b401c1dSians 
6352b401c1dSians 	hs_pix_stop = mode->hsync_end - mode->hdisplay;
6362b401c1dSians 	hs_pix_start = mode->hsync_start - mode->hdisplay;
6372b401c1dSians 
6382b401c1dSians 	de_stop = mode->htotal;
6392b401c1dSians 	de_start = mode->htotal - mode->hdisplay;
6402b401c1dSians 	ref_pix = hs_pix_start + 3;
6412b401c1dSians 
6422b401c1dSians 	if (mode->flags & VID_HSKEW)
6432b401c1dSians 		ref_pix += mode->hsync_end - mode->hsync_start;
6442b401c1dSians 
6452b401c1dSians 	if ((mode->flags & VID_INTERLACE) == 0) {
6462b401c1dSians 		ref_line = 1 + mode->vsync_start - mode->vdisplay;
6472b401c1dSians 		vwin1_line_start = mode->vtotal - mode->vdisplay - 1;
6482b401c1dSians 		vwin1_line_end = vwin1_line_start + mode->vdisplay;
6492b401c1dSians 
6502b401c1dSians 		vs1_pix_start = vs1_pix_stop = hs_pix_start;
6512b401c1dSians 		vs1_line_start = mode->vsync_start - mode->vdisplay;
6522b401c1dSians 		vs1_line_end = vs1_line_start +
6532b401c1dSians 		    mode->vsync_end - mode->vsync_start;
6542b401c1dSians 
6552b401c1dSians 		vwin2_line_start = vwin2_line_end = 0;
6562b401c1dSians 		vs2_pix_start = vs2_pix_stop = 0;
6572b401c1dSians 		vs2_line_start = vs2_line_end = 0;
6582b401c1dSians 	} else {
6592b401c1dSians 		ref_line = 1 + (mode->vsync_start - mode->vdisplay)/2;
6602b401c1dSians 		vwin1_line_start = (mode->vtotal - mode->vdisplay)/2;
6612b401c1dSians 		vwin1_line_end = vwin1_line_start + mode->vdisplay/2;
6622b401c1dSians 
6632b401c1dSians 		vs1_pix_start = vs1_pix_stop = hs_pix_start;
6642b401c1dSians 		vs1_line_start = (mode->vsync_start - mode->vdisplay)/2;
6652b401c1dSians 		vs1_line_end = vs1_line_start +
6662b401c1dSians 		    (mode->vsync_end - mode->vsync_start)/2;
6672b401c1dSians 
6682b401c1dSians 		vwin2_line_start = vwin1_line_start + mode->vtotal/2;
6692b401c1dSians 		vwin2_line_end = vwin2_line_start + mode->vdisplay/2;
6702b401c1dSians 
6712b401c1dSians 		vs2_pix_start = vs2_pix_stop = hs_pix_start + mode->htotal/2;
6722b401c1dSians 		vs2_line_start = vs1_line_start + mode->vtotal/2 ;
6732b401c1dSians 		vs2_line_end = vs2_line_start +
6742b401c1dSians 		    (mode->vsync_end - mode->vsync_start)/2;
6752b401c1dSians 	}
6762b401c1dSians 
6772b401c1dSians 	div = 148500 / mode->dot_clock;
6782b401c1dSians 	if (div != 0) {
6792b401c1dSians 		div--;
6802b401c1dSians 		if (div > 3)
6812b401c1dSians 			div = 3;
6822b401c1dSians 	}
6832b401c1dSians 
6842b401c1dSians 	/*  set HDMI HDCP mode off */
6852b401c1dSians 	nxphdmi_set(sc, TDA_TBG_CNTRL_1, TBG_CNTRL_1_DWIN_DIS);
6862b401c1dSians 	nxphdmi_clear(sc, TDA_HDCP_TX33, HDCP_TX33_HDMI);
6872b401c1dSians 	nxphdmi_write(sc, TDA_ENC_CNTRL, ENC_CNTRL_DVI_MODE);
6882b401c1dSians 
6892b401c1dSians 	/*  no pre-filter or interpolator */
6902b401c1dSians 	nxphdmi_write(sc, TDA_HVF_CNTRL_0,
6912b401c1dSians 	    HVF_CNTRL_0_INTPOL_BYPASS | HVF_CNTRL_0_PREFIL_NONE);
6922b401c1dSians 	nxphdmi_write(sc, TDA_VIP_CNTRL_5, VIP_CNTRL_5_SP_CNT(0));
6932b401c1dSians 	nxphdmi_write(sc, TDA_VIP_CNTRL_4,
6942b401c1dSians 	    VIP_CNTRL_4_BLANKIT_NDE | VIP_CNTRL_4_BLC_NONE);
6952b401c1dSians 
6962b401c1dSians 	nxphdmi_clear(sc, TDA_PLL_SERIAL_3, PLL_SERIAL_3_SRL_CCIR);
6972b401c1dSians 	nxphdmi_clear(sc, TDA_PLL_SERIAL_1, PLL_SERIAL_1_SRL_MAN_IP);
6982b401c1dSians 	nxphdmi_clear(sc, TDA_PLL_SERIAL_3, PLL_SERIAL_3_SRL_DE);
6992b401c1dSians 	nxphdmi_write(sc, TDA_SERIALIZER, 0);
7002b401c1dSians 	nxphdmi_write(sc, TDA_HVF_CNTRL_1, HVF_CNTRL_1_VQR_FULL);
7012b401c1dSians 
7022b401c1dSians 	nxphdmi_write(sc, TDA_RPT_CNTRL, 0);
7032b401c1dSians 	nxphdmi_write(sc, TDA_SEL_CLK, SEL_CLK_SEL_VRF_CLK(0) |
7042b401c1dSians 			SEL_CLK_SEL_CLK1 | SEL_CLK_ENA_SC_CLK);
7052b401c1dSians 
7062b401c1dSians 	nxphdmi_write(sc, TDA_PLL_SERIAL_2, PLL_SERIAL_2_SRL_NOSC(div) |
7072b401c1dSians 			PLL_SERIAL_2_SRL_PR(0));
7082b401c1dSians 
7092b401c1dSians 	nxphdmi_set(sc, TDA_MAT_CONTRL, MAT_CONTRL_MAT_BP);
7102b401c1dSians 
7112b401c1dSians 	nxphdmi_write(sc, TDA_ANA_GENERAL, 0x09);
7122b401c1dSians 
7132b401c1dSians 	nxphdmi_clear(sc, TDA_TBG_CNTRL_0, TBG_CNTRL_0_SYNC_MTHD);
7142b401c1dSians 
7152b401c1dSians 	/*
7162b401c1dSians 	 * Sync on rising HSYNC/VSYNC
7172b401c1dSians 	 */
7182b401c1dSians 	reg = VIP_CNTRL_3_SYNC_HS;
7192b401c1dSians 	if (mode->flags & VID_NHSYNC)
7202b401c1dSians 		reg |= VIP_CNTRL_3_H_TGL;
7212b401c1dSians 	if (mode->flags & VID_NVSYNC)
7222b401c1dSians 		reg |= VIP_CNTRL_3_V_TGL;
7232b401c1dSians 	nxphdmi_write(sc, TDA_VIP_CNTRL_3, reg);
7242b401c1dSians 
7252b401c1dSians 	reg = TBG_CNTRL_1_TGL_EN;
7262b401c1dSians 	if (mode->flags & VID_NHSYNC)
7272b401c1dSians 		reg |= TBG_CNTRL_1_H_TGL;
7282b401c1dSians 	if (mode->flags & VID_NVSYNC)
7292b401c1dSians 		reg |= TBG_CNTRL_1_V_TGL;
7302b401c1dSians 	nxphdmi_write(sc, TDA_TBG_CNTRL_1, reg);
7312b401c1dSians 
7322b401c1dSians 	/*  Program timing */
7332b401c1dSians 	nxphdmi_write(sc, TDA_VIDFORMAT, 0x00);
7342b401c1dSians 
7352b401c1dSians 	nxphdmi_write2(sc, TDA_REFPIX_MSB, ref_pix);
7362b401c1dSians 	nxphdmi_write2(sc, TDA_REFLINE_MSB, ref_line);
7372b401c1dSians 	nxphdmi_write2(sc, TDA_NPIX_MSB, n_pix);
7382b401c1dSians 	nxphdmi_write2(sc, TDA_NLINE_MSB, n_line);
7392b401c1dSians 
7402b401c1dSians 	nxphdmi_write2(sc, TDA_VS_LINE_STRT_1_MSB, vs1_line_start);
7412b401c1dSians 	nxphdmi_write2(sc, TDA_VS_PIX_STRT_1_MSB, vs1_pix_start);
7422b401c1dSians 	nxphdmi_write2(sc, TDA_VS_LINE_END_1_MSB, vs1_line_end);
7432b401c1dSians 	nxphdmi_write2(sc, TDA_VS_PIX_END_1_MSB, vs1_pix_stop);
7442b401c1dSians 	nxphdmi_write2(sc, TDA_VS_LINE_STRT_2_MSB, vs2_line_start);
7452b401c1dSians 	nxphdmi_write2(sc, TDA_VS_PIX_STRT_2_MSB, vs2_pix_start);
7462b401c1dSians 	nxphdmi_write2(sc, TDA_VS_LINE_END_2_MSB, vs2_line_end);
7472b401c1dSians 	nxphdmi_write2(sc, TDA_VS_PIX_END_2_MSB, vs2_pix_stop);
7482b401c1dSians 	nxphdmi_write2(sc, TDA_HS_PIX_START_MSB, hs_pix_start);
7492b401c1dSians 	nxphdmi_write2(sc, TDA_HS_PIX_STOP_MSB, hs_pix_stop);
7502b401c1dSians 	nxphdmi_write2(sc, TDA_VWIN_START_1_MSB, vwin1_line_start);
7512b401c1dSians 	nxphdmi_write2(sc, TDA_VWIN_END_1_MSB, vwin1_line_end);
7522b401c1dSians 	nxphdmi_write2(sc, TDA_VWIN_START_2_MSB, vwin2_line_start);
7532b401c1dSians 	nxphdmi_write2(sc, TDA_VWIN_END_2_MSB, vwin2_line_end);
7542b401c1dSians 	nxphdmi_write2(sc, TDA_DE_START_MSB, de_start);
7552b401c1dSians 	nxphdmi_write2(sc, TDA_DE_STOP_MSB, de_stop);
7562b401c1dSians 
7572b401c1dSians 	nxphdmi_write(sc, TDA_ENABLE_SPACE, 0x00);
7582b401c1dSians 
7592b401c1dSians 	/*  must be last register set */
7602b401c1dSians 	nxphdmi_clear(sc, TDA_TBG_CNTRL_0, TBG_CNTRL_0_SYNC_ONCE);
7612b401c1dSians 
7622b401c1dSians 	return ret;
7632b401c1dSians }
7642b401c1dSians 
7652b401c1dSians int
nxphdmi_get_edid(uint8_t * buf,int buflen)7662b401c1dSians nxphdmi_get_edid(uint8_t *buf, int buflen)
7672b401c1dSians {
7682b401c1dSians 	int ret = 0, i;
7692b401c1dSians 	struct nxphdmi_softc *sc = nxphdmi_cd.cd_devs[0];
7702b401c1dSians 
771675d1f44Sjsg 	if (buflen < EDID_LENGTH)
7722b401c1dSians 		return -1;
7732b401c1dSians 
7742b401c1dSians 	for (i = 0; i < EDID_LENGTH; i++)
7752b401c1dSians 		buf[i] = sc->sc_edid[i];
7762b401c1dSians 
7772b401c1dSians 	return ret;
7782b401c1dSians }
7792b401c1dSians 
7802b401c1dSians int
nxphdmi_set_videomode(struct videomode * mode)7812b401c1dSians nxphdmi_set_videomode(struct videomode *mode)
7822b401c1dSians {
7832b401c1dSians 	int ret = 0;
7842b401c1dSians 	struct nxphdmi_softc *sc = nxphdmi_cd.cd_devs[0];
7852b401c1dSians 
7862b401c1dSians 	ret = nxphdmi_init_encoder(sc, mode);
7872b401c1dSians 
7882b401c1dSians 	return ret;
7892b401c1dSians }
790